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