Fix EXPIRE status message.
[pwmd.git] / src / acl.c
blob7927a594e0b7eb020bf6fbd967c7ebcc0d78db1c
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016, 2017
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 (void)client;
246 return 0;
247 #endif
249 #ifdef WITH_GNUTLS
250 else if (client->thd->remote) // Remote client with no FP in the ACL
251 return 0;
252 #endif
254 if (*user == '@') // all users in group
255 return acl_check_group (user+1, uid, gid, not, allowed);
256 else
258 char *buf;
259 struct passwd pw;
260 struct passwd *pwd = get_pwd_struct (user, 0, &pw, &buf, &rc);
262 if (!rc && pwd && pwd->pw_uid == uid)
263 *allowed = !not;
265 xfree (buf);
268 return rc;
270 #else
271 gpg_error_t
272 acl_check_common (struct client_s *client, const char *user, uid_t uid,
273 gid_t gid, int *allowed)
275 gpg_error_t rc = 0;
276 int not = 0;
277 int rw = 0;
278 int tls = 0;
280 if (!user || !*user)
281 return 0;
283 if (*user == '-' || *user == '!')
284 not = 1;
286 if (*user == '+') // not implemented yet
287 rw = 1;
289 if (*user == '#') // TLS fingerprint hash
290 tls = 1;
292 if (not || rw || tls)
293 user++;
295 if (tls)
297 #ifdef WITH_GNUTLS
298 if (client->thd->remote)
300 if (!strcasecmp (client->thd->tls->fp, user))
301 *allowed = !not;
304 return 0;
305 #else
306 return 0;
307 #endif
310 if (*user == '@') // all users in group
311 return acl_check_group (user+1, uid, gid, not, allowed);
312 else
314 char *buf;
315 struct passwd pw;
316 struct passwd *result = get_pwd_struct (user, 0, &pw, &buf, &rc);
318 if (!rc && result && result->pw_uid == uid)
319 *allowed = !not;
321 xfree (buf);
324 return rc;
326 #endif
328 gpg_error_t
329 validate_peer (struct client_s *cl)
331 gpg_error_t rc;
333 #ifdef WITH_GNUTLS
334 if (cl->thd->remote)
335 return tls_validate_access (cl, NULL);
336 #endif
338 MUTEX_LOCK (&cn_mutex);
339 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
340 rc = do_validate_peer (cl->ctx, "global", &cl->thd->peer);
341 pthread_cleanup_pop (1);
342 log_write ("peer %s: uid=%i, gid=%i, pid=%i, rc=%u",
343 !rc ? _("accepted") : _("rejected"), cl->thd->peer->uid,
344 cl->thd->peer->gid, cl->thd->peer->pid, rc);
345 return rc;