1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 * 25 * Copyright 2022 RackTop Systems, Inc. 26 */ 27 28 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <limits.h> 33 #include <grp.h> 34 #include <pwd.h> 35 #include <strings.h> 36 #include <sys/types.h> 37 #include <errno.h> 38 #include <sys/stat.h> 39 #include <sys/varargs.h> 40 #include <locale.h> 41 #include <aclutils.h> 42 #include <sys/avl.h> 43 #include <acl_common.h> 44 #include <idmap.h> 45 46 #define ACL_PATH 0 47 #define ACL_FD 1 48 49 50 typedef union { 51 const char *file; 52 int fd; 53 } acl_inp; 54 55 56 /* 57 * Determine whether a file has a trivial ACL 58 * returns: 0 = trivial 59 * 1 = nontrivial 60 * <0 some other system failure, such as ENOENT or EPERM 61 */ 62 int 63 acl_trivial(const char *filename) 64 { 65 int acl_flavor; 66 int aclcnt; 67 int cntcmd; 68 int val = 0; 69 ace_t *acep; 70 71 acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 72 73 if (acl_flavor == _ACL_ACE_ENABLED) 74 cntcmd = ACE_GETACLCNT; 75 else 76 cntcmd = GETACLCNT; 77 78 aclcnt = acl(filename, cntcmd, 0, NULL); 79 if (aclcnt > 0) { 80 if (acl_flavor == _ACL_ACE_ENABLED) { 81 acep = malloc(sizeof (ace_t) * aclcnt); 82 if (acep == NULL) 83 return (-1); 84 if (acl(filename, ACE_GETACL, 85 aclcnt, acep) < 0) { 86 free(acep); 87 return (-1); 88 } 89 90 val = ace_trivial(acep, aclcnt); 91 free(acep); 92 93 } else if (aclcnt > MIN_ACL_ENTRIES) 94 val = 1; 95 } 96 return (val); 97 } 98 99 100 static int 101 cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 102 { 103 const char *fname; 104 int fd; 105 int ace_acl = 0; 106 int error; 107 int getcmd, cntcmd; 108 acl_t *acl_info; 109 int save_errno; 110 int stat_error; 111 struct stat64 statbuf; 112 113 *aclp = NULL; 114 if (type == ACL_PATH) { 115 fname = inp.file; 116 ace_acl = pathconf(fname, _PC_ACL_ENABLED); 117 } else { 118 fd = inp.fd; 119 ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 120 } 121 122 /* 123 * if acl's aren't supported then 124 * send it through the old GETACL interface 125 */ 126 if (ace_acl == 0 || ace_acl == -1) { 127 ace_acl = _ACL_ACLENT_ENABLED; 128 } 129 130 if (ace_acl & _ACL_ACE_ENABLED) { 131 cntcmd = ACE_GETACLCNT; 132 getcmd = ACE_GETACL; 133 acl_info = acl_alloc(ACE_T); 134 } else { 135 cntcmd = GETACLCNT; 136 getcmd = GETACL; 137 acl_info = acl_alloc(ACLENT_T); 138 } 139 140 if (acl_info == NULL) 141 return (-1); 142 143 if (type == ACL_PATH) { 144 acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 145 } else { 146 acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 147 } 148 149 save_errno = errno; 150 if (acl_info->acl_cnt < 0) { 151 acl_free(acl_info); 152 errno = save_errno; 153 return (-1); 154 } 155 156 if (acl_info->acl_cnt == 0) { 157 acl_free(acl_info); 158 errno = save_errno; 159 return (0); 160 } 161 162 acl_info->acl_aclp = 163 malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 164 save_errno = errno; 165 166 if (acl_info->acl_aclp == NULL) { 167 acl_free(acl_info); 168 errno = save_errno; 169 return (-1); 170 } 171 172 if (type == ACL_PATH) { 173 stat_error = stat64(fname, &statbuf); 174 error = acl(fname, getcmd, acl_info->acl_cnt, 175 acl_info->acl_aclp); 176 } else { 177 stat_error = fstat64(fd, &statbuf); 178 error = facl(fd, getcmd, acl_info->acl_cnt, 179 acl_info->acl_aclp); 180 } 181 182 save_errno = errno; 183 if (error == -1) { 184 acl_free(acl_info); 185 errno = save_errno; 186 return (-1); 187 } 188 189 190 if (stat_error == 0) { 191 acl_info->acl_flags = 192 (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 193 } else 194 acl_info->acl_flags = 0; 195 196 switch (acl_info->acl_type) { 197 case ACLENT_T: 198 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 199 acl_info->acl_flags |= ACL_IS_TRIVIAL; 200 break; 201 case ACE_T: 202 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 203 acl_info->acl_flags |= ACL_IS_TRIVIAL; 204 break; 205 default: 206 errno = EINVAL; 207 acl_free(acl_info); 208 return (-1); 209 } 210 211 if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 212 (get_flag & ACL_NO_TRIVIAL)) { 213 acl_free(acl_info); 214 errno = 0; 215 return (0); 216 } 217 218 *aclp = acl_info; 219 return (0); 220 } 221 222 /* 223 * return -1 on failure, otherwise the number of acl 224 * entries is returned 225 */ 226 int 227 acl_get(const char *path, int get_flag, acl_t **aclp) 228 { 229 acl_inp acl_inp; 230 acl_inp.file = path; 231 232 return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 233 } 234 235 int 236 facl_get(int fd, int get_flag, acl_t **aclp) 237 { 238 239 acl_inp acl_inp; 240 acl_inp.fd = fd; 241 242 return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 243 } 244 245 /* 246 * Set an ACL, translates acl to ace_t when appropriate. 247 */ 248 static int 249 cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 250 { 251 int error = 0; 252 int acl_flavor_target; 253 struct stat64 statbuf; 254 int stat_error; 255 int isdir; 256 257 258 if (type == ACL_PATH) { 259 stat_error = stat64(acl_inp->file, &statbuf); 260 if (stat_error) 261 return (-1); 262 acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 263 } else { 264 stat_error = fstat64(acl_inp->fd, &statbuf); 265 if (stat_error) 266 return (-1); 267 acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 268 } 269 270 /* 271 * If target returns an error or 0 from pathconf call then 272 * fall back to UFS/POSIX Draft interface. 273 * In the case of 0 we will then fail in either acl(2) or 274 * acl_translate(). We could erroneously get 0 back from 275 * a file system that is using fs_pathconf() and not answering 276 * the _PC_ACL_ENABLED question itself. 277 */ 278 if (acl_flavor_target == 0 || acl_flavor_target == -1) 279 acl_flavor_target = _ACL_ACLENT_ENABLED; 280 281 isdir = S_ISDIR(statbuf.st_mode); 282 283 if ((error = acl_translate(aclp, acl_flavor_target, isdir, 284 statbuf.st_uid, statbuf.st_gid)) != 0) { 285 return (error); 286 } 287 288 if (type == ACL_PATH) { 289 error = acl(acl_inp->file, 290 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 291 aclp->acl_cnt, aclp->acl_aclp); 292 } else { 293 error = facl(acl_inp->fd, 294 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 295 aclp->acl_cnt, aclp->acl_aclp); 296 } 297 298 return (error); 299 } 300 301 int 302 acl_set(const char *path, acl_t *aclp) 303 { 304 acl_inp acl_inp; 305 306 acl_inp.file = path; 307 308 return (cacl_set(&acl_inp, aclp, ACL_PATH)); 309 } 310 311 int 312 facl_set(int fd, acl_t *aclp) 313 { 314 acl_inp acl_inp; 315 316 acl_inp.fd = fd; 317 318 return (cacl_set(&acl_inp, aclp, ACL_FD)); 319 } 320 321 int 322 acl_cnt(acl_t *aclp) 323 { 324 return (aclp->acl_cnt); 325 } 326 327 int 328 acl_type(acl_t *aclp) 329 { 330 return (aclp->acl_type); 331 } 332 333 acl_t * 334 acl_dup(acl_t *aclp) 335 { 336 acl_t *newaclp; 337 338 newaclp = acl_alloc(aclp->acl_type); 339 if (newaclp == NULL) 340 return (NULL); 341 342 newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 343 if (newaclp->acl_aclp == NULL) { 344 acl_free(newaclp); 345 return (NULL); 346 } 347 348 (void) memcpy(newaclp->acl_aclp, 349 aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 350 newaclp->acl_cnt = aclp->acl_cnt; 351 352 return (newaclp); 353 } 354 355 int 356 acl_flags(acl_t *aclp) 357 { 358 return (aclp->acl_flags); 359 } 360 361 void * 362 acl_data(acl_t *aclp) 363 { 364 return (aclp->acl_aclp); 365 } 366 367 /* 368 * Take an acl array and build an acl_t. 369 */ 370 acl_t * 371 acl_to_aclp(enum acl_type type, void *acl, int count) 372 { 373 acl_t *aclp; 374 375 376 aclp = acl_alloc(type); 377 if (aclp == NULL) 378 return (aclp); 379 380 aclp->acl_aclp = acl; 381 aclp->acl_cnt = count; 382 383 return (aclp); 384 } 385 386 /* 387 * Remove an ACL from a file and create a trivial ACL based 388 * off of the mode argument. After acl has been set owner/group 389 * are updated to match owner,group arguments 390 */ 391 int 392 acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 393 { 394 int error = 0; 395 aclent_t min_acl[MIN_ACL_ENTRIES]; 396 ace_t *min_ace_acl; 397 int acl_flavor; 398 int aclcnt; 399 struct stat64 statbuf; 400 401 acl_flavor = pathconf(file, _PC_ACL_ENABLED); 402 403 if (stat64(file, &statbuf) != 0) { 404 error = 1; 405 return (error); 406 } 407 408 /* 409 * force it through aclent flavor when file system doesn't 410 * understand question 411 */ 412 if (acl_flavor == 0 || acl_flavor == -1) 413 acl_flavor = _ACL_ACLENT_ENABLED; 414 415 if (acl_flavor & _ACL_ACLENT_ENABLED) { 416 min_acl[0].a_type = USER_OBJ; 417 min_acl[0].a_id = owner; 418 min_acl[0].a_perm = ((mode & 0700) >> 6); 419 min_acl[1].a_type = GROUP_OBJ; 420 min_acl[1].a_id = group; 421 min_acl[1].a_perm = ((mode & 0070) >> 3); 422 min_acl[2].a_type = CLASS_OBJ; 423 min_acl[2].a_id = (uid_t)-1; 424 min_acl[2].a_perm = ((mode & 0070) >> 3); 425 min_acl[3].a_type = OTHER_OBJ; 426 min_acl[3].a_id = (uid_t)-1; 427 min_acl[3].a_perm = (mode & 0007); 428 aclcnt = 4; 429 error = acl(file, SETACL, aclcnt, min_acl); 430 } else if (acl_flavor & _ACL_ACE_ENABLED) { 431 if ((error = acl_trivial_create(mode, S_ISDIR(statbuf.st_mode), 432 &min_ace_acl, &aclcnt)) != 0) 433 return (error); 434 error = acl(file, ACE_SETACL, aclcnt, min_ace_acl); 435 free(min_ace_acl); 436 } else { 437 errno = EINVAL; 438 error = 1; 439 } 440 441 if (error == 0) 442 error = chown(file, owner, group); 443 return (error); 444 } 445 446 static int 447 ace_match(void *entry1, void *entry2) 448 { 449 ace_t *p1 = (ace_t *)entry1; 450 ace_t *p2 = (ace_t *)entry2; 451 ace_t ace1, ace2; 452 453 ace1 = *p1; 454 ace2 = *p2; 455 456 /* 457 * Need to fixup who field for abstrations for 458 * accurate comparison, since field is undefined. 459 */ 460 if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 461 ace1.a_who = (uid_t)-1; 462 if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 463 ace2.a_who = (uid_t)-1; 464 return (memcmp(&ace1, &ace2, sizeof (ace_t))); 465 } 466 467 static int 468 aclent_match(void *entry1, void *entry2) 469 { 470 aclent_t *aclent1 = (aclent_t *)entry1; 471 aclent_t *aclent2 = (aclent_t *)entry2; 472 473 return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 474 } 475 476 /* 477 * Find acl entries in acl that correspond to removeacl. Search 478 * is started from slot. The flag argument indicates whether to 479 * remove all matches or just the first match. 480 */ 481 int 482 acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 483 { 484 int i, j; 485 int match; 486 int (*acl_match)(void *acl1, void *acl2); 487 void *acl_entry, *remove_entry; 488 void *start; 489 int found = 0; 490 491 if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 492 flag = ACL_REMOVE_FIRST; 493 494 if (acl == NULL || removeacl == NULL) 495 return (EACL_NO_ACL_ENTRY); 496 497 if (acl->acl_type != removeacl->acl_type) 498 return (EACL_DIFF_TYPE); 499 500 if (acl->acl_type == ACLENT_T) 501 acl_match = aclent_match; 502 else 503 acl_match = ace_match; 504 505 for (i = 0, remove_entry = removeacl->acl_aclp; 506 i != removeacl->acl_cnt; i++) { 507 508 j = 0; 509 acl_entry = (char *)acl->acl_aclp + 510 (acl->acl_entry_size * start_slot); 511 for (;;) { 512 match = acl_match(acl_entry, remove_entry); 513 if (match == 0) { 514 found++; 515 516 /* avoid memmove if last entry */ 517 if (acl->acl_cnt == (j + 1)) { 518 acl->acl_cnt--; 519 break; 520 } 521 522 start = (char *)acl_entry + 523 acl->acl_entry_size; 524 (void) memmove(acl_entry, start, 525 acl->acl_entry_size * 526 (acl->acl_cnt-- - (j + 1))); 527 528 if (flag == ACL_REMOVE_FIRST) 529 break; 530 /* 531 * List has changed, just continue so this 532 * slot gets checked with it's new contents. 533 */ 534 continue; 535 } 536 acl_entry = ((char *)acl_entry + acl->acl_entry_size); 537 if (++j >= acl->acl_cnt) { 538 break; 539 } 540 } 541 remove_entry = (char *)remove_entry + removeacl->acl_entry_size; 542 } 543 544 return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 545 } 546 547 /* 548 * Replace entires entries in acl1 with the corresponding entries 549 * in newentries. The where argument specifies where to begin 550 * the replacement. If the where argument is 1 greater than the 551 * number of acl entries in acl1 then they are appended. If the 552 * where argument is 2+ greater than the number of acl entries then 553 * EACL_INVALID_SLOT is returned. 554 */ 555 int 556 acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 557 { 558 559 int slot; 560 int slots_needed; 561 int slots_left; 562 int newsize; 563 564 if (acl1 == NULL || newentries == NULL) 565 return (EACL_NO_ACL_ENTRY); 566 567 if (where < 0 || where >= acl1->acl_cnt) 568 return (EACL_INVALID_SLOT); 569 570 if (acl1->acl_type != newentries->acl_type) 571 return (EACL_DIFF_TYPE); 572 573 slot = where; 574 575 slots_left = acl1->acl_cnt - slot + 1; 576 if (slots_left < newentries->acl_cnt) { 577 slots_needed = newentries->acl_cnt - slots_left; 578 newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 579 (acl1->acl_entry_size * slots_needed); 580 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 581 if (acl1->acl_aclp == NULL) 582 return (-1); 583 } 584 (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 585 newentries->acl_aclp, 586 newentries->acl_entry_size * newentries->acl_cnt); 587 588 /* 589 * Did ACL grow? 590 */ 591 592 if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 593 acl1->acl_cnt = slot + newentries->acl_cnt; 594 } 595 596 return (0); 597 } 598 599 /* 600 * Add acl2 entries into acl1. The where argument specifies where 601 * to add the entries. 602 */ 603 int 604 acl_addentries(acl_t *acl1, acl_t *acl2, int where) 605 { 606 607 int newsize; 608 int len; 609 void *start; 610 void *to; 611 612 if (acl1 == NULL || acl2 == NULL) 613 return (EACL_NO_ACL_ENTRY); 614 615 if (acl1->acl_type != acl2->acl_type) 616 return (EACL_DIFF_TYPE); 617 618 /* 619 * allow where to specify 1 past last slot for an append operation 620 * but anything greater is an error. 621 */ 622 if (where < 0 || where > acl1->acl_cnt) 623 return (EACL_INVALID_SLOT); 624 625 newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 626 (acl1->acl_entry_size * acl1->acl_cnt); 627 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 628 if (acl1->acl_aclp == NULL) 629 return (-1); 630 631 /* 632 * first push down entries where new ones will be inserted 633 */ 634 635 to = (void *)((char *)acl1->acl_aclp + 636 ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 637 638 start = (void *)((char *)acl1->acl_aclp + 639 where * acl1->acl_entry_size); 640 641 if (where < acl1->acl_cnt) { 642 len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 643 (void) memmove(to, start, len); 644 } 645 646 /* 647 * now stick in new entries. 648 */ 649 650 (void) memmove(start, acl2->acl_aclp, 651 acl2->acl_cnt * acl2->acl_entry_size); 652 653 acl1->acl_cnt += acl2->acl_cnt; 654 return (0); 655 } 656 657 /* 658 * return text for an ACL error. 659 */ 660 char * 661 acl_strerror(int errnum) 662 { 663 switch (errnum) { 664 case EACL_GRP_ERROR: 665 return (dgettext(TEXT_DOMAIN, 666 "There is more than one group or default group entry")); 667 case EACL_USER_ERROR: 668 return (dgettext(TEXT_DOMAIN, 669 "There is more than one user or default user entry")); 670 case EACL_OTHER_ERROR: 671 return (dgettext(TEXT_DOMAIN, 672 "There is more than one other entry")); 673 case EACL_CLASS_ERROR: 674 return (dgettext(TEXT_DOMAIN, 675 "There is more than one mask entry")); 676 case EACL_DUPLICATE_ERROR: 677 return (dgettext(TEXT_DOMAIN, 678 "Duplicate user or group entries")); 679 case EACL_MISS_ERROR: 680 return (dgettext(TEXT_DOMAIN, 681 "Missing user/group owner, other, mask entry")); 682 case EACL_MEM_ERROR: 683 return (dgettext(TEXT_DOMAIN, 684 "Memory error")); 685 case EACL_ENTRY_ERROR: 686 return (dgettext(TEXT_DOMAIN, 687 "Unrecognized entry type")); 688 case EACL_INHERIT_ERROR: 689 return (dgettext(TEXT_DOMAIN, 690 "Invalid inheritance flags")); 691 case EACL_FLAGS_ERROR: 692 return (dgettext(TEXT_DOMAIN, 693 "Unrecognized entry flags")); 694 case EACL_PERM_MASK_ERROR: 695 return (dgettext(TEXT_DOMAIN, 696 "Invalid ACL permissions")); 697 case EACL_COUNT_ERROR: 698 return (dgettext(TEXT_DOMAIN, 699 "Invalid ACL count")); 700 case EACL_INVALID_SLOT: 701 return (dgettext(TEXT_DOMAIN, 702 "Invalid ACL entry number specified")); 703 case EACL_NO_ACL_ENTRY: 704 return (dgettext(TEXT_DOMAIN, 705 "ACL entry doesn't exist")); 706 case EACL_DIFF_TYPE: 707 return (dgettext(TEXT_DOMAIN, 708 "Different file system ACL types cannot be merged")); 709 case EACL_INVALID_USER_GROUP: 710 return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 711 case EACL_INVALID_STR: 712 return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 713 case EACL_FIELD_NOT_BLANK: 714 return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 715 case EACL_INVALID_ACCESS_TYPE: 716 return (dgettext(TEXT_DOMAIN, "Invalid access type")); 717 case EACL_UNKNOWN_DATA: 718 return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 719 case EACL_MISSING_FIELDS: 720 return (dgettext(TEXT_DOMAIN, 721 "ACL specification missing required fields")); 722 case EACL_INHERIT_NOTDIR: 723 return (dgettext(TEXT_DOMAIN, 724 "Inheritance flags are only allowed on directories")); 725 case -1: 726 return (strerror(errno)); 727 default: 728 errno = EINVAL; 729 return (dgettext(TEXT_DOMAIN, "Unknown error")); 730 } 731 } 732 733 extern int yyinteractive; 734 735 /* PRINTFLIKE1 */ 736 void 737 acl_error(const char *fmt, ...) 738 { 739 va_list va; 740 741 if (yyinteractive == 0) 742 return; 743 744 va_start(va, fmt); 745 (void) vfprintf(stderr, fmt, va); 746 va_end(va); 747 } 748 749 typedef enum id_type { 750 UID_TYPE, 751 GID_TYPE, 752 PID_TYPE 753 } id_type_t; 754 755 static int 756 sid_to_id_impl(char *sid, id_type_t type, int *is_user, uid_t *id) 757 { 758 idmap_get_handle_t *get_hdl; 759 char *rid_start; 760 idmap_stat rv; 761 idmap_rid_t rid; 762 const char *errstr; 763 idmap_stat status; 764 int error = 1; 765 766 rid_start = strrchr(sid, '-'); 767 if (rid_start == NULL) 768 return (error); 769 770 rid = strtonum(rid_start + 1, 0, UINT32_MAX, &errstr); 771 if (errstr != NULL) 772 return (error); 773 774 if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS) 775 return (error); 776 777 /* 778 * When these functions return success, the &status output is 779 * indeterminate. We only care about rv==success in this caller, 780 * so just ignore &status. 781 */ 782 /* We need sid prefix. Insert NUL on '-', restore it later. */ 783 *rid_start = '\0'; 784 switch (type) { 785 case UID_TYPE: 786 rv = idmap_get_uidbysid(get_hdl, 787 sid, rid, IDMAP_REQ_FLG_USE_CACHE, 788 id, &status); 789 break; 790 791 case GID_TYPE: 792 rv = idmap_get_gidbysid(get_hdl, 793 sid, rid, IDMAP_REQ_FLG_USE_CACHE, 794 id, &status); 795 break; 796 797 case PID_TYPE: 798 rv = idmap_get_pidbysid(get_hdl, sid, rid, 799 IDMAP_REQ_FLG_USE_CACHE, id, is_user, 800 &status); 801 break; 802 } 803 804 *rid_start = '-'; /* putback character removed earlier */ 805 if (rv == IDMAP_SUCCESS && 806 idmap_get_mappings(get_hdl) == IDMAP_SUCCESS) { 807 error = 0; 808 } 809 idmap_get_destroy(get_hdl); 810 811 return (error); 812 } 813 814 int 815 sid_to_id(char *sid, boolean_t user, uid_t *id) 816 { 817 char *domain_start; 818 int error = 1; 819 820 if ((domain_start = strchr(sid, '@')) == NULL) { 821 error = sid_to_id_impl(sid, user ? UID_TYPE : GID_TYPE, 822 NULL, id); 823 } else { 824 char *name = sid; 825 idmap_stat rv; 826 827 *domain_start++ = '\0'; 828 829 if (user) 830 rv = idmap_getuidbywinname(name, domain_start, 831 IDMAP_REQ_FLG_USE_CACHE, id); 832 else 833 rv = idmap_getgidbywinname(name, domain_start, 834 IDMAP_REQ_FLG_USE_CACHE, id); 835 *--domain_start = '@'; 836 if (rv == IDMAP_SUCCESS) 837 error = 0; 838 } 839 840 return (error); 841 } 842 843 /* 844 * Variant of sid_to_id() called when we don't know whether the SID 845 * is a user or group. 2nd arg gets the type (0:group, 1:user) 846 * Returns zero for success, 1 for errors. 847 */ 848 int 849 sid_to_xid(char *sid, int *is_user, uid_t *id) 850 { 851 if ((strchr(sid, '@')) != NULL) 852 return (1); 853 854 return (sid_to_id_impl(sid, PID_TYPE, is_user, id)); 855 } 856