Version 3.3.0.
[pwmd.git] / src / acl.c
blobb56394df6a36cd23b5d47fbe9d4f843d6ee07b8d
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 as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
11 Pwmd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <grp.h>
28 #include "common.h"
29 #include "acl.h"
30 #include "rcfile.h"
31 #include "util-misc.h"
32 #include "util-string.h"
33 #include "mutex.h"
34 #include "mem.h"
35 #ifdef WITH_GNUTLS
36 #include "tls.h"
37 #endif
39 static char *
40 acl_get_proc (pid_t pid, gpg_error_t *rc)
42 #ifndef __linux__ // FIXME: portability (BSD kvm, solaris, etc)
43 *rc = 0;
44 return NULL;
45 #else
46 char buf[64];
47 char path[PATH_MAX];
48 char *p;
49 ssize_t n;
51 snprintf (buf, sizeof (buf), "/proc/%lu/exe", (long)pid);
52 n = readlink (buf, path, sizeof (path)-1);
54 if (n == -1)
56 *rc = gpg_error_from_syserror ();
57 log_write ("%s: %s", __FUNCTION__, gpg_strerror (*rc));
58 return NULL;
61 *rc = 0;
62 path[n] = 0;
64 p = str_dup (path);
65 if (!p)
66 *rc = GPG_ERR_ENOMEM;
68 return p;
69 #endif
72 /* Check for further matches of a pathname which may be negated. */
73 static int
74 acl_check_proc_dup (char **users, const char *path)
76 char **p;
77 int allowed = 0;
79 for (p = users; p && *p; p++)
81 int not = 0;
82 char *s = *p;
84 if (*s == '!' || *s == '-')
86 not = 1;
87 s++;
90 if (*s != '/')
91 continue;
93 if (!strcmp (s, path))
94 allowed = !not;
97 return allowed;
100 static int
101 acl_check_proc (char **users, char *user, const char *path, int *have_path)
103 char *p = user;
105 if (*p == '!' || *p == '-')
106 p++;
108 if (*p != '/')
109 return 2;
111 *have_path = 1;
112 if (!strcmp (user, path))
113 return acl_check_proc_dup (users, user);
115 return 0;
118 gpg_error_t
119 do_validate_peer (assuan_context_t ctx, const char *section,
120 assuan_peercred_t *peer, char **rpath)
122 char **users;
123 int allowed = 0;
124 gpg_error_t rc;
125 struct client_s *client = assuan_get_pointer (ctx);
127 if (!client)
128 return GPG_ERR_FORBIDDEN;
130 #ifdef WITH_GNUTLS
131 if (client->thd->remote)
132 return tls_validate_access (client, section);
133 #endif
135 rc = assuan_get_peercred (ctx, peer);
136 if (rc)
137 return rc;
139 users = config_get_list (section, "allowed");
140 if (users)
142 for (char **p = users; !rc && *p; p++)
144 rc = acl_check_common(client, *p, (*peer)->uid, (*peer)->gid,
145 &allowed);
148 /* Skip getting process name from a UID that is not our own to prevent
149 * an ENOENT error since most modern systems hide process details from
150 * other UID's. Access will be allowed based on other tests (filesystem
151 * ACL to the socket, configuration, etc). */
152 if (allowed && !rc && (*peer)->uid == getuid ())
154 int exec_allowed = 0;
155 char *path = acl_get_proc ((*peer)->pid, &rc);
156 int have_path = 0;
158 for (char **p = users; !rc && path && *p; p++)
160 exec_allowed = acl_check_proc (users, *p, path, &have_path);
161 if (!rc && exec_allowed == 1)
162 break;
165 if (rpath)
166 *rpath = path;
167 else
168 xfree (path);
170 if (have_path)
171 allowed = exec_allowed == 1;
174 strv_free (users);
177 return allowed && !rc ? 0 : rc ? rc : GPG_ERR_FORBIDDEN;
180 /* Test if uid is a member of group 'name'. Invert when 'not' is true. */
181 #ifdef HAVE_GETGRNAM_R
182 static gpg_error_t
183 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
185 char *buf;
186 struct group gr, *gresult;
187 size_t len = sysconf (_SC_GETGR_R_SIZE_MAX);
188 int err;
189 gpg_error_t rc = 0;
191 if (len == -1)
192 len = 16384;
194 buf = xmalloc (len);
195 if (!buf)
196 return GPG_ERR_ENOMEM;
198 err = getgrnam_r (name, &gr, buf, len, &gresult);
199 if (!err && gresult)
201 if (gresult->gr_gid == gid)
203 xfree (buf);
204 *allowed = !not;
205 return 0;
208 for (char **t = gresult->gr_mem; !rc && *t; t++)
210 char *tbuf;
211 struct passwd pw;
212 struct passwd *result = get_pwd_struct (*t, 0, &pw, &tbuf, &rc);
214 if (!rc && result && result->pw_uid == uid)
216 xfree (tbuf);
217 *allowed = !not;
218 break;
221 xfree (tbuf);
224 xfree (buf);
225 return rc;
227 else if (err)
228 rc = gpg_error_from_errno (err);
230 xfree (buf);
231 return rc ? rc : !gresult ? 0 : GPG_ERR_EACCES;
233 #else
234 static gpg_error_t
235 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
237 struct group *gresult;
238 gpg_error_t rc = 0;
240 errno = 0;
241 gresult = getgrnam (name);
242 if (!errno && gresult && gresult->gr_gid == gid)
244 *allowed = !not;
245 return 0;
247 else if (errno)
248 rc = gpg_error_from_syserror ();
249 else if (!gresult)
250 return 0;
252 for (char **t = gresult->gr_mem; !rc && *t; t++)
254 char *buf;
255 struct passwd pw;
256 struct passwd *result = get_pwd_struct (*t, 0, &pw, &buf, &rc);
258 if (!rc && result && result->pw_uid == uid)
260 xfree (buf);
261 *allowed = !not;
262 break;
265 xfree (buf);
268 return rc;
270 #endif
272 gpg_error_t
273 peer_is_invoker(struct client_s *client)
275 struct invoking_user_s *user;
276 int allowed = 0;
278 if (client->thd->state == CLIENT_STATE_UNKNOWN)
279 return GPG_ERR_EACCES;
281 for (user = invoking_users; user; user = user->next)
283 #ifdef WITH_GNUTLS
284 if (client->thd->remote)
286 if (user->type == INVOKING_TLS
287 && !strcmp(client->thd->tls->fp, user->id))
288 allowed = user->not ? 0 : 1;
290 continue;
292 #endif
294 if (user->type == INVOKING_GID)
296 gpg_error_t rc = acl_check_group (user->id,
297 client->thd->peer->uid,
298 client->thd->peer->gid,
299 user->not, &allowed);
300 if (rc)
301 return rc;
303 else if (user->type == INVOKING_UID && client->thd->peer->uid == user->uid)
304 allowed = user->not ? 0 : 1;
307 return allowed ? 0 : GPG_ERR_EACCES;
310 #ifdef HAVE_GETGRNAM_R
311 gpg_error_t
312 acl_check_common (struct client_s *client, const char *user, uid_t uid,
313 gid_t gid, int *allowed)
315 int not = 0;
316 int rw = 0;
317 int tls = 0;
318 gpg_error_t rc = 0;
320 if (!user || !*user)
321 return 0;
323 if (*user == '-' || *user == '!')
324 not = 1;
326 if (*user == '+') // not implemented yet
327 rw = 1;
329 if (*user == '#') // TLS fingerprint hash
330 tls = 1;
332 if (not || rw || tls)
333 user++;
335 if (tls)
337 #ifdef WITH_GNUTLS
338 if (client->thd->remote)
340 if (!strcasecmp (client->thd->tls->fp, user))
341 *allowed = !not;
344 return 0;
345 #else
346 (void)client;
347 return 0;
348 #endif
350 #ifdef WITH_GNUTLS
351 else if (client->thd->remote) // Remote client with no FP in the ACL
352 return 0;
353 #endif
355 if (*user == '@') // all users in group
356 return acl_check_group (user+1, uid, gid, not, allowed);
357 else
359 char *buf;
360 struct passwd pw;
361 struct passwd *pwd = get_pwd_struct (user, 0, &pw, &buf, &rc);
363 if (!rc && pwd && pwd->pw_uid == uid)
364 *allowed = !not;
366 xfree (buf);
369 return rc;
371 #else
372 gpg_error_t
373 acl_check_common (struct client_s *client, const char *user, uid_t uid,
374 gid_t gid, int *allowed)
376 gpg_error_t rc = 0;
377 int not = 0;
378 int rw = 0;
379 int tls = 0;
381 if (!user || !*user)
382 return 0;
384 if (*user == '-' || *user == '!')
385 not = 1;
387 if (*user == '+') // not implemented yet
388 rw = 1;
390 if (*user == '#') // TLS fingerprint hash
391 tls = 1;
393 if (not || rw || tls)
394 user++;
396 if (tls)
398 #ifdef WITH_GNUTLS
399 if (client->thd->remote)
401 if (!strcasecmp (client->thd->tls->fp, user))
402 *allowed = !not;
405 return 0;
406 #else
407 return 0;
408 #endif
411 if (*user == '@') // all users in group
412 return acl_check_group (user+1, uid, gid, not, allowed);
413 else
415 char *buf;
416 struct passwd pw;
417 struct passwd *result = get_pwd_struct (user, 0, &pw, &buf, &rc);
419 if (!rc && result && result->pw_uid == uid)
420 *allowed = !not;
422 xfree (buf);
425 return rc;
427 #endif
429 gpg_error_t
430 validate_peer (struct client_s *cl)
432 gpg_error_t rc;
433 char *path = NULL;
435 #ifdef WITH_GNUTLS
436 if (cl->thd->remote)
437 return tls_validate_access (cl, NULL);
438 #endif
440 MUTEX_LOCK (&cn_mutex);
441 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
442 rc = do_validate_peer (cl->ctx, "global", &cl->thd->peer, &path);
443 pthread_cleanup_pop (1);
444 log_write ("peer %s: path=%s, uid=%i, gid=%i, pid=%i, rc=%u",
445 !rc ? _("accepted") : _("rejected"), path,
446 cl->thd->peer->uid, cl->thd->peer->gid,
447 cl->thd->peer->pid, rc);
448 xfree (path);
449 return rc;