2 * Copyright (C) 2017, 2018 "IoT.bzh"
3 * Author: José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <sys/types.h>
27 #include <sys/socket.h>
33 #define MAX_LABEL_LENGTH 1024
35 #if !defined(NO_DEFAULT_PEERCRED) && !defined(ADD_DEFAULT_PEERCRED)
36 # define NO_DEFAULT_PEERCRED
39 #if !defined(DEFAULT_PEERSEC_LABEL)
40 # define DEFAULT_PEERSEC_LABEL "NoLabel"
42 #if !defined(DEFAULT_PEERCRED_UID)
43 # define DEFAULT_PEERCRED_UID 99 /* nobody */
45 #if !defined(DEFAULT_PEERCRED_GID)
46 # define DEFAULT_PEERCRED_GID 99 /* nobody */
48 #if !defined(DEFAULT_PEERCRED_PID)
49 # define DEFAULT_PEERCRED_PID 0 /* no process */
52 static char on_behalf_credential_permission[] = "urn:AGL:permission:*:partner:on-behalf-credentials";
53 static char export_format[] = "%x:%x:%x-%s";
54 static char import_format[] = "%x:%x:%x-%n";
56 static struct afb_cred *current;
58 static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size)
60 struct afb_cred *cred;
68 user[i++] = (char)('0' + u % 10);
70 } while(u && i < sizeof user);
72 cred = malloc(2 + i + size + sizeof *cred);
80 cred->exported = NULL;
81 dest = (char*)(&cred[1]);
88 memcpy(dest, label, size);
90 dest = strrchr(dest, ':');
97 static struct afb_cred *mkcurrent()
99 char label[MAX_LABEL_LENGTH];
103 fd = open("/proc/self/attr/current", O_RDONLY);
107 rc = read(fd, label, sizeof label);
113 return mkcred(getuid(), getgid(), getpid(), label, (size_t)rc);
116 struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label)
118 label = label ? : DEFAULT_PEERSEC_LABEL;
119 return mkcred(uid, gid, pid, label, strlen(label));
122 struct afb_cred *afb_cred_create_for_socket(int fd)
127 char label[MAX_LABEL_LENGTH];
129 /* get the credentials */
130 length = (socklen_t)(sizeof ucred);
131 rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length);
132 if (rc < 0 || length != (socklen_t)(sizeof ucred) || !~ucred.uid) {
133 #if !defined(NO_DEFAULT_PEERCRED)
134 ucred.uid = DEFAULT_PEERCRED_UID;
135 ucred.gid = DEFAULT_PEERCRED_GID;
136 ucred.pid = DEFAULT_PEERCRED_PID;
144 /* get the security label */
145 length = (socklen_t)(sizeof label);
146 rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length);
147 if (rc < 0 || length > (socklen_t)(sizeof label)) {
148 #if !defined(NO_DEFAULT_PEERSEC)
149 length = (socklen_t)strlen(DEFAULT_PEERSEC_LABEL);
150 strcpy (label, DEFAULT_PEERSEC_LABEL);
158 /* makes the result */
159 return mkcred(ucred.uid, ucred.gid, ucred.pid, label, (size_t)length);
162 struct afb_cred *afb_cred_addref(struct afb_cred *cred)
165 __atomic_add_fetch(&cred->refcount, 1, __ATOMIC_RELAXED);
169 void afb_cred_unref(struct afb_cred *cred)
171 if (cred && !__atomic_sub_fetch(&cred->refcount, 1, __ATOMIC_RELAXED)) {
179 struct afb_cred *afb_cred_current()
182 current = mkcurrent();
183 return afb_cred_addref(current);
186 const char *afb_cred_export(struct afb_cred *cred)
190 if (!cred->exported) {
191 rc = asprintf((char**)&cred->exported,
199 cred->exported = NULL;
202 return cred->exported;
205 struct afb_cred *afb_cred_import(const char *string)
207 struct afb_cred *cred;
208 int rc, uid, gid, pid, pos;
210 rc = sscanf(string, import_format, &uid, &gid, &pid, &pos);
212 cred = afb_cred_create((uid_t)uid, (gid_t)gid, (pid_t)pid, &string[pos]);
220 struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported)
223 struct afb_cred *imported;
225 if (afb_cred_has_permission(cred, on_behalf_credential_permission, context)) {
226 imported = afb_cred_import(exported);
229 ERROR("Can't import on behalf credentials: %m");
231 ERROR("On behalf credentials refused");
234 return afb_cred_addref(cred);
237 /*********************************************************************************/
238 #ifdef BACKEND_PERMISSION_IS_CYNARA
241 #include <cynara-client.h>
243 static cynara *handle;
244 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
246 int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context)
251 /* case of permission for self */
255 ERROR("Got a null permission!");
259 /* cynara isn't reentrant */
260 pthread_mutex_lock(&mutex);
262 /* lazy initialisation */
264 rc = cynara_initialize(&handle, NULL);
265 if (rc != CYNARA_API_SUCCESS) {
267 ERROR("cynara initialisation failed with code %d", rc);
272 /* query cynara permission */
273 rc = cynara_check(handle, cred->label, context ?: "", cred->user, permission);
275 pthread_mutex_unlock(&mutex);
276 return rc == CYNARA_API_ACCESS_ALLOWED;
279 /*********************************************************************************/
281 int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context)
283 WARNING("Granting permission %s by default of backend", permission ?: "(null)");