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