4 * @brief The adacl (apply default acl) shared library.
8 /* Enables get_current_dir_name() in unistd.h and the O_PATH flag. */
11 #include <errno.h> /* EINVAL, ELOOP, ENOTDIR, etc. */
12 #include <fcntl.h> /* openat() */
13 #include <libgen.h> /* basename(), dirname() */
14 #include <limits.h> /* PATH_MAX */
15 #include <stdbool.h> /* the "bool" type */
16 #include <stdio.h> /* perror(), snprintf() */
17 #include <stdlib.h> /* free() */
18 #include <string.h> /* strdup() */
19 #include <sys/stat.h> /* fstat() */
20 #include <sys/xattr.h> /* fgetxattr(), fsetxattr() */
21 #include <unistd.h> /* get_current_dir_name() */
24 #include <acl/libacl.h> /* acl_get_perm, not portable */
25 #include <sys/acl.h> /* all other acl_foo functions */
27 /* XATTR_NAME_POSIX_ACL_ACCESS and XATTR_NAME_POSIX_ACL_DEFAULT */
28 #include <linux/xattr.h>
33 /* Even though most other library functions reliably return -1 for
34 * error, it feels a little wrong to re-use the ACL_ERROR constant.
36 #define CLOSE_ERROR -1
38 #define SNPRINTF_ERROR -1
40 #define XATTR_ERROR -1
44 * @brief The recursive portion of the @c safe_open function, used to
45 * open a file descriptor in a symlink-safe way when combined with
46 * the @c O_NOFOLLOW flag.
49 * A file descriptor relative to which @c pathname will be opened.
52 * The path to the file/directory/whatever whose descriptor you want.
55 * File status flags to be passed to @c openat.
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
) {
63 perror("safe_open_ex (args)");
67 char* firstslash
= strchr(pathname
, '/');
68 if (firstslash
== NULL
) {
69 /* No more slashes, this is the base case. */
70 return openat(at_fd
, pathname
, flags
);
72 if (firstslash
[1] == '\0') {
73 /* The first slash is the last character; ensure that we open
76 return openat(at_fd
, pathname
, flags
| O_DIRECTORY
);
79 /* The first slash exists and isn't the last character in the path,
80 so we can split the path wherever that first slash lies and
83 int fd
= openat(at_fd
, pathname
, flags
| O_DIRECTORY
| O_PATH
);
84 if (fd
== OPEN_ERROR
) {
85 if (errno
!= ENOTDIR
) {
86 /* Don't output anything if we ignore a symlink */
87 perror("safe_open_ex (safe_open_ex)");
92 /* The +1 is safe because there needs to be at least one character
93 after the first slash (we checked this above). */
94 int result
= safe_open_ex(fd
, firstslash
+1, flags
);
95 if (close(fd
) == CLOSE_ERROR
) {
96 perror("safe_open_ex (close)");
104 * @brief A version of @c open that is completely symlink-safe when
105 * used with the @c O_NOFOLLOW flag.
107 * The @c openat function exists to ensure that you can anchor one
108 * path to a particular directory while opening it; however, if you
109 * open "b/c/d" relative to "/a", then even the @c openat function will
110 * still follow symlinks in the "b" component. This can be exploited
111 * by an attacker to make you open the wrong path.
113 * To avoid that problem, this function uses a recursive
114 * implementation that opens every path from the root, one level at a
115 * time. So "a" is opened relative to "/", and then "b" is opened
116 * relative to "/a", and then "c" is opened relative to "/a/b",
117 * etc. When the @c O_NOFOLLOW flag is used, this approach ensures
118 * that no symlinks in any component are followed.
121 * The path to the file/directory/whatever whose descriptor you want.
124 * File status flags to be passed to @c openat.
126 * @return a file descriptor for @c pathname if everything goes well,
127 * and @c OPEN_ERROR if not.
129 int safe_open(const char* pathname
, int flags
) {
130 if (pathname
== NULL
) {
132 perror("safe_open (args)");
136 char abspath
[PATH_MAX
];
137 int snprintf_result
= 0;
138 if (strchr(pathname
, '/') == pathname
) {
139 /* pathname is already absolute; just copy it. */
140 snprintf_result
= snprintf(abspath
, PATH_MAX
, "%s", pathname
);
143 /* Concatenate the current working directory and pathname into an
144 * absolute path. We use realpath() ONLY on the cwd part, and not
145 * on the pathname part, because realpath() resolves symlinks. And
146 * the whole point of all this crap is to avoid following symlinks
149 * Using realpath() on the cwd lets us operate on relative paths
150 * while we're sitting in a directory that happens to have a
151 * symlink in it; for example: cd /var/run && apply-default-acl foo.
153 char* cwd
= get_current_dir_name();
155 perror("safe_open (get_current_dir_name)");
159 char abs_cwd
[PATH_MAX
];
160 if (realpath(cwd
, abs_cwd
) == NULL
) {
161 perror("safe_open (realpath)");
165 snprintf_result
= snprintf(abspath
, PATH_MAX
, "%s/%s", abs_cwd
, pathname
);
168 if (snprintf_result
== SNPRINTF_ERROR
|| snprintf_result
> PATH_MAX
) {
169 perror("safe_open (snprintf)");
173 bool abspath_is_root
= (strcmp(abspath
, "/") == 0);
174 int rootflags
= flags
| O_DIRECTORY
;
175 if (!abspath_is_root
) {
176 /* Use O_PATH for some added safety if "/" is not our target */
179 int rootfd
= open("/", rootflags
);
180 if (rootfd
== OPEN_ERROR
) {
181 perror("safe_open (open)");
185 if (abspath_is_root
) {
189 int result
= safe_open_ex(rootfd
, abspath
+1, flags
);
190 if (close(rootfd
) == CLOSE_ERROR
) {
191 perror("safe_open (close)");
201 * @brief Update an entry in an @b minimal ACL.
204 * A pointer to the acl_t structure whose entry we want to update.
210 * - @c ACL_SUCCESS - If we update an existing entry.
211 * - @c ACL_FAILURE - If we don't find an entry to update.
212 * - @c ACL_ERROR - Unexpected library error.
214 int acl_update_entry(acl_t aclp
, acl_entry_t entry
) {
215 if (aclp
== NULL
|| entry
== NULL
) {
217 perror("acl_update_entry (args)");
222 if (acl_get_tag_type(entry
, &entry_tag
) == ACL_ERROR
) {
223 perror("acl_update_entry (acl_get_tag_type)");
227 acl_permset_t entry_permset
;
228 if (acl_get_permset(entry
, &entry_permset
) == ACL_ERROR
) {
229 perror("acl_update_entry (acl_get_permset)");
233 acl_entry_t existing_entry
;
234 /* Loop through the given ACL looking for matching entries. */
235 int result
= acl_get_entry(aclp
, ACL_FIRST_ENTRY
, &existing_entry
);
237 while (result
== ACL_SUCCESS
) {
238 acl_tag_t existing_tag
= ACL_UNDEFINED_TAG
;
240 if (acl_get_tag_type(existing_entry
, &existing_tag
) == ACL_ERROR
) {
241 perror("set_acl_tag_permset (acl_get_tag_type)");
245 if (existing_tag
== entry_tag
) {
246 /* If we update something, we're done and return ACL_SUCCESS */
247 if (acl_set_permset(existing_entry
, entry_permset
) == ACL_ERROR
) {
248 perror("acl_update_entry (acl_set_permset)");
255 result
= acl_get_entry(aclp
, ACL_NEXT_ENTRY
, &existing_entry
);
258 /* This catches both the initial acl_get_entry and the ones at the
260 if (result
== ACL_ERROR
) {
261 perror("acl_update_entry (acl_get_entry)");
271 * @brief Determine the number of entries in the given ACL.
274 * The ACL to inspect.
276 * @return Either the non-negative number of entries in @c acl, or
277 * @c ACL_ERROR on error.
279 int acl_entry_count(acl_t acl
) {
283 int result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
285 while (result
== ACL_SUCCESS
) {
287 result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
290 if (result
== ACL_ERROR
) {
291 perror("acl_entry_count (acl_get_entry)");
301 * @brief Determine whether or not the given ACL is minimal.
303 * An ACL is minimal if it has fewer than four entries.
306 * The ACL whose minimality is in question.
309 * - @c ACL_SUCCESS - @c acl is minimal
310 * - @c ACL_FAILURE - @c acl is not minimal
311 * - @c ACL_ERROR - Unexpected library error
313 int acl_is_minimal(acl_t acl
) {
316 perror("acl_is_minimal (args)");
320 int ec
= acl_entry_count(acl
);
322 if (ec
== ACL_ERROR
) {
323 perror("acl_is_minimal (acl_entry_count)");
338 * @brief Determine whether the given ACL's mask denies execute.
341 * The ACL whose mask we want to check.
344 * - @c ACL_SUCCESS - The @c acl has a mask which denies execute.
345 * - @c ACL_FAILURE - The @c acl has a mask which does not deny execute.
346 * - @c ACL_ERROR - Unexpected library error.
348 int acl_execute_masked(acl_t acl
) {
351 perror("acl_execute_masked (args)");
356 int ge_result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
358 while (ge_result
== ACL_SUCCESS
) {
359 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
361 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
362 perror("acl_execute_masked (acl_get_tag_type)");
366 if (tag
== ACL_MASK
) {
367 /* This is the mask entry, get its permissions, and see if
368 execute is specified. */
369 acl_permset_t permset
;
371 if (acl_get_permset(entry
, &permset
) == ACL_ERROR
) {
372 perror("acl_execute_masked (acl_get_permset)");
376 int gp_result
= acl_get_perm(permset
, ACL_EXECUTE
);
377 if (gp_result
== ACL_ERROR
) {
378 perror("acl_execute_masked (acl_get_perm)");
382 if (gp_result
== ACL_FAILURE
) {
383 /* No execute bit set in the mask; execute not allowed. */
388 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
397 * @brief Determine whether @c fd is executable by anyone.
400 * This is used as part of the heuristic to determine whether or not
401 * we should mask the execute bit when inheriting an ACL. If @c fd
402 * describes a file, we check the @a effective permissions, contrary
403 * to what setfacl does.
406 * The file descriptor to check.
409 * A pointer to a stat structure for @c fd.
412 * - @c ACL_SUCCESS - Someone has effective execute permissions on @c fd.
413 * - @c ACL_FAILURE - Nobody can execute @c fd.
414 * - @c ACL_ERROR - Unexpected library error.
416 int any_can_execute(int fd
, const struct stat
* sp
) {
419 perror("any_can_execute (args)");
423 acl_t acl
= acl_get_fd(fd
);
425 if (acl
== (acl_t
)NULL
) {
426 perror("any_can_execute (acl_get_fd)");
430 /* Our return value. */
431 int result
= ACL_FAILURE
;
433 if (acl_is_minimal(acl
)) {
434 if (sp
->st_mode
& (S_IXUSR
| S_IXOTH
| S_IXGRP
)) {
435 result
= ACL_SUCCESS
;
439 result
= ACL_FAILURE
;
445 int ge_result
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
447 while (ge_result
== ACL_SUCCESS
) {
448 /* The first thing we do is check to see if this is a mask
449 entry. If it is, we skip it entirely. */
450 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
452 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
453 perror("any_can_execute_or (acl_get_tag_type)");
458 if (tag
== ACL_MASK
) {
459 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
463 /* Ok, so it's not a mask entry. Check the execute perms. */
464 acl_permset_t permset
;
466 if (acl_get_permset(entry
, &permset
) == ACL_ERROR
) {
467 perror("any_can_execute_or (acl_get_permset)");
472 int gp_result
= acl_get_perm(permset
, ACL_EXECUTE
);
473 if (gp_result
== ACL_ERROR
) {
474 perror("any_can_execute (acl_get_perm)");
479 if (gp_result
== ACL_SUCCESS
) {
480 /* Only return ACL_SUCCESS if this execute bit is not masked. */
481 if (acl_execute_masked(acl
) != ACL_SUCCESS
) {
482 result
= ACL_SUCCESS
;
487 ge_result
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
490 if (ge_result
== ACL_ERROR
) {
491 perror("any_can_execute (acl_get_entry)");
504 * @brief Copy ACLs between file descriptors as xattrs, verbatim.
506 * There is a small deficiency in libacl, namely that there is no way
507 * to get or set default ACLs through file descriptors. The @c
508 * acl_get_file and @c acl_set_file functions can do it, but they use
509 * paths, and are vulnerable to symlink attacks.
511 * Fortunately, when inheriting an ACL, we don't really need to look
512 * at what it contains. That means that we can copy the on-disk xattrs
513 * from the source directory to the destination file/directory without
514 * passing through libacl, and this can be done with file descriptors
515 * through @c fgetxattr and @c fsetxattr. That's what this function
519 * The file descriptor from which the ACL will be copied.
522 * The type of ACL (either @c ACL_TYPE_ACCESS or @c ACL_TYPE_DEFAULT)
523 * to copy from @c src_fd.
526 * The file descriptor whose ACL will be overwritten with the one
530 * The type of ACL (either @c ACL_TYPE_ACCESS or @c ACL_TYPE_DEFAULT)
531 * to replace on @c dst_fd.
534 * - @c ACL_SUCCESS - The ACL was copied successfully.
535 * - @c ACL_FAILURE - There was no ACL on @c src_fd.
536 * - @c ACL_ERROR - Unexpected library error.
538 int acl_copy_xattr(int src_fd
,
541 acl_type_t dst_type
) {
543 const char* src_name
;
544 if (src_type
== ACL_TYPE_ACCESS
) {
545 src_name
= XATTR_NAME_POSIX_ACL_ACCESS
;
547 else if (src_type
== ACL_TYPE_DEFAULT
) {
548 src_name
= XATTR_NAME_POSIX_ACL_DEFAULT
;
552 perror("acl_copy_xattr (src type)");
556 const char* dst_name
;
557 if (dst_type
== ACL_TYPE_ACCESS
) {
558 dst_name
= XATTR_NAME_POSIX_ACL_ACCESS
;
560 else if (dst_type
== ACL_TYPE_DEFAULT
) {
561 dst_name
= XATTR_NAME_POSIX_ACL_DEFAULT
;
565 perror("acl_copy_xattr (dst type)");
569 ssize_t src_size_guess
= fgetxattr(src_fd
, src_name
, NULL
, 0);
570 if (src_size_guess
== XATTR_ERROR
) {
571 if (errno
== ENODATA
) {
572 /* A missing ACL isn't really an error. ENOATTR and ENODATA are
573 synonyms, but using ENODATA here lets us avoid another
574 "include" directive. */
577 perror("acl_copy_xattr (fgetxattr size guess)");
580 char* src_acl_p
= alloca(src_size_guess
);
581 /* The actual size may be smaller than our guess? I don't know. */
582 ssize_t src_size
= fgetxattr(src_fd
, src_name
, src_acl_p
, src_size_guess
);
583 if (src_size
== XATTR_ERROR
) {
584 if (errno
== ENODATA
) {
585 /* A missing ACL isn't an error. */
588 perror("acl_copy_xattr (fgetxattr)");
592 if (fsetxattr(dst_fd
, dst_name
, src_acl_p
, src_size
, 0) == XATTR_ERROR
) {
593 perror("acl_copy_xattr (fsetxattr)");
602 * @brief Determine if a file descriptor has a default ACL.
605 * The file descriptor whose default ACL is in question.
608 * - @c ACL_SUCCESS - If @c fd has a default ACL.
609 * - @c ACL_FAILURE - If @c fd does not have a default ACL.
610 * - @c ACL_ERROR - Unexpected library error.
612 int has_default_acl_fd(int fd
) {
613 if (fgetxattr(fd
, XATTR_NAME_POSIX_ACL_DEFAULT
, NULL
, 0) == XATTR_ERROR
) {
614 if (errno
== ENODATA
) {
617 perror("has_default_acl_fd (fgetxattr)");
626 * @brief Apply parent default ACL to a path.
628 * This overwrites any existing ACLs on @c path.
631 * The path whose ACL we would like to reset to its default.
634 * A pointer to a stat structure for @c path, or @c NULL if you don't
637 * @param no_exec_mask
638 * The value (either true or false) of the --no-exec-mask flag.
641 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
642 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
643 * - @c ACL_ERROR - Unexpected library error.
645 int apply_default_acl_ex(const char* path
,
646 const struct stat
* sp
,
651 perror("apply_default_acl_ex (args)");
655 /* Define these next three variables here because we may have to
656 * jump to the cleanup routine which expects them to exist.
659 /* Our return value. */
660 int result
= ACL_SUCCESS
;
662 /* The new ACL for this path */
663 acl_t new_acl
= (acl_t
)NULL
;
665 /* A copy of new_acl, to be made before we begin mangling new_acl in
666 order to mask the execute bit. */
667 acl_t new_acl_unmasked
= (acl_t
)NULL
;
669 /* The file descriptor corresponding to "path" */
672 /* The file descriptor for the directory containing "path" */
675 /* dirname() and basename() mangle their arguments, so we need
676 to make copies of "path" before using them. */
677 char* dirname_path_copy
= NULL
;
678 char* basename_path_copy
= NULL
;
680 /* Get the parent directory of "path" with dirname(), which happens
681 * to murder its argument and necessitates a path_copy. */
682 dirname_path_copy
= strdup(path
);
683 if (dirname_path_copy
== NULL
) {
684 perror("apply_default_acl_ex (strdup)");
687 char* parent
= dirname(dirname_path_copy
);
688 parent_fd
= safe_open(parent
, O_DIRECTORY
| O_NOFOLLOW
);
689 if (parent_fd
== OPEN_ERROR
) {
690 if (errno
== ELOOP
|| errno
== ENOTDIR
) {
691 /* We hit a symlink, either in the last path component (ELOOP)
692 or higher up (ENOTDIR). */
693 result
= ACL_FAILURE
;
697 perror("apply_default_acl_ex (open parent fd)");
703 /* Check to make sure the parent descriptor actually has a default
704 ACL. If it doesn't, then we can "succeed" immediately. */
705 if (has_default_acl_fd(parent_fd
) == ACL_FAILURE
) {
706 result
= ACL_SUCCESS
;
710 /* We already obtained the parent fd safely, so if we use the
711 basename of path here instead of the full thing, then we can get
712 away with using openat() and spare ourselves the slowness of
713 another safe_open(). */
714 basename_path_copy
= strdup(path
);
715 if (basename_path_copy
== NULL
) {
716 perror("apply_default_acl_ex (strdup)");
719 fd
= openat(parent_fd
, basename(basename_path_copy
), O_NOFOLLOW
);
720 if (fd
== OPEN_ERROR
) {
721 if (errno
== ELOOP
|| errno
== ENOTDIR
) {
722 /* We hit a symlink, either in the last path component (ELOOP)
723 or higher up (ENOTDIR). */
724 result
= ACL_FAILURE
;
728 perror("apply_default_acl_ex (open fd)");
734 /* Refuse to operate on hard links, which can be abused by an
735 * attacker to trick us into changing the ACL on a file we didn't
736 * intend to; namely the "target" of the hard link. There is TOCTOU
737 * race condition here, but the window is as small as possible
738 * between when we open the file descriptor (look above) and when we
741 * Note: we only need to call fstat ourselves if we weren't passed a
742 * valid pointer to a stat structure (nftw does that).
746 if (fstat(fd
, &s
) == STAT_ERROR
) {
747 perror("apply_default_acl_ex (fstat)");
754 if (!S_ISDIR(sp
->st_mode
)) {
755 /* If it's not a directory, make sure it's a regular,
756 non-hard-linked file. */
757 if (!S_ISREG(sp
->st_mode
) || sp
->st_nlink
!= 1) {
758 result
= ACL_FAILURE
;
764 /* Default to not masking the exec bit; i.e. applying the default
765 ACL literally. If --no-exec-mask was not specified, then we try
766 to "guess" whether or not to mask the exec bit. This behavior
767 is modeled after the capital 'X' perms of setfacl. */
768 bool allow_exec
= true;
771 /* Never mask the execute bit on directories. */
772 int ace_result
= any_can_execute(fd
,sp
) || S_ISDIR(sp
->st_mode
);
774 if (ace_result
== ACL_ERROR
) {
775 perror("apply_default_acl_ex (any_can_execute)");
780 allow_exec
= (bool)ace_result
;
783 /* If it's a directory, inherit the parent's default. */
784 if (S_ISDIR(sp
->st_mode
)) {
785 if (acl_copy_xattr(parent_fd
,
788 ACL_TYPE_DEFAULT
) == ACL_ERROR
) {
789 perror("apply_default_acl_ex (acl_copy_xattr default)");
795 /* If it's anything, _apply_ the parent's default. */
796 if (acl_copy_xattr(parent_fd
,
799 ACL_TYPE_ACCESS
) == ACL_ERROR
) {
800 perror("apply_default_acl_ex (acl_copy_xattr access)");
805 /* There's a good reason why we saved the ACL above, even though
806 * we're about tto read it back into memory and mess with it on the
807 * next line. The acl_copy_xattr() function is already a hack to let
808 * us copy default ACLs without resorting to path names; we simply
809 * have no way to read the parent's default ACL into memory using
810 * parent_fd. We can, however, copy the parent's ACL to a file (with
811 * acl_copy_xattr), and then read the ACL from a file using
812 * "fd". It's quite the circus, but it works and should be safe from
813 * sym/hardlink attacks.
816 /* Now we potentially need to mask the execute permissions in the
817 ACL on fd; or maybe now. */
822 /* OK, we need to mask some execute permissions. First obtain the
824 new_acl
= acl_get_fd(fd
);
825 if (new_acl
== (acl_t
)NULL
) {
826 perror("apply_default_acl_ex (acl_get_fd)");
831 /* ...and now make a copy of it, because otherwise when we loop
832 below, some shit gets stuck (modifying the structure while
833 looping over it no worky). */
834 new_acl_unmasked
= acl_dup(new_acl
);
835 if (new_acl_unmasked
== (acl_t
)NULL
) {
836 perror("apply_default_acl_ex (acl_dup)");
842 int ge_result
= acl_get_entry(new_acl_unmasked
, ACL_FIRST_ENTRY
, &entry
);
844 while (ge_result
== ACL_SUCCESS
) {
845 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
847 if (acl_get_tag_type(entry
, &tag
) == ACL_ERROR
) {
848 perror("apply_default_acl_ex (acl_get_tag_type)");
854 /* We've got an entry/tag from the default ACL. Get its permset. */
855 acl_permset_t permset
;
856 if (acl_get_permset(entry
, &permset
) == ACL_ERROR
) {
857 perror("apply_default_acl_ex (acl_get_permset)");
862 if (tag
== ACL_MASK
||
863 tag
== ACL_USER_OBJ
||
864 tag
== ACL_GROUP_OBJ
||
867 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
868 minimal ACLs) or acl_other entries, so if execute should be
869 masked, we have to do it manually. */
870 if (acl_delete_perm(permset
, ACL_EXECUTE
) == ACL_ERROR
) {
871 perror("apply_default_acl_ex (acl_delete_perm)");
876 if (acl_set_permset(entry
, permset
) == ACL_ERROR
) {
877 perror("apply_default_acl_ex (acl_set_permset)");
883 if (acl_update_entry(new_acl
, entry
) == ACL_ERROR
) {
884 perror("apply_default_acl_ex (acl_update_entry)");
889 ge_result
= acl_get_entry(new_acl_unmasked
, ACL_NEXT_ENTRY
, &entry
);
892 /* Catches the first acl_get_entry as well as the ones at the end of
894 if (ge_result
== ACL_ERROR
) {
895 perror("apply_default_acl_ex (acl_get_entry)");
900 if (acl_set_fd(fd
, new_acl
) == ACL_ERROR
) {
901 perror("apply_default_acl_ex (acl_set_fd)");
907 free(dirname_path_copy
);
908 free(basename_path_copy
);
909 if (new_acl
!= (acl_t
)NULL
) {
912 if (new_acl_unmasked
!= (acl_t
)NULL
) {
913 acl_free(new_acl_unmasked
);
915 if (fd
> 0 && close(fd
) == CLOSE_ERROR
) {
916 perror("apply_default_acl_ex (close fd)");
919 if (parent_fd
> 0 && close(parent_fd
) == CLOSE_ERROR
) {
920 perror("apply_default_acl_ex (close parent_fd)");
929 * @brief The friendly interface to @c apply_default_acl_ex.
931 * The @c apply_default_acl_ex function holds the real implementation
932 * of this function, but it takes a weird second argument that most
933 * people won't care about (a stat structure). But, we use that
934 * argument for the recursive mode of the CLI, so it's there.
936 * If you don't have a stat structure for your @c path, use this instead.
939 * The path whose ACL we would like to reset to its default.
941 * @param no_exec_mask
942 * The value (either true or false) of the --no-exec-mask flag.
945 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
946 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
947 * or the parent of @c path is not a directory.
948 * - @c ACL_ERROR - Unexpected library error.
950 int apply_default_acl(const char* path
, bool no_exec_mask
) {
951 return apply_default_acl_ex(path
, NULL
, no_exec_mask
);