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