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