ACL: Test for invalid characters in usernames.
[pwmd.git] / src / acl.c
blobcab88e72e98339b3374e98825c9349e474efa24a
1 /*
2 Copyright (C) 2006-2020 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 gpg_error_t
40 do_validate_peer (assuan_context_t ctx, const char *section,
41 assuan_peercred_t *peer)
43 char **users;
44 int allowed = 0;
45 gpg_error_t rc;
46 struct client_s *client = assuan_get_pointer (ctx);
48 if (!client)
49 return GPG_ERR_FORBIDDEN;
51 #ifdef WITH_GNUTLS
52 if (client->thd->remote)
53 return tls_validate_access (client, section);
54 #endif
56 rc = assuan_get_peercred (ctx, peer);
57 if (rc)
58 return rc;
60 users = config_get_list (section, "allowed");
61 if (users)
63 for (char **p = users; !rc && *p; p++)
65 rc = acl_check_common(client, *p, (*peer)->uid, (*peer)->gid,
66 &allowed);
69 strv_free (users);
71 else if (client->no_access_param)
72 allowed = 1;
74 return allowed && !rc ? 0 : rc ? rc : GPG_ERR_FORBIDDEN;
77 /* Test if uid is a member of group 'name'. Invert when 'not' is true. */
78 #ifdef HAVE_GETGRNAM_R
79 static gpg_error_t
80 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
82 char *buf;
83 struct group gr, *gresult;
84 size_t len = sysconf (_SC_GETGR_R_SIZE_MAX);
85 int err;
86 gpg_error_t rc = 0;
88 if (len == -1)
89 len = 16384;
91 buf = xmalloc (len);
92 if (!buf)
93 return GPG_ERR_ENOMEM;
95 err = getgrnam_r (name, &gr, buf, len, &gresult);
96 if (!err && gresult)
98 if (gresult->gr_gid == gid)
100 xfree (buf);
101 *allowed = !not;
102 return 0;
105 for (char **t = gresult->gr_mem; !rc && *t; t++)
107 char *tbuf;
108 struct passwd pw;
109 struct passwd *result = get_pwd_struct (*t, 0, &pw, &tbuf, &rc);
111 if (!rc && result && result->pw_uid == uid)
113 xfree (tbuf);
114 *allowed = !not;
115 break;
118 xfree (tbuf);
121 xfree (buf);
122 return rc;
124 else if (err)
125 rc = gpg_error_from_errno (err);
127 xfree (buf);
128 return rc ? rc : !gresult ? 0 : GPG_ERR_EACCES;
130 #else
131 static gpg_error_t
132 acl_check_group (const char *name, uid_t uid, gid_t gid, int not, int *allowed)
134 struct group *gresult;
135 gpg_error_t rc = 0;
137 errno = 0;
138 gresult = getgrnam (name);
139 if (!errno && gresult && gresult->gr_gid == gid)
141 *allowed = !not;
142 return 0;
144 else if (errno)
145 rc = gpg_error_from_syserror ();
146 else if (!gresult)
147 return 0;
149 for (char **t = gresult->gr_mem; !rc && *t; t++)
151 char *buf;
152 struct passwd pw;
153 struct passwd *result = get_pwd_struct (*t, 0, &pw, &buf, &rc);
155 if (!rc && result && result->pw_uid == uid)
157 xfree (buf);
158 *allowed = !not;
159 break;
162 xfree (buf);
165 return rc;
167 #endif
169 gpg_error_t
170 peer_is_invoker(struct client_s *client)
172 struct invoking_user_s *user;
173 int allowed = 0;
175 if (client->thd->state == CLIENT_STATE_UNKNOWN)
176 return GPG_ERR_EACCES;
178 for (user = invoking_users; user; user = user->next)
180 #ifdef WITH_GNUTLS
181 if (client->thd->remote)
183 if (user->type == INVOKING_TLS
184 && !strcmp(client->thd->tls->fp, user->id))
185 allowed = user->not ? 0 : 1;
187 continue;
189 #endif
191 if (user->type == INVOKING_GID)
193 gpg_error_t rc = acl_check_group (user->id,
194 client->thd->peer->uid,
195 client->thd->peer->gid,
196 user->not, &allowed);
197 if (rc)
198 return rc;
200 else if (user->type == INVOKING_UID && client->thd->peer->uid == user->uid)
201 allowed = user->not ? 0 : 1;
204 return allowed ? 0 : GPG_ERR_EACCES;
207 #ifdef HAVE_GETGRNAM_R
208 gpg_error_t
209 acl_check_common (struct client_s *client, const char *user, uid_t uid,
210 gid_t gid, int *allowed)
212 int not = 0;
213 int rw = 0;
214 int tls = 0;
215 gpg_error_t rc = 0;
217 if (!user || !*user)
218 return 0;
220 if (*user == '-' || *user == '!')
221 not = 1;
223 if (*user == '+') // not implemented yet
224 rw = 1;
226 if (*user == '#') // TLS fingerprint hash
227 tls = 1;
229 if (not || rw || tls)
230 user++;
232 if (tls)
234 #ifdef WITH_GNUTLS
235 if (client->thd->remote)
237 if (!strcasecmp (client->thd->tls->fp, user))
238 *allowed = !not;
241 return 0;
242 #else
243 (void)client;
244 return 0;
245 #endif
247 #ifdef WITH_GNUTLS
248 else if (client->thd->remote) // Remote client with no FP in the ACL
249 return 0;
250 #endif
252 if (*user == '@') // all users in group
253 return acl_check_group (user+1, uid, gid, not, allowed);
254 else
256 char *buf;
257 struct passwd pw;
258 struct passwd *pwd = get_pwd_struct (user, 0, &pw, &buf, &rc);
260 if (!rc && pwd && pwd->pw_uid == uid)
261 *allowed = !not;
263 xfree (buf);
266 return rc;
268 #else
269 gpg_error_t
270 acl_check_common (struct client_s *client, const char *user, uid_t uid,
271 gid_t gid, int *allowed)
273 gpg_error_t rc = 0;
274 int not = 0;
275 int rw = 0;
276 int tls = 0;
278 if (!user || !*user)
279 return 0;
281 if (*user == '-' || *user == '!')
282 not = 1;
284 if (*user == '+') // not implemented yet
285 rw = 1;
287 if (*user == '#') // TLS fingerprint hash
288 tls = 1;
290 if (not || rw || tls)
291 user++;
293 if (tls)
295 #ifdef WITH_GNUTLS
296 if (client->thd->remote)
298 if (!strcasecmp (client->thd->tls->fp, user))
299 *allowed = !not;
302 return 0;
303 #else
304 return 0;
305 #endif
308 if (*user == '@') // all users in group
309 return acl_check_group (user+1, uid, gid, not, allowed);
310 else
312 char *buf;
313 struct passwd pw;
314 struct passwd *result = get_pwd_struct (user, 0, &pw, &buf, &rc);
316 if (!rc && result && result->pw_uid == uid)
317 *allowed = !not;
319 xfree (buf);
322 return rc;
324 #endif
326 gpg_error_t
327 validate_peer (struct client_s *cl)
329 gpg_error_t rc;
331 #ifdef WITH_GNUTLS
332 if (cl->thd->remote)
333 return tls_validate_access (cl, NULL);
334 #endif
336 MUTEX_LOCK (&cn_mutex);
337 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
338 rc = do_validate_peer (cl->ctx, "global", &cl->thd->peer);
339 pthread_cleanup_pop (1);
340 log_write ("peer %s: uid=%i, gid=%i, pid=%i, rc=%u",
341 !rc ? _("accepted") : _("rejected"), cl->thd->peer->uid,
342 cl->thd->peer->gid, cl->thd->peer->pid, rc);
343 return rc;