xref: /freebsd/lib/libcasper/services/cap_grp/cap_grp.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/cdefs.h>
32c501d73cSMariusz Zaborski #include <sys/dnv.h>
33c501d73cSMariusz Zaborski #include <sys/nv.h>
34c501d73cSMariusz Zaborski #include <sys/param.h>
35c501d73cSMariusz Zaborski 
36c501d73cSMariusz Zaborski #include <assert.h>
37c501d73cSMariusz Zaborski #include <errno.h>
38c501d73cSMariusz Zaborski #include <grp.h>
39c501d73cSMariusz Zaborski #include <stdlib.h>
40c501d73cSMariusz Zaborski #include <string.h>
41c501d73cSMariusz Zaborski 
42c501d73cSMariusz Zaborski #include <libcasper.h>
43c501d73cSMariusz Zaborski #include <libcasper_service.h>
44c501d73cSMariusz Zaborski 
45c501d73cSMariusz Zaborski #include "cap_grp.h"
46c501d73cSMariusz Zaborski 
47c501d73cSMariusz Zaborski static struct group ggrp;
48c501d73cSMariusz Zaborski static char *gbuffer;
49c501d73cSMariusz Zaborski static size_t gbufsize;
50c501d73cSMariusz Zaborski 
51c501d73cSMariusz Zaborski static int
52c501d73cSMariusz Zaborski group_resize(void)
53c501d73cSMariusz Zaborski {
54c501d73cSMariusz Zaborski 	char *buf;
55c501d73cSMariusz Zaborski 
56c501d73cSMariusz Zaborski 	if (gbufsize == 0)
57c501d73cSMariusz Zaborski 		gbufsize = 1024;
58c501d73cSMariusz Zaborski 	else
59c501d73cSMariusz Zaborski 		gbufsize *= 2;
60c501d73cSMariusz Zaborski 
61c501d73cSMariusz Zaborski 	buf = gbuffer;
62c501d73cSMariusz Zaborski 	gbuffer = realloc(buf, gbufsize);
63c501d73cSMariusz Zaborski 	if (gbuffer == NULL) {
64c501d73cSMariusz Zaborski 		free(buf);
65c501d73cSMariusz Zaborski 		gbufsize = 0;
66c501d73cSMariusz Zaborski 		return (ENOMEM);
67c501d73cSMariusz Zaborski 	}
68c501d73cSMariusz Zaborski 	memset(gbuffer, 0, gbufsize);
69c501d73cSMariusz Zaborski 
70c501d73cSMariusz Zaborski 	return (0);
71c501d73cSMariusz Zaborski }
72c501d73cSMariusz Zaborski 
73c501d73cSMariusz Zaborski static int
74c501d73cSMariusz Zaborski group_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
75c501d73cSMariusz Zaborski     char **bufferp, size_t *bufsizep)
76c501d73cSMariusz Zaborski {
77c501d73cSMariusz Zaborski 	const char *str;
78c501d73cSMariusz Zaborski 	size_t len;
79c501d73cSMariusz Zaborski 
80c501d73cSMariusz Zaborski 	str = nvlist_get_string(nvl, fieldname);
81c501d73cSMariusz Zaborski 	len = strlcpy(*bufferp, str, *bufsizep);
82c501d73cSMariusz Zaborski 	if (len >= *bufsizep)
83c501d73cSMariusz Zaborski 		return (ERANGE);
84c501d73cSMariusz Zaborski 	*fieldp = *bufferp;
85c501d73cSMariusz Zaborski 	*bufferp += len + 1;
86c501d73cSMariusz Zaborski 	*bufsizep -= len + 1;
87c501d73cSMariusz Zaborski 
88c501d73cSMariusz Zaborski 	return (0);
89c501d73cSMariusz Zaborski }
90c501d73cSMariusz Zaborski 
91c501d73cSMariusz Zaborski static int
92c501d73cSMariusz Zaborski group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
93c501d73cSMariusz Zaborski     size_t *bufsizep)
94c501d73cSMariusz Zaborski {
95c501d73cSMariusz Zaborski 	const char *mem;
96c501d73cSMariusz Zaborski 	char **outstrs, *str, nvlname[64];
97c501d73cSMariusz Zaborski 	size_t nmem, datasize, strsize;
98c501d73cSMariusz Zaborski 	unsigned int ii;
99c501d73cSMariusz Zaborski 	int n;
100c501d73cSMariusz Zaborski 
101c501d73cSMariusz Zaborski 	if (!nvlist_exists_number(nvl, "gr_nmem")) {
102c501d73cSMariusz Zaborski 		datasize = _ALIGNBYTES + sizeof(char *);
103c501d73cSMariusz Zaborski 		if (datasize >= *bufsizep)
104c501d73cSMariusz Zaborski 			return (ERANGE);
105c501d73cSMariusz Zaborski 		outstrs = (char **)_ALIGN(*bufferp);
106c501d73cSMariusz Zaborski 		outstrs[0] = NULL;
107c501d73cSMariusz Zaborski 		*fieldp = outstrs;
108c501d73cSMariusz Zaborski 		*bufferp += datasize;
109c501d73cSMariusz Zaborski 		*bufsizep -= datasize;
110c501d73cSMariusz Zaborski 		return (0);
111c501d73cSMariusz Zaborski 	}
112c501d73cSMariusz Zaborski 
113c501d73cSMariusz Zaborski 	nmem = (size_t)nvlist_get_number(nvl, "gr_nmem");
114c501d73cSMariusz Zaborski 	datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1);
115c501d73cSMariusz Zaborski 	for (ii = 0; ii < nmem; ii++) {
116c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
117c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
118c501d73cSMariusz Zaborski 		mem = dnvlist_get_string(nvl, nvlname, NULL);
119c501d73cSMariusz Zaborski 		if (mem == NULL)
120c501d73cSMariusz Zaborski 			return (EINVAL);
121c501d73cSMariusz Zaborski 		datasize += strlen(mem) + 1;
122c501d73cSMariusz Zaborski 	}
123c501d73cSMariusz Zaborski 
124c501d73cSMariusz Zaborski 	if (datasize >= *bufsizep)
125c501d73cSMariusz Zaborski 		return (ERANGE);
126c501d73cSMariusz Zaborski 
127c501d73cSMariusz Zaborski 	outstrs = (char **)_ALIGN(*bufferp);
128c501d73cSMariusz Zaborski 	str = (char *)outstrs + sizeof(char *) * (nmem + 1);
129c501d73cSMariusz Zaborski 	for (ii = 0; ii < nmem; ii++) {
130c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
131c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
132c501d73cSMariusz Zaborski 		mem = nvlist_get_string(nvl, nvlname);
133c501d73cSMariusz Zaborski 		strsize = strlen(mem) + 1;
134c501d73cSMariusz Zaborski 		memcpy(str, mem, strsize);
135c501d73cSMariusz Zaborski 		outstrs[ii] = str;
136c501d73cSMariusz Zaborski 		str += strsize;
137c501d73cSMariusz Zaborski 	}
138c501d73cSMariusz Zaborski 	assert(ii == nmem);
139c501d73cSMariusz Zaborski 	outstrs[ii] = NULL;
140c501d73cSMariusz Zaborski 
141c501d73cSMariusz Zaborski 	*fieldp = outstrs;
142c501d73cSMariusz Zaborski 	*bufferp += datasize;
143c501d73cSMariusz Zaborski 	*bufsizep -= datasize;
144c501d73cSMariusz Zaborski 
145c501d73cSMariusz Zaborski 	return (0);
146c501d73cSMariusz Zaborski }
147c501d73cSMariusz Zaborski 
148c501d73cSMariusz Zaborski static int
149c501d73cSMariusz Zaborski group_unpack(const nvlist_t *nvl, struct group *grp, char *buffer,
150c501d73cSMariusz Zaborski     size_t bufsize)
151c501d73cSMariusz Zaborski {
152c501d73cSMariusz Zaborski 	int error;
153c501d73cSMariusz Zaborski 
154c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvl, "gr_name"))
155c501d73cSMariusz Zaborski 		return (EINVAL);
156c501d73cSMariusz Zaborski 
157d9c2248dSMariusz Zaborski 	explicit_bzero(grp, sizeof(*grp));
158c501d73cSMariusz Zaborski 
159c501d73cSMariusz Zaborski 	error = group_unpack_string(nvl, "gr_name", &grp->gr_name, &buffer,
160c501d73cSMariusz Zaborski 	    &bufsize);
161c501d73cSMariusz Zaborski 	if (error != 0)
162c501d73cSMariusz Zaborski 		return (error);
163c501d73cSMariusz Zaborski 	error = group_unpack_string(nvl, "gr_passwd", &grp->gr_passwd, &buffer,
164c501d73cSMariusz Zaborski 	    &bufsize);
165c501d73cSMariusz Zaborski 	if (error != 0)
166c501d73cSMariusz Zaborski 		return (error);
167c501d73cSMariusz Zaborski 	grp->gr_gid = (gid_t)nvlist_get_number(nvl, "gr_gid");
168c501d73cSMariusz Zaborski 	error = group_unpack_members(nvl, &grp->gr_mem, &buffer, &bufsize);
169c501d73cSMariusz Zaborski 	if (error != 0)
170c501d73cSMariusz Zaborski 		return (error);
171c501d73cSMariusz Zaborski 
172c501d73cSMariusz Zaborski 	return (0);
173c501d73cSMariusz Zaborski }
174c501d73cSMariusz Zaborski 
175c501d73cSMariusz Zaborski static int
176c501d73cSMariusz Zaborski cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
177c501d73cSMariusz Zaborski     gid_t gid, struct group *grp, char *buffer, size_t bufsize,
178c501d73cSMariusz Zaborski     struct group **result)
179c501d73cSMariusz Zaborski {
180c501d73cSMariusz Zaborski 	nvlist_t *nvl;
181c501d73cSMariusz Zaborski 	bool getgr_r;
182c501d73cSMariusz Zaborski 	int error;
183c501d73cSMariusz Zaborski 
184c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
185c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", cmd);
186c501d73cSMariusz Zaborski 	if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) {
187c501d73cSMariusz Zaborski 		/* Add nothing. */
188c501d73cSMariusz Zaborski 	} else if (strcmp(cmd, "getgrnam") == 0 ||
189c501d73cSMariusz Zaborski 	    strcmp(cmd, "getgrnam_r") == 0) {
190c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "name", name);
191c501d73cSMariusz Zaborski 	} else if (strcmp(cmd, "getgrgid") == 0 ||
192c501d73cSMariusz Zaborski 	    strcmp(cmd, "getgrgid_r") == 0) {
193c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "gid", (uint64_t)gid);
194c501d73cSMariusz Zaborski 	} else {
195c501d73cSMariusz Zaborski 		abort();
196c501d73cSMariusz Zaborski 	}
1974fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
198c501d73cSMariusz Zaborski 	if (nvl == NULL) {
199c501d73cSMariusz Zaborski 		assert(errno != 0);
200c501d73cSMariusz Zaborski 		*result = NULL;
201c501d73cSMariusz Zaborski 		return (errno);
202c501d73cSMariusz Zaborski 	}
203c501d73cSMariusz Zaborski 	error = (int)nvlist_get_number(nvl, "error");
204c501d73cSMariusz Zaborski 	if (error != 0) {
205c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
206c501d73cSMariusz Zaborski 		*result = NULL;
207c501d73cSMariusz Zaborski 		return (error);
208c501d73cSMariusz Zaborski 	}
209c501d73cSMariusz Zaborski 
210c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvl, "gr_name")) {
211c501d73cSMariusz Zaborski 		/* Not found. */
212c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
213c501d73cSMariusz Zaborski 		*result = NULL;
214c501d73cSMariusz Zaborski 		return (0);
215c501d73cSMariusz Zaborski 	}
216c501d73cSMariusz Zaborski 
217c501d73cSMariusz Zaborski 	getgr_r = (strcmp(cmd, "getgrent_r") == 0 ||
218c501d73cSMariusz Zaborski 	    strcmp(cmd, "getgrnam_r") == 0 || strcmp(cmd, "getgrgid_r") == 0);
219c501d73cSMariusz Zaborski 
220c501d73cSMariusz Zaborski 	for (;;) {
221c501d73cSMariusz Zaborski 		error = group_unpack(nvl, grp, buffer, bufsize);
222c501d73cSMariusz Zaborski 		if (getgr_r || error != ERANGE)
223c501d73cSMariusz Zaborski 			break;
224c501d73cSMariusz Zaborski 		assert(buffer == gbuffer);
225c501d73cSMariusz Zaborski 		assert(bufsize == gbufsize);
226c501d73cSMariusz Zaborski 		error = group_resize();
227c501d73cSMariusz Zaborski 		if (error != 0)
228c501d73cSMariusz Zaborski 			break;
229c501d73cSMariusz Zaborski 		/* Update pointers after resize. */
230c501d73cSMariusz Zaborski 		buffer = gbuffer;
231c501d73cSMariusz Zaborski 		bufsize = gbufsize;
232c501d73cSMariusz Zaborski 	}
233c501d73cSMariusz Zaborski 
234c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
235c501d73cSMariusz Zaborski 
236c501d73cSMariusz Zaborski 	if (error == 0)
237c501d73cSMariusz Zaborski 		*result = grp;
238c501d73cSMariusz Zaborski 	else
239c501d73cSMariusz Zaborski 		*result = NULL;
240c501d73cSMariusz Zaborski 
241c501d73cSMariusz Zaborski 	return (error);
242c501d73cSMariusz Zaborski }
243c501d73cSMariusz Zaborski 
244c501d73cSMariusz Zaborski static struct group *
245c501d73cSMariusz Zaborski cap_getgrcommon(cap_channel_t *chan, const char *cmd, const char *name,
246c501d73cSMariusz Zaborski     gid_t gid)
247c501d73cSMariusz Zaborski {
248c501d73cSMariusz Zaborski 	struct group *result;
249c501d73cSMariusz Zaborski 	int error, serrno;
250c501d73cSMariusz Zaborski 
251c501d73cSMariusz Zaborski 	serrno = errno;
252c501d73cSMariusz Zaborski 
253c501d73cSMariusz Zaborski 	error = cap_getgrcommon_r(chan, cmd, name, gid, &ggrp, gbuffer,
254c501d73cSMariusz Zaborski 	    gbufsize, &result);
255c501d73cSMariusz Zaborski 	if (error != 0) {
256c501d73cSMariusz Zaborski 		errno = error;
257c501d73cSMariusz Zaborski 		return (NULL);
258c501d73cSMariusz Zaborski 	}
259c501d73cSMariusz Zaborski 
260c501d73cSMariusz Zaborski 	errno = serrno;
261c501d73cSMariusz Zaborski 
262c501d73cSMariusz Zaborski 	return (result);
263c501d73cSMariusz Zaborski }
264c501d73cSMariusz Zaborski 
265c501d73cSMariusz Zaborski struct group *
266c501d73cSMariusz Zaborski cap_getgrent(cap_channel_t *chan)
267c501d73cSMariusz Zaborski {
268c501d73cSMariusz Zaborski 
269c501d73cSMariusz Zaborski 	return (cap_getgrcommon(chan, "getgrent", NULL, 0));
270c501d73cSMariusz Zaborski }
271c501d73cSMariusz Zaborski 
272c501d73cSMariusz Zaborski struct group *
273c501d73cSMariusz Zaborski cap_getgrnam(cap_channel_t *chan, const char *name)
274c501d73cSMariusz Zaborski {
275c501d73cSMariusz Zaborski 
276c501d73cSMariusz Zaborski 	return (cap_getgrcommon(chan, "getgrnam", name, 0));
277c501d73cSMariusz Zaborski }
278c501d73cSMariusz Zaborski 
279c501d73cSMariusz Zaborski struct group *
280c501d73cSMariusz Zaborski cap_getgrgid(cap_channel_t *chan, gid_t gid)
281c501d73cSMariusz Zaborski {
282c501d73cSMariusz Zaborski 
283c501d73cSMariusz Zaborski 	return (cap_getgrcommon(chan, "getgrgid", NULL, gid));
284c501d73cSMariusz Zaborski }
285c501d73cSMariusz Zaborski 
286c501d73cSMariusz Zaborski int
287c501d73cSMariusz Zaborski cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
288c501d73cSMariusz Zaborski     size_t bufsize, struct group **result)
289c501d73cSMariusz Zaborski {
290c501d73cSMariusz Zaborski 
291c501d73cSMariusz Zaborski 	return (cap_getgrcommon_r(chan, "getgrent_r", NULL, 0, grp, buffer,
292c501d73cSMariusz Zaborski 	    bufsize, result));
293c501d73cSMariusz Zaborski }
294c501d73cSMariusz Zaborski 
295c501d73cSMariusz Zaborski int
296c501d73cSMariusz Zaborski cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
297c501d73cSMariusz Zaborski     char *buffer, size_t bufsize, struct group **result)
298c501d73cSMariusz Zaborski {
299c501d73cSMariusz Zaborski 
300c501d73cSMariusz Zaborski 	return (cap_getgrcommon_r(chan, "getgrnam_r", name, 0, grp, buffer,
301c501d73cSMariusz Zaborski 	    bufsize, result));
302c501d73cSMariusz Zaborski }
303c501d73cSMariusz Zaborski 
304c501d73cSMariusz Zaborski int
305c501d73cSMariusz Zaborski cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer,
306c501d73cSMariusz Zaborski     size_t bufsize, struct group **result)
307c501d73cSMariusz Zaborski {
308c501d73cSMariusz Zaborski 
309c501d73cSMariusz Zaborski 	return (cap_getgrcommon_r(chan, "getgrgid_r", NULL, gid, grp, buffer,
310c501d73cSMariusz Zaborski 	    bufsize, result));
311c501d73cSMariusz Zaborski }
312c501d73cSMariusz Zaborski 
313c501d73cSMariusz Zaborski int
314c501d73cSMariusz Zaborski cap_setgroupent(cap_channel_t *chan, int stayopen)
315c501d73cSMariusz Zaborski {
316c501d73cSMariusz Zaborski 	nvlist_t *nvl;
317c501d73cSMariusz Zaborski 
318c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
319c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "setgroupent");
320c501d73cSMariusz Zaborski 	nvlist_add_bool(nvl, "stayopen", stayopen != 0);
3214fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
322c501d73cSMariusz Zaborski 	if (nvl == NULL)
323c501d73cSMariusz Zaborski 		return (0);
324c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
325c501d73cSMariusz Zaborski 		errno = nvlist_get_number(nvl, "error");
326c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
327c501d73cSMariusz Zaborski 		return (0);
328c501d73cSMariusz Zaborski 	}
329c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
330c501d73cSMariusz Zaborski 
331c501d73cSMariusz Zaborski 	return (1);
332c501d73cSMariusz Zaborski }
333c501d73cSMariusz Zaborski 
334c501d73cSMariusz Zaborski int
335c501d73cSMariusz Zaborski cap_setgrent(cap_channel_t *chan)
336c501d73cSMariusz Zaborski {
337c501d73cSMariusz Zaborski 	nvlist_t *nvl;
338c501d73cSMariusz Zaborski 
339c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
340c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "setgrent");
3414fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
342c501d73cSMariusz Zaborski 	if (nvl == NULL)
343c501d73cSMariusz Zaborski 		return (0);
344c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
345c501d73cSMariusz Zaborski 		errno = nvlist_get_number(nvl, "error");
346c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
347c501d73cSMariusz Zaborski 		return (0);
348c501d73cSMariusz Zaborski 	}
349c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
350c501d73cSMariusz Zaborski 
351c501d73cSMariusz Zaborski 	return (1);
352c501d73cSMariusz Zaborski }
353c501d73cSMariusz Zaborski 
354c501d73cSMariusz Zaborski void
355c501d73cSMariusz Zaborski cap_endgrent(cap_channel_t *chan)
356c501d73cSMariusz Zaborski {
357c501d73cSMariusz Zaborski 	nvlist_t *nvl;
358c501d73cSMariusz Zaborski 
359c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
360c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "endgrent");
361c501d73cSMariusz Zaborski 	/* Ignore any errors, we have no way to report them. */
3624fc0a279SMariusz Zaborski 	nvlist_destroy(cap_xfer_nvlist(chan, nvl));
363c501d73cSMariusz Zaborski }
364c501d73cSMariusz Zaborski 
365c501d73cSMariusz Zaborski int
366c501d73cSMariusz Zaborski cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
367c501d73cSMariusz Zaborski {
368c501d73cSMariusz Zaborski 	nvlist_t *limits, *nvl;
369c501d73cSMariusz Zaborski 	unsigned int i;
370c501d73cSMariusz Zaborski 
371c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
372c501d73cSMariusz Zaborski 		return (-1);
373c501d73cSMariusz Zaborski 	if (limits == NULL) {
374c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
375c501d73cSMariusz Zaborski 	} else {
376c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "cmds"))
377c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "cmds");
378c501d73cSMariusz Zaborski 	}
379c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
380c501d73cSMariusz Zaborski 	for (i = 0; i < ncmds; i++)
381c501d73cSMariusz Zaborski 		nvlist_add_null(nvl, cmds[i]);
382c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "cmds", nvl);
383c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
384c501d73cSMariusz Zaborski }
385c501d73cSMariusz Zaborski 
386c501d73cSMariusz Zaborski int
387c501d73cSMariusz Zaborski cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
388c501d73cSMariusz Zaborski     size_t nfields)
389c501d73cSMariusz Zaborski {
390c501d73cSMariusz Zaborski 	nvlist_t *limits, *nvl;
391c501d73cSMariusz Zaborski 	unsigned int i;
392c501d73cSMariusz Zaborski 
393c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
394c501d73cSMariusz Zaborski 		return (-1);
395c501d73cSMariusz Zaborski 	if (limits == NULL) {
396c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
397c501d73cSMariusz Zaborski 	} else {
398c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "fields"))
399c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "fields");
400c501d73cSMariusz Zaborski 	}
401c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
402c501d73cSMariusz Zaborski 	for (i = 0; i < nfields; i++)
403c501d73cSMariusz Zaborski 		nvlist_add_null(nvl, fields[i]);
404c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "fields", nvl);
405c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
406c501d73cSMariusz Zaborski }
407c501d73cSMariusz Zaborski 
408c501d73cSMariusz Zaborski int
409c501d73cSMariusz Zaborski cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
4104468cd1aSMariusz Zaborski     size_t nnames, const gid_t *gids, size_t ngids)
411c501d73cSMariusz Zaborski {
412c501d73cSMariusz Zaborski 	nvlist_t *limits, *groups;
413c501d73cSMariusz Zaborski 	unsigned int i;
414c501d73cSMariusz Zaborski 	char nvlname[64];
415c501d73cSMariusz Zaborski 	int n;
416c501d73cSMariusz Zaborski 
417c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
418c501d73cSMariusz Zaborski 		return (-1);
419c501d73cSMariusz Zaborski 	if (limits == NULL) {
420c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
421c501d73cSMariusz Zaborski 	} else {
422c501d73cSMariusz Zaborski 		if (nvlist_exists_nvlist(limits, "groups"))
423c501d73cSMariusz Zaborski 			nvlist_free_nvlist(limits, "groups");
424c501d73cSMariusz Zaborski 	}
425c501d73cSMariusz Zaborski 	groups = nvlist_create(0);
426c501d73cSMariusz Zaborski 	for (i = 0; i < ngids; i++) {
427c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
428c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
429c501d73cSMariusz Zaborski 		nvlist_add_number(groups, nvlname, (uint64_t)gids[i]);
430c501d73cSMariusz Zaborski 	}
431c501d73cSMariusz Zaborski 	for (i = 0; i < nnames; i++) {
432c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
433c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
434c501d73cSMariusz Zaborski 		nvlist_add_string(groups, nvlname, names[i]);
435c501d73cSMariusz Zaborski 	}
436c501d73cSMariusz Zaborski 	nvlist_move_nvlist(limits, "groups", groups);
437c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
438c501d73cSMariusz Zaborski }
439c501d73cSMariusz Zaborski 
440c501d73cSMariusz Zaborski /*
441c501d73cSMariusz Zaborski  * Service functions.
442c501d73cSMariusz Zaborski  */
443c501d73cSMariusz Zaborski static bool
444c501d73cSMariusz Zaborski grp_allowed_cmd(const nvlist_t *limits, const char *cmd)
445c501d73cSMariusz Zaborski {
446c501d73cSMariusz Zaborski 
447c501d73cSMariusz Zaborski 	if (limits == NULL)
448c501d73cSMariusz Zaborski 		return (true);
449c501d73cSMariusz Zaborski 
450c501d73cSMariusz Zaborski 	/*
451c501d73cSMariusz Zaborski 	 * If no limit was set on allowed commands, then all commands
452c501d73cSMariusz Zaborski 	 * are allowed.
453c501d73cSMariusz Zaborski 	 */
454c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "cmds"))
455c501d73cSMariusz Zaborski 		return (true);
456c501d73cSMariusz Zaborski 
457c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "cmds");
458c501d73cSMariusz Zaborski 	return (nvlist_exists_null(limits, cmd));
459c501d73cSMariusz Zaborski }
460c501d73cSMariusz Zaborski 
461c501d73cSMariusz Zaborski static int
462c501d73cSMariusz Zaborski grp_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
463c501d73cSMariusz Zaborski {
464c501d73cSMariusz Zaborski 	const char *name;
465c501d73cSMariusz Zaborski 	void *cookie;
466c501d73cSMariusz Zaborski 	int type;
467c501d73cSMariusz Zaborski 
468c501d73cSMariusz Zaborski 	cookie = NULL;
469c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
470c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NULL)
471c501d73cSMariusz Zaborski 			return (EINVAL);
472c501d73cSMariusz Zaborski 		if (!grp_allowed_cmd(oldlimits, name))
473c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
474c501d73cSMariusz Zaborski 	}
475c501d73cSMariusz Zaborski 
476c501d73cSMariusz Zaborski 	return (0);
477c501d73cSMariusz Zaborski }
478c501d73cSMariusz Zaborski 
479c501d73cSMariusz Zaborski static bool
480c501d73cSMariusz Zaborski grp_allowed_group(const nvlist_t *limits, const char *gname, gid_t gid)
481c501d73cSMariusz Zaborski {
482c501d73cSMariusz Zaborski 	const char *name;
483c501d73cSMariusz Zaborski 	void *cookie;
484c501d73cSMariusz Zaborski 	int type;
485c501d73cSMariusz Zaborski 
486c501d73cSMariusz Zaborski 	if (limits == NULL)
487c501d73cSMariusz Zaborski 		return (true);
488c501d73cSMariusz Zaborski 
489c501d73cSMariusz Zaborski 	/*
490c501d73cSMariusz Zaborski 	 * If no limit was set on allowed groups, then all groups are allowed.
491c501d73cSMariusz Zaborski 	 */
492c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "groups"))
493c501d73cSMariusz Zaborski 		return (true);
494c501d73cSMariusz Zaborski 
495c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "groups");
496c501d73cSMariusz Zaborski 	cookie = NULL;
497c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
498c501d73cSMariusz Zaborski 		switch (type) {
499c501d73cSMariusz Zaborski 		case NV_TYPE_NUMBER:
500c501d73cSMariusz Zaborski 			if (gid != (gid_t)-1 &&
501c501d73cSMariusz Zaborski 			    nvlist_get_number(limits, name) == (uint64_t)gid) {
502c501d73cSMariusz Zaborski 				return (true);
503c501d73cSMariusz Zaborski 			}
504c501d73cSMariusz Zaborski 			break;
505c501d73cSMariusz Zaborski 		case NV_TYPE_STRING:
506c501d73cSMariusz Zaborski 			if (gname != NULL &&
507c501d73cSMariusz Zaborski 			    strcmp(nvlist_get_string(limits, name),
508c501d73cSMariusz Zaborski 			    gname) == 0) {
509c501d73cSMariusz Zaborski 				return (true);
510c501d73cSMariusz Zaborski 			}
511c501d73cSMariusz Zaborski 			break;
512c501d73cSMariusz Zaborski 		default:
513c501d73cSMariusz Zaborski 			abort();
514c501d73cSMariusz Zaborski 		}
515c501d73cSMariusz Zaborski 	}
516c501d73cSMariusz Zaborski 
517c501d73cSMariusz Zaborski 	return (false);
518c501d73cSMariusz Zaborski }
519c501d73cSMariusz Zaborski 
520c501d73cSMariusz Zaborski static int
521c501d73cSMariusz Zaborski grp_allowed_groups(const nvlist_t *oldlimits, const nvlist_t *newlimits)
522c501d73cSMariusz Zaborski {
523c501d73cSMariusz Zaborski 	const char *name, *gname;
524c501d73cSMariusz Zaborski 	void *cookie;
525c501d73cSMariusz Zaborski 	gid_t gid;
526c501d73cSMariusz Zaborski 	int type;
527c501d73cSMariusz Zaborski 
528c501d73cSMariusz Zaborski 	cookie = NULL;
529c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
530c501d73cSMariusz Zaborski 		switch (type) {
531c501d73cSMariusz Zaborski 		case NV_TYPE_NUMBER:
532c501d73cSMariusz Zaborski 			gid = (gid_t)nvlist_get_number(newlimits, name);
533c501d73cSMariusz Zaborski 			gname = NULL;
534c501d73cSMariusz Zaborski 			break;
535c501d73cSMariusz Zaborski 		case NV_TYPE_STRING:
536c501d73cSMariusz Zaborski 			gid = (gid_t)-1;
537c501d73cSMariusz Zaborski 			gname = nvlist_get_string(newlimits, name);
538c501d73cSMariusz Zaborski 			break;
539c501d73cSMariusz Zaborski 		default:
540c501d73cSMariusz Zaborski 			return (EINVAL);
541c501d73cSMariusz Zaborski 		}
542c501d73cSMariusz Zaborski 		if (!grp_allowed_group(oldlimits, gname, gid))
543c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
544c501d73cSMariusz Zaborski 	}
545c501d73cSMariusz Zaborski 
546c501d73cSMariusz Zaborski 	return (0);
547c501d73cSMariusz Zaborski }
548c501d73cSMariusz Zaborski 
549c501d73cSMariusz Zaborski static bool
550c501d73cSMariusz Zaborski grp_allowed_field(const nvlist_t *limits, const char *field)
551c501d73cSMariusz Zaborski {
552c501d73cSMariusz Zaborski 
553c501d73cSMariusz Zaborski 	if (limits == NULL)
554c501d73cSMariusz Zaborski 		return (true);
555c501d73cSMariusz Zaborski 
556c501d73cSMariusz Zaborski 	/*
557c501d73cSMariusz Zaborski 	 * If no limit was set on allowed fields, then all fields are allowed.
558c501d73cSMariusz Zaborski 	 */
559c501d73cSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "fields"))
560c501d73cSMariusz Zaborski 		return (true);
561c501d73cSMariusz Zaborski 
562c501d73cSMariusz Zaborski 	limits = nvlist_get_nvlist(limits, "fields");
563c501d73cSMariusz Zaborski 	return (nvlist_exists_null(limits, field));
564c501d73cSMariusz Zaborski }
565c501d73cSMariusz Zaborski 
566c501d73cSMariusz Zaborski static int
567c501d73cSMariusz Zaborski grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
568c501d73cSMariusz Zaborski {
569c501d73cSMariusz Zaborski 	const char *name;
570c501d73cSMariusz Zaborski 	void *cookie;
571c501d73cSMariusz Zaborski 	int type;
572c501d73cSMariusz Zaborski 
573c501d73cSMariusz Zaborski 	cookie = NULL;
574c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
575c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NULL)
576c501d73cSMariusz Zaborski 			return (EINVAL);
577c501d73cSMariusz Zaborski 		if (!grp_allowed_field(oldlimits, name))
578c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
579c501d73cSMariusz Zaborski 	}
580c501d73cSMariusz Zaborski 
581c501d73cSMariusz Zaborski 	return (0);
582c501d73cSMariusz Zaborski }
583c501d73cSMariusz Zaborski 
584c501d73cSMariusz Zaborski static bool
585c501d73cSMariusz Zaborski grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
586c501d73cSMariusz Zaborski {
587c501d73cSMariusz Zaborski 	char nvlname[64];
588c501d73cSMariusz Zaborski 	int n;
589c501d73cSMariusz Zaborski 
590c501d73cSMariusz Zaborski 	if (grp == NULL)
591c501d73cSMariusz Zaborski 		return (true);
592c501d73cSMariusz Zaborski 
593c501d73cSMariusz Zaborski 	/*
594c501d73cSMariusz Zaborski 	 * If either name or GID is allowed, we allow it.
595c501d73cSMariusz Zaborski 	 */
596c501d73cSMariusz Zaborski 	if (!grp_allowed_group(limits, grp->gr_name, grp->gr_gid))
597c501d73cSMariusz Zaborski 		return (false);
598c501d73cSMariusz Zaborski 
599c501d73cSMariusz Zaborski 	if (grp_allowed_field(limits, "gr_name"))
600c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "gr_name", grp->gr_name);
601c501d73cSMariusz Zaborski 	else
602c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "gr_name", "");
603c501d73cSMariusz Zaborski 	if (grp_allowed_field(limits, "gr_passwd"))
604c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "gr_passwd", grp->gr_passwd);
605c501d73cSMariusz Zaborski 	else
606c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "gr_passwd", "");
607c501d73cSMariusz Zaborski 	if (grp_allowed_field(limits, "gr_gid"))
608c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "gr_gid", (uint64_t)grp->gr_gid);
609c501d73cSMariusz Zaborski 	else
610c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "gr_gid", (uint64_t)-1);
611c501d73cSMariusz Zaborski 	if (grp_allowed_field(limits, "gr_mem") && grp->gr_mem[0] != NULL) {
612c501d73cSMariusz Zaborski 		unsigned int ngroups;
613c501d73cSMariusz Zaborski 
614c501d73cSMariusz Zaborski 		for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) {
615c501d73cSMariusz Zaborski 			n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]",
616c501d73cSMariusz Zaborski 			    ngroups);
617c501d73cSMariusz Zaborski 			assert(n > 0 && n < (ssize_t)sizeof(nvlname));
618c501d73cSMariusz Zaborski 			nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]);
619c501d73cSMariusz Zaborski 		}
620c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups);
621c501d73cSMariusz Zaborski 	}
622c501d73cSMariusz Zaborski 
623c501d73cSMariusz Zaborski 	return (true);
624c501d73cSMariusz Zaborski }
625c501d73cSMariusz Zaborski 
626c501d73cSMariusz Zaborski static int
627c501d73cSMariusz Zaborski grp_getgrent(const nvlist_t *limits, const nvlist_t *nvlin __unused,
628c501d73cSMariusz Zaborski     nvlist_t *nvlout)
629c501d73cSMariusz Zaborski {
630c501d73cSMariusz Zaborski 	struct group *grp;
631c501d73cSMariusz Zaborski 
632c501d73cSMariusz Zaborski 	for (;;) {
633c501d73cSMariusz Zaborski 		errno = 0;
634c501d73cSMariusz Zaborski 		grp = getgrent();
635c501d73cSMariusz Zaborski 		if (errno != 0)
636c501d73cSMariusz Zaborski 			return (errno);
637c501d73cSMariusz Zaborski 		if (grp_pack(limits, grp, nvlout))
638c501d73cSMariusz Zaborski 			return (0);
639c501d73cSMariusz Zaborski 	}
640c501d73cSMariusz Zaborski 
641c501d73cSMariusz Zaborski 	/* NOTREACHED */
642c501d73cSMariusz Zaborski }
643c501d73cSMariusz Zaborski 
644c501d73cSMariusz Zaborski static int
645c501d73cSMariusz Zaborski grp_getgrnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
646c501d73cSMariusz Zaborski {
647c501d73cSMariusz Zaborski 	struct group *grp;
648c501d73cSMariusz Zaborski 	const char *name;
649c501d73cSMariusz Zaborski 
650c501d73cSMariusz Zaborski 	if (!nvlist_exists_string(nvlin, "name"))
651c501d73cSMariusz Zaborski 		return (EINVAL);
652c501d73cSMariusz Zaborski 	name = nvlist_get_string(nvlin, "name");
653c501d73cSMariusz Zaborski 	assert(name != NULL);
654c501d73cSMariusz Zaborski 
655c501d73cSMariusz Zaborski 	errno = 0;
656c501d73cSMariusz Zaborski 	grp = getgrnam(name);
657c501d73cSMariusz Zaborski 	if (errno != 0)
658c501d73cSMariusz Zaborski 		return (errno);
659c501d73cSMariusz Zaborski 
660c501d73cSMariusz Zaborski 	(void)grp_pack(limits, grp, nvlout);
661c501d73cSMariusz Zaborski 
662c501d73cSMariusz Zaborski 	return (0);
663c501d73cSMariusz Zaborski }
664c501d73cSMariusz Zaborski 
665c501d73cSMariusz Zaborski static int
666c501d73cSMariusz Zaborski grp_getgrgid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
667c501d73cSMariusz Zaborski {
668c501d73cSMariusz Zaborski 	struct group *grp;
669c501d73cSMariusz Zaborski 	gid_t gid;
670c501d73cSMariusz Zaborski 
671c501d73cSMariusz Zaborski 	if (!nvlist_exists_number(nvlin, "gid"))
672c501d73cSMariusz Zaborski 		return (EINVAL);
673c501d73cSMariusz Zaborski 
674c501d73cSMariusz Zaborski 	gid = (gid_t)nvlist_get_number(nvlin, "gid");
675c501d73cSMariusz Zaborski 
676c501d73cSMariusz Zaborski 	errno = 0;
677c501d73cSMariusz Zaborski 	grp = getgrgid(gid);
678c501d73cSMariusz Zaborski 	if (errno != 0)
679c501d73cSMariusz Zaborski 		return (errno);
680c501d73cSMariusz Zaborski 
681c501d73cSMariusz Zaborski 	(void)grp_pack(limits, grp, nvlout);
682c501d73cSMariusz Zaborski 
683c501d73cSMariusz Zaborski 	return (0);
684c501d73cSMariusz Zaborski }
685c501d73cSMariusz Zaborski 
686c501d73cSMariusz Zaborski static int
687c501d73cSMariusz Zaborski grp_setgroupent(const nvlist_t *limits __unused, const nvlist_t *nvlin,
688c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
689c501d73cSMariusz Zaborski {
690c501d73cSMariusz Zaborski 	int stayopen;
691c501d73cSMariusz Zaborski 
692c501d73cSMariusz Zaborski 	if (!nvlist_exists_bool(nvlin, "stayopen"))
693c501d73cSMariusz Zaborski 		return (EINVAL);
694c501d73cSMariusz Zaborski 
695c501d73cSMariusz Zaborski 	stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
696c501d73cSMariusz Zaborski 
697c501d73cSMariusz Zaborski 	return (setgroupent(stayopen) == 0 ? EFAULT : 0);
698c501d73cSMariusz Zaborski }
699c501d73cSMariusz Zaborski 
700c501d73cSMariusz Zaborski static int
701c501d73cSMariusz Zaborski grp_setgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
702c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
703c501d73cSMariusz Zaborski {
704c501d73cSMariusz Zaborski 
7052ca9ffa9SEd Schouten 	setgrent();
7062ca9ffa9SEd Schouten 
7072ca9ffa9SEd Schouten 	return (0);
708c501d73cSMariusz Zaborski }
709c501d73cSMariusz Zaborski 
710c501d73cSMariusz Zaborski static int
711c501d73cSMariusz Zaborski grp_endgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
712c501d73cSMariusz Zaborski     nvlist_t *nvlout __unused)
713c501d73cSMariusz Zaborski {
714c501d73cSMariusz Zaborski 
715c501d73cSMariusz Zaborski 	endgrent();
716c501d73cSMariusz Zaborski 
717c501d73cSMariusz Zaborski 	return (0);
718c501d73cSMariusz Zaborski }
719c501d73cSMariusz Zaborski 
720c501d73cSMariusz Zaborski static int
721c501d73cSMariusz Zaborski grp_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
722c501d73cSMariusz Zaborski {
723c501d73cSMariusz Zaborski 	const nvlist_t *limits;
724c501d73cSMariusz Zaborski 	const char *name;
725c501d73cSMariusz Zaborski 	void *cookie;
726c501d73cSMariusz Zaborski 	int error, type;
727c501d73cSMariusz Zaborski 
728c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
729c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "cmds")) {
730c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
731c501d73cSMariusz Zaborski 	}
732c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
733c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "fields")) {
734c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
735c501d73cSMariusz Zaborski 	}
736c501d73cSMariusz Zaborski 	if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "groups") &&
737c501d73cSMariusz Zaborski 	    !nvlist_exists_nvlist(newlimits, "groups")) {
738c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
739c501d73cSMariusz Zaborski 	}
740c501d73cSMariusz Zaborski 
741c501d73cSMariusz Zaborski 	cookie = NULL;
742c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
743c501d73cSMariusz Zaborski 		if (type != NV_TYPE_NVLIST)
744c501d73cSMariusz Zaborski 			return (EINVAL);
745c501d73cSMariusz Zaborski 		limits = nvlist_get_nvlist(newlimits, name);
746c501d73cSMariusz Zaborski 		if (strcmp(name, "cmds") == 0)
747c501d73cSMariusz Zaborski 			error = grp_allowed_cmds(oldlimits, limits);
748c501d73cSMariusz Zaborski 		else if (strcmp(name, "fields") == 0)
749c501d73cSMariusz Zaborski 			error = grp_allowed_fields(oldlimits, limits);
750c501d73cSMariusz Zaborski 		else if (strcmp(name, "groups") == 0)
751c501d73cSMariusz Zaborski 			error = grp_allowed_groups(oldlimits, limits);
752c501d73cSMariusz Zaborski 		else
753c501d73cSMariusz Zaborski 			error = EINVAL;
754c501d73cSMariusz Zaborski 		if (error != 0)
755c501d73cSMariusz Zaborski 			return (error);
756c501d73cSMariusz Zaborski 	}
757c501d73cSMariusz Zaborski 
758c501d73cSMariusz Zaborski 	return (0);
759c501d73cSMariusz Zaborski }
760c501d73cSMariusz Zaborski 
761c501d73cSMariusz Zaborski static int
762c501d73cSMariusz Zaborski grp_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
763c501d73cSMariusz Zaborski     nvlist_t *nvlout)
764c501d73cSMariusz Zaborski {
765c501d73cSMariusz Zaborski 	int error;
766c501d73cSMariusz Zaborski 
767c501d73cSMariusz Zaborski 	if (!grp_allowed_cmd(limits, cmd))
768c501d73cSMariusz Zaborski 		return (ENOTCAPABLE);
769c501d73cSMariusz Zaborski 
770c501d73cSMariusz Zaborski 	if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0)
771c501d73cSMariusz Zaborski 		error = grp_getgrent(limits, nvlin, nvlout);
772c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0)
773c501d73cSMariusz Zaborski 		error = grp_getgrnam(limits, nvlin, nvlout);
774c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0)
775c501d73cSMariusz Zaborski 		error = grp_getgrgid(limits, nvlin, nvlout);
776c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "setgroupent") == 0)
777c501d73cSMariusz Zaborski 		error = grp_setgroupent(limits, nvlin, nvlout);
778c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "setgrent") == 0)
779c501d73cSMariusz Zaborski 		error = grp_setgrent(limits, nvlin, nvlout);
780c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "endgrent") == 0)
781c501d73cSMariusz Zaborski 		error = grp_endgrent(limits, nvlin, nvlout);
782c501d73cSMariusz Zaborski 	else
783c501d73cSMariusz Zaborski 		error = EINVAL;
784c501d73cSMariusz Zaborski 
785c501d73cSMariusz Zaborski 	return (error);
786c501d73cSMariusz Zaborski }
787c501d73cSMariusz Zaborski 
788920be817SMariusz Zaborski CREATE_SERVICE("system.grp", grp_limit, grp_command, 0);
789