Print this page
5218 posix definition of NULL
correct unistd.h and iso/stddef_iso.h
update gate source affected
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/chmod/chmod.c
+++ new/usr/src/cmd/chmod/chmod.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 28 /* */
29 29
30 30 /*
31 31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 32 * The Regents of the University of California
33 33 * All Rights Reserved
34 34 *
35 35 * University Acknowledgment- Portions of this document are derived from
36 36 * software developed by the University of California, Berkeley, and its
37 37 * contributors.
38 38 */
39 39
40 40 /*
41 41 * chmod option mode files
42 42 * where
43 43 * mode is [ugoa][+-=][rwxXlstugo] or an octal number
44 44 * mode is [<+|->A[# <number] ]<aclspec>
45 45 * mode is S<attrspec>
46 46 * option is -R, -f, and -@
47 47 */
48 48
49 49 /*
50 50 * Note that many convolutions are necessary
51 51 * due to the re-use of bits between locking
52 52 * and setgid
53 53 */
54 54
55 55 #include <unistd.h>
56 56 #include <stdlib.h>
57 57 #include <stdio.h>
58 58 #include <sys/types.h>
59 59 #include <sys/stat.h>
60 60 #include <fcntl.h>
61 61 #include <dirent.h>
62 62 #include <locale.h>
63 63 #include <string.h> /* strerror() */
64 64 #include <stdarg.h>
65 65 #include <limits.h>
66 66 #include <ctype.h>
67 67 #include <errno.h>
68 68 #include <sys/acl.h>
69 69 #include <aclutils.h>
70 70 #include <libnvpair.h>
71 71 #include <libcmdutils.h>
72 72 #include <libgen.h>
73 73 #include <attr.h>
74 74
75 75 static int rflag;
76 76 static int fflag;
77 77
78 78 extern int optind;
79 79 extern int errno;
80 80
81 81 static int mac; /* Alternate to argc (for parseargs) */
82 82 static char **mav; /* Alternate to argv (for parseargs) */
83 83
84 84 static char *ms; /* Points to the mode argument */
85 85
86 86 #define ACL_ADD 1
87 87 #define ACL_DELETE 2
88 88 #define ACL_SLOT_DELETE 3
89 89 #define ACL_REPLACE 4
90 90 #define ACL_STRIP 5
91 91
92 92 #define LEFTBRACE '{'
93 93 #define RIGHTBRACE '}'
94 94 #define A_SEP ','
95 95 #define A_SEP_TOK ","
96 96
97 97 #define A_COMPACT_TYPE 'c'
98 98 #define A_VERBOSE_TYPE 'v'
99 99 #define A_ALLATTRS_TYPE 'a'
100 100
101 101 #define A_SET_OP '+'
102 102 #define A_INVERSE_OP '-'
103 103 #define A_REPLACE_OP '='
104 104 #define A_UNDEF_OP '\0'
105 105
106 106 #define A_SET_TEXT "set"
107 107 #define A_INVERSE_TEXT "clear"
108 108
109 109 #define A_SET_VAL B_TRUE
110 110 #define A_CLEAR_VAL B_FALSE
111 111
112 112 #define ATTR_OPTS 0
113 113 #define ATTR_NAMES 1
114 114
115 115 #define sec_acls secptr.acls
116 116 #define sec_attrs secptr.attrs
117 117
118 118 typedef struct acl_args {
119 119 acl_t *acl_aclp;
120 120 int acl_slot;
121 121 int acl_action;
122 122 } acl_args_t;
123 123
124 124 typedef enum {
125 125 SEC_ACL,
126 126 SEC_ATTR
127 127 } chmod_sec_t;
128 128
129 129 typedef struct {
130 130 chmod_sec_t sec_type;
131 131 union {
132 132 acl_args_t *acls;
133 133 nvlist_t *attrs;
134 134 } secptr;
135 135 } sec_args_t;
136 136
137 137 typedef struct attr_name {
138 138 char *name;
139 139 struct attr_name *next;
140 140 } attr_name_t;
141 141
142 142
143 143 extern mode_t newmode_common(char *ms, mode_t new_mode, mode_t umsk,
144 144 char *file, char *path, o_mode_t *group_clear_bits,
145 145 o_mode_t *group_set_bits);
146 146
147 147 static int chmodr(char *dir, char *path, mode_t mode, mode_t umsk,
148 148 sec_args_t *secp, attr_name_t *attrname);
149 149 static int doacl(char *file, struct stat *st, acl_args_t *aclp);
150 150 static int dochmod(char *name, char *path, mode_t umsk, sec_args_t *secp,
151 151 attr_name_t *attrnames);
152 152 static void handle_acl(char *name, o_mode_t group_clear_bits,
153 153 o_mode_t group_set_bits);
154 154 void errmsg(int severity, int code, char *format, ...);
155 155 static void free_attr_names(attr_name_t *attrnames);
156 156 static void parseargs(int ac, char *av[]);
157 157 static int parse_acl_args(char *arg, sec_args_t **sec_args);
158 158 static int parse_attr_args(char *arg, sec_args_t **sec_args);
159 159 static void print_attrs(int flag);
160 160 static int set_attrs(char *file, attr_name_t *attrnames, nvlist_t *attr_nvlist);
161 161 static void usage(void);
162 162
163 163 int
164 164 main(int argc, char *argv[])
165 165 {
166 166 int i, c;
167 167 int status = 0;
168 168 mode_t umsk;
169 169 sec_args_t *sec_args = NULL;
170 170 attr_name_t *attrnames = NULL;
171 171 attr_name_t *attrend = NULL;
172 172 attr_name_t *tattr;
173 173
174 174 (void) setlocale(LC_ALL, "");
175 175 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
176 176 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
177 177 #endif
178 178 (void) textdomain(TEXT_DOMAIN);
179 179
180 180 parseargs(argc, argv);
181 181
182 182 while ((c = getopt(mac, mav, "Rf@:")) != EOF) {
183 183 switch (c) {
184 184 case 'R':
185 185 rflag++;
186 186 break;
187 187 case 'f':
188 188 fflag++;
189 189 break;
190 190 case '@':
191 191 if (((tattr = malloc(sizeof (attr_name_t))) == NULL) ||
192 192 ((tattr->name = strdup(optarg)) == NULL)) {
193 193 perror("chmod");
194 194 exit(2);
195 195 }
196 196 if (attrnames == NULL) {
197 197 attrnames = tattr;
198 198 attrnames->next = NULL;
199 199 } else {
200 200 attrend->next = tattr;
201 201 }
202 202 attrend = tattr;
203 203 break;
204 204 case '?':
205 205 usage();
206 206 exit(2);
207 207 }
208 208 }
209 209
210 210 /*
211 211 * Check for sufficient arguments
212 212 * or a usage error.
213 213 */
214 214
215 215 mac -= optind;
216 216 mav += optind;
217 217 if ((mac >= 2) && (mav[0][0] == 'A')) {
218 218 if (attrnames != NULL) {
219 219 free_attr_names(attrnames);
220 220 attrnames = NULL;
221 221 }
222 222 if (parse_acl_args(*mav, &sec_args)) {
223 223 usage();
224 224 exit(2);
225 225 }
226 226 } else if ((mac >= 2) && (mav[0][0] == 'S')) {
227 227 if (parse_attr_args(*mav, &sec_args)) {
228 228 usage();
229 229 exit(2);
230 230
231 231 /* A no-op attribute operation was specified. */
232 232 } else if (sec_args->sec_attrs == NULL) {
233 233 exit(0);
234 234 }
235 235 } else {
236 236 if (mac < 2) {
237 237 usage();
238 238 exit(2);
239 239 }
240 240 if (attrnames != NULL) {
241 241 free_attr_names(attrnames);
242 242 attrnames = NULL;
243 243 }
244 244 }
245 245
246 246 ms = mav[0];
247 247
248 248 umsk = umask(0);
249 249 (void) umask(umsk);
250 250
251 251 for (i = 1; i < mac; i++) {
252 252 status += dochmod(mav[i], mav[i], umsk, sec_args, attrnames);
253 253 }
254 254
255 255 return (fflag ? 0 : status);
256 256 }
257 257
258 258 static void
259 259 free_attr_names(attr_name_t *attrnames)
260 260 {
261 261 attr_name_t *attrnamesptr = attrnames;
262 262 attr_name_t *tptr;
263 263
264 264 while (attrnamesptr != NULL) {
265 265 tptr = attrnamesptr->next;
266 266 if (attrnamesptr->name != NULL) {
267 267 free(attrnamesptr->name);
268 268 }
269 269 attrnamesptr = tptr;
270 270 }
271 271 }
272 272
273 273 static int
274 274 dochmod(char *name, char *path, mode_t umsk, sec_args_t *secp,
275 275 attr_name_t *attrnames)
276 276 {
277 277 static struct stat st;
278 278 int linkflg = 0;
279 279 o_mode_t group_clear_bits, group_set_bits;
280 280
281 281 if (lstat(name, &st) < 0) {
282 282 errmsg(2, 0, gettext("can't access %s\n"), path);
283 283 return (1);
284 284 }
285 285
286 286 if ((st.st_mode & S_IFMT) == S_IFLNK) {
287 287 linkflg = 1;
288 288 if (stat(name, &st) < 0) {
289 289 errmsg(2, 0, gettext("can't access %s\n"), path);
290 290 return (1);
291 291 }
292 292 }
293 293
294 294 /* Do not recurse if directory is object of symbolic link */
295 295 if (rflag && ((st.st_mode & S_IFMT) == S_IFDIR) && !linkflg) {
296 296 return (chmodr(name, path, st.st_mode, umsk, secp, attrnames));
297 297 }
298 298
299 299 if (secp != NULL) {
300 300 if (secp->sec_type == SEC_ACL) {
301 301 return (doacl(name, &st, secp->sec_acls));
302 302 } else if (secp->sec_type == SEC_ATTR) {
303 303 return (set_attrs(name, attrnames, secp->sec_attrs));
304 304 } else {
305 305 return (1);
306 306 }
307 307 } else {
308 308 if (chmod(name, newmode_common(ms, st.st_mode, umsk, name, path,
309 309 &group_clear_bits, &group_set_bits)) == -1) {
310 310 errmsg(2, 0, gettext("can't change %s\n"), path);
311 311 return (1);
312 312 }
313 313 }
314 314
315 315 /*
316 316 * If the group permissions of the file are being modified,
317 317 * make sure that the file's ACL (if it has one) is
318 318 * modified also, since chmod is supposed to apply group
319 319 * permissions changes to both the acl mask and the
320 320 * general group permissions.
321 321 */
322 322 if (group_clear_bits || group_set_bits)
323 323 handle_acl(name, group_clear_bits, group_set_bits);
324 324
325 325 return (0);
326 326 }
327 327
328 328 static int
329 329 chmodr(char *dir, char *path, mode_t mode, mode_t umsk, sec_args_t *secp,
330 330 attr_name_t *attrnames)
331 331 {
332 332
333 333 DIR *dirp;
334 334 struct dirent *dp;
335 335 char savedir[PATH_MAX]; /* dir name to restore */
336 336 char currdir[PATH_MAX+1]; /* current dir name + '/' */
337 337 char parentdir[PATH_MAX+1]; /* parent dir name + '/' */
338 338 int ecode;
339 339 struct stat st;
340 340 o_mode_t group_clear_bits, group_set_bits;
341 341
342 342 if (getcwd(savedir, PATH_MAX) == 0)
343 343 errmsg(2, 255, gettext("chmod: could not getcwd %s\n"),
344 344 savedir);
345 345
346 346 /*
347 347 * Change what we are given before doing it's contents
348 348 */
349 349 if (secp != NULL) {
350 350 if (lstat(dir, &st) < 0) {
351 351 errmsg(2, 0, gettext("can't access %s\n"), path);
352 352 return (1);
353 353 }
354 354 if (secp->sec_type == SEC_ACL) {
355 355 (void) doacl(dir, &st, secp->sec_acls);
356 356 } else if (secp->sec_type == SEC_ATTR) {
357 357 (void) set_attrs(dir, attrnames, secp->sec_attrs);
358 358 } else {
359 359 return (1);
360 360 }
361 361 } else if (chmod(dir, newmode_common(ms, mode, umsk, dir, path,
362 362 &group_clear_bits, &group_set_bits)) < 0) {
363 363 errmsg(2, 0, gettext("can't change %s\n"), path);
364 364 }
365 365
366 366 /*
367 367 * If the group permissions of the file are being modified,
368 368 * make sure that the file's ACL (if it has one) is
369 369 * modified also, since chmod is supposed to apply group
370 370 * permissions changes to both the acl mask and the
371 371 * general group permissions.
372 372 */
373 373
374 374 if (secp != NULL) {
375 375 /* only necessary when not setting ACL or system attributes */
376 376 if (group_clear_bits || group_set_bits)
377 377 handle_acl(dir, group_clear_bits, group_set_bits);
378 378 }
379 379
380 380 if (chdir(dir) < 0) {
381 381 errmsg(2, 0, "%s/%s: %s\n", savedir, dir, strerror(errno));
382 382 return (1);
383 383 }
384 384 if ((dirp = opendir(".")) == NULL) {
385 385 errmsg(2, 0, "%s\n", strerror(errno));
386 386 return (1);
387 387 }
388 388 ecode = 0;
389 389
390 390 /*
391 391 * Save parent directory path before recursive chmod.
392 392 * We'll need this for error printing purposes. Add
393 393 * a trailing '/' to the path except in the case where
394 394 * the path is just '/'
395 395 */
396 396
397 397 if (strlcpy(parentdir, path, PATH_MAX + 1) >= PATH_MAX + 1) {
398 398 errmsg(2, 0, gettext("directory path name too long: %s\n"),
399 399 path);
400 400 return (1);
401 401 }
402 402 if (strcmp(path, "/") != 0)
403 403 if (strlcat(parentdir, "/", PATH_MAX + 1) >= PATH_MAX + 1) {
404 404 errmsg(2, 0,
405 405 gettext("directory path name too long: %s/\n"),
406 406 parentdir);
407 407 return (1);
408 408 }
409 409
410 410
411 411 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
412 412
413 413 if (strcmp(dp->d_name, ".") == 0 || /* skip . and .. */
414 414 strcmp(dp->d_name, "..") == 0) {
415 415 continue;
416 416 }
417 417 if (strlcpy(currdir, parentdir, PATH_MAX + 1) >= PATH_MAX + 1) {
418 418 errmsg(2, 0,
419 419 gettext("directory path name too long: %s\n"),
420 420 parentdir);
421 421 return (1);
422 422 }
423 423 if (strlcat(currdir, dp->d_name, PATH_MAX + 1)
424 424 >= PATH_MAX + 1) {
425 425 errmsg(2, 0,
426 426 gettext("directory path name too long: %s%s\n"),
427 427 currdir, dp->d_name);
428 428 return (1);
429 429 }
430 430 ecode += dochmod(dp->d_name, currdir, umsk, secp, attrnames);
431 431 }
432 432 (void) closedir(dirp);
433 433 if (chdir(savedir) < 0) {
434 434 errmsg(2, 255, gettext("can't change back to %s\n"), savedir);
435 435 }
436 436 return (ecode ? 1 : 0);
437 437 }
438 438
439 439 /* PRINTFLIKE3 */
440 440 void
441 441 errmsg(int severity, int code, char *format, ...)
442 442 {
443 443 va_list ap;
444 444 static char *msg[] = {
445 445 "",
446 446 "ERROR",
447 447 "WARNING",
448 448 ""
449 449 };
450 450
451 451 va_start(ap, format);
452 452
453 453 /*
454 454 * Always print error message if this is a fatal error (code != 0);
455 455 * otherwise, print message if fflag == 0 (no -f option specified)
456 456 */
457 457 if (!fflag || (code != 0)) {
458 458 (void) fprintf(stderr,
459 459 "chmod: %s: ", gettext(msg[severity]));
460 460 (void) vfprintf(stderr, format, ap);
461 461 }
462 462
463 463 va_end(ap);
464 464
465 465 if (code != 0)
466 466 exit(fflag ? 0 : code);
467 467 }
468 468
469 469 static void
470 470 usage(void)
471 471 {
472 472 (void) fprintf(stderr, gettext(
473 473 "usage:\tchmod [-fR] <absolute-mode> file ...\n"));
474 474
475 475 (void) fprintf(stderr, gettext(
476 476 "\tchmod [-fR] [-@ attribute] ... "
477 477 "S<attribute-operation> file ...\n"));
478 478
479 479 (void) fprintf(stderr, gettext(
480 480 "\tchmod [-fR] <ACL-operation> file ...\n"));
481 481
482 482 (void) fprintf(stderr, gettext(
483 483 "\tchmod [-fR] <symbolic-mode-list> file ...\n\n"));
484 484
485 485 (void) fprintf(stderr, gettext(
486 486 "where \t<symbolic-mode-list> is a comma-separated list of\n"));
487 487 (void) fprintf(stderr, gettext(
488 488 "\t[ugoa]{+|-|=}[rwxXlstugo]\n\n"));
489 489
490 490 (void) fprintf(stderr, gettext(
491 491 "where \t<attribute-operation> is a comma-separated list of\n"
492 492 "\tone or more of the following\n"));
493 493 (void) fprintf(stderr, gettext(
494 494 "\t[+|-|=]c[<compact-attribute-list>|{<compact-attribute-list>}]\n"
495 495 "\t[+|-|=]v[<verbose-attribute-setting>|"
496 496 "\'{\'<verbose-attribute-setting-list>\'}\']\n"
497 497 "\t[+|-|=]a\n"));
498 498 (void) fprintf(stderr, gettext(
499 499 "where \t<compact-attribute-list> is a list of zero or more of\n"));
500 500 print_attrs(ATTR_OPTS);
501 501 (void) fprintf(stderr, gettext(
502 502 "where \t<verbose-attribute-setting> is one of\n"));
503 503 print_attrs(ATTR_NAMES);
504 504 (void) fprintf(stderr, gettext(
505 505 "\tand can be, optionally, immediately preceded by \"no\"\n\n"));
506 506
507 507 (void) fprintf(stderr, gettext(
508 508 "where \t<ACL-operation> is one of the following\n"));
509 509 (void) fprintf(stderr, gettext("\tA-<acl_specification>\n"));
510 510 (void) fprintf(stderr, gettext("\tA[number]-\n"));
511 511 (void) fprintf(stderr, gettext(
512 512 "\tA[number]{+|=}<acl_specification>\n"));
513 513 (void) fprintf(stderr, gettext(
514 514 "where \t<acl-specification> is a comma-separated list of ACEs\n"));
515 515 }
516 516
517 517 /*
518 518 * parseargs - generate getopt-friendly argument list for backwards
519 519 * compatibility with earlier Solaris usage (eg, chmod -w
520 520 * foo).
521 521 *
522 522 * assumes the existence of a static set of alternates to argc and argv,
523 523 * (namely, mac, and mav[]).
524 524 *
525 525 */
526 526
527 527 static void
528 528 parseargs(int ac, char *av[])
529 529 {
530 530 int i; /* current argument */
531 531 int fflag; /* arg list contains "--" */
532 532 size_t mav_num; /* number of entries in mav[] */
533 533
534 534 /*
535 535 * We add an extra argument slot, in case we need to jam a "--"
536 536 * argument into the list.
537 537 */
538 538
539 539 mav_num = (size_t)ac+2;
540 540
541 541 if ((mav = calloc(mav_num, sizeof (char *))) == NULL) {
542 542 perror("chmod");
543 543 exit(2);
544 544 }
545 545
↓ open down ↓ |
545 lines elided |
↑ open up ↑ |
546 546 /* scan for the use of "--" in the argument list */
547 547
548 548 for (fflag = i = 0; i < ac; i ++) {
549 549 if (strcmp(av[i], "--") == 0)
550 550 fflag = 1;
551 551 }
552 552
553 553 /* process the arguments */
554 554
555 555 for (i = mac = 0;
556 - (av[i] != (char *)NULL) && (av[i][0] != (char)NULL);
556 + (av[i] != NULL) && (av[i][0] != '\0');
557 557 i++) {
558 558 if (!fflag && av[i][0] == '-') {
559 559 /*
560 560 * If there is not already a "--" argument specified,
561 561 * and the argument starts with '-' but does not
562 562 * contain any of the official option letters, then it
563 563 * is probably a mode argument beginning with '-'.
564 564 * Force a "--" into the argument stream in front of
565 565 * it.
566 566 */
567 567
568 568 if ((strchr(av[i], 'R') == NULL &&
569 569 strchr(av[i], 'f') == NULL) &&
570 570 strchr(av[i], '@') == NULL) {
571 571 if ((mav[mac++] = strdup("--")) == NULL) {
572 572 perror("chmod");
573 573 exit(2);
574 574 }
575 575 }
576 576 }
577 577
578 578 if ((mav[mac++] = strdup(av[i])) == NULL) {
579 579 perror("chmod");
580 580 exit(2);
581 581 }
582 582 }
583 583
584 584 mav[mac] = (char *)NULL;
585 585 }
586 586
587 587 static int
588 588 parse_acl_args(char *arg, sec_args_t **sec_args)
589 589 {
590 590 acl_t *new_acl = NULL;
591 591 int slot;
592 592 int len;
593 593 int action;
594 594 acl_args_t *new_acl_args;
595 595 char *acl_spec = NULL;
596 596 char *end;
597 597
598 598 if (arg[0] != 'A')
599 599 return (1);
600 600
601 601 slot = strtol(&arg[1], &end, 10);
602 602
603 603 len = strlen(arg);
604 604 switch (*end) {
605 605 case '+':
606 606 action = ACL_ADD;
607 607 acl_spec = ++end;
608 608 break;
609 609 case '-':
610 610 if (len == 2 && arg[0] == 'A' && arg[1] == '-')
611 611 action = ACL_STRIP;
612 612 else
613 613 action = ACL_DELETE;
614 614 if (action != ACL_STRIP) {
615 615 acl_spec = ++end;
616 616 if (acl_spec[0] == '\0') {
617 617 action = ACL_SLOT_DELETE;
618 618 acl_spec = NULL;
619 619 } else if (arg[1] != '-')
620 620 return (1);
621 621 }
622 622 break;
623 623 case '=':
624 624 /*
625 625 * Was slot specified?
626 626 */
627 627 if (arg[1] == '=')
628 628 slot = -1;
629 629 action = ACL_REPLACE;
630 630 acl_spec = ++end;
631 631 break;
632 632 default:
633 633 return (1);
634 634 }
635 635
636 636 if ((action == ACL_REPLACE || action == ACL_ADD) && acl_spec[0] == '\0')
637 637 return (1);
638 638
639 639 if (acl_spec) {
640 640 if (acl_parse(acl_spec, &new_acl)) {
641 641 exit(1);
642 642 }
643 643 }
644 644
645 645 new_acl_args = malloc(sizeof (acl_args_t));
646 646 if (new_acl_args == NULL)
647 647 return (1);
648 648
649 649 new_acl_args->acl_aclp = new_acl;
650 650 new_acl_args->acl_slot = slot;
651 651 new_acl_args->acl_action = action;
652 652
653 653 if ((*sec_args = malloc(sizeof (sec_args_t))) == NULL) {
654 654 perror("chmod");
655 655 exit(2);
656 656 }
657 657 (*sec_args)->sec_type = SEC_ACL;
658 658 (*sec_args)->sec_acls = new_acl_args;
659 659
660 660 return (0);
661 661 }
662 662
663 663 /*
664 664 * This function is called whenever the group permissions of a file
665 665 * is being modified. According to the chmod(1) manpage, any
666 666 * change made to the group permissions must be applied to both
667 667 * the acl mask and the acl's GROUP_OBJ. The chmod(2) already
668 668 * set the mask, so this routine needs to make the same change
669 669 * to the GROUP_OBJ.
670 670 */
671 671 static void
672 672 handle_acl(char *name, o_mode_t group_clear_bits, o_mode_t group_set_bits)
673 673 {
674 674 int aclcnt, n;
675 675 aclent_t *aclp, *tp;
676 676 o_mode_t newperm;
677 677 /*
678 678 * if this file system support ace_t acl's
679 679 * then simply return since we don't have an
680 680 * acl mask to deal with
681 681 */
682 682 if (pathconf(name, _PC_ACL_ENABLED) == _ACL_ACE_ENABLED)
683 683 return;
684 684 if ((aclcnt = acl(name, GETACLCNT, 0, NULL)) <= MIN_ACL_ENTRIES)
685 685 return; /* it's just a trivial acl; no need to change it */
686 686 if ((aclp = (aclent_t *)malloc((sizeof (aclent_t)) * aclcnt))
687 687 == NULL) {
688 688 perror("chmod");
689 689 exit(2);
690 690 }
691 691
692 692 if (acl(name, GETACL, aclcnt, aclp) < 0) {
693 693 free(aclp);
694 694 (void) fprintf(stderr, "chmod: ");
695 695 perror(name);
696 696 return;
697 697 }
698 698 for (tp = aclp, n = aclcnt; n--; tp++) {
699 699 if (tp->a_type == GROUP_OBJ) {
700 700 newperm = tp->a_perm;
701 701 if (group_clear_bits != 0)
702 702 newperm &= ~group_clear_bits;
703 703 if (group_set_bits != 0)
704 704 newperm |= group_set_bits;
705 705 if (newperm != tp->a_perm) {
706 706 tp->a_perm = newperm;
707 707 if (acl(name, SETACL, aclcnt, aclp)
708 708 < 0) {
709 709 (void) fprintf(stderr, "chmod: ");
710 710 perror(name);
711 711 }
712 712 }
713 713 break;
714 714 }
715 715 }
716 716 free(aclp);
717 717 }
718 718
719 719 static int
720 720 doacl(char *file, struct stat *st, acl_args_t *acl_args)
721 721 {
722 722 acl_t *aclp;
723 723 acl_t *set_aclp;
724 724 int error = 0;
725 725 void *to, *from;
726 726 int len;
727 727 int isdir;
728 728 isdir = S_ISDIR(st->st_mode);
729 729
730 730 error = acl_get(file, 0, &aclp);
731 731
732 732 if (error != 0) {
733 733 errmsg(1, 0, "%s\n", acl_strerror(error));
734 734 return (1);
735 735 }
736 736 switch (acl_args->acl_action) {
737 737 case ACL_ADD:
738 738 if ((error = acl_addentries(aclp,
739 739 acl_args->acl_aclp, acl_args->acl_slot)) != 0) {
740 740 errmsg(1, 0, "%s\n", acl_strerror(error));
741 741 acl_free(aclp);
742 742 return (1);
743 743 }
744 744 set_aclp = aclp;
745 745 break;
746 746 case ACL_SLOT_DELETE:
747 747 if (acl_args->acl_slot + 1 > aclp->acl_cnt) {
748 748 errmsg(1, 0,
749 749 gettext("Invalid slot specified for removal\n"));
750 750 acl_free(aclp);
751 751 return (1);
752 752 }
753 753
754 754 if (acl_args->acl_slot == 0 && aclp->acl_cnt == 1) {
755 755 errmsg(1, 0,
756 756 gettext("Can't remove all ACL "
757 757 "entries from a file\n"));
758 758 acl_free(aclp);
759 759 return (1);
760 760 }
761 761
762 762 /*
763 763 * remove a single entry
764 764 *
765 765 * if last entry just adjust acl_cnt
766 766 */
767 767
768 768 if ((acl_args->acl_slot + 1) == aclp->acl_cnt)
769 769 aclp->acl_cnt--;
770 770 else {
771 771 to = (char *)aclp->acl_aclp +
772 772 (acl_args->acl_slot * aclp->acl_entry_size);
773 773 from = (char *)to + aclp->acl_entry_size;
774 774 len = (aclp->acl_cnt - acl_args->acl_slot - 1) *
775 775 aclp->acl_entry_size;
776 776 (void) memmove(to, from, len);
777 777 aclp->acl_cnt--;
778 778 }
779 779 set_aclp = aclp;
780 780 break;
781 781
782 782 case ACL_DELETE:
783 783 if ((error = acl_removeentries(aclp, acl_args->acl_aclp,
784 784 acl_args->acl_slot, ACL_REMOVE_ALL)) != 0) {
785 785 errmsg(1, 0, "%s\n", acl_strerror(error));
786 786 acl_free(aclp);
787 787 return (1);
788 788 }
789 789
790 790 if (aclp->acl_cnt == 0) {
791 791 errmsg(1, 0,
792 792 gettext("Can't remove all ACL "
793 793 "entries from a file\n"));
794 794 acl_free(aclp);
795 795 return (1);
796 796 }
797 797
798 798 set_aclp = aclp;
799 799 break;
800 800 case ACL_REPLACE:
801 801 if (acl_args->acl_slot >= 0) {
802 802 error = acl_modifyentries(aclp, acl_args->acl_aclp,
803 803 acl_args->acl_slot);
804 804 if (error) {
805 805 errmsg(1, 0, "%s\n", acl_strerror(error));
806 806 acl_free(aclp);
807 807 return (1);
808 808 }
809 809 set_aclp = aclp;
810 810 } else {
811 811 set_aclp = acl_args->acl_aclp;
812 812 }
813 813 break;
814 814 case ACL_STRIP:
815 815 error = acl_strip(file, st->st_uid, st->st_gid, st->st_mode);
816 816 if (error) {
817 817 errmsg(1, 0, "%s\n", acl_strerror(error));
818 818 acl_free(aclp);
819 819 return (1);
820 820 }
821 821 acl_free(aclp);
822 822 return (0);
823 823 /*NOTREACHED*/
824 824 default:
825 825 errmsg(1, 2, gettext("Unknown ACL action requested\n"));
826 826 /*NOTREACHED*/
827 827 }
828 828 error = acl_check(set_aclp, isdir);
829 829
830 830 if (error) {
831 831 errmsg(1, 2, "%s\n%s", acl_strerror(error),
832 832 gettext("See chmod(1) for more information on "
833 833 "valid ACL syntax\n"));
834 834 }
835 835 if ((error = acl_set(file, set_aclp)) != 0) {
836 836 errmsg(1, 0, gettext("Failed to set ACL: %s\n"),
837 837 acl_strerror(error));
838 838 acl_free(aclp);
839 839 return (1);
840 840 }
841 841 acl_free(aclp);
842 842 return (0);
843 843 }
844 844
845 845 /*
846 846 * Prints out the attributes in their verbose form:
847 847 * '{'[["no"]<attribute-name>][,["no"]<attribute-name>]...'}'
848 848 * similar to output of ls -/v.
849 849 */
850 850 static void
851 851 print_nvlist(nvlist_t *attr_nvlist)
852 852 {
853 853 int firsttime = 1;
854 854 boolean_t value;
855 855 nvlist_t *lptr = attr_nvlist;
856 856 nvpair_t *pair = NULL;
857 857
858 858 (void) fprintf(stderr, "\t%c", LEFTBRACE);
859 859 while (pair = nvlist_next_nvpair(lptr, pair)) {
860 860 if (nvpair_value_boolean_value(pair, &value) == 0) {
861 861 (void) fprintf(stderr, "%s%s%s",
862 862 firsttime ? "" : A_SEP_TOK,
863 863 (value == A_SET_VAL) ? "" : "no",
864 864 nvpair_name(pair));
865 865 firsttime = 0;
866 866 } else {
867 867 (void) fprintf(stderr, gettext(
868 868 "<error retrieving attributes: %s>"),
869 869 strerror(errno));
870 870 break;
871 871 }
872 872 }
873 873 (void) fprintf(stderr, "%c\n", RIGHTBRACE);
874 874 }
875 875
876 876 /*
877 877 * Add an attribute name and boolean value to an nvlist if an action is to be
878 878 * performed for that attribute. The nvlist will be used later to set all the
879 879 * attributes in the nvlist in one operation through a call to setattrat().
880 880 *
881 881 * If a set operation ('+') was specified, then a boolean representation of the
882 882 * attribute's value will be added to the nvlist for that attribute name. If an
883 883 * inverse operation ('-') was specified, then a boolean representation of the
884 884 * inverse of the attribute's value will be added to the nvlist for that
885 885 * attribute name.
886 886 *
887 887 * Returns an nvlist of attribute name and boolean value pairs if there are
888 888 * attribute actions to be performed, otherwise returns NULL.
889 889 */
890 890 static nvlist_t *
891 891 set_attrs_nvlist(char *attractptr, int numofattrs)
892 892 {
893 893 int attribute_set = 0;
894 894 f_attr_t i;
895 895 nvlist_t *attr_nvlist;
896 896
897 897 if (nvlist_alloc(&attr_nvlist, NV_UNIQUE_NAME, 0) != 0) {
898 898 perror("chmod");
899 899 exit(2);
900 900 }
901 901
902 902 for (i = 0; i < numofattrs; i++) {
903 903 if (attractptr[i] != '\0') {
904 904 if ((nvlist_add_boolean_value(attr_nvlist,
905 905 attr_to_name(i),
906 906 (attractptr[i] == A_SET_OP))) != 0) {
907 907 errmsg(1, 2, gettext(
908 908 "unable to propagate attribute names and"
909 909 "values: %s\n"), strerror(errno));
910 910 } else {
911 911 attribute_set = 1;
912 912 }
913 913 }
914 914 }
915 915 return (attribute_set ? attr_nvlist : NULL);
916 916 }
917 917
918 918 /*
919 919 * Set the attributes of file, or if specified, of the named attribute file,
920 920 * attrname. Build an nvlist of attribute names and values and call setattrat()
921 921 * to set the attributes in one operation.
922 922 *
923 923 * Returns 0 if successful, otherwise returns 1.
924 924 */
925 925 static int
926 926 set_file_attrs(char *file, char *attrname, nvlist_t *attr_nvlist)
927 927 {
928 928 int rc;
929 929 char *filename;
930 930
931 931 if (attrname != NULL) {
932 932 filename = attrname;
933 933 } else {
934 934 filename = basename(file);
935 935 }
936 936
937 937 if ((rc = setattrat(AT_FDCWD, XATTR_VIEW_READWRITE, filename,
938 938 attr_nvlist)) != 0) {
939 939 char *emsg;
940 940 switch (errno) {
941 941 case EINVAL:
942 942 emsg = gettext("not supported");
943 943 break;
944 944 case EPERM:
945 945 emsg = gettext("not privileged");
946 946 break;
947 947 default:
948 948 emsg = strerror(rc);
949 949 }
950 950 errmsg(1, 0, gettext(
951 951 "cannot set the following attributes on "
952 952 "%s%s%s%s: %s\n"),
953 953 (attrname == NULL) ? "" : gettext("attribute "),
954 954 (attrname == NULL) ? "" : attrname,
955 955 (attrname == NULL) ? "" : gettext(" of "),
956 956 file, emsg);
957 957 print_nvlist(attr_nvlist);
958 958 }
959 959
960 960 return (rc);
961 961 }
962 962
963 963 static int
964 964 save_cwd(void)
965 965 {
966 966 return (open(".", O_RDONLY));
967 967 }
968 968
969 969 static void
970 970 rest_cwd(int cwd)
971 971 {
972 972 if (cwd != -1) {
973 973 if (fchdir(cwd) != 0) {
974 974 errmsg(1, 1, gettext(
975 975 "can't change to current working directory\n"));
976 976 }
977 977 (void) close(cwd);
978 978 }
979 979 }
980 980
981 981 /*
982 982 * Returns 1 if filename is a system attribute file, otherwise
983 983 * returns 0.
984 984 */
985 985 static int
986 986 is_sattr(char *filename)
987 987 {
988 988 return (sysattr_type(filename) != _NOT_SATTR);
989 989 }
990 990
991 991 /*
992 992 * Perform the action on the specified named attribute file for the file
993 993 * associated with the input file descriptor. If the named attribute file
994 994 * is "*", then the action is to be performed on all the named attribute files
995 995 * of the file associated with the input file descriptor.
996 996 */
997 997 static int
998 998 set_named_attrs(char *file, int parentfd, char *attrname, nvlist_t *attr_nvlist)
999 999 {
1000 1000 int dirfd;
1001 1001 int error = 0;
1002 1002 DIR *dirp = NULL;
1003 1003 struct dirent *dp;
1004 1004 struct stat st;
1005 1005
1006 1006 if ((attrname == NULL) || (strcmp(attrname, "*") != 0)) {
1007 1007 /*
1008 1008 * Make sure the named attribute exists and extended system
1009 1009 * attributes are supported on the underlying file system.
1010 1010 */
1011 1011 if (attrname != NULL) {
1012 1012 if (fstatat(parentfd, attrname, &st,
1013 1013 AT_SYMLINK_NOFOLLOW) < 0) {
1014 1014 errmsg(2, 0, gettext(
1015 1015 "can't access attribute %s of %s\n"),
1016 1016 attrname, file);
1017 1017 return (1);
1018 1018 }
1019 1019 if (sysattr_support(attrname, _PC_SATTR_ENABLED) != 1) {
1020 1020 errmsg(1, 0, gettext(
1021 1021 "extended system attributes not supported "
1022 1022 "for attribute %s of %s\n"),
1023 1023 attrname, file);
1024 1024 return (1);
1025 1025 }
1026 1026 }
1027 1027
1028 1028 error = set_file_attrs(file, attrname, attr_nvlist);
1029 1029
1030 1030 } else {
1031 1031 if (((dirfd = dup(parentfd)) == -1) ||
1032 1032 ((dirp = fdopendir(dirfd)) == NULL)) {
1033 1033 errmsg(1, 0, gettext(
1034 1034 "cannot open dir pointer of file %s\n"), file);
1035 1035 if (dirfd > 0) {
1036 1036 (void) close(dirfd);
1037 1037 }
1038 1038 return (1);
1039 1039 }
1040 1040
1041 1041 while (dp = readdir(dirp)) {
1042 1042 /*
1043 1043 * Process all extended attribute files except
1044 1044 * ".", "..", and extended system attribute files.
1045 1045 */
1046 1046 if ((strcmp(dp->d_name, ".") == 0) ||
1047 1047 (strcmp(dp->d_name, "..") == 0) ||
1048 1048 is_sattr(dp->d_name)) {
1049 1049 continue;
1050 1050 }
1051 1051
1052 1052 if (set_named_attrs(file, parentfd, dp->d_name,
1053 1053 attr_nvlist) != 0) {
1054 1054 error++;
1055 1055 }
1056 1056 }
1057 1057 if (dirp != NULL) {
1058 1058 (void) closedir(dirp);
1059 1059 }
1060 1060 }
1061 1061
1062 1062 return ((error == 0) ? 0 : 1);
1063 1063 }
1064 1064
1065 1065 /*
1066 1066 * Set the attributes of the specified file, or if specified with -@ on the
1067 1067 * command line, the specified named attributes of the specified file.
1068 1068 *
1069 1069 * Returns 0 if successful, otherwise returns 1.
1070 1070 */
1071 1071 static int
1072 1072 set_attrs(char *file, attr_name_t *attrnames, nvlist_t *attr_nvlist)
1073 1073 {
1074 1074 char *parentd;
1075 1075 char *tpath = NULL;
1076 1076 int cwd;
1077 1077 int error = 0;
1078 1078 int parentfd;
1079 1079 attr_name_t *tattr = attrnames;
1080 1080
1081 1081 if (attr_nvlist == NULL) {
1082 1082 return (0);
1083 1083 }
1084 1084
1085 1085 if (sysattr_support(file, _PC_SATTR_ENABLED) != 1) {
1086 1086 errmsg(1, 0, gettext(
1087 1087 "extended system attributes not supported for %s\n"), file);
1088 1088 return (1);
1089 1089 }
1090 1090
1091 1091 /*
1092 1092 * Open the parent directory and change into it before attempting
1093 1093 * to set the attributes of the file.
1094 1094 */
1095 1095 if (attrnames == NULL) {
1096 1096 tpath = strdup(file);
1097 1097 parentd = dirname(tpath);
1098 1098 parentfd = open(parentd, O_RDONLY);
1099 1099 } else {
1100 1100 parentfd = attropen(file, ".", O_RDONLY);
1101 1101 }
1102 1102 if (parentfd == -1) {
1103 1103 errmsg(1, 0, gettext(
1104 1104 "cannot open attribute directory of %s\n"), file);
1105 1105 if (tpath != NULL) {
1106 1106 free(tpath);
1107 1107 }
1108 1108 return (1);
1109 1109 }
1110 1110
1111 1111 if ((cwd = save_cwd()) < 0) {
1112 1112 errmsg(1, 1, gettext(
1113 1113 "can't get current working directory\n"));
1114 1114 }
1115 1115 if (fchdir(parentfd) != 0) {
1116 1116 errmsg(1, 0, gettext(
1117 1117 "can't change to parent %sdirectory of %s\n"),
1118 1118 (attrnames == NULL) ? "" : gettext("attribute "), file);
1119 1119 (void) close(cwd);
1120 1120 (void) close(parentfd);
1121 1121 if (tpath != NULL) {
1122 1122 free(tpath);
1123 1123 }
1124 1124 return (1);
1125 1125 }
1126 1126
1127 1127 /*
1128 1128 * If no named attribute file names were provided on the command line
1129 1129 * then set the attributes of the base file, otherwise, set the
1130 1130 * attributes for each of the named attribute files specified.
1131 1131 */
1132 1132 if (attrnames == NULL) {
1133 1133 error = set_named_attrs(file, parentfd, NULL, attr_nvlist);
1134 1134 free(tpath);
1135 1135 } else {
1136 1136 while (tattr != NULL) {
1137 1137 if (set_named_attrs(file, parentfd, tattr->name,
1138 1138 attr_nvlist) != 0) {
1139 1139 error++;
1140 1140 }
1141 1141 tattr = tattr->next;
1142 1142 }
1143 1143 }
1144 1144 (void) close(parentfd);
1145 1145 rest_cwd(cwd);
1146 1146
1147 1147 return ((error == 0) ? 0 : 1);
1148 1148 }
1149 1149
1150 1150 /*
1151 1151 * Prints the attributes in either the compact or verbose form indicated
1152 1152 * by flag.
1153 1153 */
1154 1154 static void
1155 1155 print_attrs(int flag)
1156 1156 {
1157 1157 f_attr_t i;
1158 1158 static int numofattrs;
1159 1159 int firsttime = 1;
1160 1160
1161 1161 numofattrs = attr_count();
1162 1162
1163 1163 (void) fprintf(stderr, gettext("\t["));
1164 1164 for (i = 0; i < numofattrs; i++) {
1165 1165 if ((attr_to_xattr_view(i) != XATTR_VIEW_READWRITE) ||
1166 1166 (attr_to_data_type(i) != DATA_TYPE_BOOLEAN_VALUE)) {
1167 1167 continue;
1168 1168 }
1169 1169 (void) fprintf(stderr, "%s%s",
1170 1170 (firsttime == 1) ? "" : gettext("|"),
1171 1171 (flag == ATTR_OPTS) ? attr_to_option(i) : attr_to_name(i));
1172 1172 firsttime = 0;
1173 1173 }
1174 1174 (void) fprintf(stderr, gettext("]\n"));
1175 1175 }
1176 1176
1177 1177 /*
1178 1178 * Record what action should be taken on the specified attribute. Only boolean
1179 1179 * read-write attributes can be manipulated.
1180 1180 *
1181 1181 * Returns 0 if successful, otherwise returns 1.
1182 1182 */
1183 1183 static int
1184 1184 set_attr_args(f_attr_t attr, char action, char *attractptr)
1185 1185 {
1186 1186 if ((attr_to_xattr_view(attr) == XATTR_VIEW_READWRITE) &&
1187 1187 (attr_to_data_type(attr) == DATA_TYPE_BOOLEAN_VALUE)) {
1188 1188 attractptr[attr] = action;
1189 1189 return (0);
1190 1190 }
1191 1191 return (1);
1192 1192 }
1193 1193
1194 1194 /*
1195 1195 * Parses the entry and assigns the appropriate action (either '+' or '-' in
1196 1196 * attribute's position in the character array pointed to by attractptr, where
1197 1197 * upon exit, attractptr is positional and the value of each character specifies
1198 1198 * whether to set (a '+'), clear (a '-'), or leave untouched (a '\0') the
1199 1199 * attribute value.
1200 1200 *
1201 1201 * If the entry is an attribute name, then the A_SET_OP action is to be
1202 1202 * performed for this attribute. If the entry is an attribute name proceeded
1203 1203 * with "no", then the A_INVERSE_OP action is to be performed for this
1204 1204 * attribute. If the entry is one or more attribute option letters, then step
1205 1205 * through each of the option letters marking the action to be performed for
1206 1206 * each of the attributes associated with the letter as A_SET_OP.
1207 1207 *
1208 1208 * Returns 0 if the entry was a valid attribute(s) and the action to be
1209 1209 * performed on that attribute(s) has been recorded, otherwise returns 1.
1210 1210 */
1211 1211 static int
1212 1212 parse_entry(char *entry, char action, char atype, int len, char *attractptr)
1213 1213 {
1214 1214 char aopt[2] = {'\0', '\0'};
1215 1215 char *aptr;
1216 1216 f_attr_t attr;
1217 1217
1218 1218 if (atype == A_VERBOSE_TYPE) {
1219 1219 if ((attr = name_to_attr(entry)) != F_ATTR_INVAL) {
1220 1220 return (set_attr_args(attr,
1221 1221 (action == A_REPLACE_OP) ? A_SET_OP : action,
1222 1222 attractptr));
1223 1223 } else if ((len > 2) && (strncmp(entry, "no", 2) == 0) &&
1224 1224 ((attr = name_to_attr(entry + 2)) != F_ATTR_INVAL)) {
1225 1225 return (set_attr_args(attr, ((action == A_REPLACE_OP) ||
1226 1226 (action == A_SET_OP)) ? A_INVERSE_OP : A_SET_OP,
1227 1227 attractptr));
1228 1228 } else {
1229 1229 return (1);
1230 1230 }
1231 1231 } else if (atype == A_COMPACT_TYPE) {
1232 1232 for (aptr = entry; *aptr != '\0'; aptr++) {
1233 1233 *aopt = *aptr;
1234 1234 /*
1235 1235 * The output of 'ls' can be used as the attribute mode
1236 1236 * specification for chmod. This output can contain a
1237 1237 * hypen ('-') for each attribute that is not set. If
1238 1238 * so, ignore them. If a replace action is being
1239 1239 * performed, then all attributes that don't have an
1240 1240 * action set here, will be cleared down the line.
1241 1241 */
1242 1242 if (*aptr == '-') {
1243 1243 continue;
1244 1244 }
1245 1245 if (set_attr_args(option_to_attr(aopt),
1246 1246 (action == A_REPLACE_OP) ? A_SET_OP : action,
1247 1247 attractptr) != 0) {
1248 1248 return (1);
1249 1249 }
1250 1250 }
1251 1251 return (0);
1252 1252 }
1253 1253 return (1);
1254 1254 }
1255 1255
1256 1256 /*
1257 1257 * Parse the attribute specification, aoptsstr. Upon completion, attr_nvlist
1258 1258 * will point to an nvlist which contains pairs of attribute names and values
1259 1259 * to be set; attr_nvlist will be NULL if it is a no-op.
1260 1260 *
1261 1261 * The attribute specification format is
1262 1262 * S[oper]attr_type[attribute_list]
1263 1263 * where oper is
1264 1264 * + set operation of specified attributes in attribute list.
1265 1265 * This is the default operation.
1266 1266 * - inverse operation of specified attributes in attribute list
1267 1267 * = replace operation of all attributes. All attribute operations
1268 1268 * depend on those specified in the attribute list. Attributes
1269 1269 * not specified in the attribute list will be cleared.
1270 1270 * where attr_type is
1271 1271 * c compact type. Each entry in the attribute list is a character
1272 1272 * option representing an associated attribute name.
1273 1273 * v verbose type. Each entry in the attribute list is an
1274 1274 * an attribute name which can optionally be preceeded with "no"
1275 1275 * (to imply the attribute should be cleared).
1276 1276 * a all attributes type. The oper should be applied to all
1277 1277 * read-write boolean system attributes. No attribute list should
1278 1278 * be specified after an 'a' attribute type.
1279 1279 *
1280 1280 * Returns 0 if aoptsstr contained a valid attribute specification,
1281 1281 * otherwise, returns 1.
1282 1282 */
1283 1283 static int
1284 1284 parse_attr_args(char *aoptsstr, sec_args_t **sec_args)
1285 1285 {
1286 1286 char action;
1287 1287 char *attractptr;
1288 1288 char atype;
1289 1289 char *entry;
1290 1290 char *eptr;
1291 1291 char *nextattr;
1292 1292 char *nextentry;
1293 1293 char *subentry;
1294 1294 char *teptr;
1295 1295 char tok[] = {'\0', '\0'};
1296 1296 int len;
1297 1297 f_attr_t i;
1298 1298 int numofattrs;
1299 1299
1300 1300 if ((*aoptsstr != 'S') || (*(aoptsstr + 1) == '\0')) {
1301 1301 return (1);
1302 1302 }
1303 1303
1304 1304 if ((eptr = strdup(aoptsstr + 1)) == NULL) {
1305 1305 perror("chmod");
1306 1306 exit(2);
1307 1307 }
1308 1308 entry = eptr;
1309 1309
1310 1310 /*
1311 1311 * Create a positional character array to determine a single attribute
1312 1312 * operation to be performed, where each index represents the system
1313 1313 * attribute affected, and it's value in the array represents the action
1314 1314 * to be performed, i.e., a value of '+' means to set the attribute, a
1315 1315 * value of '-' means to clear the attribute, and a value of '\0' means
1316 1316 * to leave the attribute untouched. Initially, this positional
1317 1317 * character array is all '\0's, representing a no-op.
1318 1318 */
1319 1319 if ((numofattrs = attr_count()) < 1) {
1320 1320 errmsg(1, 1, gettext("system attributes not supported\n"));
1321 1321 }
1322 1322
1323 1323 if ((attractptr = calloc(numofattrs, sizeof (char))) == NULL) {
1324 1324 perror("chmod");
1325 1325 exit(2);
1326 1326 }
1327 1327
1328 1328 if ((*sec_args = malloc(sizeof (sec_args_t))) == NULL) {
1329 1329 perror("chmod");
1330 1330 exit(2);
1331 1331 }
1332 1332 (*sec_args)->sec_type = SEC_ATTR;
1333 1333 (*sec_args)->sec_attrs = NULL;
1334 1334
1335 1335 /* Parse each attribute operation within the attribute specification. */
1336 1336 while ((entry != NULL) && (*entry != '\0')) {
1337 1337 action = A_SET_OP;
1338 1338 atype = '\0';
1339 1339
1340 1340 /* Get the operator. */
1341 1341 switch (*entry) {
1342 1342 case A_SET_OP:
1343 1343 case A_INVERSE_OP:
1344 1344 case A_REPLACE_OP:
1345 1345 action = *entry++;
1346 1346 break;
1347 1347 case A_COMPACT_TYPE:
1348 1348 case A_VERBOSE_TYPE:
1349 1349 case A_ALLATTRS_TYPE:
1350 1350 atype = *entry++;
1351 1351 action = A_SET_OP;
1352 1352 break;
1353 1353 default:
1354 1354 break;
1355 1355 }
1356 1356
1357 1357 /* An attribute type must be specified. */
1358 1358 if (atype == '\0') {
1359 1359 if ((*entry == A_COMPACT_TYPE) ||
1360 1360 (*entry == A_VERBOSE_TYPE) ||
1361 1361 (*entry == A_ALLATTRS_TYPE)) {
1362 1362 atype = *entry++;
1363 1363 } else {
1364 1364 return (1);
1365 1365 }
1366 1366 }
1367 1367
1368 1368 /* Get the attribute specification separator. */
1369 1369 if (*entry == LEFTBRACE) {
1370 1370 *tok = RIGHTBRACE;
1371 1371 entry++;
1372 1372 } else {
1373 1373 *tok = A_SEP;
1374 1374 }
1375 1375
1376 1376 /* Get the attribute operation */
1377 1377 if ((nextentry = strpbrk(entry, tok)) != NULL) {
1378 1378 *nextentry = '\0';
1379 1379 nextentry++;
1380 1380 }
1381 1381
1382 1382 /* Check for a no-op */
1383 1383 if ((*entry == '\0') && (atype != A_ALLATTRS_TYPE) &&
1384 1384 (action != A_REPLACE_OP)) {
1385 1385 entry = nextentry;
1386 1386 continue;
1387 1387 }
1388 1388
1389 1389 /*
1390 1390 * Step through the attribute operation, setting the
1391 1391 * appropriate values for the specified attributes in the
1392 1392 * character array, attractptr. A value of '+' will mean the
1393 1393 * attribute is to be set, and a value of '-' will mean the
1394 1394 * attribute is to be cleared. If the value of an attribute
1395 1395 * remains '\0', then no action is to be taken on that
1396 1396 * attribute. As multiple operations specified are
1397 1397 * accumulated, a single attribute setting operation is
1398 1398 * represented in attractptr.
1399 1399 */
1400 1400 len = strlen(entry);
1401 1401 if ((*tok == RIGHTBRACE) || (action == A_REPLACE_OP) ||
1402 1402 (atype == A_ALLATTRS_TYPE)) {
1403 1403
1404 1404 if ((action == A_REPLACE_OP) ||
1405 1405 (atype == A_ALLATTRS_TYPE)) {
1406 1406 (void) memset(attractptr, '\0', numofattrs);
1407 1407 }
1408 1408
1409 1409 if (len > 0) {
1410 1410 if ((teptr = strdup(entry)) == NULL) {
1411 1411 perror("chmod");
1412 1412 exit(2);
1413 1413 }
1414 1414 subentry = teptr;
1415 1415 while (subentry != NULL) {
1416 1416 if ((nextattr = strpbrk(subentry,
1417 1417 A_SEP_TOK)) != NULL) {
1418 1418 *nextattr = '\0';
1419 1419 nextattr++;
1420 1420 }
1421 1421 if (parse_entry(subentry, action,
1422 1422 atype, len, attractptr) != 0) {
1423 1423 return (1);
1424 1424 }
1425 1425 subentry = nextattr;
1426 1426 }
1427 1427 free(teptr);
1428 1428 }
1429 1429
1430 1430 /*
1431 1431 * If performing the replace action, record the
1432 1432 * attributes and values for the rest of the
1433 1433 * attributes that have not already been recorded,
1434 1434 * otherwise record the specified action for all
1435 1435 * attributes. Note: set_attr_args() will only record
1436 1436 * the attribute and action if it is a boolean
1437 1437 * read-write attribute so we don't need to worry
1438 1438 * about checking it here.
1439 1439 */
1440 1440 if ((action == A_REPLACE_OP) ||
1441 1441 (atype == A_ALLATTRS_TYPE)) {
1442 1442 for (i = 0; i < numofattrs; i++) {
1443 1443 if (attractptr[i] == A_UNDEF_OP) {
1444 1444 (void) set_attr_args(i,
1445 1445 (action == A_SET_OP) ?
1446 1446 A_SET_OP : A_INVERSE_OP,
1447 1447 attractptr);
1448 1448 }
1449 1449 }
1450 1450 }
1451 1451
1452 1452 } else {
1453 1453 if (parse_entry(entry, action, atype, len,
1454 1454 attractptr) != 0) {
1455 1455 return (1);
1456 1456 }
1457 1457 }
1458 1458 entry = nextentry;
1459 1459 }
1460 1460
1461 1461 /*
1462 1462 * Populate an nvlist with attribute name and boolean value pairs
1463 1463 * using the single attribute operation.
1464 1464 */
1465 1465 (*sec_args)->sec_attrs = set_attrs_nvlist(attractptr, numofattrs);
1466 1466 free(attractptr);
1467 1467 free(eptr);
1468 1468
1469 1469 return (0);
1470 1470 }
↓ open down ↓ |
904 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX