Move some TLS stuff to tls.c.
[libpwmd.git] / src / acl.c
blob4f36bbf7aeee8b7ff45a46a305c929d4a9bfe0ac
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <pwd.h>
28 #include <grp.h>
30 #include "common.h"
31 #include "acl.h"
32 #include "rcfile.h"
33 #include "util-misc.h"
34 #include "util-string.h"
35 #include "mutex.h"
36 #include "mem.h"
37 #ifdef WITH_GNUTLS
38 #include "tls.h"
39 #endif
41 gpg_error_t
42 do_validate_peer (assuan_context_t ctx, const char *section,
43 assuan_peercred_t *peer)
45 char **users;
46 int allowed = 0;
47 gpg_error_t rc;
48 struct client_s *client = assuan_get_pointer (ctx);
50 if (!client)
51 return GPG_ERR_FORBIDDEN;
53 #ifdef WITH_GNUTLS
54 if (client->thd->remote)
55 return tls_validate_access (client, section);
56 #endif
58 rc = assuan_get_peercred (ctx, peer);
59 if (rc)
60 return rc;
62 users = config_get_list (section, "allowed");
63 if (users)
65 for (char **p = users; !rc && *p; p++)
67 rc = acl_check_common(client, *p, (*peer)->uid, (*peer)->gid,
68 &allowed);
71 strv_free (users);
73 else if (client->no_access_param)
74 allowed = 1;
76 return allowed && !rc ? 0 : rc ? rc : GPG_ERR_FORBIDDEN;
79 /* Test if uid is a member of group 'name'. Invert when 'not' is true. */
80 #ifdef HAVE_GETGRNAM_R
81 static gpg_error_t
82 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
84 char *buf;
85 struct group gr, *gresult;
86 size_t len = sysconf (_SC_GETGR_R_SIZE_MAX);
87 int err;
88 gpg_error_t rc = 0;
90 if (len == -1)
91 len = 16384;
93 buf = xmalloc (len);
94 if (!buf)
95 return GPG_ERR_ENOMEM;
97 err = getgrnam_r (name, &gr, buf, len, &gresult);
98 if (!err && gresult)
100 if (gresult->gr_gid == gid)
102 xfree (buf);
103 *allowed = !not;
104 return 0;
107 for (char **t = gresult->gr_mem; !rc && *t; t++)
109 char *tbuf;
110 struct passwd pw;
111 struct passwd *result = get_pwd_struct (*t, 0, &pw, &tbuf, &rc);
113 if (!rc && result && result->pw_uid == uid)
115 xfree (tbuf);
116 *allowed = !not;
117 break;
120 xfree (tbuf);
123 xfree (buf);
124 return rc;
126 else if (err)
127 rc = gpg_error_from_errno (err);
129 xfree (buf);
130 return rc ? rc : !gresult ? 0 : GPG_ERR_EACCES;
132 #else
133 static gpg_error_t
134 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
136 struct group *gresult;
137 gpg_error_t rc = 0;
139 errno = 0;
140 gresult = getgrnam (name);
141 if (!errno && gresult && gresult->gr_gid == gid)
143 *allowed = !not;
144 return 0;
146 else if (errno)
147 rc = gpg_error_from_syserror ();
148 else if (!gresult)
149 return 0;
151 for (char **t = gresult->gr_mem; !rc && *t; t++)
153 char *buf;
154 struct passwd pw;
155 struct passwd *result = get_pwd_struct (*t, 0, &pw, &buf, &rc);
157 if (!rc && result && result->pw_uid == uid)
159 xfree (buf);
160 *allowed = !not;
161 break;
164 xfree (buf);
167 return rc;
169 #endif
171 gpg_error_t
172 peer_is_invoker(struct client_s *client)
174 struct invoking_user_s *user;
175 int allowed = 0;
177 if (client->thd->state == CLIENT_STATE_UNKNOWN)
178 return GPG_ERR_EACCES;
180 for (user = invoking_users; user; user = user->next)
182 #ifdef WITH_GNUTLS
183 if (client->thd->remote)
185 if (user->type == INVOKING_TLS
186 && !strcmp(client->thd->tls->fp, user->id))
187 allowed = user->not ? 0 : 1;
189 continue;
191 #endif
193 if (user->type == INVOKING_GID)
195 gpg_error_t rc = acl_check_group (user->id,
196 client->thd->peer->uid,
197 client->thd->peer->gid,
198 user->not, &allowed);
199 if (rc)
200 return rc;
202 else if (user->type == INVOKING_UID && client->thd->peer->uid == user->uid)
203 allowed = user->not ? 0 : 1;
206 return allowed ? 0 : GPG_ERR_EACCES;
209 #ifdef HAVE_GETGRNAM_R
210 gpg_error_t
211 acl_check_common (struct client_s *client, const char *user, uid_t uid,
212 gid_t gid, int *allowed)
214 int not = 0;
215 int rw = 0;
216 int tls = 0;
217 gpg_error_t rc = 0;
219 if (!user || !*user)
220 return 0;
222 if (*user == '-' || *user == '!')
223 not = 1;
225 if (*user == '+') // not implemented yet
226 rw = 1;
228 if (*user == '#') // TLS fingerprint hash
229 tls = 1;
231 if (not || rw || tls)
232 user++;
234 if (tls)
236 #ifdef WITH_GNUTLS
237 if (client->thd->remote)
239 if (!strcasecmp (client->thd->tls->fp, user))
240 *allowed = !not;
243 return 0;
244 #else
245 return 0;
246 #endif
248 #ifdef WITH_GNUTLS
249 else if (client->thd->remote) // Remote client with no FP in the ACL
250 return 0;
251 #endif
253 if (*user == '@') // all users in group
254 return acl_check_group (user+1, uid, gid, not, allowed);
255 else
257 char *buf;
258 struct passwd pw;
259 struct passwd *pwd = get_pwd_struct (user, 0, &pw, &buf, &rc);
261 if (!rc && pwd && pwd->pw_uid == uid)
262 *allowed = !not;
264 xfree (buf);
267 return rc;
269 #else
270 gpg_error_t
271 acl_check_common (struct client_s *client, const char *user, uid_t uid,
272 gid_t gid, int *allowed)
274 gpg_error_t rc = 0;
275 int not = 0;
276 int rw = 0;
277 int tls = 0;
279 if (!user || !*user)
280 return 0;
282 if (*user == '-' || *user == '!')
283 not = 1;
285 if (*user == '+') // not implemented yet
286 rw = 1;
288 if (*user == '#') // TLS fingerprint hash
289 tls = 1;
291 if (not || rw || tls)
292 user++;
294 if (tls)
296 #ifdef WITH_GNUTLS
297 if (client->thd->remote)
299 if (!strcasecmp (client->thd->tls->fp, user))
300 *allowed = !not;
303 return 0;
304 #else
305 return 0;
306 #endif
309 if (*user == '@') // all users in group
310 return acl_check_group (user+1, uid, gid, not, allowed);
311 else
313 char *buf;
314 struct passwd pw;
315 struct passwd *result = get_pwd_struct (user, 0, &pw, &buf, &rc);
317 if (!rc && result && result->pw_uid == uid)
318 *allowed = !not;
320 xfree (buf);
323 return rc;
325 #endif
327 gpg_error_t
328 validate_peer (struct client_s *cl)
330 gpg_error_t rc;
332 #ifdef WITH_GNUTLS
333 if (cl->thd->remote)
334 return tls_validate_access (cl, NULL);
335 #endif
337 MUTEX_LOCK (&cn_mutex);
338 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
339 rc = do_validate_peer (cl->ctx, "global", &cl->thd->peer);
340 pthread_cleanup_pop (1);
341 log_write ("peer %s: uid=%i, gid=%i, pid=%i, rc=%u",
342 !rc ? _("accepted") : _("rejected"), cl->thd->peer->uid,
343 cl->thd->peer->gid, cl->thd->peer->pid, rc);
344 return rc;