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) 1993, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2020 Peter Tribble. 24 */ 25 26 /* 27 * setfacl [-r] -f aclfile file ... 28 * setfacl [-r] -d acl_entries file ... 29 * setfacl [-r] -m acl_entries file ... 30 * setfacl [-r] -s acl_entries file ... 31 * This command deletes/adds/modifies/sets discretionary information for a file 32 * or files. 33 */ 34 35 #include <stdlib.h> 36 #include <stdio.h> 37 #include <pwd.h> 38 #include <grp.h> 39 #include <string.h> 40 #include <locale.h> 41 #include <sys/acl.h> 42 #include <sys/types.h> 43 #include <unistd.h> 44 #include <errno.h> 45 #include <ctype.h> 46 47 #define ADD 1 48 #define MODIFY 2 49 #define DELETE 3 50 #define SET 4 51 52 static int get_acl_info(char *filep, aclent_t **aclpp); 53 static int mod_entries(aclent_t *, int, char *, char *, char *, int); 54 static int set_file_entries(char *, char *, int); 55 static int set_online_entries(char *, char *, int); 56 static void usage(); 57 static int parse_entry_list(aclent_t **, int *, char *, int); 58 static int convert_to_aclent_t(char *, int *, aclent_t **, int); 59 static int parse_entry(char *, aclent_t *, int); 60 static void err_handle(int, aclent_t *); 61 static int conv_id(char *); 62 63 int 64 main(int argc, char *argv[]) 65 { 66 int c; 67 int dflag = 0; 68 int mflag = 0; 69 int rflag = 0; 70 int sflag = 0; 71 int fflag = 0; 72 int errflag = 0; 73 int aclcnt; /* used by -m -d */ 74 aclent_t *aclp; /* used by -m -d */ 75 char *aclfilep = NULL; /* acl file argument */ 76 char *d_entryp = NULL; /* ptr to del entry list */ 77 char *m_entryp = NULL; /* ptr to mod entry list */ 78 char *s_entryp = NULL; /* ptr to set entry list */ 79 char *work_dp = NULL; /* working ptrs for the above */ 80 char *work_mp = NULL; 81 char *work_sp = NULL; 82 83 (void) setlocale(LC_ALL, ""); 84 (void) textdomain(TEXT_DOMAIN); 85 86 if (argc < 3) 87 usage(); 88 89 while ((c = getopt(argc, argv, "rm:d:s:f:")) != EOF) { 90 switch (c) { 91 case 'r': 92 rflag++; 93 break; 94 case 'd': 95 if (dflag || fflag || sflag) 96 usage(); 97 dflag++; 98 d_entryp = optarg; 99 break; 100 case 'm': 101 if (mflag || fflag || sflag) 102 usage(); 103 mflag++; 104 m_entryp = optarg; 105 break; 106 case 's': 107 if (fflag || sflag || mflag || dflag) 108 usage(); 109 sflag++; 110 s_entryp = optarg; 111 break; 112 case 'f': 113 if (fflag || sflag || mflag || dflag) 114 usage(); 115 fflag++; 116 aclfilep = optarg; 117 break; 118 case '?': 119 errflag++; 120 break; 121 } 122 } 123 if (errflag) 124 usage(); 125 126 /* one of these flags should be set */ 127 if (!fflag && !sflag && !mflag && !dflag) 128 usage(); 129 130 /* no file arguments */ 131 if (optind >= argc) 132 usage(); 133 134 for (; optind < argc; optind++) { 135 register char *filep; 136 137 filep = argv[optind]; 138 139 /* modify and delete: we need to get the ACL first */ 140 if (mflag || dflag) { 141 if (m_entryp != NULL) { 142 free(work_mp); 143 work_mp = strdup(m_entryp); 144 if (work_mp == NULL) { 145 fprintf(stderr, 146 gettext("out of memory %s\n"), 147 m_entryp); 148 exit(1); 149 } 150 } 151 152 if (d_entryp != NULL) { 153 free(work_dp); 154 work_dp = strdup(d_entryp); 155 if (work_dp == NULL) { 156 fprintf(stderr, 157 gettext("out of memory %s\n"), 158 d_entryp); 159 exit(1); 160 } 161 } 162 163 aclcnt = get_acl_info(filep, &aclp); 164 if (aclcnt == -1) 165 exit(2); 166 if (mod_entries(aclp, aclcnt, work_mp, 167 work_dp, filep, rflag) == -1) 168 exit(2); 169 } else if (fflag) { 170 if (set_file_entries(aclfilep, filep, rflag) == -1) 171 exit(2); 172 } else if (sflag) { 173 if (s_entryp != NULL) { 174 free(work_sp); 175 work_sp = strdup(s_entryp); 176 if (work_sp == NULL) { 177 fprintf(stderr, 178 gettext("out of memory %s\n"), 179 s_entryp); 180 exit(1); 181 } 182 } 183 if (set_online_entries(work_sp, filep, rflag) == -1) 184 exit(2); 185 } 186 } 187 return (0); 188 } 189 190 /* 191 * For add, modify, and delete, we need to get the ACL of the file first. 192 */ 193 static int 194 get_acl_info(char *filep, aclent_t **aclpp) 195 { 196 int aclcnt; 197 198 if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) { 199 if (errno == ENOSYS) { 200 (void) fprintf(stderr, 201 gettext("File system doesn't support aclent_t " 202 "style ACL's.\n" 203 "See acl(7) for more information on " 204 "POSIX-draft ACL support.\n")); 205 return (-1); 206 } 207 (void) fprintf(stderr, 208 gettext("%s: failed to get acl count\n"), filep); 209 perror("get acl count error"); 210 return (-1); 211 } 212 if (aclcnt < MIN_ACL_ENTRIES) { 213 (void) fprintf(stderr, 214 gettext("%d: acl count is too small from %s\n"), 215 aclcnt, filep); 216 return (-1); 217 } 218 219 if ((*aclpp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt)) == NULL) { 220 (void) fprintf(stderr, gettext("out of memory\n")); 221 return (-1); 222 } 223 if (acl(filep, GETACL, aclcnt, *aclpp) < 0) { 224 (void) fprintf(stderr, 225 gettext("%s: failed to get acl entries\n"), filep); 226 perror("getacl error"); 227 return (-1); 228 } 229 return (aclcnt); 230 } 231 232 /* 233 * mod_entries() handles add, delete, and modify ACL entries of a file. 234 * The real action is in convert_to_aclent_t() called by parse_entry_list(). 235 * aclp: points ACL of a file and may be changed by lower level routine. 236 * modp: modify entry list in ascii format 237 * delp: delete entry list in ascii format 238 * fnamep: file of interest 239 */ 240 static int 241 mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp, 242 char *fnamep, int rfg) 243 { 244 /* modify and add: from -m option */ 245 if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1) 246 return (-1); 247 248 /* deletion: from -d option */ 249 if (parse_entry_list(&aclp, &cnt, delp, DELETE) == -1) 250 return (-1); 251 252 if (aclsort(cnt, rfg, aclp) == -1) { 253 (void) err_handle(cnt, aclp); 254 (void) fprintf(stderr, 255 gettext("aclcnt %d, file %s\n"), cnt, fnamep); 256 return (-1); 257 } 258 259 if (acl(fnamep, SETACL, cnt, aclp) < 0) { 260 fprintf(stderr, 261 gettext("%s: failed to set acl entries\n"), fnamep); 262 perror("setacl error"); 263 return (-1); 264 } 265 return (0); 266 } 267 268 /* 269 * set_file_entries() creates ACL entries from ACL file (acl_fnamep). 270 * It opens the file and converts every line (one line per acl entry) 271 * into aclent_t format. It then recalculates the mask according to rflag. 272 * Finally it sets ACL to the file (fnamep). 273 */ 274 static int 275 set_file_entries(char *acl_fnamep, char *fnamep, int rflag) 276 { 277 int aclcnt = 0; 278 FILE *acl_fp; 279 aclent_t *aclp; 280 char buf[BUFSIZ]; 281 char *tp; 282 283 if (strcmp(acl_fnamep, "-") == 0) 284 acl_fp = stdin; 285 else { 286 if ((acl_fp = fopen(acl_fnamep, "r")) == NULL) { 287 fprintf(stderr, gettext("Can't open acl file %s\n"), 288 acl_fnamep); 289 return (-1); 290 } 291 } 292 while (fgets(buf, BUFSIZ, acl_fp) != NULL) { 293 if (buf[0] == '#' || buf[0] == '\n') 294 continue; 295 296 /* check effective permission: add a null after real perm */ 297 if ((tp = (char *)strchr(buf, '#')) != NULL) { 298 tp--; 299 while (*tp == ' ' || *tp == '\t') { 300 if (tp != buf) 301 tp--; 302 else { 303 fprintf(stderr, 304 gettext("entry format error %s\n"), 305 buf); 306 exit(1); 307 } 308 } 309 *(tp+1) = '\0'; 310 } 311 312 /* remove <nl> at the end if there is one */ 313 if ((tp = (char *)strchr(buf, '\n')) != NULL) 314 *tp = '\0'; 315 aclcnt++; 316 if (convert_to_aclent_t(buf, &aclcnt, &aclp, SET) == -1) 317 return (-1); 318 } 319 320 if (aclsort(aclcnt, rflag, aclp) == -1) { 321 (void) err_handle(aclcnt, aclp); 322 (void) fprintf(stderr, gettext("aclcnt %d, aclfile %s\n"), 323 aclcnt, acl_fnamep); 324 return (-1); 325 } 326 327 if (acl(fnamep, SETACL, aclcnt, aclp) < 0) { 328 fprintf(stderr, 329 gettext("%s: failed to set acl entries\n"), fnamep); 330 perror("setacl error"); 331 return (-1); 332 } 333 return (0); 334 } 335 336 /* 337 * set_online_entries() parses the acl entries from command line (setp). 338 * It converts the comma separated acl entries into aclent_t format. 339 * It then recalculates the mask according to rflag. 340 * Finally it sets ACL to the file (fnamep). 341 */ 342 static int 343 set_online_entries(char *setp, char *fnamep, int rflag) 344 { 345 aclent_t *aclp; 346 int aclcnt = 0; 347 348 if (parse_entry_list(&aclp, &aclcnt, setp, SET) == -1) 349 return (-1); 350 351 if (aclsort(aclcnt, rflag, aclp) == -1) { 352 (void) err_handle(aclcnt, aclp); 353 (void) fprintf(stderr, 354 gettext("aclcnt %d, file %s\n"), aclcnt, fnamep); 355 return (-1); 356 } 357 358 if (acl(fnamep, SETACL, aclcnt, aclp) < 0) { 359 fprintf(stderr, 360 gettext("%s: failed to set acl entries\n"), fnamep); 361 perror("setacl error"); 362 return (-1); 363 } 364 return (0); 365 } 366 367 /* 368 * parse_entry_list() parses entry list (listp) separated by commas. 369 * Once it gets an ACL entry, it calls convert_to_aclent_t() to convert 370 * to internal format. 371 */ 372 static int 373 parse_entry_list(aclent_t **aclpp, int *aclcntp, char *listp, int mode) 374 { 375 char *commap; 376 377 if (listp == NULL) 378 return (0); 379 while ((commap = (char *)strchr(listp, ',')) != NULL) { 380 *commap = '\0'; 381 *aclcntp += 1; 382 /* aclcnt may be updated after the call: add or modify */ 383 if (convert_to_aclent_t(listp, aclcntp, aclpp, mode) == -1) 384 return (-1); 385 listp = ++commap; 386 } 387 /* this is for only one entry or last entry */ 388 if (*listp != '\0') { 389 *aclcntp += 1; 390 if (convert_to_aclent_t(listp, aclcntp, aclpp, mode) == -1) 391 return (-1); 392 } 393 return (0); 394 } 395 396 /* 397 * convert_to_aclent_t() converts an acl entry in ascii format (fields separated 398 * by colon) into aclent_t and appends it to the current ACL. It also handles 399 * memory allocation/deallocation for acl entries in aclent_t format. 400 * aclpp that contains acl entries in acl format will be returned. 401 * We don't check duplicates. 402 */ 403 static int 404 convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode) 405 { 406 aclent_t *new_aclp; 407 aclent_t tmpacl; 408 aclent_t *taclp, *centry = NULL, *gentry = NULL; 409 int cur_cnt; 410 int found = 0; 411 int is_obj; 412 413 if (entryp == NULL) 414 return (0); 415 416 tmpacl.a_id = 0; /* id field needs to be initialized */ 417 if (entryp[0] == 'u') 418 tmpacl.a_id = getuid(); /* id field for user */ 419 if (entryp[0] == 'g') 420 tmpacl.a_id = getgid(); /* id field for group */ 421 422 tmpacl.a_type = 0; 423 if (parse_entry(entryp, &tmpacl, mode) == -1) 424 return (-1); 425 426 is_obj = ((tmpacl.a_type == USER_OBJ) || 427 (tmpacl.a_type == GROUP_OBJ) || 428 (tmpacl.a_type == CLASS_OBJ) || 429 (tmpacl.a_type == DEF_USER_OBJ) || 430 (tmpacl.a_type == DEF_GROUP_OBJ) || 431 (tmpacl.a_type == DEF_OTHER_OBJ)); 432 433 if (*cntp > 1) 434 new_aclp = (aclent_t *)realloc(*aclpp, 435 sizeof (aclent_t) * (*cntp)); 436 else 437 new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp)); 438 if (new_aclp == NULL) { 439 fprintf(stderr, 440 gettext("Insufficient memory for acl %d\n"), *cntp); 441 return (-1); 442 } 443 444 cur_cnt = *cntp - 1; 445 switch (mode) { 446 case MODIFY: /* and add */ 447 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) { 448 if (taclp->a_type == tmpacl.a_type && 449 ((taclp->a_id == tmpacl.a_id) || is_obj)) { 450 found++; 451 /* cnt is added before it's called */ 452 *cntp -= 1; 453 taclp->a_perm = tmpacl.a_perm; 454 break; 455 } 456 } 457 if (!found) /* Add it to the end: no need to change cntp */ 458 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t)); 459 break; 460 461 case DELETE: 462 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) { 463 if (taclp->a_type == tmpacl.a_type && 464 ((taclp->a_id == tmpacl.a_id) || is_obj)) { 465 found++; 466 /* move up the rest */ 467 while (cur_cnt-- > 0) { 468 memcpy(taclp, taclp+1, 469 sizeof (aclent_t)); 470 taclp++; 471 } 472 *cntp = *cntp - 2; 473 break; 474 } 475 } 476 if (!found) 477 *cntp -= 1; 478 break; 479 480 case SET: 481 /* we may check duplicate before copying over?? */ 482 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t)); 483 break; 484 485 default: 486 fprintf(stderr, 487 gettext("Unrecognized mode: internal error\n")); 488 break; 489 } 490 491 /* 492 * If converting from non-trivial acl entry to trivial one, 493 * reset CLASS_OBJ's permission with that of GROUP_OBJ. 494 */ 495 496 if (mode == DELETE) { 497 boolean_t trivial = B_TRUE; /* assumption */ 498 cur_cnt = *cntp; 499 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) { 500 switch (taclp->a_type) { 501 case USER_OBJ: 502 case OTHER_OBJ: 503 break; 504 case CLASS_OBJ: 505 centry = taclp; 506 break; 507 case GROUP_OBJ: 508 gentry = taclp; 509 break; 510 default: 511 /* 512 * Confirmed that the new acl set is 513 * still a non-trivial acl. 514 * Skip reset. 515 */ 516 trivial = B_FALSE; 517 } 518 } 519 if (centry != NULL && gentry != NULL && trivial == B_TRUE) 520 centry->a_perm = gentry->a_perm; 521 } 522 *aclpp = new_aclp; /* return new acl entries */ 523 return (0); 524 } 525 526 static void 527 usage() 528 { 529 (void) fprintf(stderr, gettext("usage:\n")); 530 (void) fprintf(stderr, 531 gettext("\tsetfacl [-r] -f aclfile file ...\n")); 532 (void) fprintf(stderr, 533 gettext("\tsetfacl [-r] -d acl_entries file ...\n")); 534 (void) fprintf(stderr, 535 gettext("\tsetfacl [-r] -m acl_entries file ...\n")); 536 (void) fprintf(stderr, 537 gettext("\tsetfacl [-r] -s acl_entries file ...\n")); 538 exit(1); 539 } 540 541 static void 542 err_handle(int cnt, aclent_t *aclentp) 543 { 544 int rc; 545 int which; 546 547 rc = aclcheck(aclentp, cnt, &which); 548 switch (rc) { 549 case USER_ERROR: 550 fprintf(stderr, 551 gettext("There is more than one user owner entry")); 552 fprintf(stderr, 553 gettext(" -- error found at entry index %d\n"), which); 554 break; 555 case GRP_ERROR: 556 fprintf(stderr, 557 gettext("There is more than one group owner entry")); 558 fprintf(stderr, 559 gettext(" -- error found at entry index %d\n"), which); 560 break; 561 case CLASS_ERROR: 562 fprintf(stderr, 563 gettext("There is more than one mask entry")); 564 fprintf(stderr, 565 gettext(" -- error found at entry index %d\n"), which); 566 break; 567 case OTHER_ERROR: 568 fprintf(stderr, 569 gettext("There is more than one other entry")); 570 fprintf(stderr, 571 gettext(" -- error found at entry index %d\n"), which); 572 break; 573 case DUPLICATE_ERROR: 574 fprintf(stderr, 575 gettext("Duplicate user or group entries")); 576 fprintf(stderr, 577 gettext(" -- error found at entry index %d\n"), which); 578 break; 579 case MISS_ERROR: 580 fprintf(stderr, 581 gettext("Missing user/group owner, other, mask entry\n")); 582 break; 583 case MEM_ERROR: 584 fprintf(stderr, 585 gettext("Insufficient memory\n")); 586 break; 587 case ENTRY_ERROR: 588 fprintf(stderr, 589 gettext("Unrecognized entry type")); 590 fprintf(stderr, 591 gettext(" -- error found at entry index %d\n"), which); 592 break; 593 default: 594 /* error is not from aclcheck */ 595 fprintf(stderr, 596 gettext("aclsort error\n")); 597 break; 598 } 599 } 600 601 static int 602 parse_entry(char *fieldp, aclent_t *aclentp, int mode) 603 { 604 char *colonp; 605 int def_flag = 0, mo_flag = 0; 606 int id; 607 struct passwd *pwp; 608 struct group *grp; 609 610 colonp = (char *)strchr(fieldp, ':'); 611 if (colonp == NULL) { 612 fprintf(stderr, 613 gettext("Can't find colon delimiter %s\n"), fieldp); 614 return (-1); 615 } 616 *colonp = '\0'; 617 if ((strcmp(fieldp, "default") == 0) || (strcmp(fieldp, "d") == 0)) { 618 def_flag++; 619 fieldp = ++colonp; 620 colonp = (char *)strchr(fieldp, ':'); 621 if (colonp == NULL) { 622 fprintf(stderr, 623 gettext("Can't find colon delimiter %s\n"), fieldp); 624 return (-1); 625 } 626 *colonp = '\0'; 627 } 628 629 /* process entry type */ 630 if ((strcmp(fieldp, "user") == 0) || (strcmp(fieldp, "u") == 0)) { 631 if (def_flag) 632 aclentp->a_type = DEF_USER; 633 else 634 aclentp->a_type = USER; 635 } 636 if ((strcmp(fieldp, "group") == 0) || (strcmp(fieldp, "g") == 0)) { 637 if (def_flag) 638 aclentp->a_type = DEF_GROUP; 639 else 640 aclentp->a_type = GROUP; 641 } 642 if ((strcmp(fieldp, "mask") == 0) || (strcmp(fieldp, "m") == 0)) { 643 if (def_flag) 644 aclentp->a_type = DEF_CLASS_OBJ; 645 else 646 aclentp->a_type = CLASS_OBJ; 647 } 648 if ((strcmp(fieldp, "other") == 0) || (strcmp(fieldp, "o") == 0)) { 649 if (def_flag) 650 aclentp->a_type = DEF_OTHER_OBJ; 651 else 652 aclentp->a_type = OTHER_OBJ; 653 } 654 655 /* still can't determine entry type */ 656 if (aclentp->a_type == 0) { 657 fprintf(stderr, 658 gettext("Unrecognized entry type %s \n"), fieldp); 659 return (-1); 660 } 661 662 /* mask and other entries dont have id field */ 663 if (aclentp->a_type != CLASS_OBJ && aclentp->a_type != OTHER_OBJ && 664 aclentp->a_type != DEF_CLASS_OBJ && 665 aclentp->a_type != DEF_OTHER_OBJ) { 666 /* process id: */ 667 fieldp = ++colonp; 668 colonp = (char *)strchr(fieldp, ':'); 669 if (colonp == NULL) { 670 if (mode != DELETE) { 671 fprintf(stderr, 672 gettext("Can't find colon delimiter %s\n"), 673 fieldp); 674 return (-1); 675 } 676 } else 677 *colonp = '\0'; 678 679 if (*fieldp == '\0') { 680 /* empty uid */ 681 if (aclentp->a_type == USER) 682 aclentp->a_type = USER_OBJ; 683 if (aclentp->a_type == DEF_USER) 684 aclentp->a_type = DEF_USER_OBJ; 685 if (aclentp->a_type == GROUP) 686 aclentp->a_type = GROUP_OBJ; 687 if (aclentp->a_type == DEF_GROUP) 688 aclentp->a_type = DEF_GROUP_OBJ; 689 } else { 690 /* see if it's a user/group name */ 691 if (aclentp->a_type == USER || 692 aclentp->a_type == USER_OBJ || 693 aclentp->a_type == DEF_USER || 694 aclentp->a_type == DEF_USER_OBJ) { 695 if ((pwp = getpwnam(fieldp)) != NULL) 696 aclentp->a_id = pwp->pw_uid; 697 else { 698 /* treat it as numeric id */ 699 id = conv_id(fieldp); 700 if (id == -1) 701 return (-1); 702 aclentp->a_id = id; 703 } 704 } else { 705 /* group name */ 706 if ((grp = getgrnam(fieldp)) != NULL) 707 aclentp->a_id = grp->gr_gid; 708 else { 709 id = conv_id(fieldp); 710 if (id == -1) 711 return (-1); 712 aclentp->a_id = id; 713 } 714 } 715 } 716 } else { 717 /* it is mask/other entry */ 718 mo_flag = 1; 719 } 720 721 /* process permission: rwx and [0]n format */ 722 if (mode == DELETE) 723 /* delete format: no permission field */ 724 return (0); 725 fieldp = ++colonp; 726 colonp = (char *)strchr(fieldp, ':'); 727 if (colonp != NULL) { 728 if (mo_flag == 1) { 729 /* Use only single : on mask/other entry */ 730 (void) fprintf(stderr, gettext("use only 1 colon for " 731 "mask and other entries.\n")); 732 return (-1); 733 } else { 734 /* it's ok to have extra colon */ 735 *colonp = '\0'; 736 } 737 } 738 739 if ((int)strlen(fieldp) > 3) { 740 fprintf(stderr, 741 gettext("only rwx or [0]n format is allowed\n")); 742 return (-1); 743 } 744 if (strlen(fieldp) == 3) { 745 aclentp->a_perm = 0; 746 /* treat it as rwx */ 747 if (*fieldp == 'r') 748 aclentp->a_perm += 4; 749 else 750 if (*fieldp != '-') { 751 fprintf(stderr, 752 gettext("Unrecognized character ")); 753 fprintf(stderr, 754 gettext("found in mode field\n")); 755 return (-1); 756 } 757 fieldp++; 758 if (*fieldp == 'w') 759 aclentp->a_perm += 2; 760 else 761 if (*fieldp != '-') { 762 fprintf(stderr, 763 gettext("Unrecognized character ")); 764 fprintf(stderr, 765 gettext("found in mode field\n")); 766 return (-1); 767 } 768 fieldp++; 769 if (*fieldp == 'x') 770 aclentp->a_perm += 1; 771 else 772 if (*fieldp != '-') { 773 fprintf(stderr, 774 gettext("Unrecognized character ")); 775 fprintf(stderr, 776 gettext("found in mode field\n")); 777 return (-1); 778 } 779 return (0); 780 } 781 782 if (*fieldp == '\0') 783 return (0); 784 785 if (*fieldp >= '0' && *fieldp <= '7') 786 aclentp->a_perm = *fieldp - '0'; 787 else { 788 fprintf(stderr, gettext("Unrecognized character ")); 789 fprintf(stderr, gettext("found in mode field\n")); 790 return (-1); 791 } 792 if (aclentp->a_perm == 0 && *++fieldp != '\0') { 793 /* look at next char */ 794 if (*fieldp >= '0' && *fieldp <= '7') 795 aclentp->a_perm = *fieldp - '0'; 796 else { 797 fprintf(stderr, gettext("Unrecognized character ")); 798 fprintf(stderr, gettext("found in mode field\n")); 799 fprintf(stderr, 800 gettext("Check also the number of fields ")); 801 fprintf(stderr, 802 gettext("(default) mask and other entries\n")); 803 return (-1); 804 } 805 } 806 /* check for junk at the end ??? */ 807 return (0); 808 } 809 810 /* 811 * This function is different from atoi() in that it checks for 812 * valid digit in the id field whereas atoi() won't report any 813 * error. 814 */ 815 static int 816 conv_id(char *fieldp) 817 { 818 int a_id = 0; 819 820 for (; *fieldp != '\0'; fieldp++) { 821 if (!isdigit(*fieldp)) { 822 fprintf(stderr, gettext("non-digit in id field\n")); 823 return (-1); 824 } 825 a_id = a_id * 10 + (*fieldp - '0'); 826 } 827 return (a_id); 828 } 829