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
main(int argc,char * argv[])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
get_acl_info(char * filep,aclent_t ** aclpp)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
mod_entries(aclent_t * aclp,int cnt,char * modp,char * delp,char * fnamep,int rfg)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
set_file_entries(char * acl_fnamep,char * fnamep,int rflag)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
set_online_entries(char * setp,char * fnamep,int rflag)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
parse_entry_list(aclent_t ** aclpp,int * aclcntp,char * listp,int mode)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
convert_to_aclent_t(char * entryp,int * cntp,aclent_t ** aclpp,int mode)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
usage()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
err_handle(int cnt,aclent_t * aclentp)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
parse_entry(char * fieldp,aclent_t * aclentp,int mode)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
conv_id(char * fieldp)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