xref: /freebsd/lib/libcasper/services/cap_pwd/cap_pwd.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
1c501d73cSMariusz Zaborski /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
328b6f7c8SMariusz Zaborski  *
4c501d73cSMariusz Zaborski  * Copyright (c) 2013 The FreeBSD Foundation
5c501d73cSMariusz Zaborski  *
6c501d73cSMariusz Zaborski  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7c501d73cSMariusz Zaborski  * the FreeBSD Foundation.
8c501d73cSMariusz Zaborski  *
9c501d73cSMariusz Zaborski  * Redistribution and use in source and binary forms, with or without
10c501d73cSMariusz Zaborski  * modification, are permitted provided that the following conditions
11c501d73cSMariusz Zaborski  * are met:
12c501d73cSMariusz Zaborski  * 1. Redistributions of source code must retain the above copyright
13c501d73cSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer.
14c501d73cSMariusz Zaborski  * 2. Redistributions in binary form must reproduce the above copyright
15c501d73cSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer in the
16c501d73cSMariusz Zaborski  *    documentation and/or other materials provided with the distribution.
17c501d73cSMariusz Zaborski  *
18c501d73cSMariusz Zaborski  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19c501d73cSMariusz Zaborski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c501d73cSMariusz Zaborski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21c501d73cSMariusz Zaborski  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22c501d73cSMariusz Zaborski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23c501d73cSMariusz Zaborski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24c501d73cSMariusz Zaborski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25c501d73cSMariusz Zaborski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26c501d73cSMariusz Zaborski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27c501d73cSMariusz Zaborski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28c501d73cSMariusz Zaborski  * SUCH DAMAGE.
29c501d73cSMariusz Zaborski  */
30c501d73cSMariusz Zaborski 
31c501d73cSMariusz Zaborski #include <sys/types.h>
32c501d73cSMariusz Zaborski #include <sys/nv.h>
33c501d73cSMariusz Zaborski 
34c501d73cSMariusz Zaborski #include <assert.h>
35c501d73cSMariusz Zaborski #include <errno.h>
36c501d73cSMariusz Zaborski #include <pwd.h>
37c501d73cSMariusz Zaborski #include <stdlib.h>
38c501d73cSMariusz Zaborski #include <string.h>
39c501d73cSMariusz Zaborski #include <unistd.h>
40c501d73cSMariusz Zaborski 
41c501d73cSMariusz Zaborski #include <libcasper.h>
42c501d73cSMariusz Zaborski #include <libcasper_service.h>
43c501d73cSMariusz Zaborski 
44c501d73cSMariusz Zaborski #include "cap_pwd.h"
45c501d73cSMariusz Zaborski 
46c501d73cSMariusz Zaborski static struct passwd gpwd;
47c501d73cSMariusz Zaborski static char *gbuffer;
48c501d73cSMariusz Zaborski static size_t gbufsize;
49c501d73cSMariusz Zaborski 
50c501d73cSMariusz Zaborski static int
51c501d73cSMariusz Zaborski passwd_resize(void)
52c501d73cSMariusz Zaborski {
53c501d73cSMariusz Zaborski 	char *buf;
54c501d73cSMariusz Zaborski 
55c501d73cSMariusz Zaborski 	if (gbufsize == 0)
56c501d73cSMariusz Zaborski 		gbufsize = 1024;
57c501d73cSMariusz Zaborski 	else
58c501d73cSMariusz Zaborski 		gbufsize *= 2;
59c501d73cSMariusz Zaborski 
60c501d73cSMariusz Zaborski 	buf = gbuffer;
61c501d73cSMariusz Zaborski 	gbuffer = realloc(buf, gbufsize);
62c501d73cSMariusz Zaborski 	if (gbuffer == NULL) {
63c501d73cSMariusz Zaborski 		free(buf);
64c501d73cSMariusz Zaborski 		gbufsize = 0;
65c501d73cSMariusz Zaborski 		return (ENOMEM);
66c501d73cSMariusz Zaborski 	}
67c501d73cSMariusz Zaborski 	memset(gbuffer, 0, gbufsize);
68c501d73cSMariusz Zaborski 
69c501d73cSMariusz Zaborski 	return (0);
70c501d73cSMariusz Zaborski }
71c501d73cSMariusz Zaborski 
72c501d73cSMariusz Zaborski static int
73c501d73cSMariusz Zaborski passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
74c501d73cSMariusz Zaborski     char **bufferp, size_t *bufsizep)
75c501d73cSMariusz Zaborski {
76c501d73cSMariusz Zaborski 	const char *str;
77c501d73cSMariusz Zaborski 	size_t len;
78c501d73cSMariusz Zaborski 
79c501d73cSMariusz Zaborski 	str = nvlist_get_string(nvl, fieldname);
80c501d73cSMariusz Zaborski 	len = strlcpy(*bufferp, str, *bufsizep);
81c501d73cSMariusz Zaborski 	if (len >= *bufsizep)
82c501d73cSMariusz Zaborski 		return (ERANGE);
83c501d73cSMariusz Zaborski 	*fieldp = *bufferp;
84c501d73cSMariusz Zaborski 	*bufferp += len + 1;
85c501d73cSMariusz Zaborski 	*bufsizep -= len + 1;
86c501d73cSMariusz Zaborski 
87c501d73cSMariusz Zaborski 	return (0);
88c501d73cSMariusz Zaborski }
89c501d73cSMariusz Zaborski 
90c501d73cSMariusz Zaborski static int
91c501d73cSMariusz Zaborski passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
92c501d73cSMariusz Zaborski     size_t bufsize)
93c501d73cSMariusz Zaborski {
94c501d73cSMariusz Zaborski 	int error;
95c501d73cSMariusz Zaborski 
96c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvl, "pw_name"))
97c501d73cSMariusz Zaborski 		return (EINVAL);
98c501d73cSMariusz Zaborski 
9900e94733SMariusz Zaborski 	explicit_bzero(pwd, sizeof(*pwd));
100c501d73cSMariusz Zaborski 
101c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
102c501d73cSMariusz Zaborski 	    &bufsize);
103c501d73cSMariusz Zaborski 	if (error != 0)
104c501d73cSMariusz Zaborski 		return (error);
105c501d73cSMariusz Zaborski 	pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
106c501d73cSMariusz Zaborski 	pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
107c501d73cSMariusz Zaborski 	pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
108c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
109c501d73cSMariusz Zaborski 	    &bufsize);
110c501d73cSMariusz Zaborski 	if (error != 0)
111c501d73cSMariusz Zaborski 		return (error);
112c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
113c501d73cSMariusz Zaborski 	    &bufsize);
114c501d73cSMariusz Zaborski 	if (error != 0)
115c501d73cSMariusz Zaborski 		return (error);
116c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
117c501d73cSMariusz Zaborski 	    &bufsize);
118c501d73cSMariusz Zaborski 	if (error != 0)
119c501d73cSMariusz Zaborski 		return (error);
120c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
121c501d73cSMariusz Zaborski 	    &bufsize);
122c501d73cSMariusz Zaborski 	if (error != 0)
123c501d73cSMariusz Zaborski 		return (error);
124c501d73cSMariusz Zaborski 	error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
125c501d73cSMariusz Zaborski 	    &bufsize);
126c501d73cSMariusz Zaborski 	if (error != 0)
127c501d73cSMariusz Zaborski 		return (error);
128c501d73cSMariusz Zaborski 	pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
129c501d73cSMariusz Zaborski 	pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
130c501d73cSMariusz Zaborski 
131c501d73cSMariusz Zaborski 	return (0);
132c501d73cSMariusz Zaborski }
133c501d73cSMariusz Zaborski 
134c501d73cSMariusz Zaborski static int
135c501d73cSMariusz Zaborski cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
136c501d73cSMariusz Zaborski     uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
137c501d73cSMariusz Zaborski     struct passwd **result)
138c501d73cSMariusz Zaborski {
139c501d73cSMariusz Zaborski 	nvlist_t *nvl;
140c501d73cSMariusz Zaborski 	bool getpw_r;
141c501d73cSMariusz Zaborski 	int error;
142c501d73cSMariusz Zaborski 
143c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
144c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", cmd);
145c501d73cSMariusz Zaborski 	if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
146c501d73cSMariusz Zaborski 		/* Add nothing. */
147c501d73cSMariusz Zaborski 	} else if (strcmp(cmd, "getpwnam") == 0 ||
148c501d73cSMariusz Zaborski 	    strcmp(cmd, "getpwnam_r") == 0) {
149c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "name", login);
150c501d73cSMariusz Zaborski 	} else if (strcmp(cmd, "getpwuid") == 0 ||
151c501d73cSMariusz Zaborski 	    strcmp(cmd, "getpwuid_r") == 0) {
152c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "uid", (uint64_t)uid);
153c501d73cSMariusz Zaborski 	} else {
154c501d73cSMariusz Zaborski 		abort();
155c501d73cSMariusz Zaborski 	}
1564fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
157c501d73cSMariusz Zaborski 	if (nvl == NULL) {
158c501d73cSMariusz Zaborski 		assert(errno != 0);
159c501d73cSMariusz Zaborski 		*result = NULL;
160c501d73cSMariusz Zaborski 		return (errno);
161c501d73cSMariusz Zaborski 	}
162c501d73cSMariusz Zaborski 	error = (int)nvlist_get_number(nvl, "error");
163c501d73cSMariusz Zaborski 	if (error != 0) {
164c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
165c501d73cSMariusz Zaborski 		*result = NULL;
166c501d73cSMariusz Zaborski 		return (error);
167c501d73cSMariusz Zaborski 	}
168c501d73cSMariusz Zaborski 
169c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvl, "pw_name")) {
170c501d73cSMariusz Zaborski 		/* Not found. */
171c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
172c501d73cSMariusz Zaborski 		*result = NULL;
173c501d73cSMariusz Zaborski 		return (0);
174c501d73cSMariusz Zaborski 	}
175c501d73cSMariusz Zaborski 
176c501d73cSMariusz Zaborski 	getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
177c501d73cSMariusz Zaborski 	    strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
178c501d73cSMariusz Zaborski 
179c501d73cSMariusz Zaborski 	for (;;) {
180c501d73cSMariusz Zaborski 		error = passwd_unpack(nvl, pwd, buffer, bufsize);
181c501d73cSMariusz Zaborski 		if (getpw_r || error != ERANGE)
182c501d73cSMariusz Zaborski 			break;
183c501d73cSMariusz Zaborski 		assert(buffer == gbuffer);
184c501d73cSMariusz Zaborski 		assert(bufsize == gbufsize);
185c501d73cSMariusz Zaborski 		error = passwd_resize();
186c501d73cSMariusz Zaborski 		if (error != 0)
187c501d73cSMariusz Zaborski 			break;
188c501d73cSMariusz Zaborski 		/* Update pointers after resize. */
189c501d73cSMariusz Zaborski 		buffer = gbuffer;
190c501d73cSMariusz Zaborski 		bufsize = gbufsize;
191c501d73cSMariusz Zaborski 	}
192c501d73cSMariusz Zaborski 
193c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
194c501d73cSMariusz Zaborski 
195c501d73cSMariusz Zaborski 	if (error == 0)
196c501d73cSMariusz Zaborski 		*result = pwd;
197c501d73cSMariusz Zaborski 	else
198c501d73cSMariusz Zaborski 		*result = NULL;
199c501d73cSMariusz Zaborski 
200c501d73cSMariusz Zaborski 	return (error);
201c501d73cSMariusz Zaborski }
202c501d73cSMariusz Zaborski 
203c501d73cSMariusz Zaborski static struct passwd *
204c501d73cSMariusz Zaborski cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
205c501d73cSMariusz Zaborski     uid_t uid)
206c501d73cSMariusz Zaborski {
207c501d73cSMariusz Zaborski 	struct passwd *result;
208c501d73cSMariusz Zaborski 	int error, serrno;
209c501d73cSMariusz Zaborski 
210c501d73cSMariusz Zaborski 	serrno = errno;
211c501d73cSMariusz Zaborski 
212c501d73cSMariusz Zaborski 	error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
213c501d73cSMariusz Zaborski 	    gbufsize, &result);
214c501d73cSMariusz Zaborski 	if (error != 0) {
215c501d73cSMariusz Zaborski 		errno = error;
216c501d73cSMariusz Zaborski 		return (NULL);
217c501d73cSMariusz Zaborski 	}
218c501d73cSMariusz Zaborski 
219c501d73cSMariusz Zaborski 	errno = serrno;
220c501d73cSMariusz Zaborski 
221c501d73cSMariusz Zaborski 	return (result);
222c501d73cSMariusz Zaborski }
223c501d73cSMariusz Zaborski 
224c501d73cSMariusz Zaborski struct passwd *
225c501d73cSMariusz Zaborski cap_getpwent(cap_channel_t *chan)
226c501d73cSMariusz Zaborski {
227c501d73cSMariusz Zaborski 
228c501d73cSMariusz Zaborski 	return (cap_getpwcommon(chan, "getpwent", NULL, 0));
229c501d73cSMariusz Zaborski }
230c501d73cSMariusz Zaborski 
231c501d73cSMariusz Zaborski struct passwd *
232c501d73cSMariusz Zaborski cap_getpwnam(cap_channel_t *chan, const char *login)
233c501d73cSMariusz Zaborski {
234c501d73cSMariusz Zaborski 
235c501d73cSMariusz Zaborski 	return (cap_getpwcommon(chan, "getpwnam", login, 0));
236c501d73cSMariusz Zaborski }
237c501d73cSMariusz Zaborski 
238c501d73cSMariusz Zaborski struct passwd *
239c501d73cSMariusz Zaborski cap_getpwuid(cap_channel_t *chan, uid_t uid)
240c501d73cSMariusz Zaborski {
241c501d73cSMariusz Zaborski 
242c501d73cSMariusz Zaborski 	return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
243c501d73cSMariusz Zaborski }
244c501d73cSMariusz Zaborski 
245c501d73cSMariusz Zaborski int
246c501d73cSMariusz Zaborski cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
247c501d73cSMariusz Zaborski     size_t bufsize, struct passwd **result)
248c501d73cSMariusz Zaborski {
249c501d73cSMariusz Zaborski 
250c501d73cSMariusz Zaborski 	return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
251c501d73cSMariusz Zaborski 	    bufsize, result));
252c501d73cSMariusz Zaborski }
253c501d73cSMariusz Zaborski 
254c501d73cSMariusz Zaborski int
255c501d73cSMariusz Zaborski cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
256c501d73cSMariusz Zaborski     char *buffer, size_t bufsize, struct passwd **result)
257c501d73cSMariusz Zaborski {
258c501d73cSMariusz Zaborski 
259c501d73cSMariusz Zaborski 	return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
260c501d73cSMariusz Zaborski 	    bufsize, result));
261c501d73cSMariusz Zaborski }
262c501d73cSMariusz Zaborski 
263c501d73cSMariusz Zaborski int
264c501d73cSMariusz Zaborski cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
265c501d73cSMariusz Zaborski     size_t bufsize, struct passwd **result)
266c501d73cSMariusz Zaborski {
267c501d73cSMariusz Zaborski 
268c501d73cSMariusz Zaborski 	return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
269c501d73cSMariusz Zaborski 	    bufsize, result));
270c501d73cSMariusz Zaborski }
271c501d73cSMariusz Zaborski 
272c501d73cSMariusz Zaborski int
273c501d73cSMariusz Zaborski cap_setpassent(cap_channel_t *chan, int stayopen)
274c501d73cSMariusz Zaborski {
275c501d73cSMariusz Zaborski 	nvlist_t *nvl;
276c501d73cSMariusz Zaborski 
277c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
278c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "setpassent");
279c501d73cSMariusz Zaborski 	nvlist_add_bool(nvl, "stayopen", stayopen != 0);
2804fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
281c501d73cSMariusz Zaborski 	if (nvl == NULL)
282c501d73cSMariusz Zaborski 		return (0);
283c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
284c501d73cSMariusz Zaborski 		errno = nvlist_get_number(nvl, "error");
285c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
286c501d73cSMariusz Zaborski 		return (0);
287c501d73cSMariusz Zaborski 	}
288c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
289c501d73cSMariusz Zaborski 
290c501d73cSMariusz Zaborski 	return (1);
291c501d73cSMariusz Zaborski }
292c501d73cSMariusz Zaborski 
293c501d73cSMariusz Zaborski static void
294c501d73cSMariusz Zaborski cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
295c501d73cSMariusz Zaborski {
296c501d73cSMariusz Zaborski 	nvlist_t *nvl;
297c501d73cSMariusz Zaborski 
298c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
299c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", cmd);
300c501d73cSMariusz Zaborski 	/* Ignore any errors, we have no way to report them. */
3014fc0a279SMariusz Zaborski 	nvlist_destroy(cap_xfer_nvlist(chan, nvl));
302c501d73cSMariusz Zaborski }
303c501d73cSMariusz Zaborski 
304c501d73cSMariusz Zaborski void
305c501d73cSMariusz Zaborski cap_setpwent(cap_channel_t *chan)
306c501d73cSMariusz Zaborski {
307c501d73cSMariusz Zaborski 
308c501d73cSMariusz Zaborski 	cap_set_end_pwent(chan, "setpwent");
309c501d73cSMariusz Zaborski }
310c501d73cSMariusz Zaborski 
311c501d73cSMariusz Zaborski void
312c501d73cSMariusz Zaborski cap_endpwent(cap_channel_t *chan)
313c501d73cSMariusz Zaborski {
314c501d73cSMariusz Zaborski 
315c501d73cSMariusz Zaborski 	cap_set_end_pwent(chan, "endpwent");
316c501d73cSMariusz Zaborski }
317c501d73cSMariusz Zaborski 
318c501d73cSMariusz Zaborski int
319c501d73cSMariusz Zaborski cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
320c501d73cSMariusz Zaborski {
321c501d73cSMariusz Zaborski 	nvlist_t *limits, *nvl;
322c501d73cSMariusz Zaborski 	unsigned int i;
323c501d73cSMariusz Zaborski 
324c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
325c501d73cSMariusz Zaborski 		return (-1);
326c501d73cSMariusz Zaborski 	if (limits == NULL) {
327c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
328c501d73cSMariusz Zaborski 	} else {
329c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "cmds"))
330c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "cmds");
331c501d73cSMariusz Zaborski 	}
332c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
333c501d73cSMariusz Zaborski 	for (i = 0; i < ncmds; i++)
334c501d73cSMariusz Zaborski 		nvlist_add_null(nvl, cmds[i]);
335c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "cmds", nvl);
336c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
337c501d73cSMariusz Zaborski }
338c501d73cSMariusz Zaborski 
339c501d73cSMariusz Zaborski int
340c501d73cSMariusz Zaborski cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
341c501d73cSMariusz Zaborski     size_t nfields)
342c501d73cSMariusz Zaborski {
343c501d73cSMariusz Zaborski 	nvlist_t *limits, *nvl;
344c501d73cSMariusz Zaborski 	unsigned int i;
345c501d73cSMariusz Zaborski 
346c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
347c501d73cSMariusz Zaborski 		return (-1);
348c501d73cSMariusz Zaborski 	if (limits == NULL) {
349c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
350c501d73cSMariusz Zaborski 	} else {
351c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "fields"))
352c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "fields");
353c501d73cSMariusz Zaborski 	}
354c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
355c501d73cSMariusz Zaborski 	for (i = 0; i < nfields; i++)
356c501d73cSMariusz Zaborski 		nvlist_add_null(nvl, fields[i]);
357c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "fields", nvl);
358c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
359c501d73cSMariusz Zaborski }
360c501d73cSMariusz Zaborski 
361c501d73cSMariusz Zaborski int
362c501d73cSMariusz Zaborski cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
363c501d73cSMariusz Zaborski     size_t nnames, uid_t *uids, size_t nuids)
364c501d73cSMariusz Zaborski {
365c501d73cSMariusz Zaborski 	nvlist_t *limits, *users;
366c501d73cSMariusz Zaborski 	char nvlname[64];
367c501d73cSMariusz Zaborski 	unsigned int i;
368c501d73cSMariusz Zaborski 	int n;
369c501d73cSMariusz Zaborski 
370c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
371c501d73cSMariusz Zaborski 		return (-1);
372c501d73cSMariusz Zaborski 	if (limits == NULL) {
373c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
374c501d73cSMariusz Zaborski 	} else {
375c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "users"))
376c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "users");
377c501d73cSMariusz Zaborski 	}
378c501d73cSMariusz Zaborski 	users = nvlist_create(0);
379c501d73cSMariusz Zaborski 	for (i = 0; i < nuids; i++) {
380c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
381c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
382c501d73cSMariusz Zaborski 		nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
383c501d73cSMariusz Zaborski 	}
384c501d73cSMariusz Zaborski 	for (i = 0; i < nnames; i++) {
385c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
386c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
387c501d73cSMariusz Zaborski 		nvlist_add_string(users, nvlname, names[i]);
388c501d73cSMariusz Zaborski 	}
389c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "users", users);
390c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
391c501d73cSMariusz Zaborski }
392c501d73cSMariusz Zaborski 
393c501d73cSMariusz Zaborski 
394c501d73cSMariusz Zaborski /*
395c501d73cSMariusz Zaborski  * Service functions.
396c501d73cSMariusz Zaborski  */
397c501d73cSMariusz Zaborski static bool
398c501d73cSMariusz Zaborski pwd_allowed_cmd(const nvlist_t *limits, const char *cmd)
399c501d73cSMariusz Zaborski {
400c501d73cSMariusz Zaborski 
401c501d73cSMariusz Zaborski 	if (limits == NULL)
402c501d73cSMariusz Zaborski 		return (true);
403c501d73cSMariusz Zaborski 
404c501d73cSMariusz Zaborski 	/*
405c501d73cSMariusz Zaborski 	 * If no limit was set on allowed commands, then all commands
406c501d73cSMariusz Zaborski 	 * are allowed.
407c501d73cSMariusz Zaborski 	 */
408c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "cmds"))
409c501d73cSMariusz Zaborski 		return (true);
410c501d73cSMariusz Zaborski 
411c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "cmds");
412c501d73cSMariusz Zaborski 	return (nvlist_exists_null(limits, cmd));
413c501d73cSMariusz Zaborski }
414c501d73cSMariusz Zaborski 
415c501d73cSMariusz Zaborski static int
416c501d73cSMariusz Zaborski pwd_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
417c501d73cSMariusz Zaborski {
418c501d73cSMariusz Zaborski 	const char *name;
419c501d73cSMariusz Zaborski 	void *cookie;
420c501d73cSMariusz Zaborski 	int type;
421c501d73cSMariusz Zaborski 
422c501d73cSMariusz Zaborski 	cookie = NULL;
423c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
424c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NULL)
425c501d73cSMariusz Zaborski 			return (EINVAL);
426c501d73cSMariusz Zaborski 		if (!pwd_allowed_cmd(oldlimits, name))
427c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
428c501d73cSMariusz Zaborski 	}
429c501d73cSMariusz Zaborski 
430c501d73cSMariusz Zaborski 	return (0);
431c501d73cSMariusz Zaborski }
432c501d73cSMariusz Zaborski 
433c501d73cSMariusz Zaborski static bool
434c501d73cSMariusz Zaborski pwd_allowed_user(const nvlist_t *limits, const char *uname, uid_t uid)
435c501d73cSMariusz Zaborski {
436c501d73cSMariusz Zaborski 	const char *name;
437c501d73cSMariusz Zaborski 	void *cookie;
438c501d73cSMariusz Zaborski 	int type;
439c501d73cSMariusz Zaborski 
440c501d73cSMariusz Zaborski 	if (limits == NULL)
441c501d73cSMariusz Zaborski 		return (true);
442c501d73cSMariusz Zaborski 
443c501d73cSMariusz Zaborski 	/*
444c501d73cSMariusz Zaborski 	 * If no limit was set on allowed users, then all users are allowed.
445c501d73cSMariusz Zaborski 	 */
446c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "users"))
447c501d73cSMariusz Zaborski 		return (true);
448c501d73cSMariusz Zaborski 
449c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "users");
450c501d73cSMariusz Zaborski 	cookie = NULL;
451c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
452c501d73cSMariusz Zaborski 		switch (type) {
453c501d73cSMariusz Zaborski 		case NV_TYPE_NUMBER:
454c501d73cSMariusz Zaborski 			if (uid != (uid_t)-1 &&
455c501d73cSMariusz Zaborski 			    nvlist_get_number(limits, name) == (uint64_t)uid) {
456c501d73cSMariusz Zaborski 				return (true);
457c501d73cSMariusz Zaborski 			}
458c501d73cSMariusz Zaborski 			break;
459c501d73cSMariusz Zaborski 		case NV_TYPE_STRING:
460c501d73cSMariusz Zaborski 			if (uname != NULL &&
461c501d73cSMariusz Zaborski 			    strcmp(nvlist_get_string(limits, name),
462c501d73cSMariusz Zaborski 			    uname) == 0) {
463c501d73cSMariusz Zaborski 				return (true);
464c501d73cSMariusz Zaborski 			}
465c501d73cSMariusz Zaborski 			break;
466c501d73cSMariusz Zaborski 		default:
467c501d73cSMariusz Zaborski 			abort();
468c501d73cSMariusz Zaborski 		}
469c501d73cSMariusz Zaborski 	}
470c501d73cSMariusz Zaborski 
471c501d73cSMariusz Zaborski 	return (false);
472c501d73cSMariusz Zaborski }
473c501d73cSMariusz Zaborski 
474c501d73cSMariusz Zaborski static int
475c501d73cSMariusz Zaborski pwd_allowed_users(const nvlist_t *oldlimits, const nvlist_t *newlimits)
476c501d73cSMariusz Zaborski {
477c501d73cSMariusz Zaborski 	const char *name, *uname;
478c501d73cSMariusz Zaborski 	void *cookie;
479c501d73cSMariusz Zaborski 	uid_t uid;
480c501d73cSMariusz Zaborski 	int type;
481c501d73cSMariusz Zaborski 
482c501d73cSMariusz Zaborski 	cookie = NULL;
483c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
484c501d73cSMariusz Zaborski 		switch (type) {
485c501d73cSMariusz Zaborski 		case NV_TYPE_NUMBER:
486c501d73cSMariusz Zaborski 			uid = (uid_t)nvlist_get_number(newlimits, name);
487c501d73cSMariusz Zaborski 			uname = NULL;
488c501d73cSMariusz Zaborski 			break;
489c501d73cSMariusz Zaborski 		case NV_TYPE_STRING:
490c501d73cSMariusz Zaborski 			uid = (uid_t)-1;
491c501d73cSMariusz Zaborski 			uname = nvlist_get_string(newlimits, name);
492c501d73cSMariusz Zaborski 			break;
493c501d73cSMariusz Zaborski 		default:
494c501d73cSMariusz Zaborski 			return (EINVAL);
495c501d73cSMariusz Zaborski 		}
496c501d73cSMariusz Zaborski 		if (!pwd_allowed_user(oldlimits, uname, uid))
497c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
498c501d73cSMariusz Zaborski 	}
499c501d73cSMariusz Zaborski 
500c501d73cSMariusz Zaborski 	return (0);
501c501d73cSMariusz Zaborski }
502c501d73cSMariusz Zaborski 
503c501d73cSMariusz Zaborski static bool
504c501d73cSMariusz Zaborski pwd_allowed_field(const nvlist_t *limits, const char *field)
505c501d73cSMariusz Zaborski {
506c501d73cSMariusz Zaborski 
507c501d73cSMariusz Zaborski 	if (limits == NULL)
508c501d73cSMariusz Zaborski 		return (true);
509c501d73cSMariusz Zaborski 
510c501d73cSMariusz Zaborski 	/*
511c501d73cSMariusz Zaborski 	 * If no limit was set on allowed fields, then all fields are allowed.
512c501d73cSMariusz Zaborski 	 */
513c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "fields"))
514c501d73cSMariusz Zaborski 		return (true);
515c501d73cSMariusz Zaborski 
516c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "fields");
517c501d73cSMariusz Zaborski 	return (nvlist_exists_null(limits, field));
518c501d73cSMariusz Zaborski }
519c501d73cSMariusz Zaborski 
520c501d73cSMariusz Zaborski static int
521c501d73cSMariusz Zaborski pwd_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
522c501d73cSMariusz Zaborski {
523c501d73cSMariusz Zaborski 	const char *name;
524c501d73cSMariusz Zaborski 	void *cookie;
525c501d73cSMariusz Zaborski 	int type;
526c501d73cSMariusz Zaborski 
527c501d73cSMariusz Zaborski 	cookie = NULL;
528c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
529c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NULL)
530c501d73cSMariusz Zaborski 			return (EINVAL);
531c501d73cSMariusz Zaborski 		if (!pwd_allowed_field(oldlimits, name))
532c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
533c501d73cSMariusz Zaborski 	}
534c501d73cSMariusz Zaborski 
535c501d73cSMariusz Zaborski 	return (0);
536c501d73cSMariusz Zaborski }
537c501d73cSMariusz Zaborski 
538c501d73cSMariusz Zaborski static bool
539c501d73cSMariusz Zaborski pwd_pack(const nvlist_t *limits, const struct passwd *pwd, nvlist_t *nvl)
540c501d73cSMariusz Zaborski {
541c501d73cSMariusz Zaborski 	int fields;
542c501d73cSMariusz Zaborski 
543c501d73cSMariusz Zaborski 	if (pwd == NULL)
544c501d73cSMariusz Zaborski 		return (true);
545c501d73cSMariusz Zaborski 
546c501d73cSMariusz Zaborski 	/*
547c501d73cSMariusz Zaborski 	 * If either name or UID is allowed, we allow it.
548c501d73cSMariusz Zaborski 	 */
549c501d73cSMariusz Zaborski 	if (!pwd_allowed_user(limits, pwd->pw_name, pwd->pw_uid))
550c501d73cSMariusz Zaborski 		return (false);
551c501d73cSMariusz Zaborski 
552c501d73cSMariusz Zaborski 	fields = pwd->pw_fields;
553c501d73cSMariusz Zaborski 
554c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_name")) {
555c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_name", pwd->pw_name);
556c501d73cSMariusz Zaborski 	} else {
557c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_name", "");
558c501d73cSMariusz Zaborski 		fields &= ~_PWF_NAME;
559c501d73cSMariusz Zaborski 	}
560c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_uid")) {
561c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_uid", (uint64_t)pwd->pw_uid);
562c501d73cSMariusz Zaborski 	} else {
563c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_uid", (uint64_t)-1);
564c501d73cSMariusz Zaborski 		fields &= ~_PWF_UID;
565c501d73cSMariusz Zaborski 	}
566c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_gid")) {
567c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_gid", (uint64_t)pwd->pw_gid);
568c501d73cSMariusz Zaborski 	} else {
569c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_gid", (uint64_t)-1);
570c501d73cSMariusz Zaborski 		fields &= ~_PWF_GID;
571c501d73cSMariusz Zaborski 	}
572c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_change")) {
573c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_change", (uint64_t)pwd->pw_change);
574c501d73cSMariusz Zaborski 	} else {
575c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_change", (uint64_t)0);
576c501d73cSMariusz Zaborski 		fields &= ~_PWF_CHANGE;
577c501d73cSMariusz Zaborski 	}
578c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_passwd")) {
579c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_passwd", pwd->pw_passwd);
580c501d73cSMariusz Zaborski 	} else {
581c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_passwd", "");
582c501d73cSMariusz Zaborski 		fields &= ~_PWF_PASSWD;
583c501d73cSMariusz Zaborski 	}
584c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_class")) {
585c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_class", pwd->pw_class);
586c501d73cSMariusz Zaborski 	} else {
587c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_class", "");
588c501d73cSMariusz Zaborski 		fields &= ~_PWF_CLASS;
589c501d73cSMariusz Zaborski 	}
590c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_gecos")) {
591c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_gecos", pwd->pw_gecos);
592c501d73cSMariusz Zaborski 	} else {
593c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_gecos", "");
594c501d73cSMariusz Zaborski 		fields &= ~_PWF_GECOS;
595c501d73cSMariusz Zaborski 	}
596c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_dir")) {
597c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_dir", pwd->pw_dir);
598c501d73cSMariusz Zaborski 	} else {
599c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_dir", "");
600c501d73cSMariusz Zaborski 		fields &= ~_PWF_DIR;
601c501d73cSMariusz Zaborski 	}
602c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_shell")) {
603c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_shell", pwd->pw_shell);
604c501d73cSMariusz Zaborski 	} else {
605c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "pw_shell", "");
606c501d73cSMariusz Zaborski 		fields &= ~_PWF_SHELL;
607c501d73cSMariusz Zaborski 	}
608c501d73cSMariusz Zaborski 	if (pwd_allowed_field(limits, "pw_expire")) {
609c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_expire", (uint64_t)pwd->pw_expire);
610c501d73cSMariusz Zaborski 	} else {
611c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "pw_expire", (uint64_t)0);
612c501d73cSMariusz Zaborski 		fields &= ~_PWF_EXPIRE;
613c501d73cSMariusz Zaborski 	}
614c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "pw_fields", (uint64_t)fields);
615c501d73cSMariusz Zaborski 
616c501d73cSMariusz Zaborski 	return (true);
617c501d73cSMariusz Zaborski }
618c501d73cSMariusz Zaborski 
619c501d73cSMariusz Zaborski static int
620c501d73cSMariusz Zaborski pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin __unused,
621c501d73cSMariusz Zaborski     nvlist_t *nvlout)
622c501d73cSMariusz Zaborski {
623c501d73cSMariusz Zaborski 	struct passwd *pwd;
624c501d73cSMariusz Zaborski 
625c501d73cSMariusz Zaborski 	for (;;) {
626c501d73cSMariusz Zaborski 		errno = 0;
627c501d73cSMariusz Zaborski 		pwd = getpwent();
628c501d73cSMariusz Zaborski 		if (errno != 0)
629c501d73cSMariusz Zaborski 			return (errno);
630c501d73cSMariusz Zaborski 		if (pwd_pack(limits, pwd, nvlout))
631c501d73cSMariusz Zaborski 			return (0);
632c501d73cSMariusz Zaborski 	}
633c501d73cSMariusz Zaborski 
634c501d73cSMariusz Zaborski 	/* NOTREACHED */
635c501d73cSMariusz Zaborski }
636c501d73cSMariusz Zaborski 
637c501d73cSMariusz Zaborski static int
638c501d73cSMariusz Zaborski pwd_getpwnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
639c501d73cSMariusz Zaborski {
640c501d73cSMariusz Zaborski 	struct passwd *pwd;
641c501d73cSMariusz Zaborski 	const char *name;
642c501d73cSMariusz Zaborski 
643c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvlin, "name"))
644c501d73cSMariusz Zaborski 		return (EINVAL);
645c501d73cSMariusz Zaborski 	name = nvlist_get_string(nvlin, "name");
646c501d73cSMariusz Zaborski 	assert(name != NULL);
647c501d73cSMariusz Zaborski 
648c501d73cSMariusz Zaborski 	errno = 0;
649c501d73cSMariusz Zaborski 	pwd = getpwnam(name);
650c501d73cSMariusz Zaborski 	if (errno != 0)
651c501d73cSMariusz Zaborski 		return (errno);
652c501d73cSMariusz Zaborski 
653c501d73cSMariusz Zaborski 	(void)pwd_pack(limits, pwd, nvlout);
654c501d73cSMariusz Zaborski 
655c501d73cSMariusz Zaborski 	return (0);
656c501d73cSMariusz Zaborski }
657c501d73cSMariusz Zaborski 
658c501d73cSMariusz Zaborski static int
659c501d73cSMariusz Zaborski pwd_getpwuid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
660c501d73cSMariusz Zaborski {
661c501d73cSMariusz Zaborski 	struct passwd *pwd;
662c501d73cSMariusz Zaborski 	uid_t uid;
663c501d73cSMariusz Zaborski 
664c501d73cSMariusz Zaborski 	if (!nvlist_exists_number(nvlin, "uid"))
665c501d73cSMariusz Zaborski 		return (EINVAL);
666c501d73cSMariusz Zaborski 
667c501d73cSMariusz Zaborski 	uid = (uid_t)nvlist_get_number(nvlin, "uid");
668c501d73cSMariusz Zaborski 
669c501d73cSMariusz Zaborski 	errno = 0;
670c501d73cSMariusz Zaborski 	pwd = getpwuid(uid);
671c501d73cSMariusz Zaborski 	if (errno != 0)
672c501d73cSMariusz Zaborski 		return (errno);
673c501d73cSMariusz Zaborski 
674c501d73cSMariusz Zaborski 	(void)pwd_pack(limits, pwd, nvlout);
675c501d73cSMariusz Zaborski 
676c501d73cSMariusz Zaborski 	return (0);
677c501d73cSMariusz Zaborski }
678c501d73cSMariusz Zaborski 
679c501d73cSMariusz Zaborski static int
680c501d73cSMariusz Zaborski pwd_setpassent(const nvlist_t *limits __unused, const nvlist_t *nvlin,
681c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
682c501d73cSMariusz Zaborski {
683c501d73cSMariusz Zaborski 	int stayopen;
684c501d73cSMariusz Zaborski 
685c501d73cSMariusz Zaborski 	if (!nvlist_exists_bool(nvlin, "stayopen"))
686c501d73cSMariusz Zaborski 		return (EINVAL);
687c501d73cSMariusz Zaborski 
688c501d73cSMariusz Zaborski 	stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
689c501d73cSMariusz Zaborski 
690c501d73cSMariusz Zaborski 	return (setpassent(stayopen) == 0 ? EFAULT : 0);
691c501d73cSMariusz Zaborski }
692c501d73cSMariusz Zaborski 
693c501d73cSMariusz Zaborski static int
694c501d73cSMariusz Zaborski pwd_setpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
695c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
696c501d73cSMariusz Zaborski {
697c501d73cSMariusz Zaborski 
698c501d73cSMariusz Zaborski 	setpwent();
699c501d73cSMariusz Zaborski 
700c501d73cSMariusz Zaborski 	return (0);
701c501d73cSMariusz Zaborski }
702c501d73cSMariusz Zaborski 
703c501d73cSMariusz Zaborski static int
704c501d73cSMariusz Zaborski pwd_endpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
705c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
706c501d73cSMariusz Zaborski {
707c501d73cSMariusz Zaborski 
708c501d73cSMariusz Zaborski 	endpwent();
709c501d73cSMariusz Zaborski 
710c501d73cSMariusz Zaborski 	return (0);
711c501d73cSMariusz Zaborski }
712c501d73cSMariusz Zaborski 
713c501d73cSMariusz Zaborski static int
714c501d73cSMariusz Zaborski pwd_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
715c501d73cSMariusz Zaborski {
716c501d73cSMariusz Zaborski 	const nvlist_t *limits;
717c501d73cSMariusz Zaborski 	const char *name;
718c501d73cSMariusz Zaborski 	void *cookie;
719c501d73cSMariusz Zaborski 	int error, type;
720c501d73cSMariusz Zaborski 
721c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
722c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "cmds")) {
723c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
724c501d73cSMariusz Zaborski 	}
725c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
726c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "fields")) {
727c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
728c501d73cSMariusz Zaborski 	}
729c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "users") &&
730c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "users")) {
731c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
732c501d73cSMariusz Zaborski 	}
733c501d73cSMariusz Zaborski 
734c501d73cSMariusz Zaborski 	cookie = NULL;
735c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
736c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NVLIST)
737c501d73cSMariusz Zaborski 			return (EINVAL);
738c501d73cSMariusz Zaborski 		limits = nvlist_get_nvlist(newlimits, name);
739c501d73cSMariusz Zaborski 		if (strcmp(name, "cmds") == 0)
740c501d73cSMariusz Zaborski 			error = pwd_allowed_cmds(oldlimits, limits);
741c501d73cSMariusz Zaborski 		else if (strcmp(name, "fields") == 0)
742c501d73cSMariusz Zaborski 			error = pwd_allowed_fields(oldlimits, limits);
743c501d73cSMariusz Zaborski 		else if (strcmp(name, "users") == 0)
744c501d73cSMariusz Zaborski 			error = pwd_allowed_users(oldlimits, limits);
745c501d73cSMariusz Zaborski 		else
746c501d73cSMariusz Zaborski 			error = EINVAL;
747c501d73cSMariusz Zaborski 		if (error != 0)
748c501d73cSMariusz Zaborski 			return (error);
749c501d73cSMariusz Zaborski 	}
750c501d73cSMariusz Zaborski 
751c501d73cSMariusz Zaborski 	return (0);
752c501d73cSMariusz Zaborski }
753c501d73cSMariusz Zaborski 
754c501d73cSMariusz Zaborski static int
755c501d73cSMariusz Zaborski pwd_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
756c501d73cSMariusz Zaborski     nvlist_t *nvlout)
757c501d73cSMariusz Zaborski {
758c501d73cSMariusz Zaborski 	int error;
759c501d73cSMariusz Zaborski 
760c501d73cSMariusz Zaborski 	if (!pwd_allowed_cmd(limits, cmd))
761c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
762c501d73cSMariusz Zaborski 
763c501d73cSMariusz Zaborski 	if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0)
764c501d73cSMariusz Zaborski 		error = pwd_getpwent(limits, nvlin, nvlout);
765c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getpwnam") == 0 || strcmp(cmd, "getpwnam_r") == 0)
766c501d73cSMariusz Zaborski 		error = pwd_getpwnam(limits, nvlin, nvlout);
767c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getpwuid") == 0 || strcmp(cmd, "getpwuid_r") == 0)
768c501d73cSMariusz Zaborski 		error = pwd_getpwuid(limits, nvlin, nvlout);
769c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "setpassent") == 0)
770c501d73cSMariusz Zaborski 		error = pwd_setpassent(limits, nvlin, nvlout);
771c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "setpwent") == 0)
772c501d73cSMariusz Zaborski 		error = pwd_setpwent(limits, nvlin, nvlout);
773c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "endpwent") == 0)
774c501d73cSMariusz Zaborski 		error = pwd_endpwent(limits, nvlin, nvlout);
775c501d73cSMariusz Zaborski 	else
776c501d73cSMariusz Zaborski 		error = EINVAL;
777c501d73cSMariusz Zaborski 
778c501d73cSMariusz Zaborski 	return (error);
779c501d73cSMariusz Zaborski }
780c501d73cSMariusz Zaborski 
781920be817SMariusz Zaborski CREATE_SERVICE("system.pwd", pwd_limit, pwd_command, 0);
782