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