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