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