Add computation of credentials
[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 static struct afb_cred *current;
33
34 static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size)
35 {
36         struct afb_cred *cred;
37         char *dest;
38
39         cred = malloc(1 + size + sizeof *cred);
40         if (!cred)
41                 errno = ENOMEM;
42         else {
43                 cred->refcount = 1;
44                 cred->uid = uid;
45                 cred->gid = gid;
46                 cred->pid = pid;
47                 dest = (char*)(&cred[1]);
48                 memcpy(dest, label, size);
49                 dest[size] = 0;
50                 cred->label = dest;
51                 cred->id = dest;
52                 dest = strrchr(dest, ':');
53                 if (dest && dest[1])
54                         cred->id = &dest[1];
55         }
56         return cred;
57 }
58
59 static struct afb_cred *mkcurrent()
60 {
61         char label[MAX_LABEL_LENGTH];
62         int fd;
63         ssize_t rc;
64
65         fd = open("/proc/self/attr/current", O_RDONLY);
66         if (fd < 0)
67                 rc = 0;
68         else {
69                 rc = read(fd, label, sizeof label);
70                 if (rc < 0)
71                         rc = 0;
72                 close(fd);
73         }
74
75         return mkcred(getuid(), getgid(), getpid(), label, (size_t)rc);
76 }
77
78 struct afb_cred *afb_cred_create(uid_t uid, gid_t gid, pid_t pid, const char *label)
79 {
80         label = label ? : "";
81         return mkcred(uid, gid, pid, label, strlen(label));
82 }
83
84 struct afb_cred *afb_cred_create_for_socket(int fd)
85 {
86         int rc;
87         socklen_t length;
88         struct ucred ucred;
89         char label[MAX_LABEL_LENGTH];
90
91         /* get the credentials */
92         length = (socklen_t)(sizeof ucred);
93         rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length);
94         if (rc < 0 || length != (socklen_t)(sizeof ucred)) {
95                 if (!rc)
96                         errno = EINVAL;
97                 return NULL;
98         }
99
100         /* get the security label */
101         length = (socklen_t)(sizeof label);
102         rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, label, &length);
103         if (rc < 0 || length > (socklen_t)(sizeof label)) {
104                 if (!rc)
105                         errno = EINVAL;
106                 return NULL;
107         }
108
109         /* makes the result */
110         return mkcred(ucred.uid, ucred.gid, ucred.pid, label, (size_t)length);
111 }
112
113 struct afb_cred *afb_cred_addref(struct afb_cred *cred)
114 {
115         if (cred)
116                 __atomic_add_fetch(&cred->refcount, 1, __ATOMIC_RELAXED);
117         return cred;
118 }
119
120 void afb_cred_unref(struct afb_cred *cred)
121 {
122         if (cred && !__atomic_sub_fetch(&cred->refcount, 1, __ATOMIC_RELAXED)) {
123                 if (cred != current)
124                         free(cred);
125                 else
126                         cred->refcount = 1;
127         }
128 }
129
130 struct afb_cred *afb_cred_current()
131 {
132         if (!current)
133                 current = mkcurrent();
134         return afb_cred_addref(current);
135 }
136