2 * Copyright (c) 2013 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
44 #include "libcapsicum.h"
45 #include "libcapsicum_pwd.h"
47 static struct passwd gpwd;
49 static size_t gbufsize;
62 gbuffer = realloc(buf, gbufsize);
63 if (gbuffer == NULL) {
68 memset(gbuffer, 0, gbufsize);
74 passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
75 char **bufferp, size_t *bufsizep)
80 str = nvlist_get_string(nvl, fieldname);
81 len = strlcpy(*bufferp, str, *bufsizep);
92 passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
97 if (!nvlist_exists_string(nvl, "pw_name"))
100 memset(pwd, 0, sizeof(*pwd));
102 error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
106 pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
107 pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
108 pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
109 error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
113 error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
117 error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
121 error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
125 error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
129 pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
130 pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
136 cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
137 uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
138 struct passwd **result)
144 nvl = nvlist_create(0);
145 nvlist_add_string(nvl, "cmd", cmd);
146 if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
148 } else if (strcmp(cmd, "getpwnam") == 0 ||
149 strcmp(cmd, "getpwnam_r") == 0) {
150 nvlist_add_string(nvl, "name", login);
151 } else if (strcmp(cmd, "getpwuid") == 0 ||
152 strcmp(cmd, "getpwuid_r") == 0) {
153 nvlist_add_number(nvl, "uid", (uint64_t)uid);
157 nvl = cap_xfer_nvlist(chan, nvl, 0);
163 error = (int)nvlist_get_number(nvl, "error");
170 if (!nvlist_exists_string(nvl, "pw_name")) {
177 getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
178 strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
181 error = passwd_unpack(nvl, pwd, buffer, bufsize);
182 if (getpw_r || error != ERANGE)
184 assert(buffer == gbuffer);
185 assert(bufsize == gbufsize);
186 error = passwd_resize();
189 /* Update pointers after resize. */
204 static struct passwd *
205 cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
208 struct passwd *result;
213 error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
226 cap_getpwent(cap_channel_t *chan)
229 return (cap_getpwcommon(chan, "getpwent", NULL, 0));
233 cap_getpwnam(cap_channel_t *chan, const char *login)
236 return (cap_getpwcommon(chan, "getpwnam", login, 0));
240 cap_getpwuid(cap_channel_t *chan, uid_t uid)
243 return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
247 cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
248 size_t bufsize, struct passwd **result)
251 return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
256 cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
257 char *buffer, size_t bufsize, struct passwd **result)
260 return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
265 cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
266 size_t bufsize, struct passwd **result)
269 return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
274 cap_setpassent(cap_channel_t *chan, int stayopen)
278 nvl = nvlist_create(0);
279 nvlist_add_string(nvl, "cmd", "setpassent");
280 nvlist_add_bool(nvl, "stayopen", stayopen != 0);
281 nvl = cap_xfer_nvlist(chan, nvl, 0);
284 if (nvlist_get_number(nvl, "error") != 0) {
285 errno = nvlist_get_number(nvl, "error");
295 cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
299 nvl = nvlist_create(0);
300 nvlist_add_string(nvl, "cmd", cmd);
301 /* Ignore any errors, we have no way to report them. */
302 nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
306 cap_setpwent(cap_channel_t *chan)
309 cap_set_end_pwent(chan, "setpwent");
313 cap_endpwent(cap_channel_t *chan)
316 cap_set_end_pwent(chan, "endpwent");
320 cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
322 nvlist_t *limits, *nvl;
325 if (cap_limit_get(chan, &limits) < 0)
327 if (limits == NULL) {
328 limits = nvlist_create(0);
330 if (nvlist_exists_nvlist(limits, "cmds"))
331 nvlist_free_nvlist(limits, "cmds");
333 nvl = nvlist_create(0);
334 for (i = 0; i < ncmds; i++)
335 nvlist_add_null(nvl, cmds[i]);
336 nvlist_move_nvlist(limits, "cmds", nvl);
337 return (cap_limit_set(chan, limits));
341 cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
344 nvlist_t *limits, *nvl;
347 if (cap_limit_get(chan, &limits) < 0)
349 if (limits == NULL) {
350 limits = nvlist_create(0);
352 if (nvlist_exists_nvlist(limits, "fields"))
353 nvlist_free_nvlist(limits, "fields");
355 nvl = nvlist_create(0);
356 for (i = 0; i < nfields; i++)
357 nvlist_add_null(nvl, fields[i]);
358 nvlist_move_nvlist(limits, "fields", nvl);
359 return (cap_limit_set(chan, limits));
363 cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
364 size_t nnames, uid_t *uids, size_t nuids)
366 nvlist_t *limits, *users;
371 if (cap_limit_get(chan, &limits) < 0)
373 if (limits == NULL) {
374 limits = nvlist_create(0);
376 if (nvlist_exists_nvlist(limits, "users"))
377 nvlist_free_nvlist(limits, "users");
379 users = nvlist_create(0);
380 for (i = 0; i < nuids; i++) {
381 n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
382 assert(n > 0 && n < (int)sizeof(nvlname));
383 nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
385 for (i = 0; i < nnames; i++) {
386 n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
387 assert(n > 0 && n < (int)sizeof(nvlname));
388 nvlist_add_string(users, nvlname, names[i]);
390 nvlist_move_nvlist(limits, "users", users);
391 return (cap_limit_set(chan, limits));