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