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