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