afb-cred: fix default values
[src/app-framework-binder.git] / src / afb-cred.c
1 /*
2  * Copyright (C) 2017 "IoT.bzh"
3  * Author: José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #include "afb-cred.h"
29
30 #define MAX_LABEL_LENGTH  1024
31
32 #if !defined(NO_DEFAULT_PEERCRED) && !defined(ADD_DEFAULT_PEERCRED)
33 #  define NO_DEFAULT_PEERCRED
34 #endif
35
36 #if !defined(DEFAULT_PEERSEC_LABEL)
37 #  define DEFAULT_PEERSEC_LABEL "NoLabel"
38 #endif
39 #if !defined(DEFAULT_PEERCRED_UID)
40 #  define DEFAULT_PEERCRED_UID 99 /* nobody */
41 #endif
42 #if !defined(DEFAULT_PEERCRED_GID)
43 #  define DEFAULT_PEERCRED_GID 99 /* nobody */
44 #endif
45 #if !defined(DEFAULT_PEERCRED_PID)
46 #  define DEFAULT_PEERCRED_PID 0  /* no process */
47 #endif
48
49 static struct afb_cred *current;
50
51 static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size)
52 {
53         struct afb_cred *cred;
54         char *dest, user[64];
55         size_t i;
56         uid_t u;
57
58         i = 0;
59         u = uid;
60         do {
61                 user[i++] = (char)('0' + u % 10);
62                 u = u / 10;
63         } while(u && i < sizeof user);
64
65         cred = malloc(2 + i + size + sizeof *cred);
66         if (!cred)
67                 errno = ENOMEM;
68         else {
69                 cred->refcount = 1;
70                 cred->uid = uid;
71                 cred->gid = gid;
72                 cred->pid = pid;
73                 dest = (char*)(&cred[1]);
74                 cred->user = dest;
75                 while(i)
76                         *dest++ = user[--i];
77                 *dest++ = 0;
78                 cred->label = dest;
79                 cred->id = dest;
80                 memcpy(dest, label, size);
81                 dest[size] = 0;
82                 dest = strrchr(dest, ':');
83                 if (dest)
84                         cred->id = &dest[1];
85         }
86         return cred;
87 }
88
89 static struct afb_cred *mkcurrent()
90 {
91         char label[MAX_LABEL_LENGTH];
92         int fd;
93         ssize_t rc;
94
95         fd = open("/proc/self/attr/current", O_RDONLY);
96         if (fd < 0)
97                 rc = 0;
98         else {
99                 rc = read(fd, label, sizeof label);
100                 if (rc < 0)
101                         rc = 0;
102                 close(fd);
103         }
104
105         return mkcred(getuid(), getgid(), getpid(), label, (size_t)rc);
106 }
107
108 struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label)
109 {
110         label = label ? : DEFAULT_PEERSEC_LABEL;
111         return mkcred(uid, gid, pid, label, strlen(label));
112 }
113
114 struct afb_cred *afb_cred_create_for_socket(int fd)
115 {
116         int rc;
117         socklen_t length;
118         struct ucred ucred;
119         char label[MAX_LABEL_LENGTH];
120
121         /* get the credentials */
122         length = (socklen_t)(sizeof ucred);
123         rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length);
124         if (rc < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) {
125 #if !defined(NO_DEFAULT_PEERCRED)
126                 ucred.uid = DEFAULT_PEERCRED_UID;
127                 ucred.gid = DEFAULT_PEERCRED_GID;
128                 ucred.pid = DEFAULT_PEERCRED_PID;
129 #else
130                 if (!rc)
131                         errno = EINVAL;
132                 return NULL;
133 #endif
134         }
135
136         /* get the security label */
137         length = (socklen_t)(sizeof label);
138         rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length);
139         if (rc < 0 || length > (socklen_t)(sizeof label)) {
140 #if !defined(NO_DEFAULT_PEERSEC)
141                 length = (socklen_t)strlen(DEFAULT_PEERSEC_LABEL);
142                 strcpy (label, DEFAULT_PEERSEC_LABEL);
143 #else
144                 if (!rc)
145                         errno = EINVAL;
146                 return NULL;
147 #endif
148         }
149
150         /* makes the result */
151         return mkcred(ucred.uid, ucred.gid, ucred.pid, label, (size_t)length);
152 }
153
154 struct afb_cred *afb_cred_addref(struct afb_cred *cred)
155 {
156         if (cred)
157                 __atomic_add_fetch(&cred->refcount, 1, __ATOMIC_RELAXED);
158         return cred;
159 }
160
161 void afb_cred_unref(struct afb_cred *cred)
162 {
163         if (cred && !__atomic_sub_fetch(&cred->refcount, 1, __ATOMIC_RELAXED)) {
164                 if (cred != current)
165                         free(cred);
166                 else
167                         cred->refcount = 1;
168         }
169 }
170
171 struct afb_cred *afb_cred_current()
172 {
173         if (!current)
174                 current = mkcurrent();
175         return afb_cred_addref(current);
176 }
177