1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Pawel Jakub Dawidek under sponsorship from
8  * the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/capsicum.h>
33 #include <sys/nv.h>
34 
35 #include <assert.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <grp.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include <libcasper.h>
45 
46 #include <casper/cap_grp.h>
47 
48 static int ntest = 1;
49 
50 #define CHECK(expr)     do {						\
51 	if ((expr))							\
52 		printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__);	\
53 	else								\
54 		printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__);	\
55 	fflush(stdout);							\
56 	ntest++;							\
57 } while (0)
58 #define CHECKX(expr)     do {						\
59 	if ((expr)) {							\
60 		printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__);	\
61 	} else {							\
62 		printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__);	\
63 		exit(1);						\
64 	}								\
65 	fflush(stdout);							\
66 	ntest++;							\
67 } while (0)
68 
69 #define	GID_WHEEL	0
70 #define	GID_OPERATOR	5
71 
72 #define	GETGRENT0	0x0001
73 #define	GETGRENT1	0x0002
74 #define	GETGRENT2	0x0004
75 #define	GETGRENT	(GETGRENT0 | GETGRENT1 | GETGRENT2)
76 #define	GETGRENT_R0	0x0008
77 #define	GETGRENT_R1	0x0010
78 #define	GETGRENT_R2	0x0020
79 #define	GETGRENT_R	(GETGRENT_R0 | GETGRENT_R1 | GETGRENT_R2)
80 #define	GETGRNAM	0x0040
81 #define	GETGRNAM_R	0x0080
82 #define	GETGRGID	0x0100
83 #define	GETGRGID_R	0x0200
84 #define	SETGRENT	0x0400
85 
86 static bool
87 group_mem_compare(char **mem0, char **mem1)
88 {
89 	int i0, i1;
90 
91 	if (mem0 == NULL && mem1 == NULL)
92 		return (true);
93 	if (mem0 == NULL || mem1 == NULL)
94 		return (false);
95 
96 	for (i0 = 0; mem0[i0] != NULL; i0++) {
97 		for (i1 = 0; mem1[i1] != NULL; i1++) {
98 			if (strcmp(mem0[i0], mem1[i1]) == 0)
99 				break;
100 		}
101 		if (mem1[i1] == NULL)
102 			return (false);
103 	}
104 
105 	return (true);
106 }
107 
108 static bool
109 group_compare(const struct group *grp0, const struct group *grp1)
110 {
111 
112 	if (grp0 == NULL && grp1 == NULL)
113 		return (true);
114 	if (grp0 == NULL || grp1 == NULL)
115 		return (false);
116 
117 	if (strcmp(grp0->gr_name, grp1->gr_name) != 0)
118 		return (false);
119 
120 	if (grp0->gr_passwd != NULL || grp1->gr_passwd != NULL) {
121 		if (grp0->gr_passwd == NULL || grp1->gr_passwd == NULL)
122 			return (false);
123 		if (strcmp(grp0->gr_passwd, grp1->gr_passwd) != 0)
124 			return (false);
125 	}
126 
127 	if (grp0->gr_gid != grp1->gr_gid)
128 		return (false);
129 
130 	if (!group_mem_compare(grp0->gr_mem, grp1->gr_mem))
131 		return (false);
132 
133 	return (true);
134 }
135 
136 static unsigned int
137 runtest_cmds(cap_channel_t *capgrp)
138 {
139 	char bufs[1024], bufc[1024];
140 	unsigned int result;
141 	struct group *grps, *grpc;
142 	struct group sts, stc;
143 
144 	result = 0;
145 
146 	(void)setgrent();
147 	if (cap_setgrent(capgrp) == 1)
148 		result |= SETGRENT;
149 
150 	grps = getgrent();
151 	grpc = cap_getgrent(capgrp);
152 	if (group_compare(grps, grpc)) {
153 		result |= GETGRENT0;
154 		grps = getgrent();
155 		grpc = cap_getgrent(capgrp);
156 		if (group_compare(grps, grpc))
157 			result |= GETGRENT1;
158 	}
159 
160 	getgrent_r(&sts, bufs, sizeof(bufs), &grps);
161 	cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
162 	if (group_compare(grps, grpc)) {
163 		result |= GETGRENT_R0;
164 		getgrent_r(&sts, bufs, sizeof(bufs), &grps);
165 		cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
166 		if (group_compare(grps, grpc))
167 			result |= GETGRENT_R1;
168 	}
169 
170 	(void)setgrent();
171 	if (cap_setgrent(capgrp) == 1)
172 		result |= SETGRENT;
173 
174 	getgrent_r(&sts, bufs, sizeof(bufs), &grps);
175 	cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
176 	if (group_compare(grps, grpc))
177 		result |= GETGRENT_R2;
178 
179 	grps = getgrent();
180 	grpc = cap_getgrent(capgrp);
181 	if (group_compare(grps, grpc))
182 		result |= GETGRENT2;
183 
184 	grps = getgrnam("wheel");
185 	grpc = cap_getgrnam(capgrp, "wheel");
186 	if (group_compare(grps, grpc)) {
187 		grps = getgrnam("operator");
188 		grpc = cap_getgrnam(capgrp, "operator");
189 		if (group_compare(grps, grpc))
190 			result |= GETGRNAM;
191 	}
192 
193 	getgrnam_r("wheel", &sts, bufs, sizeof(bufs), &grps);
194 	cap_getgrnam_r(capgrp, "wheel", &stc, bufc, sizeof(bufc), &grpc);
195 	if (group_compare(grps, grpc)) {
196 		getgrnam_r("operator", &sts, bufs, sizeof(bufs), &grps);
197 		cap_getgrnam_r(capgrp, "operator", &stc, bufc, sizeof(bufc),
198 		    &grpc);
199 		if (group_compare(grps, grpc))
200 			result |= GETGRNAM_R;
201 	}
202 
203 	grps = getgrgid(GID_WHEEL);
204 	grpc = cap_getgrgid(capgrp, GID_WHEEL);
205 	if (group_compare(grps, grpc)) {
206 		grps = getgrgid(GID_OPERATOR);
207 		grpc = cap_getgrgid(capgrp, GID_OPERATOR);
208 		if (group_compare(grps, grpc))
209 			result |= GETGRGID;
210 	}
211 
212 	getgrgid_r(GID_WHEEL, &sts, bufs, sizeof(bufs), &grps);
213 	cap_getgrgid_r(capgrp, GID_WHEEL, &stc, bufc, sizeof(bufc), &grpc);
214 	if (group_compare(grps, grpc)) {
215 		getgrgid_r(GID_OPERATOR, &sts, bufs, sizeof(bufs), &grps);
216 		cap_getgrgid_r(capgrp, GID_OPERATOR, &stc, bufc, sizeof(bufc),
217 		    &grpc);
218 		if (group_compare(grps, grpc))
219 			result |= GETGRGID_R;
220 	}
221 
222 	return (result);
223 }
224 
225 static void
226 test_cmds(cap_channel_t *origcapgrp)
227 {
228 	cap_channel_t *capgrp;
229 	const char *cmds[7], *fields[4], *names[5];
230 	gid_t gids[5];
231 
232 	fields[0] = "gr_name";
233 	fields[1] = "gr_passwd";
234 	fields[2] = "gr_gid";
235 	fields[3] = "gr_mem";
236 
237 	names[0] = "wheel";
238 	names[1] = "daemon";
239 	names[2] = "kmem";
240 	names[3] = "sys";
241 	names[4] = "operator";
242 
243 	gids[0] = 0;
244 	gids[1] = 1;
245 	gids[2] = 2;
246 	gids[3] = 3;
247 	gids[4] = 5;
248 
249 	/*
250 	 * Allow:
251 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
252 	 *       getgrgid, getgrgid_r
253 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
254 	 * groups:
255 	 *     names: wheel, daemon, kmem, sys, operator
256 	 *     gids:
257 	 */
258 	capgrp = cap_clone(origcapgrp);
259 	CHECK(capgrp != NULL);
260 
261 	cmds[0] = "setgrent";
262 	cmds[1] = "getgrent";
263 	cmds[2] = "getgrent_r";
264 	cmds[3] = "getgrnam";
265 	cmds[4] = "getgrnam_r";
266 	cmds[5] = "getgrgid";
267 	cmds[6] = "getgrgid_r";
268 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == 0);
269 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
270 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
271 
272 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
273 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
274 
275 	cap_close(capgrp);
276 
277 	/*
278 	 * Allow:
279 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
280 	 *       getgrgid, getgrgid_r
281 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
282 	 * groups:
283 	 *     names:
284 	 *     gids: 0, 1, 2, 3, 5
285 	 */
286 	capgrp = cap_clone(origcapgrp);
287 	CHECK(capgrp != NULL);
288 
289 	cmds[0] = "setgrent";
290 	cmds[1] = "getgrent";
291 	cmds[2] = "getgrent_r";
292 	cmds[3] = "getgrnam";
293 	cmds[4] = "getgrnam_r";
294 	cmds[5] = "getgrgid";
295 	cmds[6] = "getgrgid_r";
296 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == 0);
297 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
298 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
299 
300 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
301 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
302 
303 	cap_close(capgrp);
304 
305 	/*
306 	 * Allow:
307 	 * cmds: getgrent, getgrent_r, getgrnam, getgrnam_r,
308 	 *       getgrgid, getgrgid_r
309 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
310 	 * groups:
311 	 *     names: wheel, daemon, kmem, sys, operator
312 	 *     gids:
313 	 * Disallow:
314 	 * cmds: setgrent
315 	 * fields:
316 	 * groups:
317 	 */
318 	capgrp = cap_clone(origcapgrp);
319 	CHECK(capgrp != NULL);
320 
321 	cap_setgrent(capgrp);
322 
323 	cmds[0] = "getgrent";
324 	cmds[1] = "getgrent_r";
325 	cmds[2] = "getgrnam";
326 	cmds[3] = "getgrnam_r";
327 	cmds[4] = "getgrgid";
328 	cmds[5] = "getgrgid_r";
329 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
330 	cmds[0] = "setgrent";
331 	cmds[1] = "getgrent";
332 	cmds[2] = "getgrent_r";
333 	cmds[3] = "getgrnam";
334 	cmds[4] = "getgrnam_r";
335 	cmds[5] = "getgrgid";
336 	cmds[6] = "getgrgid_r";
337 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
338 	cmds[0] = "setgrent";
339 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
340 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
341 
342 	CHECK(runtest_cmds(capgrp) == (GETGRENT0 | GETGRENT1 | GETGRENT_R0 |
343 	    GETGRENT_R1 | GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
344 
345 	cap_close(capgrp);
346 
347 	/*
348 	 * Allow:
349 	 * cmds: getgrent, getgrent_r, getgrnam, getgrnam_r,
350 	 *       getgrgid, getgrgid_r
351 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
352 	 * groups:
353 	 *     names:
354 	 *     gids: 0, 1, 2, 3, 5
355 	 * Disallow:
356 	 * cmds: setgrent
357 	 * fields:
358 	 * groups:
359 	 */
360 	capgrp = cap_clone(origcapgrp);
361 	CHECK(capgrp != NULL);
362 
363 	cap_setgrent(capgrp);
364 
365 	cmds[0] = "getgrent";
366 	cmds[1] = "getgrent_r";
367 	cmds[2] = "getgrnam";
368 	cmds[3] = "getgrnam_r";
369 	cmds[4] = "getgrgid";
370 	cmds[5] = "getgrgid_r";
371 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
372 	cmds[0] = "setgrent";
373 	cmds[1] = "getgrent";
374 	cmds[2] = "getgrent_r";
375 	cmds[3] = "getgrnam";
376 	cmds[4] = "getgrnam_r";
377 	cmds[5] = "getgrgid";
378 	cmds[6] = "getgrgid_r";
379 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
380 	cmds[0] = "setgrent";
381 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
382 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
383 
384 	CHECK(runtest_cmds(capgrp) == (GETGRENT0 | GETGRENT1 | GETGRENT_R0 |
385 	    GETGRENT_R1 | GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
386 
387 	cap_close(capgrp);
388 
389 	/*
390 	 * Allow:
391 	 * cmds: setgrent, getgrent_r, getgrnam, getgrnam_r,
392 	 *       getgrgid, getgrgid_r
393 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
394 	 * groups:
395 	 *     names: wheel, daemon, kmem, sys, operator
396 	 *     gids:
397 	 * Disallow:
398 	 * cmds: getgrent
399 	 * fields:
400 	 * groups:
401 	 */
402 	capgrp = cap_clone(origcapgrp);
403 	CHECK(capgrp != NULL);
404 
405 	cmds[0] = "setgrent";
406 	cmds[1] = "getgrent_r";
407 	cmds[2] = "getgrnam";
408 	cmds[3] = "getgrnam_r";
409 	cmds[4] = "getgrgid";
410 	cmds[5] = "getgrgid_r";
411 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
412 	cmds[0] = "setgrent";
413 	cmds[1] = "getgrent";
414 	cmds[2] = "getgrent_r";
415 	cmds[3] = "getgrnam";
416 	cmds[4] = "getgrnam_r";
417 	cmds[5] = "getgrgid";
418 	cmds[6] = "getgrgid_r";
419 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
420 	cmds[0] = "getgrent";
421 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
422 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
423 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
424 
425 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT_R2 |
426 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
427 
428 	cap_close(capgrp);
429 
430 	/*
431 	 * Allow:
432 	 * cmds: setgrent, getgrent_r, getgrnam, getgrnam_r,
433 	 *       getgrgid, getgrgid_r
434 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
435 	 * groups:
436 	 *     names:
437 	 *     gids: 0, 1, 2, 3, 5
438 	 * Disallow:
439 	 * cmds: getgrent
440 	 * fields:
441 	 * groups:
442 	 */
443 	capgrp = cap_clone(origcapgrp);
444 	CHECK(capgrp != NULL);
445 
446 	cmds[0] = "setgrent";
447 	cmds[1] = "getgrent_r";
448 	cmds[2] = "getgrnam";
449 	cmds[3] = "getgrnam_r";
450 	cmds[4] = "getgrgid";
451 	cmds[5] = "getgrgid_r";
452 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
453 	cmds[0] = "setgrent";
454 	cmds[1] = "getgrent";
455 	cmds[2] = "getgrent_r";
456 	cmds[3] = "getgrnam";
457 	cmds[4] = "getgrnam_r";
458 	cmds[5] = "getgrgid";
459 	cmds[6] = "getgrgid_r";
460 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
461 	cmds[0] = "getgrent";
462 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
463 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
464 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
465 
466 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT_R2 |
467 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
468 
469 	cap_close(capgrp);
470 
471 	/*
472 	 * Allow:
473 	 * cmds: setgrent, getgrent, getgrnam, getgrnam_r,
474 	 *       getgrgid, getgrgid_r
475 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
476 	 * groups:
477 	 *     names: wheel, daemon, kmem, sys, operator
478 	 *     gids:
479 	 * Disallow:
480 	 * cmds: getgrent_r
481 	 * fields:
482 	 * groups:
483 	 */
484 	capgrp = cap_clone(origcapgrp);
485 	CHECK(capgrp != NULL);
486 
487 	cmds[0] = "setgrent";
488 	cmds[1] = "getgrent";
489 	cmds[2] = "getgrnam";
490 	cmds[3] = "getgrnam_r";
491 	cmds[4] = "getgrgid";
492 	cmds[5] = "getgrgid_r";
493 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
494 	cmds[0] = "setgrent";
495 	cmds[1] = "getgrent";
496 	cmds[2] = "getgrent_r";
497 	cmds[3] = "getgrnam";
498 	cmds[4] = "getgrnam_r";
499 	cmds[5] = "getgrgid";
500 	cmds[6] = "getgrgid_r";
501 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
502 	cmds[0] = "getgrent_r";
503 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
504 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
505 
506 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT0 | GETGRENT1 |
507 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
508 
509 	cap_close(capgrp);
510 
511 	/*
512 	 * Allow:
513 	 * cmds: setgrent, getgrent, getgrnam, getgrnam_r,
514 	 *       getgrgid, getgrgid_r
515 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
516 	 * groups:
517 	 *     names:
518 	 *     gids: 0, 1, 2, 3, 5
519 	 * Disallow:
520 	 * cmds: getgrent_r
521 	 * fields:
522 	 * groups:
523 	 */
524 	capgrp = cap_clone(origcapgrp);
525 	CHECK(capgrp != NULL);
526 
527 	cmds[0] = "setgrent";
528 	cmds[1] = "getgrent";
529 	cmds[2] = "getgrnam";
530 	cmds[3] = "getgrnam_r";
531 	cmds[4] = "getgrgid";
532 	cmds[5] = "getgrgid_r";
533 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
534 	cmds[0] = "setgrent";
535 	cmds[1] = "getgrent";
536 	cmds[2] = "getgrent_r";
537 	cmds[3] = "getgrnam";
538 	cmds[4] = "getgrnam_r";
539 	cmds[5] = "getgrgid";
540 	cmds[6] = "getgrgid_r";
541 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
542 	cmds[0] = "getgrent_r";
543 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
544 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
545 
546 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT0 | GETGRENT1 |
547 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
548 
549 	cap_close(capgrp);
550 
551 	/*
552 	 * Allow:
553 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam_r,
554 	 *       getgrgid, getgrgid_r
555 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
556 	 * groups:
557 	 *     names: wheel, daemon, kmem, sys, operator
558 	 *     gids:
559 	 * Disallow:
560 	 * cmds: getgrnam
561 	 * fields:
562 	 * groups:
563 	 */
564 	capgrp = cap_clone(origcapgrp);
565 	CHECK(capgrp != NULL);
566 
567 	cmds[0] = "setgrent";
568 	cmds[1] = "getgrent";
569 	cmds[2] = "getgrent_r";
570 	cmds[3] = "getgrnam_r";
571 	cmds[4] = "getgrgid";
572 	cmds[5] = "getgrgid_r";
573 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
574 	cmds[0] = "setgrent";
575 	cmds[1] = "getgrent";
576 	cmds[2] = "getgrent_r";
577 	cmds[3] = "getgrnam";
578 	cmds[4] = "getgrnam_r";
579 	cmds[5] = "getgrgid";
580 	cmds[6] = "getgrgid_r";
581 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
582 	cmds[0] = "getgrnam";
583 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
584 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
585 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
586 
587 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
588 	    GETGRNAM_R | GETGRGID | GETGRGID_R));
589 
590 	cap_close(capgrp);
591 
592 	/*
593 	 * Allow:
594 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam_r,
595 	 *       getgrgid, getgrgid_r
596 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
597 	 * groups:
598 	 *     names:
599 	 *     gids: 0, 1, 2, 3, 5
600 	 * Disallow:
601 	 * cmds: getgrnam
602 	 * fields:
603 	 * groups:
604 	 */
605 	capgrp = cap_clone(origcapgrp);
606 	CHECK(capgrp != NULL);
607 
608 	cmds[0] = "setgrent";
609 	cmds[1] = "getgrent";
610 	cmds[2] = "getgrent_r";
611 	cmds[3] = "getgrnam_r";
612 	cmds[4] = "getgrgid";
613 	cmds[5] = "getgrgid_r";
614 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
615 	cmds[0] = "setgrent";
616 	cmds[1] = "getgrent";
617 	cmds[2] = "getgrent_r";
618 	cmds[3] = "getgrnam";
619 	cmds[4] = "getgrnam_r";
620 	cmds[5] = "getgrgid";
621 	cmds[6] = "getgrgid_r";
622 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
623 	cmds[0] = "getgrnam";
624 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
625 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
626 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
627 
628 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
629 	    GETGRNAM_R | GETGRGID | GETGRGID_R));
630 
631 	cap_close(capgrp);
632 
633 	/*
634 	 * Allow:
635 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam,
636 	 *       getgrgid, getgrgid_r
637 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
638 	 * groups:
639 	 *     names: wheel, daemon, kmem, sys, operator
640 	 *     gids:
641 	 * Disallow:
642 	 * cmds: getgrnam_r
643 	 * fields:
644 	 * groups:
645 	 */
646 	capgrp = cap_clone(origcapgrp);
647 	CHECK(capgrp != NULL);
648 
649 	cmds[0] = "setgrent";
650 	cmds[1] = "getgrent";
651 	cmds[2] = "getgrent_r";
652 	cmds[3] = "getgrnam";
653 	cmds[4] = "getgrgid";
654 	cmds[5] = "getgrgid_r";
655 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
656 	cmds[0] = "setgrent";
657 	cmds[1] = "getgrent";
658 	cmds[2] = "getgrent_r";
659 	cmds[3] = "getgrnam";
660 	cmds[4] = "getgrnam_r";
661 	cmds[5] = "getgrgid";
662 	cmds[6] = "getgrgid_r";
663 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
664 	cmds[0] = "getgrnam_r";
665 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
666 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
667 
668 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
669 	    GETGRNAM | GETGRGID | GETGRGID_R));
670 
671 	cap_close(capgrp);
672 
673 	/*
674 	 * Allow:
675 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam,
676 	 *       getgrgid, getgrgid_r
677 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
678 	 * groups:
679 	 *     names:
680 	 *     gids: 0, 1, 2, 3, 5
681 	 * Disallow:
682 	 * cmds: getgrnam_r
683 	 * fields:
684 	 * groups:
685 	 */
686 	capgrp = cap_clone(origcapgrp);
687 	CHECK(capgrp != NULL);
688 
689 	cmds[0] = "setgrent";
690 	cmds[1] = "getgrent";
691 	cmds[2] = "getgrent_r";
692 	cmds[3] = "getgrnam";
693 	cmds[4] = "getgrgid";
694 	cmds[5] = "getgrgid_r";
695 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
696 	cmds[0] = "setgrent";
697 	cmds[1] = "getgrent";
698 	cmds[2] = "getgrent_r";
699 	cmds[3] = "getgrnam";
700 	cmds[4] = "getgrnam_r";
701 	cmds[5] = "getgrgid";
702 	cmds[6] = "getgrgid_r";
703 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
704 	cmds[0] = "getgrnam_r";
705 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
706 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
707 
708 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
709 	    GETGRNAM | GETGRGID | GETGRGID_R));
710 
711 	cap_close(capgrp);
712 
713 	/*
714 	 * Allow:
715 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
716 	 *       getgrgid_r
717 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
718 	 * groups:
719 	 *     names: wheel, daemon, kmem, sys, operator
720 	 *     gids:
721 	 * Disallow:
722 	 * cmds: getgrgid
723 	 * fields:
724 	 * groups:
725 	 */
726 	capgrp = cap_clone(origcapgrp);
727 	CHECK(capgrp != NULL);
728 
729 	cmds[0] = "setgrent";
730 	cmds[1] = "getgrent";
731 	cmds[2] = "getgrent_r";
732 	cmds[3] = "getgrnam";
733 	cmds[4] = "getgrnam_r";
734 	cmds[5] = "getgrgid_r";
735 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
736 	cmds[0] = "setgrent";
737 	cmds[1] = "getgrent";
738 	cmds[2] = "getgrent_r";
739 	cmds[3] = "getgrnam";
740 	cmds[4] = "getgrnam_r";
741 	cmds[5] = "getgrgid";
742 	cmds[6] = "getgrgid_r";
743 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
744 	cmds[0] = "getgrgid";
745 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
746 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
747 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
748 
749 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
750 	    GETGRNAM | GETGRNAM_R | GETGRGID_R));
751 
752 	cap_close(capgrp);
753 
754 	/*
755 	 * Allow:
756 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
757 	 *       getgrgid_r
758 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
759 	 * groups:
760 	 *     names:
761 	 *     gids: 0, 1, 2, 3, 5
762 	 * Disallow:
763 	 * cmds: getgrgid
764 	 * fields:
765 	 * groups:
766 	 */
767 	capgrp = cap_clone(origcapgrp);
768 	CHECK(capgrp != NULL);
769 
770 	cmds[0] = "setgrent";
771 	cmds[1] = "getgrent";
772 	cmds[2] = "getgrent_r";
773 	cmds[3] = "getgrnam";
774 	cmds[4] = "getgrnam_r";
775 	cmds[5] = "getgrgid_r";
776 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
777 	cmds[0] = "setgrent";
778 	cmds[1] = "getgrent";
779 	cmds[2] = "getgrent_r";
780 	cmds[3] = "getgrnam";
781 	cmds[4] = "getgrnam_r";
782 	cmds[5] = "getgrgid";
783 	cmds[6] = "getgrgid_r";
784 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
785 	cmds[0] = "getgrgid";
786 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
787 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
788 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
789 
790 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
791 	    GETGRNAM | GETGRNAM_R | GETGRGID_R));
792 
793 	cap_close(capgrp);
794 
795 	/*
796 	 * Allow:
797 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
798 	 *       getgrgid
799 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
800 	 * groups:
801 	 *     names: wheel, daemon, kmem, sys, operator
802 	 *     gids:
803 	 * Disallow:
804 	 * cmds: getgrgid_r
805 	 * fields:
806 	 * groups:
807 	 */
808 	capgrp = cap_clone(origcapgrp);
809 	CHECK(capgrp != NULL);
810 
811 	cmds[0] = "setgrent";
812 	cmds[1] = "getgrent";
813 	cmds[2] = "getgrent_r";
814 	cmds[3] = "getgrnam";
815 	cmds[4] = "getgrnam_r";
816 	cmds[5] = "getgrgid";
817 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
818 	cmds[0] = "setgrent";
819 	cmds[1] = "getgrent";
820 	cmds[2] = "getgrent_r";
821 	cmds[3] = "getgrnam";
822 	cmds[4] = "getgrnam_r";
823 	cmds[5] = "getgrgid";
824 	cmds[6] = "getgrgid_r";
825 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
826 	cmds[0] = "getgrgid_r";
827 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
828 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
829 
830 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
831 	    GETGRNAM | GETGRNAM_R | GETGRGID));
832 
833 	cap_close(capgrp);
834 
835 	/*
836 	 * Allow:
837 	 * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
838 	 *       getgrgid
839 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
840 	 * groups:
841 	 *     names:
842 	 *     gids: 0, 1, 2, 3, 5
843 	 * Disallow:
844 	 * cmds: getgrgid_r
845 	 * fields:
846 	 * groups:
847 	 */
848 	capgrp = cap_clone(origcapgrp);
849 	CHECK(capgrp != NULL);
850 
851 	cmds[0] = "setgrent";
852 	cmds[1] = "getgrent";
853 	cmds[2] = "getgrent_r";
854 	cmds[3] = "getgrnam";
855 	cmds[4] = "getgrnam_r";
856 	cmds[5] = "getgrgid";
857 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
858 	cmds[0] = "setgrent";
859 	cmds[1] = "getgrent";
860 	cmds[2] = "getgrent_r";
861 	cmds[3] = "getgrnam";
862 	cmds[4] = "getgrnam_r";
863 	cmds[5] = "getgrgid";
864 	cmds[6] = "getgrgid_r";
865 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
866 	cmds[0] = "getgrgid_r";
867 	CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
868 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
869 
870 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
871 	    GETGRNAM | GETGRNAM_R | GETGRGID));
872 
873 	cap_close(capgrp);
874 }
875 
876 #define	GR_NAME		0x01
877 #define	GR_PASSWD	0x02
878 #define	GR_GID		0x04
879 #define	GR_MEM		0x08
880 
881 static unsigned int
882 group_fields(const struct group *grp)
883 {
884 	unsigned int result;
885 
886 	result = 0;
887 
888 	if (grp->gr_name != NULL && grp->gr_name[0] != '\0')
889 		result |= GR_NAME;
890 
891 	if (grp->gr_passwd != NULL && grp->gr_passwd[0] != '\0')
892 		result |= GR_PASSWD;
893 
894 	if (grp->gr_gid != (gid_t)-1)
895 		result |= GR_GID;
896 
897 	if (grp->gr_mem != NULL && grp->gr_mem[0] != NULL)
898 		result |= GR_MEM;
899 
900 	return (result);
901 }
902 
903 static bool
904 runtest_fields(cap_channel_t *capgrp, unsigned int expected)
905 {
906 	char buf[1024];
907 	struct group *grp;
908 	struct group st;
909 
910 	(void)cap_setgrent(capgrp);
911 	grp = cap_getgrent(capgrp);
912 	if (group_fields(grp) != expected)
913 		return (false);
914 
915 	(void)cap_setgrent(capgrp);
916 	cap_getgrent_r(capgrp, &st, buf, sizeof(buf), &grp);
917 	if (group_fields(grp) != expected)
918 		return (false);
919 
920 	grp = cap_getgrnam(capgrp, "wheel");
921 	if (group_fields(grp) != expected)
922 		return (false);
923 
924 	cap_getgrnam_r(capgrp, "wheel", &st, buf, sizeof(buf), &grp);
925 	if (group_fields(grp) != expected)
926 		return (false);
927 
928 	grp = cap_getgrgid(capgrp, GID_WHEEL);
929 	if (group_fields(grp) != expected)
930 		return (false);
931 
932 	cap_getgrgid_r(capgrp, GID_WHEEL, &st, buf, sizeof(buf), &grp);
933 	if (group_fields(grp) != expected)
934 		return (false);
935 
936 	return (true);
937 }
938 
939 static void
940 test_fields(cap_channel_t *origcapgrp)
941 {
942 	cap_channel_t *capgrp;
943 	const char *fields[4];
944 
945 	/* No limits. */
946 
947 	CHECK(runtest_fields(origcapgrp, GR_NAME | GR_PASSWD | GR_GID | GR_MEM));
948 
949 	/*
950 	 * Allow:
951 	 * fields: gr_name, gr_passwd, gr_gid, gr_mem
952 	 */
953 	capgrp = cap_clone(origcapgrp);
954 	CHECK(capgrp != NULL);
955 
956 	fields[0] = "gr_name";
957 	fields[1] = "gr_passwd";
958 	fields[2] = "gr_gid";
959 	fields[3] = "gr_mem";
960 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
961 
962 	CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_GID | GR_MEM));
963 
964 	cap_close(capgrp);
965 
966 	/*
967 	 * Allow:
968 	 * fields: gr_passwd, gr_gid, gr_mem
969 	 */
970 	capgrp = cap_clone(origcapgrp);
971 	CHECK(capgrp != NULL);
972 
973 	fields[0] = "gr_passwd";
974 	fields[1] = "gr_gid";
975 	fields[2] = "gr_mem";
976 	CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
977 	fields[0] = "gr_name";
978 	fields[1] = "gr_passwd";
979 	fields[2] = "gr_gid";
980 	fields[3] = "gr_mem";
981 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
982 	    errno == ENOTCAPABLE);
983 
984 	CHECK(runtest_fields(capgrp, GR_PASSWD | GR_GID | GR_MEM));
985 
986 	cap_close(capgrp);
987 
988 	/*
989 	 * Allow:
990 	 * fields: gr_name, gr_gid, gr_mem
991 	 */
992 	capgrp = cap_clone(origcapgrp);
993 	CHECK(capgrp != NULL);
994 
995 	fields[0] = "gr_name";
996 	fields[1] = "gr_gid";
997 	fields[2] = "gr_mem";
998 	CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
999 	fields[0] = "gr_name";
1000 	fields[1] = "gr_passwd";
1001 	fields[2] = "gr_gid";
1002 	fields[3] = "gr_mem";
1003 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1004 	    errno == ENOTCAPABLE);
1005 	fields[0] = "gr_passwd";
1006 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1007 	    errno == ENOTCAPABLE);
1008 
1009 	CHECK(runtest_fields(capgrp, GR_NAME | GR_GID | GR_MEM));
1010 
1011 	cap_close(capgrp);
1012 
1013 	/*
1014 	 * Allow:
1015 	 * fields: gr_name, gr_passwd, gr_mem
1016 	 */
1017 	capgrp = cap_clone(origcapgrp);
1018 	CHECK(capgrp != NULL);
1019 
1020 	fields[0] = "gr_name";
1021 	fields[1] = "gr_passwd";
1022 	fields[2] = "gr_mem";
1023 	CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
1024 	fields[0] = "gr_name";
1025 	fields[1] = "gr_passwd";
1026 	fields[2] = "gr_gid";
1027 	fields[3] = "gr_mem";
1028 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1029 	    errno == ENOTCAPABLE);
1030 	fields[0] = "gr_gid";
1031 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1032 	    errno == ENOTCAPABLE);
1033 
1034 	CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_MEM));
1035 
1036 	cap_close(capgrp);
1037 
1038 	/*
1039 	 * Allow:
1040 	 * fields: gr_name, gr_passwd, gr_gid
1041 	 */
1042 	capgrp = cap_clone(origcapgrp);
1043 	CHECK(capgrp != NULL);
1044 
1045 	fields[0] = "gr_name";
1046 	fields[1] = "gr_passwd";
1047 	fields[2] = "gr_gid";
1048 	CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
1049 	fields[0] = "gr_name";
1050 	fields[1] = "gr_passwd";
1051 	fields[2] = "gr_gid";
1052 	fields[3] = "gr_mem";
1053 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1054 	    errno == ENOTCAPABLE);
1055 	fields[0] = "gr_mem";
1056 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1057 	    errno == ENOTCAPABLE);
1058 
1059 	CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_GID));
1060 
1061 	cap_close(capgrp);
1062 
1063 	/*
1064 	 * Allow:
1065 	 * fields: gr_name, gr_passwd
1066 	 */
1067 	capgrp = cap_clone(origcapgrp);
1068 	CHECK(capgrp != NULL);
1069 
1070 	fields[0] = "gr_name";
1071 	fields[1] = "gr_passwd";
1072 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1073 	fields[0] = "gr_name";
1074 	fields[1] = "gr_passwd";
1075 	fields[2] = "gr_gid";
1076 	fields[3] = "gr_mem";
1077 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1078 	    errno == ENOTCAPABLE);
1079 	fields[0] = "gr_gid";
1080 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1081 	    errno == ENOTCAPABLE);
1082 
1083 	CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD));
1084 
1085 	cap_close(capgrp);
1086 
1087 	/*
1088 	 * Allow:
1089 	 * fields: gr_name, gr_gid
1090 	 */
1091 	capgrp = cap_clone(origcapgrp);
1092 	CHECK(capgrp != NULL);
1093 
1094 	fields[0] = "gr_name";
1095 	fields[1] = "gr_gid";
1096 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1097 	fields[0] = "gr_name";
1098 	fields[1] = "gr_passwd";
1099 	fields[2] = "gr_gid";
1100 	fields[3] = "gr_mem";
1101 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1102 	    errno == ENOTCAPABLE);
1103 	fields[0] = "gr_mem";
1104 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1105 	    errno == ENOTCAPABLE);
1106 
1107 	CHECK(runtest_fields(capgrp, GR_NAME | GR_GID));
1108 
1109 	cap_close(capgrp);
1110 
1111 	/*
1112 	 * Allow:
1113 	 * fields: gr_name, gr_mem
1114 	 */
1115 	capgrp = cap_clone(origcapgrp);
1116 	CHECK(capgrp != NULL);
1117 
1118 	fields[0] = "gr_name";
1119 	fields[1] = "gr_mem";
1120 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1121 	fields[0] = "gr_name";
1122 	fields[1] = "gr_passwd";
1123 	fields[2] = "gr_gid";
1124 	fields[3] = "gr_mem";
1125 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1126 	    errno == ENOTCAPABLE);
1127 	fields[0] = "gr_passwd";
1128 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1129 	    errno == ENOTCAPABLE);
1130 
1131 	CHECK(runtest_fields(capgrp, GR_NAME | GR_MEM));
1132 
1133 	cap_close(capgrp);
1134 
1135 	/*
1136 	 * Allow:
1137 	 * fields: gr_passwd, gr_gid
1138 	 */
1139 	capgrp = cap_clone(origcapgrp);
1140 	CHECK(capgrp != NULL);
1141 
1142 	fields[0] = "gr_passwd";
1143 	fields[1] = "gr_gid";
1144 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1145 	fields[0] = "gr_name";
1146 	fields[1] = "gr_passwd";
1147 	fields[2] = "gr_gid";
1148 	fields[3] = "gr_mem";
1149 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1150 	    errno == ENOTCAPABLE);
1151 	fields[0] = "gr_mem";
1152 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1153 	    errno == ENOTCAPABLE);
1154 
1155 	CHECK(runtest_fields(capgrp, GR_PASSWD | GR_GID));
1156 
1157 	cap_close(capgrp);
1158 
1159 	/*
1160 	 * Allow:
1161 	 * fields: gr_passwd, gr_mem
1162 	 */
1163 	capgrp = cap_clone(origcapgrp);
1164 	CHECK(capgrp != NULL);
1165 
1166 	fields[0] = "gr_passwd";
1167 	fields[1] = "gr_mem";
1168 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1169 	fields[0] = "gr_name";
1170 	fields[1] = "gr_passwd";
1171 	fields[2] = "gr_gid";
1172 	fields[3] = "gr_mem";
1173 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1174 	    errno == ENOTCAPABLE);
1175 	fields[0] = "gr_gid";
1176 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1177 	    errno == ENOTCAPABLE);
1178 
1179 	CHECK(runtest_fields(capgrp, GR_PASSWD | GR_MEM));
1180 
1181 	cap_close(capgrp);
1182 
1183 	/*
1184 	 * Allow:
1185 	 * fields: gr_gid, gr_mem
1186 	 */
1187 	capgrp = cap_clone(origcapgrp);
1188 	CHECK(capgrp != NULL);
1189 
1190 	fields[0] = "gr_gid";
1191 	fields[1] = "gr_mem";
1192 	CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
1193 	fields[0] = "gr_name";
1194 	fields[1] = "gr_passwd";
1195 	fields[2] = "gr_gid";
1196 	fields[3] = "gr_mem";
1197 	CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
1198 	    errno == ENOTCAPABLE);
1199 	fields[0] = "gr_passwd";
1200 	CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
1201 	    errno == ENOTCAPABLE);
1202 
1203 	CHECK(runtest_fields(capgrp, GR_GID | GR_MEM));
1204 
1205 	cap_close(capgrp);
1206 }
1207 
1208 static bool
1209 runtest_groups(cap_channel_t *capgrp, const char **names, const gid_t *gids,
1210     size_t ngroups)
1211 {
1212 	char buf[1024];
1213 	struct group *grp;
1214 	struct group st;
1215 	unsigned int i, got;
1216 
1217 	(void)cap_setgrent(capgrp);
1218 	got = 0;
1219 	for (;;) {
1220 		grp = cap_getgrent(capgrp);
1221 		if (grp == NULL)
1222 			break;
1223 		got++;
1224 		for (i = 0; i < ngroups; i++) {
1225 			if (strcmp(names[i], grp->gr_name) == 0 &&
1226 			    gids[i] == grp->gr_gid) {
1227 				break;
1228 			}
1229 		}
1230 		if (i == ngroups)
1231 			return (false);
1232 	}
1233 	if (got != ngroups)
1234 		return (false);
1235 
1236 	(void)cap_setgrent(capgrp);
1237 	got = 0;
1238 	for (;;) {
1239 		cap_getgrent_r(capgrp, &st, buf, sizeof(buf), &grp);
1240 		if (grp == NULL)
1241 			break;
1242 		got++;
1243 		for (i = 0; i < ngroups; i++) {
1244 			if (strcmp(names[i], grp->gr_name) == 0 &&
1245 			    gids[i] == grp->gr_gid) {
1246 				break;
1247 			}
1248 		}
1249 		if (i == ngroups)
1250 			return (false);
1251 	}
1252 	if (got != ngroups)
1253 		return (false);
1254 
1255 	for (i = 0; i < ngroups; i++) {
1256 		grp = cap_getgrnam(capgrp, names[i]);
1257 		if (grp == NULL)
1258 			return (false);
1259 	}
1260 
1261 	for (i = 0; i < ngroups; i++) {
1262 		cap_getgrnam_r(capgrp, names[i], &st, buf, sizeof(buf), &grp);
1263 		if (grp == NULL)
1264 			return (false);
1265 	}
1266 
1267 	for (i = 0; i < ngroups; i++) {
1268 		grp = cap_getgrgid(capgrp, gids[i]);
1269 		if (grp == NULL)
1270 			return (false);
1271 	}
1272 
1273 	for (i = 0; i < ngroups; i++) {
1274 		cap_getgrgid_r(capgrp, gids[i], &st, buf, sizeof(buf), &grp);
1275 		if (grp == NULL)
1276 			return (false);
1277 	}
1278 
1279 	return (true);
1280 }
1281 
1282 static void
1283 test_groups(cap_channel_t *origcapgrp)
1284 {
1285 	cap_channel_t *capgrp;
1286 	const char *names[5];
1287 	gid_t gids[5];
1288 
1289 	/*
1290 	 * Allow:
1291 	 * groups:
1292 	 *     names: wheel, daemon, kmem, sys, tty
1293 	 *     gids:
1294 	 */
1295 	capgrp = cap_clone(origcapgrp);
1296 	CHECK(capgrp != NULL);
1297 
1298 	names[0] = "wheel";
1299 	names[1] = "daemon";
1300 	names[2] = "kmem";
1301 	names[3] = "sys";
1302 	names[4] = "tty";
1303 	CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
1304 	gids[0] = 0;
1305 	gids[1] = 1;
1306 	gids[2] = 2;
1307 	gids[3] = 3;
1308 	gids[4] = 4;
1309 
1310 	CHECK(runtest_groups(capgrp, names, gids, 5));
1311 
1312 	cap_close(capgrp);
1313 
1314 	/*
1315 	 * Allow:
1316 	 * groups:
1317 	 *     names: kmem, sys, tty
1318 	 *     gids:
1319 	 */
1320 	capgrp = cap_clone(origcapgrp);
1321 	CHECK(capgrp != NULL);
1322 
1323 	names[0] = "kmem";
1324 	names[1] = "sys";
1325 	names[2] = "tty";
1326 	CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == 0);
1327 	names[3] = "daemon";
1328 	CHECK(cap_grp_limit_groups(capgrp, names, 4, NULL, 0) == -1 &&
1329 	    errno == ENOTCAPABLE);
1330 	names[0] = "daemon";
1331 	CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
1332 	    errno == ENOTCAPABLE);
1333 	names[0] = "kmem";
1334 	gids[0] = 2;
1335 	gids[1] = 3;
1336 	gids[2] = 4;
1337 
1338 	CHECK(runtest_groups(capgrp, names, gids, 3));
1339 
1340 	cap_close(capgrp);
1341 
1342 	/*
1343 	 * Allow:
1344 	 * groups:
1345 	 *     names: wheel, kmem, tty
1346 	 *     gids:
1347 	 */
1348 	capgrp = cap_clone(origcapgrp);
1349 	CHECK(capgrp != NULL);
1350 
1351 	names[0] = "wheel";
1352 	names[1] = "kmem";
1353 	names[2] = "tty";
1354 	CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == 0);
1355 	names[3] = "daemon";
1356 	CHECK(cap_grp_limit_groups(capgrp, names, 4, NULL, 0) == -1 &&
1357 	    errno == ENOTCAPABLE);
1358 	names[0] = "daemon";
1359 	CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
1360 	    errno == ENOTCAPABLE);
1361 	names[0] = "wheel";
1362 	gids[0] = 0;
1363 	gids[1] = 2;
1364 	gids[2] = 4;
1365 
1366 	CHECK(runtest_groups(capgrp, names, gids, 3));
1367 
1368 	cap_close(capgrp);
1369 
1370 	/*
1371 	 * Allow:
1372 	 * groups:
1373 	 *     names:
1374 	 *     gids: 2, 3, 4
1375 	 */
1376 	capgrp = cap_clone(origcapgrp);
1377 	CHECK(capgrp != NULL);
1378 
1379 	names[0] = "kmem";
1380 	names[1] = "sys";
1381 	names[2] = "tty";
1382 	gids[0] = 2;
1383 	gids[1] = 3;
1384 	gids[2] = 4;
1385 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == 0);
1386 	gids[3] = 0;
1387 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 4) == -1 &&
1388 	    errno == ENOTCAPABLE);
1389 	gids[0] = 0;
1390 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
1391 	    errno == ENOTCAPABLE);
1392 	gids[0] = 2;
1393 
1394 	CHECK(runtest_groups(capgrp, names, gids, 3));
1395 
1396 	cap_close(capgrp);
1397 
1398 	/*
1399 	 * Allow:
1400 	 * groups:
1401 	 *     names:
1402 	 *     gids: 0, 2, 4
1403 	 */
1404 	capgrp = cap_clone(origcapgrp);
1405 	CHECK(capgrp != NULL);
1406 
1407 	names[0] = "wheel";
1408 	names[1] = "kmem";
1409 	names[2] = "tty";
1410 	gids[0] = 0;
1411 	gids[1] = 2;
1412 	gids[2] = 4;
1413 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == 0);
1414 	gids[3] = 1;
1415 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 4) == -1 &&
1416 	    errno == ENOTCAPABLE);
1417 	gids[0] = 1;
1418 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
1419 	    errno == ENOTCAPABLE);
1420 	gids[0] = 0;
1421 
1422 	CHECK(runtest_groups(capgrp, names, gids, 3));
1423 
1424 	cap_close(capgrp);
1425 
1426 	/*
1427 	 * Allow:
1428 	 * groups:
1429 	 *     names: kmem
1430 	 *     gids:
1431 	 */
1432 	capgrp = cap_clone(origcapgrp);
1433 	CHECK(capgrp != NULL);
1434 
1435 	names[0] = "kmem";
1436 	CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == 0);
1437 	names[1] = "daemon";
1438 	CHECK(cap_grp_limit_groups(capgrp, names, 2, NULL, 0) == -1 &&
1439 	    errno == ENOTCAPABLE);
1440 	names[0] = "daemon";
1441 	CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
1442 	    errno == ENOTCAPABLE);
1443 	names[0] = "kmem";
1444 	gids[0] = 2;
1445 
1446 	CHECK(runtest_groups(capgrp, names, gids, 1));
1447 
1448 	cap_close(capgrp);
1449 
1450 	/*
1451 	 * Allow:
1452 	 * groups:
1453 	 *     names: wheel, tty
1454 	 *     gids:
1455 	 */
1456 	capgrp = cap_clone(origcapgrp);
1457 	CHECK(capgrp != NULL);
1458 
1459 	names[0] = "wheel";
1460 	names[1] = "tty";
1461 	CHECK(cap_grp_limit_groups(capgrp, names, 2, NULL, 0) == 0);
1462 	names[2] = "daemon";
1463 	CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == -1 &&
1464 	    errno == ENOTCAPABLE);
1465 	names[0] = "daemon";
1466 	CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
1467 	    errno == ENOTCAPABLE);
1468 	names[0] = "wheel";
1469 	gids[0] = 0;
1470 	gids[1] = 4;
1471 
1472 	CHECK(runtest_groups(capgrp, names, gids, 2));
1473 
1474 	cap_close(capgrp);
1475 
1476 	/*
1477 	 * Allow:
1478 	 * groups:
1479 	 *     names:
1480 	 *     gids: 2
1481 	 */
1482 	capgrp = cap_clone(origcapgrp);
1483 	CHECK(capgrp != NULL);
1484 
1485 	names[0] = "kmem";
1486 	gids[0] = 2;
1487 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == 0);
1488 	gids[1] = 1;
1489 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 2) == -1 &&
1490 	    errno == ENOTCAPABLE);
1491 	gids[0] = 1;
1492 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
1493 	    errno == ENOTCAPABLE);
1494 	gids[0] = 2;
1495 
1496 	CHECK(runtest_groups(capgrp, names, gids, 1));
1497 
1498 	cap_close(capgrp);
1499 
1500 	/*
1501 	 * Allow:
1502 	 * groups:
1503 	 *     names:
1504 	 *     gids: 0, 4
1505 	 */
1506 	capgrp = cap_clone(origcapgrp);
1507 	CHECK(capgrp != NULL);
1508 
1509 	names[0] = "wheel";
1510 	names[1] = "tty";
1511 	gids[0] = 0;
1512 	gids[1] = 4;
1513 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 2) == 0);
1514 	gids[2] = 1;
1515 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == -1 &&
1516 	    errno == ENOTCAPABLE);
1517 	gids[0] = 1;
1518 	CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
1519 	    errno == ENOTCAPABLE);
1520 	gids[0] = 0;
1521 
1522 	CHECK(runtest_groups(capgrp, names, gids, 2));
1523 
1524 	cap_close(capgrp);
1525 }
1526 
1527 int
1528 main(void)
1529 {
1530 	cap_channel_t *capcas, *capgrp;
1531 
1532 	printf("1..199\n");
1533 	fflush(stdout);
1534 
1535 	capcas = cap_init();
1536 	CHECKX(capcas != NULL);
1537 
1538 	capgrp = cap_service_open(capcas, "system.grp");
1539 	CHECKX(capgrp != NULL);
1540 
1541 	cap_close(capcas);
1542 
1543 	/* No limits. */
1544 
1545 	CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
1546 	    GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
1547 
1548 	test_cmds(capgrp);
1549 
1550 	test_fields(capgrp);
1551 
1552 	test_groups(capgrp);
1553 
1554 	cap_close(capgrp);
1555 
1556 	exit(0);
1557 }
1558