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