]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/apply-default-acl.c
Add documentation for the safe_open() and safe_open_ex() functions.
[apply-default-acl.git] / src / apply-default-acl.c
1 /**
2 * @file apply-default-acl.c
3 *
4 * @brief The entire implementation.
5 *
6 */
7
8 /* On Linux, ftw.h needs this special voodoo to work. */
9 #define _XOPEN_SOURCE 500
10 #define _GNU_SOURCE
11
12 #include <errno.h>
13 #include <fcntl.h> /* AT_FOO constants */
14 #include <ftw.h> /* nftw() et al. */
15 #include <getopt.h>
16 #include <libgen.h> /* basename(), dirname() */
17 #include <limits.h> /* PATH_MAX */
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 /* ACLs */
26 #include <acl/libacl.h> /* acl_get_perm, not portable */
27 #include <sys/types.h>
28 #include <sys/acl.h>
29
30 /* Most of the libacl functions return 1 for success, 0 for failure,
31 and -1 on error */
32 #define ACL_ERROR -1
33 #define ACL_FAILURE 0
34 #define ACL_SUCCESS 1
35
36 /* Even though most other library functions reliably return -1 for
37 * error, it feels a little wrong to re-use the ACL_ERROR constant.
38 */
39 #define CLOSE_ERROR -1
40 #define NFTW_ERROR -1
41 #define OPEN_ERROR -1
42 #define SNPRINTF_ERROR -1
43 #define STAT_ERROR -1
44
45
46 /**
47 * @brief The recursive portion of the @c safe_open function, used to
48 * open a file descriptor in a symlink-safe way when combined with
49 * the @c O_NOFOLLOW flag.
50 *
51 * @param at_fd
52 * A file descriptor relative to which @c pathname will be opened.
53 *
54 * @param pathname
55 * The path to the file/directory/whatever whose descriptor you want.
56 *
57 * @return a file descriptor for @c pathname if everything goes well,
58 * and @c OPEN_ERROR if not.
59 */
60 int safe_open_ex(int at_fd, char* pathname, int flags) {
61 if (pathname != NULL && strlen(pathname) == 0) {
62 /* Oops, went one level to deep with nothing to do. */
63 return at_fd;
64 }
65
66 char* firstslash = strchr(pathname, '/');
67 if (firstslash == NULL) {
68 /* No more slashes, this is the base case. */
69 int r = openat(at_fd, pathname, flags);
70 return r;
71 }
72
73 /* Temporarily disable the slash, so that the subsequent call to
74 openat() opens only the next directory (and doesn't recurse). */
75 *firstslash = '\0';
76 int fd = safe_open_ex(at_fd, pathname, flags);
77 if (fd == OPEN_ERROR) {
78 if (errno != ELOOP) {
79 /* Don't output anything if we ignore a symlink */
80 perror("safe_open_ex (safe_open_ex)");
81 }
82 return OPEN_ERROR;
83 }
84
85 /* The ++ is safe because there needs to be at least a null byte
86 after the first slash, even if it's the last real character in
87 the string. */
88 int result = safe_open_ex(fd, firstslash+1, flags);
89 if (close(fd) == CLOSE_ERROR) {
90 perror("safe_open_ex (close)");
91 return OPEN_ERROR;
92 }
93 return result;
94 }
95
96
97 /**
98 * @brief A version of @c open that is completely symlink-safe when
99 * used with the @c O_NOFOLLOW flag.
100 *
101 * The @c openat function exists to ensure that you can anchor one
102 * path to a particular directory while opening it; however, if you
103 * open "b/c/d" relative to "/a", then even the @c openat function will
104 * still follow symlinks in the "b" component. This can be exploited
105 * by an attacker to make you open the wrong path.
106 *
107 * To avoid that problem, this function uses a recursive
108 * implementation that opens every path from the root, one level at a
109 * time. So "a" is opened relative to "/", and then "b" is opened
110 * relative to "/a", and then "c" is opened relative to "/a/b",
111 * etc. When the @c O_NOFOLLOW flag is used, this approach ensures
112 * that no symlinks in any component are followed.
113 *
114 * @param pathname
115 * The path to the file/directory/whatever whose descriptor you want.
116 *
117 * @return a file descriptor for @c pathname if everything goes well,
118 * and @c OPEN_ERROR if not.
119 */
120 int safe_open(const char* pathname, int flags) {
121 if (pathname == NULL || strlen(pathname) == 0 || pathname[0] == '\0') {
122 /* error? */
123 return OPEN_ERROR;
124 }
125
126 char abspath[PATH_MAX];
127 int snprintf_result = 0;
128 if (strchr(pathname, '/') == pathname) {
129 /* pathname is already absolute; just copy it. */
130 snprintf_result = snprintf(abspath, PATH_MAX, "%s", pathname);
131 }
132 else {
133 /* Concatenate the current working directory and pathname into an
134 * absolute path. We use realpath() ONLY on the cwd part, and not
135 * on the pathname part, because realpath() resolves symlinks. And
136 * the whole point of all this crap is to avoid following symlinks
137 * in the pathname.
138 *
139 * Using realpath() on the cwd lets us operate on relative paths
140 * while we're sitting in a directory that happens to have a
141 * symlink in it; for example: cd /var/run && apply-default-acl foo.
142 */
143 char* cwd = get_current_dir_name();
144 if (cwd == NULL) {
145 perror("safe_open (get_current_dir_name)");
146 return OPEN_ERROR;
147 }
148
149 char abs_cwd[PATH_MAX];
150 if (realpath(cwd, abs_cwd) == NULL) {
151 perror("safe_open (realpath)");
152 free(cwd);
153 return OPEN_ERROR;
154 }
155 snprintf_result = snprintf(abspath, PATH_MAX, "%s/%s", abs_cwd, pathname);
156 free(cwd);
157 }
158 if (snprintf_result == SNPRINTF_ERROR || snprintf_result > PATH_MAX) {
159 perror("safe_open (snprintf)");
160 return OPEN_ERROR;
161 }
162
163 int fd = open("/", flags);
164 if (strcmp(abspath, "/") == 0) {
165 return fd;
166 }
167
168 int result = safe_open_ex(fd, abspath+1, flags);
169 if (close(fd) == CLOSE_ERROR) {
170 perror("safe_open (close)");
171 return OPEN_ERROR;
172 }
173 return result;
174 }
175
176
177
178 /**
179 * @brief Determine whether or not the given path is accessible.
180 *
181 * @param path
182 * The path to test.
183 *
184 * @return true if @c path is accessible to the current effective
185 * user/group, false otherwise.
186 */
187 bool path_accessible(const char* path) {
188 if (path == NULL) {
189 return false;
190 }
191
192 /* Test for access using the effective user and group rather than
193 the real one. */
194 int flags = AT_EACCESS;
195
196 /* Don't follow symlinks when checking for a path's existence,
197 since we won't follow them to set its ACLs either. */
198 flags |= AT_SYMLINK_NOFOLLOW;
199
200 /* If the path is relative, interpret it relative to the current
201 working directory (just like the access() system call). */
202 if (faccessat(AT_FDCWD, path, F_OK, flags) == 0) {
203 return true;
204 }
205 else {
206 return false;
207 }
208 }
209
210
211
212 /**
213 * @brief Update (or create) an entry in an @b minimal ACL.
214 *
215 * This function will not work if @c aclp contains extended
216 * entries. This is fine for our purposes, since we call @c wipe_acls
217 * on each path before applying the default to it.
218 *
219 * The assumption that there are no extended entries makes things much
220 * simpler. For example, we only have to update the @c ACL_USER_OBJ,
221 * @c ACL_GROUP_OBJ, and @c ACL_OTHER entries -- all others can simply
222 * be created anew. This means we don't have to fool around comparing
223 * named-user/group entries.
224 *
225 * @param aclp
226 * A pointer to the acl_t structure whose entry we want to modify.
227 *
228 * @param entry
229 * The new entry. If @c entry contains a user/group/other entry, we
230 * update the existing one. Otherwise we create a new entry.
231 *
232 * @return If there is an unexpected library error, @c ACL_ERROR is
233 * returned. Otherwise, @c ACL_SUCCESS.
234 *
235 */
236 int acl_set_entry(acl_t* aclp, acl_entry_t entry) {
237
238 acl_tag_t entry_tag;
239 if (acl_get_tag_type(entry, &entry_tag) == ACL_ERROR) {
240 perror("acl_set_entry (acl_get_tag_type)");
241 return ACL_ERROR;
242 }
243
244 acl_permset_t entry_permset;
245 if (acl_get_permset(entry, &entry_permset) == ACL_ERROR) {
246 perror("acl_set_entry (acl_get_permset)");
247 return ACL_ERROR;
248 }
249
250 acl_entry_t existing_entry;
251 /* Loop through the given ACL looking for matching entries. */
252 int result = acl_get_entry(*aclp, ACL_FIRST_ENTRY, &existing_entry);
253
254 while (result == ACL_SUCCESS) {
255 acl_tag_t existing_tag = ACL_UNDEFINED_TAG;
256
257 if (acl_get_tag_type(existing_entry, &existing_tag) == ACL_ERROR) {
258 perror("set_acl_tag_permset (acl_get_tag_type)");
259 return ACL_ERROR;
260 }
261
262 if (existing_tag == entry_tag) {
263 if (entry_tag == ACL_USER_OBJ ||
264 entry_tag == ACL_GROUP_OBJ ||
265 entry_tag == ACL_OTHER) {
266 /* Only update for these three since all other tags will have
267 been wiped. These three are guaranteed to exist, so if we
268 match one of them, we're allowed to return ACL_SUCCESS
269 below and bypass the rest of the function. */
270 acl_permset_t existing_permset;
271 if (acl_get_permset(existing_entry, &existing_permset) == ACL_ERROR) {
272 perror("acl_set_entry (acl_get_permset)");
273 return ACL_ERROR;
274 }
275
276 if (acl_set_permset(existing_entry, entry_permset) == ACL_ERROR) {
277 perror("acl_set_entry (acl_set_permset)");
278 return ACL_ERROR;
279 }
280
281 return ACL_SUCCESS;
282 }
283
284 }
285
286 result = acl_get_entry(*aclp, ACL_NEXT_ENTRY, &existing_entry);
287 }
288
289 /* This catches both the initial acl_get_entry and the ones at the
290 end of the loop. */
291 if (result == ACL_ERROR) {
292 perror("acl_set_entry (acl_get_entry)");
293 return ACL_ERROR;
294 }
295
296 /* If we've made it this far, we need to add a new entry to the
297 ACL. */
298 acl_entry_t new_entry;
299
300 /* The acl_create_entry() function can allocate new memory and/or
301 * change the location of the ACL structure entirely. When that
302 * happens, the value pointed to by aclp is updated, which means
303 * that a new acl_t gets "passed out" to our caller, eventually to
304 * be fed to acl_free(). In other words, we should still be freeing
305 * the right thing, even if the value pointed to by aclp changes.
306 */
307 if (acl_create_entry(aclp, &new_entry) == ACL_ERROR) {
308 perror("acl_set_entry (acl_create_entry)");
309 return ACL_ERROR;
310 }
311
312 if (acl_set_tag_type(new_entry, entry_tag) == ACL_ERROR) {
313 perror("acl_set_entry (acl_set_tag_type)");
314 return ACL_ERROR;
315 }
316
317 if (acl_set_permset(new_entry, entry_permset) == ACL_ERROR) {
318 perror("acl_set_entry (acl_set_permset)");
319 return ACL_ERROR;
320 }
321
322 if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) {
323 /* We need to set the qualifier too. */
324 void* entry_qual = acl_get_qualifier(entry);
325 if (entry_qual == (void*)NULL) {
326 perror("acl_set_entry (acl_get_qualifier)");
327 return ACL_ERROR;
328 }
329
330 if (acl_set_qualifier(new_entry, entry_qual) == ACL_ERROR) {
331 perror("acl_set_entry (acl_set_qualifier)");
332 return ACL_ERROR;
333 }
334 }
335
336 return ACL_SUCCESS;
337 }
338
339
340
341 /**
342 * @brief Determine the number of entries in the given ACL.
343 *
344 * @param acl
345 * The ACL to inspect.
346 *
347 * @return Either the non-negative number of entries in @c acl, or
348 * @c ACL_ERROR on error.
349 */
350 int acl_entry_count(acl_t acl) {
351
352 acl_entry_t entry;
353 int entry_count = 0;
354 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
355
356 while (result == ACL_SUCCESS) {
357 entry_count++;
358 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
359 }
360
361 if (result == ACL_ERROR) {
362 perror("acl_entry_count (acl_get_entry)");
363 return ACL_ERROR;
364 }
365
366 return entry_count;
367 }
368
369
370
371 /**
372 * @brief Determine whether or not the given ACL is minimal.
373 *
374 * An ACL is minimal if it has fewer than four entries.
375 *
376 * @param acl
377 * The ACL whose minimality is in question.
378 *
379 * @return
380 * - @c ACL_SUCCESS - @c acl is minimal
381 * - @c ACL_FAILURE - @c acl is not minimal
382 * - @c ACL_ERROR - Unexpected library error
383 */
384 int acl_is_minimal(acl_t acl) {
385
386 int ec = acl_entry_count(acl);
387
388 if (ec == ACL_ERROR) {
389 perror("acl_is_minimal (acl_entry_count)");
390 return ACL_ERROR;
391 }
392
393 if (ec < 4) {
394 return ACL_SUCCESS;
395 }
396 else {
397 return ACL_FAILURE;
398 }
399 }
400
401
402
403 /**
404 * @brief Determine whether the given ACL's mask denies execute.
405 *
406 * @param acl
407 * The ACL whose mask we want to check.
408 *
409 * @return
410 * - @c ACL_SUCCESS - The @c acl has a mask which denies execute.
411 * - @c ACL_FAILURE - The @c acl has a mask which does not deny execute.
412 * - @c ACL_ERROR - Unexpected library error.
413 */
414 int acl_execute_masked(acl_t acl) {
415
416 acl_entry_t entry;
417 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
418
419 while (ge_result == ACL_SUCCESS) {
420 acl_tag_t tag = ACL_UNDEFINED_TAG;
421
422 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
423 perror("acl_execute_masked (acl_get_tag_type)");
424 return ACL_ERROR;
425 }
426
427 if (tag == ACL_MASK) {
428 /* This is the mask entry, get its permissions, and see if
429 execute is specified. */
430 acl_permset_t permset;
431
432 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
433 perror("acl_execute_masked (acl_get_permset)");
434 return ACL_ERROR;
435 }
436
437 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
438 if (gp_result == ACL_ERROR) {
439 perror("acl_execute_masked (acl_get_perm)");
440 return ACL_ERROR;
441 }
442
443 if (gp_result == ACL_FAILURE) {
444 /* No execute bit set in the mask; execute not allowed. */
445 return ACL_SUCCESS;
446 }
447 }
448
449 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
450 }
451
452 return ACL_FAILURE;
453 }
454
455
456
457 /**
458 * @brief Determine whether @c fd is executable by anyone.
459 *
460 *
461 * This is used as part of the heuristic to determine whether or not
462 * we should mask the execute bit when inheriting an ACL. If @c fd
463 * describes a file, we check the @a effective permissions, contrary
464 * to what setfacl does.
465 *
466 * @param fd
467 * The file descriptor to check.
468 *
469 * @param sp
470 * A pointer to a stat structure for @c fd.
471 *
472 * @return
473 * - @c ACL_SUCCESS - Someone has effective execute permissions on @c fd.
474 * - @c ACL_FAILURE - Nobody can execute @c fd.
475 * - @c ACL_ERROR - Unexpected library error.
476 */
477 int any_can_execute(int fd, const struct stat* sp) {
478 acl_t acl = acl_get_fd(fd);
479
480 if (acl == (acl_t)NULL) {
481 perror("any_can_execute (acl_get_file)");
482 return ACL_ERROR;
483 }
484
485 /* Our return value. */
486 int result = ACL_FAILURE;
487
488 if (acl_is_minimal(acl)) {
489 if (sp->st_mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
490 result = ACL_SUCCESS;
491 goto cleanup;
492 }
493 else {
494 result = ACL_FAILURE;
495 goto cleanup;
496 }
497 }
498
499 acl_entry_t entry;
500 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
501
502 while (ge_result == ACL_SUCCESS) {
503 /* The first thing we do is check to see if this is a mask
504 entry. If it is, we skip it entirely. */
505 acl_tag_t tag = ACL_UNDEFINED_TAG;
506
507 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
508 perror("any_can_execute_or (acl_get_tag_type)");
509 result = ACL_ERROR;
510 goto cleanup;
511 }
512
513 if (tag == ACL_MASK) {
514 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
515 continue;
516 }
517
518 /* Ok, so it's not a mask entry. Check the execute perms. */
519 acl_permset_t permset;
520
521 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
522 perror("any_can_execute_or (acl_get_permset)");
523 result = ACL_ERROR;
524 goto cleanup;
525 }
526
527 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
528 if (gp_result == ACL_ERROR) {
529 perror("any_can_execute (acl_get_perm)");
530 result = ACL_ERROR;
531 goto cleanup;
532 }
533
534 if (gp_result == ACL_SUCCESS) {
535 /* Only return ACL_SUCCESS if this execute bit is not masked. */
536 if (acl_execute_masked(acl) != ACL_SUCCESS) {
537 result = ACL_SUCCESS;
538 goto cleanup;
539 }
540 }
541
542 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
543 }
544
545 if (ge_result == ACL_ERROR) {
546 perror("any_can_execute (acl_get_entry)");
547 result = ACL_ERROR;
548 goto cleanup;
549 }
550
551 cleanup:
552 acl_free(acl);
553 return result;
554 }
555
556
557
558 /**
559 * @brief Set @c acl as the default ACL on @c path.
560 *
561 * This overwrites any existing default ACL on @c path. If @c path is
562 * not a directory, we return ACL_ERROR and @c errno is set.
563 *
564 * @param path
565 * The target directory whose ACL we wish to replace or create.
566 *
567 * @param acl
568 * The ACL to set as default on @c path.
569 *
570 * @return
571 * - @c ACL_SUCCESS - The default ACL was assigned successfully.
572 * - @c ACL_ERROR - Unexpected library error.
573 */
574 int assign_default_acl(const char* path, acl_t acl) {
575
576 if (path == NULL) {
577 errno = EINVAL;
578 perror("assign_default_acl (args)");
579 return ACL_ERROR;
580 }
581
582 /* Our return value; success unless something bad happens. */
583 int result = ACL_SUCCESS;
584 acl_t path_acl = acl_dup(acl);
585
586 if (path_acl == (acl_t)NULL) {
587 perror("assign_default_acl (acl_dup)");
588 return ACL_ERROR; /* Nothing to clean up in this case. */
589 }
590
591 if (acl_set_file(path, ACL_TYPE_DEFAULT, path_acl) == ACL_ERROR) {
592 perror("assign_default_acl (acl_set_file)");
593 result = ACL_ERROR;
594 }
595
596 acl_free(path_acl);
597 return result;
598 }
599
600
601
602 /**
603 * @brief Remove all @c ACL_TYPE_ACCESS entries from the given file
604 * descriptor, leaving the UNIX permission bits.
605 *
606 * @param fd
607 * The file descriptor whose ACLs we want to wipe.
608 *
609 * @return
610 * - @c ACL_SUCCESS - The ACLs were wiped successfully, or none
611 * existed in the first place.
612 * - @c ACL_ERROR - Unexpected library error.
613 */
614 int wipe_acls(int fd) {
615 /* Initialize an empty ACL, and then overwrite the one on "fd" with it. */
616 acl_t empty_acl = acl_init(0);
617
618 if (empty_acl == (acl_t)NULL) {
619 perror("wipe_acls (acl_init)");
620 return ACL_ERROR;
621 }
622
623 if (acl_set_fd(fd, empty_acl) == ACL_ERROR) {
624 perror("wipe_acls (acl_set_fd)");
625 acl_free(empty_acl);
626 return ACL_ERROR;
627 }
628
629 acl_free(empty_acl);
630 return ACL_SUCCESS;
631 }
632
633
634
635 /**
636 * @brief Apply parent default ACL to a path.
637 *
638 * This overwrites any existing ACLs on @c path.
639 *
640 * @param path
641 * The path whose ACL we would like to reset to its default.
642 *
643 * @param sp
644 * A pointer to a stat structure for @c path, or @c NULL if you don't
645 * have one handy.
646 *
647 * @param no_exec_mask
648 * The value (either true or false) of the --no-exec-mask flag.
649 *
650 * @return
651 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
652 * - @c ACL_FAILURE - The target path is not a regular file/directory,
653 * or the parent of @c path is not a directory.
654 * - @c ACL_ERROR - Unexpected library error.
655 */
656 int apply_default_acl(const char* path,
657 const struct stat* sp,
658 bool no_exec_mask) {
659
660 if (path == NULL) {
661 errno = EINVAL;
662 perror("apply_default_acl (args)");
663 return ACL_ERROR;
664 }
665
666 /* Define these next three variables here because we may have to
667 * jump to the cleanup routine which expects them to exist.
668 */
669
670 /* Our return value. */
671 int result = ACL_SUCCESS;
672
673 /* The default ACL on path's parent directory */
674 acl_t defacl = (acl_t)NULL;
675
676 /* The file descriptor corresponding to "path" */
677 int fd = 0;
678
679 /* Get the parent directory of "path" with dirname(), which happens
680 * to murder its argument and necessitates a path_copy.
681 */
682 char* path_copy = strdup(path);
683 if (path_copy == NULL) {
684 perror("apply_default_acl (strdup)");
685 return ACL_ERROR;
686 }
687 char* parent = dirname(path_copy);
688
689 fd = safe_open(path, O_NOFOLLOW);
690 if (fd == OPEN_ERROR) {
691 if (errno == ELOOP) {
692 result = ACL_FAILURE; /* hit a symlink */
693 goto cleanup;
694 }
695 else {
696 perror("apply_default_acl (open fd)");
697 result = ACL_ERROR;
698 goto cleanup;
699 }
700 }
701
702
703 /* Refuse to operate on hard links, which can be abused by an
704 * attacker to trick us into changing the ACL on a file we didn't
705 * intend to; namely the "target" of the hard link. There is TOCTOU
706 * race condition here, but the window is as small as possible
707 * between when we open the file descriptor (look above) and when we
708 * fstat it.
709 *
710 * Note: we only need to call fstat ourselves if we weren't passed a
711 * valid pointer to a stat structure (nftw does that).
712 */
713 if (sp == NULL) {
714 struct stat s;
715 if (fstat(fd, &s) == STAT_ERROR) {
716 perror("apply_default_acl (fstat)");
717 goto cleanup;
718 }
719
720 sp = &s;
721 }
722
723 if (!S_ISDIR(sp->st_mode)) {
724 /* If it's not a directory, make sure it's a regular,
725 non-hard-linked file. */
726 if (!S_ISREG(sp->st_mode) || sp->st_nlink != 1) {
727 result = ACL_FAILURE;
728 goto cleanup;
729 }
730 }
731
732
733 /* Default to not masking the exec bit; i.e. applying the default
734 ACL literally. If --no-exec-mask was not specified, then we try
735 to "guess" whether or not to mask the exec bit. This behavior
736 is modeled after the capital 'X' perms of setfacl. */
737 bool allow_exec = true;
738
739 if (!no_exec_mask) {
740 /* Never mask the execute bit on directories. */
741 int ace_result = any_can_execute(fd,sp) || S_ISDIR(sp->st_mode);
742
743 if (ace_result == ACL_ERROR) {
744 perror("apply_default_acl (any_can_execute)");
745 result = ACL_ERROR;
746 goto cleanup;
747 }
748
749 allow_exec = (bool)ace_result;
750 }
751
752 defacl = acl_get_file(parent, ACL_TYPE_DEFAULT);
753
754 if (defacl == (acl_t)NULL) {
755 perror("apply_default_acl (acl_get_file)");
756 result = ACL_ERROR;
757 goto cleanup;
758 }
759
760 if (wipe_acls(fd) == ACL_ERROR) {
761 perror("apply_default_acl (wipe_acls)");
762 result = ACL_ERROR;
763 goto cleanup;
764 }
765
766 /* Do this after wipe_acls(), otherwise we'll overwrite the wiped
767 ACL with this one. */
768 acl_t acl = acl_get_fd(fd);
769 if (acl == (acl_t)NULL) {
770 perror("apply_default_acl (acl_get_fd)");
771 result = ACL_ERROR;
772 goto cleanup;
773 }
774
775 /* If it's a directory, inherit the parent's default. We sure hope
776 * that "path" still points to the same thing that "fd" and this
777 * "sp" describe. If not, we may wind up trying to set a default ACL
778 * on a file, and this will throw an error. I guess that's what we
779 * want to do?
780 */
781 if (S_ISDIR(sp->st_mode) && assign_default_acl(path, defacl) == ACL_ERROR) {
782 perror("apply_default_acl (assign_default_acl)");
783 result = ACL_ERROR;
784 goto cleanup;
785 }
786
787 acl_entry_t entry;
788 int ge_result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry);
789
790 while (ge_result == ACL_SUCCESS) {
791 acl_tag_t tag = ACL_UNDEFINED_TAG;
792
793 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
794 perror("apply_default_acl (acl_get_tag_type)");
795 result = ACL_ERROR;
796 goto cleanup;
797 }
798
799
800 /* We've got an entry/tag from the default ACL. Get its permset. */
801 acl_permset_t permset;
802 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
803 perror("apply_default_acl (acl_get_permset)");
804 result = ACL_ERROR;
805 goto cleanup;
806 }
807
808 /* If this is a default mask, fix it up. */
809 if (tag == ACL_MASK ||
810 tag == ACL_USER_OBJ ||
811 tag == ACL_GROUP_OBJ ||
812 tag == ACL_OTHER) {
813
814 if (!allow_exec) {
815 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
816 minimal ACLs) or acl_other entries, so if execute should be
817 masked, we have to do it manually. */
818 if (acl_delete_perm(permset, ACL_EXECUTE) == ACL_ERROR) {
819 perror("apply_default_acl (acl_delete_perm)");
820 result = ACL_ERROR;
821 goto cleanup;
822 }
823
824 if (acl_set_permset(entry, permset) == ACL_ERROR) {
825 perror("apply_default_acl (acl_set_permset)");
826 result = ACL_ERROR;
827 goto cleanup;
828 }
829 }
830 }
831
832 /* Finally, add the permset to the access ACL. It's actually
833 * important that we pass in the address of "acl" here, and not
834 * "acl" itself. Why? The call to acl_create_entry() within
835 * acl_set_entry() can allocate new memory for the entry.
836 * Sometimes that can be done in-place, in which case everything
837 * is cool and the new memory gets released when we call
838 * acl_free(acl).
839 *
840 * But occasionally, the whole ACL structure will have to be moved
841 * in order to allocate the extra space. When that happens,
842 * acl_create_entry() modifies the pointer it was passed (in this
843 * case, &acl) to point to the new location. We want to call
844 * acl_free() on the new location, and since acl_free() gets
845 * called right here, we need acl_create_entry() to update the
846 * value of "acl". To do that, it needs the address of "acl".
847 */
848 if (acl_set_entry(&acl, entry) == ACL_ERROR) {
849 perror("apply_default_acl (acl_set_entry)");
850 result = ACL_ERROR;
851 goto cleanup;
852 }
853
854 ge_result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
855 }
856
857 /* Catches the first acl_get_entry as well as the ones at the end of
858 the loop. */
859 if (ge_result == ACL_ERROR) {
860 perror("apply_default_acl (acl_get_entry)");
861 result = ACL_ERROR;
862 goto cleanup;
863 }
864
865 if (acl_set_fd(fd, acl) == ACL_ERROR) {
866 perror("apply_default_acl (acl_set_fd)");
867 result = ACL_ERROR;
868 goto cleanup;
869 }
870
871 cleanup:
872 free(path_copy);
873 if (defacl != (acl_t)NULL) {
874 acl_free(defacl);
875 }
876 if (fd >= 0 && close(fd) == CLOSE_ERROR) {
877 perror("apply_default_acl (close)");
878 result = ACL_ERROR;
879 }
880 return result;
881 }
882
883
884
885 /**
886 * @brief Display program usage information.
887 *
888 * @param program_name
889 * The program name to use in the output.
890 *
891 */
892 void usage(const char* program_name) {
893 printf("Apply any applicable default ACLs to the given files or "
894 "directories.\n\n");
895 printf("Usage: %s [flags] <target1> [<target2> [ <target3>...]]\n\n",
896 program_name);
897 printf("Flags:\n");
898 printf(" -h, --help Print this help message\n");
899 printf(" -r, --recursive Act on any given directories recursively\n");
900 printf(" -x, --no-exec-mask Apply execute permissions unconditionally\n");
901
902 return;
903 }
904
905
906 /**
907 * @brief Wrapper around @c apply_default_acl() for use with @c nftw().
908 *
909 * For parameter information, see the @c nftw man page.
910 *
911 * @return If the ACL was applied to @c target successfully, we return
912 * @c FTW_CONTINUE to signal to @ nftw() that we should proceed onto
913 * the next file or directory. Otherwise, we return @c FTW_STOP to
914 * signal failure.
915 *
916 */
917 int apply_default_acl_nftw(const char *target,
918 const struct stat *sp,
919 int info,
920 struct FTW *ftw) {
921
922 if (apply_default_acl(target, sp, false)) {
923 return FTW_CONTINUE;
924 }
925 else {
926 return FTW_STOP;
927 }
928 }
929
930
931
932 /**
933 * @brief Wrapper around @c apply_default_acl() for use with @c nftw().
934 *
935 * This is identical to @c apply_default_acl_nftw(), except it passes
936 * @c true to @c apply_default_acl() as its no_exec_mask argument.
937 *
938 */
939 int apply_default_acl_nftw_x(const char *target,
940 const struct stat *sp,
941 int info,
942 struct FTW *ftw) {
943
944 if (apply_default_acl(target, sp, true)) {
945 return FTW_CONTINUE;
946 }
947 else {
948 return FTW_STOP;
949 }
950 }
951
952
953
954 /**
955 * @brief Recursive version of @c apply_default_acl().
956 *
957 * If @c target is a directory, we use @c nftw() to call @c
958 * apply_default_acl() recursively on all of its children. Otherwise,
959 * we just delegate to @c apply_default_acl().
960 *
961 * We ignore symlinks for consistency with chmod -r.
962 *
963 * @param target
964 * The root (path) of the recursive application.
965 *
966 * @param no_exec_mask
967 * The value (either true or false) of the --no-exec-mask flag.
968 *
969 * @return
970 * If @c target is not a directory, we return the result of
971 * calling @c apply_default_acl() on @c target. Otherwise, we convert
972 * the return value of @c nftw(). If @c nftw() succeeds (returns 0),
973 * then we return @c true. Otherwise, we return @c false.
974 * \n\n
975 * If there is an error, it will be reported via @c perror, but
976 * we still return @c false.
977 */
978 bool apply_default_acl_recursive(const char *target, bool no_exec_mask) {
979 int max_levels = 256;
980 int flags = FTW_PHYS; /* Don't follow links. */
981
982 /* There are two separate functions that could be passed to
983 nftw(). One passes no_exec_mask = true to apply_default_acl(),
984 and the other passes no_exec_mask = false. Since the function we
985 pass to nftw() cannot have parameters, we have to create separate
986 options and make the decision here. */
987 int (*fn)(const char *, const struct stat *, int, struct FTW *) = NULL;
988 fn = no_exec_mask ? apply_default_acl_nftw_x : apply_default_acl_nftw;
989
990 int nftw_result = nftw(target, fn, max_levels, flags);
991
992 if (nftw_result == 0) {
993 /* Success */
994 return true;
995 }
996
997 /* nftw will return NFTW_ERROR on error, or if the supplied function
998 * (apply_default_acl_nftw) returns a non-zero result, nftw will
999 * return that.
1000 */
1001 if (nftw_result == NFTW_ERROR) {
1002 perror("apply_default_acl_recursive (nftw)");
1003 }
1004
1005 return false;
1006 }
1007
1008
1009
1010 /**
1011 * @brief Call apply_default_acl (possibly recursively) on each
1012 * command-line argument.
1013 *
1014 * @return Either @c EXIT_FAILURE or @c EXIT_SUCCESS. If everything
1015 * goes as expected, we return @c EXIT_SUCCESS. Otherwise, we return
1016 * @c EXIT_FAILURE.
1017 */
1018 int main(int argc, char* argv[]) {
1019
1020 if (argc < 2) {
1021 usage(argv[0]);
1022 return EXIT_FAILURE;
1023 }
1024
1025 bool recursive = false;
1026 bool no_exec_mask = false;
1027
1028 struct option long_options[] = {
1029 /* These options set a flag. */
1030 {"help", no_argument, NULL, 'h'},
1031 {"recursive", no_argument, NULL, 'r'},
1032 {"no-exec-mask", no_argument, NULL, 'x'},
1033 {NULL, 0, NULL, 0}
1034 };
1035
1036 int opt = 0;
1037
1038 while ((opt = getopt_long(argc, argv, "hrx", long_options, NULL)) != -1) {
1039 switch (opt) {
1040 case 'h':
1041 usage(argv[0]);
1042 return EXIT_SUCCESS;
1043 case 'r':
1044 recursive = true;
1045 break;
1046 case 'x':
1047 no_exec_mask = true;
1048 break;
1049 default:
1050 usage(argv[0]);
1051 return EXIT_FAILURE;
1052 }
1053 }
1054
1055 int result = EXIT_SUCCESS;
1056
1057 int arg_index = 1;
1058 for (arg_index = optind; arg_index < argc; arg_index++) {
1059 const char* target = argv[arg_index];
1060 bool reapp_result = false;
1061
1062 /* Make sure we can access the given path before we go out of our
1063 * way to please it. Doing this check outside of
1064 * apply_default_acl() lets us spit out a better error message for
1065 * typos, too.
1066 */
1067 if (!path_accessible(target)) {
1068 fprintf(stderr, "%s: %s: No such file or directory\n", argv[0], target);
1069 result = EXIT_FAILURE;
1070 continue;
1071 }
1072
1073 if (recursive) {
1074 reapp_result = apply_default_acl_recursive(target, no_exec_mask);
1075 }
1076 else {
1077 /* It's either a normal file, or we're not operating recursively. */
1078 reapp_result = apply_default_acl(target, NULL, no_exec_mask);
1079 }
1080
1081 if (!reapp_result) {
1082 result = EXIT_FAILURE;
1083 }
1084 }
1085
1086 return result;
1087 }