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/types.h> 32 #include <sys/nv.h> 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <pwd.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include <libcasper.h> 42 #include <libcasper_service.h> 43 44 #include "cap_pwd.h" 45 46 static struct passwd gpwd; 47 static char *gbuffer; 48 static size_t gbufsize; 49 50 static int 51 passwd_resize(void) 52 { 53 char *buf; 54 55 if (gbufsize == 0) 56 gbufsize = 1024; 57 else 58 gbufsize *= 2; 59 60 buf = gbuffer; 61 gbuffer = realloc(buf, gbufsize); 62 if (gbuffer == NULL) { 63 free(buf); 64 gbufsize = 0; 65 return (ENOMEM); 66 } 67 memset(gbuffer, 0, gbufsize); 68 69 return (0); 70 } 71 72 static int 73 passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp, 74 char **bufferp, size_t *bufsizep) 75 { 76 const char *str; 77 size_t len; 78 79 str = nvlist_get_string(nvl, fieldname); 80 len = strlcpy(*bufferp, str, *bufsizep); 81 if (len >= *bufsizep) 82 return (ERANGE); 83 *fieldp = *bufferp; 84 *bufferp += len + 1; 85 *bufsizep -= len + 1; 86 87 return (0); 88 } 89 90 static int 91 passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer, 92 size_t bufsize) 93 { 94 int error; 95 96 if (!nvlist_exists_string(nvl, "pw_name")) 97 return (EINVAL); 98 99 explicit_bzero(pwd, sizeof(*pwd)); 100 101 error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer, 102 &bufsize); 103 if (error != 0) 104 return (error); 105 pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid"); 106 pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid"); 107 pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change"); 108 error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer, 109 &bufsize); 110 if (error != 0) 111 return (error); 112 error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer, 113 &bufsize); 114 if (error != 0) 115 return (error); 116 error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer, 117 &bufsize); 118 if (error != 0) 119 return (error); 120 error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer, 121 &bufsize); 122 if (error != 0) 123 return (error); 124 error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer, 125 &bufsize); 126 if (error != 0) 127 return (error); 128 pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire"); 129 pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields"); 130 131 return (0); 132 } 133 134 static int 135 cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login, 136 uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, 137 struct passwd **result) 138 { 139 nvlist_t *nvl; 140 bool getpw_r; 141 int error; 142 143 nvl = nvlist_create(0); 144 nvlist_add_string(nvl, "cmd", cmd); 145 if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) { 146 /* Add nothing. */ 147 } else if (strcmp(cmd, "getpwnam") == 0 || 148 strcmp(cmd, "getpwnam_r") == 0) { 149 nvlist_add_string(nvl, "name", login); 150 } else if (strcmp(cmd, "getpwuid") == 0 || 151 strcmp(cmd, "getpwuid_r") == 0) { 152 nvlist_add_number(nvl, "uid", (uint64_t)uid); 153 } else { 154 abort(); 155 } 156 nvl = cap_xfer_nvlist(chan, nvl); 157 if (nvl == NULL) { 158 assert(errno != 0); 159 *result = NULL; 160 return (errno); 161 } 162 error = (int)nvlist_get_number(nvl, "error"); 163 if (error != 0) { 164 nvlist_destroy(nvl); 165 *result = NULL; 166 return (error); 167 } 168 169 if (!nvlist_exists_string(nvl, "pw_name")) { 170 /* Not found. */ 171 nvlist_destroy(nvl); 172 *result = NULL; 173 return (0); 174 } 175 176 getpw_r = (strcmp(cmd, "getpwent_r") == 0 || 177 strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0); 178 179 for (;;) { 180 error = passwd_unpack(nvl, pwd, buffer, bufsize); 181 if (getpw_r || error != ERANGE) 182 break; 183 assert(buffer == gbuffer); 184 assert(bufsize == gbufsize); 185 error = passwd_resize(); 186 if (error != 0) 187 break; 188 /* Update pointers after resize. */ 189 buffer = gbuffer; 190 bufsize = gbufsize; 191 } 192 193 nvlist_destroy(nvl); 194 195 if (error == 0) 196 *result = pwd; 197 else 198 *result = NULL; 199 200 return (error); 201 } 202 203 static struct passwd * 204 cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login, 205 uid_t uid) 206 { 207 struct passwd *result; 208 int error, serrno; 209 210 serrno = errno; 211 212 error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer, 213 gbufsize, &result); 214 if (error != 0) { 215 errno = error; 216 return (NULL); 217 } 218 219 errno = serrno; 220 221 return (result); 222 } 223 224 struct passwd * 225 cap_getpwent(cap_channel_t *chan) 226 { 227 228 return (cap_getpwcommon(chan, "getpwent", NULL, 0)); 229 } 230 231 struct passwd * 232 cap_getpwnam(cap_channel_t *chan, const char *login) 233 { 234 235 return (cap_getpwcommon(chan, "getpwnam", login, 0)); 236 } 237 238 struct passwd * 239 cap_getpwuid(cap_channel_t *chan, uid_t uid) 240 { 241 242 return (cap_getpwcommon(chan, "getpwuid", NULL, uid)); 243 } 244 245 int 246 cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer, 247 size_t bufsize, struct passwd **result) 248 { 249 250 return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer, 251 bufsize, result)); 252 } 253 254 int 255 cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd, 256 char *buffer, size_t bufsize, struct passwd **result) 257 { 258 259 return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer, 260 bufsize, result)); 261 } 262 263 int 264 cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer, 265 size_t bufsize, struct passwd **result) 266 { 267 268 return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer, 269 bufsize, result)); 270 } 271 272 int 273 cap_setpassent(cap_channel_t *chan, int stayopen) 274 { 275 nvlist_t *nvl; 276 277 nvl = nvlist_create(0); 278 nvlist_add_string(nvl, "cmd", "setpassent"); 279 nvlist_add_bool(nvl, "stayopen", stayopen != 0); 280 nvl = cap_xfer_nvlist(chan, nvl); 281 if (nvl == NULL) 282 return (0); 283 if (nvlist_get_number(nvl, "error") != 0) { 284 errno = nvlist_get_number(nvl, "error"); 285 nvlist_destroy(nvl); 286 return (0); 287 } 288 nvlist_destroy(nvl); 289 290 return (1); 291 } 292 293 static void 294 cap_set_end_pwent(cap_channel_t *chan, const char *cmd) 295 { 296 nvlist_t *nvl; 297 298 nvl = nvlist_create(0); 299 nvlist_add_string(nvl, "cmd", cmd); 300 /* Ignore any errors, we have no way to report them. */ 301 nvlist_destroy(cap_xfer_nvlist(chan, nvl)); 302 } 303 304 void 305 cap_setpwent(cap_channel_t *chan) 306 { 307 308 cap_set_end_pwent(chan, "setpwent"); 309 } 310 311 void 312 cap_endpwent(cap_channel_t *chan) 313 { 314 315 cap_set_end_pwent(chan, "endpwent"); 316 } 317 318 int 319 cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds) 320 { 321 nvlist_t *limits, *nvl; 322 unsigned int i; 323 324 if (cap_limit_get(chan, &limits) < 0) 325 return (-1); 326 if (limits == NULL) { 327 limits = nvlist_create(0); 328 } else { 329 if (nvlist_exists_nvlist(limits, "cmds")) 330 nvlist_free_nvlist(limits, "cmds"); 331 } 332 nvl = nvlist_create(0); 333 for (i = 0; i < ncmds; i++) 334 nvlist_add_null(nvl, cmds[i]); 335 nvlist_move_nvlist(limits, "cmds", nvl); 336 return (cap_limit_set(chan, limits)); 337 } 338 339 int 340 cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields, 341 size_t nfields) 342 { 343 nvlist_t *limits, *nvl; 344 unsigned int i; 345 346 if (cap_limit_get(chan, &limits) < 0) 347 return (-1); 348 if (limits == NULL) { 349 limits = nvlist_create(0); 350 } else { 351 if (nvlist_exists_nvlist(limits, "fields")) 352 nvlist_free_nvlist(limits, "fields"); 353 } 354 nvl = nvlist_create(0); 355 for (i = 0; i < nfields; i++) 356 nvlist_add_null(nvl, fields[i]); 357 nvlist_move_nvlist(limits, "fields", nvl); 358 return (cap_limit_set(chan, limits)); 359 } 360 361 int 362 cap_pwd_limit_users(cap_channel_t *chan, const char * const *names, 363 size_t nnames, uid_t *uids, size_t nuids) 364 { 365 nvlist_t *limits, *users; 366 char nvlname[64]; 367 unsigned int i; 368 int n; 369 370 if (cap_limit_get(chan, &limits) < 0) 371 return (-1); 372 if (limits == NULL) { 373 limits = nvlist_create(0); 374 } else { 375 if (nvlist_exists_nvlist(limits, "users")) 376 nvlist_free_nvlist(limits, "users"); 377 } 378 users = nvlist_create(0); 379 for (i = 0; i < nuids; i++) { 380 n = snprintf(nvlname, sizeof(nvlname), "uid%u", i); 381 assert(n > 0 && n < (int)sizeof(nvlname)); 382 nvlist_add_number(users, nvlname, (uint64_t)uids[i]); 383 } 384 for (i = 0; i < nnames; i++) { 385 n = snprintf(nvlname, sizeof(nvlname), "name%u", i); 386 assert(n > 0 && n < (int)sizeof(nvlname)); 387 nvlist_add_string(users, nvlname, names[i]); 388 } 389 nvlist_move_nvlist(limits, "users", users); 390 return (cap_limit_set(chan, limits)); 391 } 392 393 394 /* 395 * Service functions. 396 */ 397 static bool 398 pwd_allowed_cmd(const nvlist_t *limits, const char *cmd) 399 { 400 401 if (limits == NULL) 402 return (true); 403 404 /* 405 * If no limit was set on allowed commands, then all commands 406 * are allowed. 407 */ 408 if (!nvlist_exists_nvlist(limits, "cmds")) 409 return (true); 410 411 limits = nvlist_get_nvlist(limits, "cmds"); 412 return (nvlist_exists_null(limits, cmd)); 413 } 414 415 static int 416 pwd_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits) 417 { 418 const char *name; 419 void *cookie; 420 int type; 421 422 cookie = NULL; 423 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { 424 if (type != NV_TYPE_NULL) 425 return (EINVAL); 426 if (!pwd_allowed_cmd(oldlimits, name)) 427 return (ENOTCAPABLE); 428 } 429 430 return (0); 431 } 432 433 static bool 434 pwd_allowed_user(const nvlist_t *limits, const char *uname, uid_t uid) 435 { 436 const char *name; 437 void *cookie; 438 int type; 439 440 if (limits == NULL) 441 return (true); 442 443 /* 444 * If no limit was set on allowed users, then all users are allowed. 445 */ 446 if (!nvlist_exists_nvlist(limits, "users")) 447 return (true); 448 449 limits = nvlist_get_nvlist(limits, "users"); 450 cookie = NULL; 451 while ((name = nvlist_next(limits, &type, &cookie)) != NULL) { 452 switch (type) { 453 case NV_TYPE_NUMBER: 454 if (uid != (uid_t)-1 && 455 nvlist_get_number(limits, name) == (uint64_t)uid) { 456 return (true); 457 } 458 break; 459 case NV_TYPE_STRING: 460 if (uname != NULL && 461 strcmp(nvlist_get_string(limits, name), 462 uname) == 0) { 463 return (true); 464 } 465 break; 466 default: 467 abort(); 468 } 469 } 470 471 return (false); 472 } 473 474 static int 475 pwd_allowed_users(const nvlist_t *oldlimits, const nvlist_t *newlimits) 476 { 477 const char *name, *uname; 478 void *cookie; 479 uid_t uid; 480 int type; 481 482 cookie = NULL; 483 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { 484 switch (type) { 485 case NV_TYPE_NUMBER: 486 uid = (uid_t)nvlist_get_number(newlimits, name); 487 uname = NULL; 488 break; 489 case NV_TYPE_STRING: 490 uid = (uid_t)-1; 491 uname = nvlist_get_string(newlimits, name); 492 break; 493 default: 494 return (EINVAL); 495 } 496 if (!pwd_allowed_user(oldlimits, uname, uid)) 497 return (ENOTCAPABLE); 498 } 499 500 return (0); 501 } 502 503 static bool 504 pwd_allowed_field(const nvlist_t *limits, const char *field) 505 { 506 507 if (limits == NULL) 508 return (true); 509 510 /* 511 * If no limit was set on allowed fields, then all fields are allowed. 512 */ 513 if (!nvlist_exists_nvlist(limits, "fields")) 514 return (true); 515 516 limits = nvlist_get_nvlist(limits, "fields"); 517 return (nvlist_exists_null(limits, field)); 518 } 519 520 static int 521 pwd_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits) 522 { 523 const char *name; 524 void *cookie; 525 int type; 526 527 cookie = NULL; 528 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { 529 if (type != NV_TYPE_NULL) 530 return (EINVAL); 531 if (!pwd_allowed_field(oldlimits, name)) 532 return (ENOTCAPABLE); 533 } 534 535 return (0); 536 } 537 538 static bool 539 pwd_pack(const nvlist_t *limits, const struct passwd *pwd, nvlist_t *nvl) 540 { 541 int fields; 542 543 if (pwd == NULL) 544 return (true); 545 546 /* 547 * If either name or UID is allowed, we allow it. 548 */ 549 if (!pwd_allowed_user(limits, pwd->pw_name, pwd->pw_uid)) 550 return (false); 551 552 fields = pwd->pw_fields; 553 554 if (pwd_allowed_field(limits, "pw_name")) { 555 nvlist_add_string(nvl, "pw_name", pwd->pw_name); 556 } else { 557 nvlist_add_string(nvl, "pw_name", ""); 558 fields &= ~_PWF_NAME; 559 } 560 if (pwd_allowed_field(limits, "pw_uid")) { 561 nvlist_add_number(nvl, "pw_uid", (uint64_t)pwd->pw_uid); 562 } else { 563 nvlist_add_number(nvl, "pw_uid", (uint64_t)-1); 564 fields &= ~_PWF_UID; 565 } 566 if (pwd_allowed_field(limits, "pw_gid")) { 567 nvlist_add_number(nvl, "pw_gid", (uint64_t)pwd->pw_gid); 568 } else { 569 nvlist_add_number(nvl, "pw_gid", (uint64_t)-1); 570 fields &= ~_PWF_GID; 571 } 572 if (pwd_allowed_field(limits, "pw_change")) { 573 nvlist_add_number(nvl, "pw_change", (uint64_t)pwd->pw_change); 574 } else { 575 nvlist_add_number(nvl, "pw_change", (uint64_t)0); 576 fields &= ~_PWF_CHANGE; 577 } 578 if (pwd_allowed_field(limits, "pw_passwd")) { 579 nvlist_add_string(nvl, "pw_passwd", pwd->pw_passwd); 580 } else { 581 nvlist_add_string(nvl, "pw_passwd", ""); 582 fields &= ~_PWF_PASSWD; 583 } 584 if (pwd_allowed_field(limits, "pw_class")) { 585 nvlist_add_string(nvl, "pw_class", pwd->pw_class); 586 } else { 587 nvlist_add_string(nvl, "pw_class", ""); 588 fields &= ~_PWF_CLASS; 589 } 590 if (pwd_allowed_field(limits, "pw_gecos")) { 591 nvlist_add_string(nvl, "pw_gecos", pwd->pw_gecos); 592 } else { 593 nvlist_add_string(nvl, "pw_gecos", ""); 594 fields &= ~_PWF_GECOS; 595 } 596 if (pwd_allowed_field(limits, "pw_dir")) { 597 nvlist_add_string(nvl, "pw_dir", pwd->pw_dir); 598 } else { 599 nvlist_add_string(nvl, "pw_dir", ""); 600 fields &= ~_PWF_DIR; 601 } 602 if (pwd_allowed_field(limits, "pw_shell")) { 603 nvlist_add_string(nvl, "pw_shell", pwd->pw_shell); 604 } else { 605 nvlist_add_string(nvl, "pw_shell", ""); 606 fields &= ~_PWF_SHELL; 607 } 608 if (pwd_allowed_field(limits, "pw_expire")) { 609 nvlist_add_number(nvl, "pw_expire", (uint64_t)pwd->pw_expire); 610 } else { 611 nvlist_add_number(nvl, "pw_expire", (uint64_t)0); 612 fields &= ~_PWF_EXPIRE; 613 } 614 nvlist_add_number(nvl, "pw_fields", (uint64_t)fields); 615 616 return (true); 617 } 618 619 static int 620 pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin __unused, 621 nvlist_t *nvlout) 622 { 623 struct passwd *pwd; 624 625 for (;;) { 626 errno = 0; 627 pwd = getpwent(); 628 if (errno != 0) 629 return (errno); 630 if (pwd_pack(limits, pwd, nvlout)) 631 return (0); 632 } 633 634 /* NOTREACHED */ 635 } 636 637 static int 638 pwd_getpwnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 639 { 640 struct passwd *pwd; 641 const char *name; 642 643 if (!nvlist_exists_string(nvlin, "name")) 644 return (EINVAL); 645 name = nvlist_get_string(nvlin, "name"); 646 assert(name != NULL); 647 648 errno = 0; 649 pwd = getpwnam(name); 650 if (errno != 0) 651 return (errno); 652 653 (void)pwd_pack(limits, pwd, nvlout); 654 655 return (0); 656 } 657 658 static int 659 pwd_getpwuid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout) 660 { 661 struct passwd *pwd; 662 uid_t uid; 663 664 if (!nvlist_exists_number(nvlin, "uid")) 665 return (EINVAL); 666 667 uid = (uid_t)nvlist_get_number(nvlin, "uid"); 668 669 errno = 0; 670 pwd = getpwuid(uid); 671 if (errno != 0) 672 return (errno); 673 674 (void)pwd_pack(limits, pwd, nvlout); 675 676 return (0); 677 } 678 679 static int 680 pwd_setpassent(const nvlist_t *limits __unused, const nvlist_t *nvlin, 681 nvlist_t *nvlout __unused) 682 { 683 int stayopen; 684 685 if (!nvlist_exists_bool(nvlin, "stayopen")) 686 return (EINVAL); 687 688 stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0; 689 690 return (setpassent(stayopen) == 0 ? EFAULT : 0); 691 } 692 693 static int 694 pwd_setpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused, 695 nvlist_t *nvlout __unused) 696 { 697 698 setpwent(); 699 700 return (0); 701 } 702 703 static int 704 pwd_endpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused, 705 nvlist_t *nvlout __unused) 706 { 707 708 endpwent(); 709 710 return (0); 711 } 712 713 static int 714 pwd_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) 715 { 716 const nvlist_t *limits; 717 const char *name; 718 void *cookie; 719 int error, type; 720 721 if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") && 722 !nvlist_exists_nvlist(newlimits, "cmds")) { 723 return (ENOTCAPABLE); 724 } 725 if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") && 726 !nvlist_exists_nvlist(newlimits, "fields")) { 727 return (ENOTCAPABLE); 728 } 729 if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "users") && 730 !nvlist_exists_nvlist(newlimits, "users")) { 731 return (ENOTCAPABLE); 732 } 733 734 cookie = NULL; 735 while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { 736 if (type != NV_TYPE_NVLIST) 737 return (EINVAL); 738 limits = nvlist_get_nvlist(newlimits, name); 739 if (strcmp(name, "cmds") == 0) 740 error = pwd_allowed_cmds(oldlimits, limits); 741 else if (strcmp(name, "fields") == 0) 742 error = pwd_allowed_fields(oldlimits, limits); 743 else if (strcmp(name, "users") == 0) 744 error = pwd_allowed_users(oldlimits, limits); 745 else 746 error = EINVAL; 747 if (error != 0) 748 return (error); 749 } 750 751 return (0); 752 } 753 754 static int 755 pwd_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, 756 nvlist_t *nvlout) 757 { 758 int error; 759 760 if (!pwd_allowed_cmd(limits, cmd)) 761 return (ENOTCAPABLE); 762 763 if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) 764 error = pwd_getpwent(limits, nvlin, nvlout); 765 else if (strcmp(cmd, "getpwnam") == 0 || strcmp(cmd, "getpwnam_r") == 0) 766 error = pwd_getpwnam(limits, nvlin, nvlout); 767 else if (strcmp(cmd, "getpwuid") == 0 || strcmp(cmd, "getpwuid_r") == 0) 768 error = pwd_getpwuid(limits, nvlin, nvlout); 769 else if (strcmp(cmd, "setpassent") == 0) 770 error = pwd_setpassent(limits, nvlin, nvlout); 771 else if (strcmp(cmd, "setpwent") == 0) 772 error = pwd_setpwent(limits, nvlin, nvlout); 773 else if (strcmp(cmd, "endpwent") == 0) 774 error = pwd_endpwent(limits, nvlin, nvlout); 775 else 776 error = EINVAL; 777 778 return (error); 779 } 780 781 CREATE_SERVICE("system.pwd", pwd_limit, pwd_command, 0); 782