1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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
51static 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
89static bool
90group_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
111static bool
112group_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
139static unsigned int
140runtest_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
228static void
229test_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
884static unsigned int
885group_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
906static bool
907runtest_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
942static void
943test_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
1211static bool
1212runtest_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
1285static void
1286test_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
1530int
1531main(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