2 * @file apply-default-acl.c
4 * @brief The entire implementation.
8 /* On Linux, ftw.h needs this special voodoo to work. */
9 #define _XOPEN_SOURCE 500
13 #include <fcntl.h> /* AT_FOO constants */
14 #include <ftw.h> /* nftw() et al. */
16 #include <libgen.h> /* basename(), dirname() */
17 #include <limits.h> /* PATH_MAX */
26 #include <acl/libacl.h> /* acl_get_perm, not portable */
27 #include <sys/types.h>
30 /* Most of the libacl functions return 1 for success, 0 for failure,
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.
39 #define CLOSE_ERROR -1
42 #define SNPRINTF_ERROR -1
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.
52 * A file descriptor relative to which @c pathname will be opened.
55 * The path to the file/directory/whatever whose descriptor you want.
57 * @return a file descriptor for @c pathname if everything goes well,
58 * and @c OPEN_ERROR if not.
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. */
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
);
73 /* Temporarily disable the slash, so that the subsequent call to
74 openat() opens only the next directory (and doesn't recurse). */
76 int fd
= safe_open_ex(at_fd
, pathname
, flags
);
77 if (fd
== OPEN_ERROR
) {
79 /* Don't output anything if we ignore a symlink */
80 perror("safe_open_ex (safe_open_ex)");
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
88 int result
= safe_open_ex(fd
, firstslash
+1, flags
);
89 if (close(fd
) == CLOSE_ERROR
) {
90 perror("safe_open_ex (close)");
98 * @brief A version of @c open that is completely symlink-safe when
99 * used with the @c O_NOFOLLOW flag.
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.
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.
115 * The path to the file/directory/whatever whose descriptor you want.
117 * @return a file descriptor for @c pathname if everything goes well,
118 * and @c OPEN_ERROR if not.
120 int safe_open(const char* pathname
, int flags
) {
121 if (pathname
== NULL
|| strlen(pathname
) == 0 || pathname
[0] == '\0') {
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
);
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
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.
143 char* cwd
= get_current_dir_name();
145 perror("safe_open (get_current_dir_name)");
149 char abs_cwd
[PATH_MAX
];
150 if (realpath(cwd
, abs_cwd
) == NULL
) {
151 perror("safe_open (realpath)");
155 snprintf_result
= snprintf(abspath
, PATH_MAX
, "%s/%s", abs_cwd
, pathname
);
158 if (snprintf_result
== SNPRINTF_ERROR
|| snprintf_result
> PATH_MAX
) {
159 perror("safe_open (snprintf)");
163 int fd
= open("/", flags
);
164 if (strcmp(abspath
, "/") == 0) {
168 int result
= safe_open_ex(fd
, abspath
+1, flags
);
169 if (close(fd
) == CLOSE_ERROR
) {
170 perror("safe_open (close)");
179 * @brief Determine whether or not the given path is accessible.
184 * @return true if @c path is accessible to the current effective
185 * user/group, false otherwise.
187 bool path_accessible(const char* path
) {
192 /* Test for access using the effective user and group rather than
194 int flags
= AT_EACCESS
;
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
;
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) {
213 * @brief Update (or create) an entry in an @b minimal ACL.
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.
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.
226 * A pointer to the acl_t structure whose entry we want to modify.
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.
232 * @return If there is an unexpected library error, @c ACL_ERROR is
233 * returned. Otherwise, @c ACL_SUCCESS.
236 int acl_set_entry(acl_t
* aclp
, acl_entry_t entry
) {
239 if (acl_get_tag_type(entry
, &entry_tag
) == ACL_ERROR
) {
240 perror("acl_set_entry (acl_get_tag_type)");
244 acl_permset_t entry_permset
;
245 if (acl_get_permset(entry
, &entry_permset
) == ACL_ERROR
) {
246 perror("acl_set_entry (acl_get_permset)");
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
);
254 while (result
== ACL_SUCCESS
) {
255 acl_tag_t existing_tag
= ACL_UNDEFINED_TAG
;
257 if (acl_get_tag_type(existing_entry
, &existing_tag
) == ACL_ERROR
) {
258 perror("set_acl_tag_permset (acl_get_tag_type)");
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)");
276 if (acl_set_permset(existing_entry
, entry_permset
) == ACL_ERROR
) {
277 perror("acl_set_entry (acl_set_permset)");
286 result
= acl_get_entry(*aclp
, ACL_NEXT_ENTRY
, &existing_entry
);
289 /* This catches both the initial acl_get_entry and the ones at the
291 if (result
== ACL_ERROR
) {
292 perror("acl_set_entry (acl_get_entry)");
296 /* If we've made it this far, we need to add a new entry to the
298 acl_entry_t new_entry
;
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.
307 if (acl_create_entry(aclp
, &new_entry
) == ACL_ERROR
) {
308 perror("acl_set_entry (acl_create_entry)");
312 if (acl_set_tag_type(new_entry
, entry_tag
) == ACL_ERROR
) {
313 perror("acl_set_entry (acl_set_tag_type)");
317 if (acl_set_permset(new_entry
, entry_permset
) == ACL_ERROR
) {
318 perror("acl_set_entry (acl_set_permset)");
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)");
330 if (acl_set_qualifier(new_entry
, entry_qual
) == ACL_ERROR
) {
331 perror("acl_set_entry (acl_set_qualifier)");
342 * @brief Determine the number of entries in the given ACL.
345 * The ACL to inspect.
347 * @return Either the non-negative number of entries in @c acl, or
348 * @c ACL_ERROR on error.
350 int acl_entry_count(acl_t acl
) {
354 int result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
356 while (result
== ACL_SUCCESS
) {
358 result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
361 if (result
== ACL_ERROR
) {
362 perror("acl_entry_count (acl_get_entry)");
372 * @brief Determine whether or not the given ACL is minimal.
374 * An ACL is minimal if it has fewer than four entries.
377 * The ACL whose minimality is in question.
380 * - @c ACL_SUCCESS - @c acl is minimal
381 * - @c ACL_FAILURE - @c acl is not minimal
382 * - @c ACL_ERROR - Unexpected library error
384 int acl_is_minimal(acl_t acl
) {
386 int ec
= acl_entry_count(acl
);
388 if (ec
== ACL_ERROR
) {
389 perror("acl_is_minimal (acl_entry_count)");
404 * @brief Determine whether the given ACL's mask denies execute.
407 * The ACL whose mask we want to check.
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.
414 int acl_execute_masked(acl_t acl
) {
417 int ge_result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
419 while (ge_result
== ACL_SUCCESS
) {
420 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
422 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
423 perror("acl_execute_masked (acl_get_tag_type)");
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
;
432 if (acl_get_permset(entry
, &permset
) == ACL_ERROR
) {
433 perror("acl_execute_masked (acl_get_permset)");
437 int gp_result
= acl_get_perm(permset
, ACL_EXECUTE
);
438 if (gp_result
== ACL_ERROR
) {
439 perror("acl_execute_masked (acl_get_perm)");
443 if (gp_result
== ACL_FAILURE
) {
444 /* No execute bit set in the mask; execute not allowed. */
449 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
458 * @brief Determine whether @c fd is executable by anyone.
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.
467 * The file descriptor to check.
470 * A pointer to a stat structure for @c fd.
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.
477 int any_can_execute(int fd
, const struct stat
* sp
) {
478 acl_t acl
= acl_get_fd(fd
);
480 if (acl
== (acl_t
)NULL
) {
481 perror("any_can_execute (acl_get_file)");
485 /* Our return value. */
486 int result
= ACL_FAILURE
;
488 if (acl_is_minimal(acl
)) {
489 if (sp
->st_mode
& (S_IXUSR
| S_IXOTH
| S_IXGRP
)) {
490 result
= ACL_SUCCESS
;
494 result
= ACL_FAILURE
;
500 int ge_result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
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
;
507 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
508 perror("any_can_execute_or (acl_get_tag_type)");
513 if (tag
== ACL_MASK
) {
514 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
518 /* Ok, so it's not a mask entry. Check the execute perms. */
519 acl_permset_t permset
;
521 if (acl_get_permset(entry
, &permset
) == ACL_ERROR
) {
522 perror("any_can_execute_or (acl_get_permset)");
527 int gp_result
= acl_get_perm(permset
, ACL_EXECUTE
);
528 if (gp_result
== ACL_ERROR
) {
529 perror("any_can_execute (acl_get_perm)");
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
;
542 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
545 if (ge_result
== ACL_ERROR
) {
546 perror("any_can_execute (acl_get_entry)");
559 * @brief Set @c acl as the default ACL on @c path.
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.
565 * The target directory whose ACL we wish to replace or create.
568 * The ACL to set as default on @c path.
571 * - @c ACL_SUCCESS - The default ACL was assigned successfully.
572 * - @c ACL_ERROR - Unexpected library error.
574 int assign_default_acl(const char* path
, acl_t acl
) {
578 perror("assign_default_acl (args)");
582 /* Our return value; success unless something bad happens. */
583 int result
= ACL_SUCCESS
;
584 acl_t path_acl
= acl_dup(acl
);
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. */
591 if (acl_set_file(path
, ACL_TYPE_DEFAULT
, path_acl
) == ACL_ERROR
) {
592 perror("assign_default_acl (acl_set_file)");
603 * @brief Remove all @c ACL_TYPE_ACCESS entries from the given file
604 * descriptor, leaving the UNIX permission bits.
607 * The file descriptor whose ACLs we want to wipe.
610 * - @c ACL_SUCCESS - The ACLs were wiped successfully, or none
611 * existed in the first place.
612 * - @c ACL_ERROR - Unexpected library error.
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);
618 if (empty_acl
== (acl_t
)NULL
) {
619 perror("wipe_acls (acl_init)");
623 if (acl_set_fd(fd
, empty_acl
) == ACL_ERROR
) {
624 perror("wipe_acls (acl_set_fd)");
636 * @brief Apply parent default ACL to a path.
638 * This overwrites any existing ACLs on @c path.
641 * The path whose ACL we would like to reset to its default.
644 * A pointer to a stat structure for @c path, or @c NULL if you don't
647 * @param no_exec_mask
648 * The value (either true or false) of the --no-exec-mask flag.
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.
656 int apply_default_acl(const char* path
,
657 const struct stat
* sp
,
662 perror("apply_default_acl (args)");
666 /* Define these next three variables here because we may have to
667 * jump to the cleanup routine which expects them to exist.
670 /* Our return value. */
671 int result
= ACL_SUCCESS
;
673 /* The default ACL on path's parent directory */
674 acl_t defacl
= (acl_t
)NULL
;
676 /* The file descriptor corresponding to "path" */
679 /* Get the parent directory of "path" with dirname(), which happens
680 * to murder its argument and necessitates a path_copy.
682 char* path_copy
= strdup(path
);
683 if (path_copy
== NULL
) {
684 perror("apply_default_acl (strdup)");
687 char* parent
= dirname(path_copy
);
689 fd
= safe_open(path
, O_NOFOLLOW
);
690 if (fd
== OPEN_ERROR
) {
691 if (errno
== ELOOP
) {
692 result
= ACL_FAILURE
; /* hit a symlink */
696 perror("apply_default_acl (open fd)");
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
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).
715 if (fstat(fd
, &s
) == STAT_ERROR
) {
716 perror("apply_default_acl (fstat)");
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
;
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;
740 /* Never mask the execute bit on directories. */
741 int ace_result
= any_can_execute(fd
,sp
) || S_ISDIR(sp
->st_mode
);
743 if (ace_result
== ACL_ERROR
) {
744 perror("apply_default_acl (any_can_execute)");
749 allow_exec
= (bool)ace_result
;
752 defacl
= acl_get_file(parent
, ACL_TYPE_DEFAULT
);
754 if (defacl
== (acl_t
)NULL
) {
755 perror("apply_default_acl (acl_get_file)");
760 if (wipe_acls(fd
) == ACL_ERROR
) {
761 perror("apply_default_acl (wipe_acls)");
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)");
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
781 if (S_ISDIR(sp
->st_mode
) && assign_default_acl(path
, defacl
) == ACL_ERROR
) {
782 perror("apply_default_acl (assign_default_acl)");
788 int ge_result
= acl_get_entry(defacl
, ACL_FIRST_ENTRY
, &entry
);
790 while (ge_result
== ACL_SUCCESS
) {
791 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
793 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
794 perror("apply_default_acl (acl_get_tag_type)");
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)");
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
||
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)");
824 if (acl_set_permset(entry
, permset
) == ACL_ERROR
) {
825 perror("apply_default_acl (acl_set_permset)");
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
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".
848 if (acl_set_entry(&acl
, entry
) == ACL_ERROR
) {
849 perror("apply_default_acl (acl_set_entry)");
854 ge_result
= acl_get_entry(defacl
, ACL_NEXT_ENTRY
, &entry
);
857 /* Catches the first acl_get_entry as well as the ones at the end of
859 if (ge_result
== ACL_ERROR
) {
860 perror("apply_default_acl (acl_get_entry)");
865 if (acl_set_fd(fd
, acl
) == ACL_ERROR
) {
866 perror("apply_default_acl (acl_set_fd)");
873 if (defacl
!= (acl_t
)NULL
) {
876 if (fd
>= 0 && close(fd
) == CLOSE_ERROR
) {
877 perror("apply_default_acl (close)");
886 * @brief Display program usage information.
888 * @param program_name
889 * The program name to use in the output.
892 void usage(const char* program_name
) {
893 printf("Apply any applicable default ACLs to the given files or "
895 printf("Usage: %s [flags] <target1> [<target2> [ <target3>...]]\n\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");
907 * @brief Wrapper around @c apply_default_acl() for use with @c nftw().
909 * For parameter information, see the @c nftw man page.
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
917 int apply_default_acl_nftw(const char *target
,
918 const struct stat
*sp
,
922 if (apply_default_acl(target
, sp
, false)) {
933 * @brief Wrapper around @c apply_default_acl() for use with @c nftw().
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.
939 int apply_default_acl_nftw_x(const char *target
,
940 const struct stat
*sp
,
944 if (apply_default_acl(target
, sp
, true)) {
955 * @brief Recursive version of @c apply_default_acl().
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().
961 * We ignore symlinks for consistency with chmod -r.
964 * The root (path) of the recursive application.
966 * @param no_exec_mask
967 * The value (either true or false) of the --no-exec-mask flag.
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.
975 * If there is an error, it will be reported via @c perror, but
976 * we still return @c false.
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. */
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
;
990 int nftw_result
= nftw(target
, fn
, max_levels
, flags
);
992 if (nftw_result
== 0) {
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
1001 if (nftw_result
== NFTW_ERROR
) {
1002 perror("apply_default_acl_recursive (nftw)");
1011 * @brief Call apply_default_acl (possibly recursively) on each
1012 * command-line argument.
1014 * @return Either @c EXIT_FAILURE or @c EXIT_SUCCESS. If everything
1015 * goes as expected, we return @c EXIT_SUCCESS. Otherwise, we return
1018 int main(int argc
, char* argv
[]) {
1022 return EXIT_FAILURE
;
1025 bool recursive
= false;
1026 bool no_exec_mask
= false;
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'},
1038 while ((opt
= getopt_long(argc
, argv
, "hrx", long_options
, NULL
)) != -1) {
1042 return EXIT_SUCCESS
;
1047 no_exec_mask
= true;
1051 return EXIT_FAILURE
;
1055 int result
= EXIT_SUCCESS
;
1058 for (arg_index
= optind
; arg_index
< argc
; arg_index
++) {
1059 const char* target
= argv
[arg_index
];
1060 bool reapp_result
= false;
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
1067 if (!path_accessible(target
)) {
1068 fprintf(stderr
, "%s: %s: No such file or directory\n", argv
[0], target
);
1069 result
= EXIT_FAILURE
;
1074 reapp_result
= apply_default_acl_recursive(target
, no_exec_mask
);
1077 /* It's either a normal file, or we're not operating recursively. */
1078 reapp_result
= apply_default_acl(target
, NULL
, no_exec_mask
);
1081 if (!reapp_result
) {
1082 result
= EXIT_FAILURE
;