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