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