BULK: Safety bounds check.
[pwmd.git] / src / acl.c
blob6f9c6fa52bab8e735b2445a20bb159d730a2da3e
1 /*
2 Copyright (C) 2006-2021 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <grp.h>
29 #include "common.h"
30 #include "acl.h"
31 #include "rcfile.h"
32 #include "util-misc.h"
33 #include "util-string.h"
34 #include "mutex.h"
35 #include "mem.h"
36 #ifdef WITH_GNUTLS
37 #include "tls.h"
38 #endif
40 static char *
41 acl_get_proc (pid_t pid, gpg_error_t *rc)
43 #ifndef __linux__ // FIXME: portability (BSD kvm, solaris, etc)
44 *rc = 0;
45 return NULL;
46 #else
47 char buf[64];
48 char path[PATH_MAX];
49 char *p;
50 ssize_t n;
52 snprintf (buf, sizeof (buf), "/proc/%lu/exe", (long)pid);
53 n = readlink (buf, path, sizeof (path)-1);
55 if (n == -1)
57 *rc = gpg_error_from_syserror ();
58 log_write ("%s: %s", __FUNCTION__, gpg_strerror (*rc));
59 return NULL;
62 *rc = 0;
63 path[n] = 0;
65 p = str_dup (path);
66 if (!p)
67 *rc = GPG_ERR_ENOMEM;
69 return p;
70 #endif
73 /* Check for further matches of a pathname which may be negated. */
74 static int
75 acl_check_proc_dup (char **users, const char *path)
77 char **p;
78 int allowed = 0;
80 for (p = users; p && *p; p++)
82 int not = 0;
83 char *s = *p;
85 if (*s == '!' || *s == '-')
87 not = 1;
88 s++;
91 if (*s != '/')
92 continue;
94 if (!strcmp (s, path))
95 allowed = !not;
98 return allowed;
101 static int
102 acl_check_proc (char **users, char *user, const char *path, int *have_path)
104 char *p = user;
106 if (*p == '!' || *p == '-')
107 p++;
109 if (*p != '/')
110 return 2;
112 *have_path = 1;
113 if (!strcmp (user, path))
114 return acl_check_proc_dup (users, user);
116 return 0;
119 gpg_error_t
120 do_validate_peer (assuan_context_t ctx, const char *section,
121 assuan_peercred_t *peer, char **rpath)
123 char **users;
124 int allowed = 0;
125 gpg_error_t rc;
126 struct client_s *client = assuan_get_pointer (ctx);
128 if (!client)
129 return GPG_ERR_FORBIDDEN;
131 #ifdef WITH_GNUTLS
132 if (client->thd->remote)
133 return tls_validate_access (client, section);
134 #endif
136 rc = assuan_get_peercred (ctx, peer);
137 if (rc)
138 return rc;
140 users = config_get_list (section, "allowed");
141 if (users)
143 for (char **p = users; !rc && *p; p++)
145 rc = acl_check_common(client, *p, (*peer)->uid, (*peer)->gid,
146 &allowed);
149 /* Skip getting process name from a UID that is not our own to prevent
150 * an ENOENT error since most modern systems hide process details from
151 * other UID's. Access will be allowed based on other tests (filesystem
152 * ACL to the socket, configuration, etc). */
153 if (allowed && !rc && (*peer)->uid == getuid ())
155 int exec_allowed = 0;
156 char *path = acl_get_proc ((*peer)->pid, &rc);
157 int have_path = 0;
159 for (char **p = users; !rc && path && *p; p++)
161 exec_allowed = acl_check_proc (users, *p, path, &have_path);
162 if (!rc && exec_allowed == 1)
163 break;
166 if (rpath)
167 *rpath = path;
168 else
169 xfree (path);
171 if (have_path)
172 allowed = exec_allowed == 1;
175 strv_free (users);
178 return allowed && !rc ? 0 : rc ? rc : GPG_ERR_FORBIDDEN;
181 /* Test if uid is a member of group 'name'. Invert when 'not' is true. */
182 #ifdef HAVE_GETGRNAM_R
183 static gpg_error_t
184 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
186 char *buf;
187 struct group gr, *gresult;
188 size_t len = sysconf (_SC_GETGR_R_SIZE_MAX);
189 int err;
190 gpg_error_t rc = 0;
192 if (len == -1)
193 len = 16384;
195 buf = xmalloc (len);
196 if (!buf)
197 return GPG_ERR_ENOMEM;
199 err = getgrnam_r (name, &gr, buf, len, &gresult);
200 if (!err && gresult)
202 if (gresult->gr_gid == gid)
204 xfree (buf);
205 *allowed = !not;
206 return 0;
209 for (char **t = gresult->gr_mem; !rc && *t; t++)
211 char *tbuf;
212 struct passwd pw;
213 struct passwd *result = get_pwd_struct (*t, 0, &pw, &tbuf, &rc);
215 if (!rc && result && result->pw_uid == uid)
217 xfree (tbuf);
218 *allowed = !not;
219 break;
222 xfree (tbuf);
225 xfree (buf);
226 return rc;
228 else if (err)
229 rc = gpg_error_from_errno (err);
231 xfree (buf);
232 return rc ? rc : !gresult ? 0 : GPG_ERR_EACCES;
234 #else
235 static gpg_error_t
236 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
238 struct group *gresult;
239 gpg_error_t rc = 0;
241 errno = 0;
242 gresult = getgrnam (name);
243 if (!errno && gresult && gresult->gr_gid == gid)
245 *allowed = !not;
246 return 0;
248 else if (errno)
249 rc = gpg_error_from_syserror ();
250 else if (!gresult)
251 return 0;
253 for (char **t = gresult->gr_mem; !rc && *t; t++)
255 char *buf;
256 struct passwd pw;
257 struct passwd *result = get_pwd_struct (*t, 0, &pw, &buf, &rc);
259 if (!rc && result && result->pw_uid == uid)
261 xfree (buf);
262 *allowed = !not;
263 break;
266 xfree (buf);
269 return rc;
271 #endif
273 gpg_error_t
274 peer_is_invoker(struct client_s *client)
276 struct invoking_user_s *user;
277 int allowed = 0;
279 if (client->thd->state == CLIENT_STATE_UNKNOWN)
280 return GPG_ERR_EACCES;
282 for (user = invoking_users; user; user = user->next)
284 #ifdef WITH_GNUTLS
285 if (client->thd->remote)
287 if (user->type == INVOKING_TLS
288 && !strcmp(client->thd->tls->fp, user->id))
289 allowed = user->not ? 0 : 1;
291 continue;
293 #endif
295 if (user->type == INVOKING_GID)
297 gpg_error_t rc = acl_check_group (user->id,
298 client->thd->peer->uid,
299 client->thd->peer->gid,
300 user->not, &allowed);
301 if (rc)
302 return rc;
304 else if (user->type == INVOKING_UID && client->thd->peer->uid == user->uid)
305 allowed = user->not ? 0 : 1;
308 return allowed ? 0 : GPG_ERR_EACCES;
311 #ifdef HAVE_GETGRNAM_R
312 gpg_error_t
313 acl_check_common (struct client_s *client, const char *user, uid_t uid,
314 gid_t gid, int *allowed)
316 int not = 0;
317 int rw = 0;
318 int tls = 0;
319 gpg_error_t rc = 0;
321 if (!user || !*user)
322 return 0;
324 if (*user == '-' || *user == '!')
325 not = 1;
327 if (*user == '+') // not implemented yet
328 rw = 1;
330 if (*user == '#') // TLS fingerprint hash
331 tls = 1;
333 if (not || rw || tls)
334 user++;
336 if (tls)
338 #ifdef WITH_GNUTLS
339 if (client->thd->remote)
341 if (!strcasecmp (client->thd->tls->fp, user))
342 *allowed = !not;
345 return 0;
346 #else
347 (void)client;
348 return 0;
349 #endif
351 #ifdef WITH_GNUTLS
352 else if (client->thd->remote) // Remote client with no FP in the ACL
353 return 0;
354 #endif
356 if (*user == '@') // all users in group
357 return acl_check_group (user+1, uid, gid, not, allowed);
358 else
360 char *buf;
361 struct passwd pw;
362 struct passwd *pwd = get_pwd_struct (user, 0, &pw, &buf, &rc);
364 if (!rc && pwd && pwd->pw_uid == uid)
365 *allowed = !not;
367 xfree (buf);
370 return rc;
372 #else
373 gpg_error_t
374 acl_check_common (struct client_s *client, const char *user, uid_t uid,
375 gid_t gid, int *allowed)
377 gpg_error_t rc = 0;
378 int not = 0;
379 int rw = 0;
380 int tls = 0;
382 if (!user || !*user)
383 return 0;
385 if (*user == '-' || *user == '!')
386 not = 1;
388 if (*user == '+') // not implemented yet
389 rw = 1;
391 if (*user == '#') // TLS fingerprint hash
392 tls = 1;
394 if (not || rw || tls)
395 user++;
397 if (tls)
399 #ifdef WITH_GNUTLS
400 if (client->thd->remote)
402 if (!strcasecmp (client->thd->tls->fp, user))
403 *allowed = !not;
406 return 0;
407 #else
408 return 0;
409 #endif
412 if (*user == '@') // all users in group
413 return acl_check_group (user+1, uid, gid, not, allowed);
414 else
416 char *buf;
417 struct passwd pw;
418 struct passwd *result = get_pwd_struct (user, 0, &pw, &buf, &rc);
420 if (!rc && result && result->pw_uid == uid)
421 *allowed = !not;
423 xfree (buf);
426 return rc;
428 #endif
430 gpg_error_t
431 validate_peer (struct client_s *cl)
433 gpg_error_t rc;
434 char *path = NULL;
436 #ifdef WITH_GNUTLS
437 if (cl->thd->remote)
438 return tls_validate_access (cl, NULL);
439 #endif
441 MUTEX_LOCK (&cn_mutex);
442 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
443 rc = do_validate_peer (cl->ctx, "global", &cl->thd->peer, &path);
444 pthread_cleanup_pop (1);
445 log_write ("peer %s: path=%s, uid=%i, gid=%i, pid=%i, rc=%u",
446 !rc ? _("accepted") : _("rejected"), path,
447 cl->thd->peer->uid, cl->thd->peer->gid,
448 cl->thd->peer->pid, rc);
449 xfree (path);
450 return rc;