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