- /* Refuse to operate on hard links, which can be abused by an
- * attacker to trick us into changing the ACL on a file we didn't
- * intend to; namely the "target" of the hard link. To truly prevent
- * that sort of mischief, we should be using file descriptors for
- * the target and its parent directory. Then modulo a tiny race
- * condition, we would be sure that "path" and "parent" don't change
- * their nature between the time that we test them and when we
- * utilize them. For contrast, the same attacker is free to replace
- * "path" with a hard link after is_hardlink_safe() has returned
- * "true" below.
- *
- * Unfortunately, our API is lacking in this area. For example,
- * acl_set_fd() is only capable of setting the ACL_TYPE_ACCESS list,
- * and not the ACL_TYPE_DEFAULT. Apparently the only way to operate
- * on default ACLs is through the path name, which is inherently
- * unreliable since the acl_*_file() calls themselves might follow
- * links (both hard and symbolic).
- *
- * Some improvement could still be made by using descriptors where
- * possible -- this would shrink the exploit window -- but for now
- * we use a naive implementation that only keeps honest men honest.
- */
- if (!is_hardlink_safe(path)) {
- return ACL_FAILURE;
+ /* Define these next three variables here because we may have to
+ * jump to the cleanup routine which expects them to exist.
+ */
+
+ /* Our return value. */
+ int result = ACL_SUCCESS;
+
+ /* The default ACL on path's parent directory */
+ acl_t defacl = (acl_t)NULL;
+
+ /* The file descriptor corresponding to "path" */
+ int fd = 0;
+
+ /* Split "path" into base/dirname parts to be used with openat().
+ * We duplicate the strings involved because dirname/basename mangle
+ * their arguments.
+ */
+ char* path_copy = strdup(path);
+ if (path_copy == NULL) {
+ perror("apply_default_acl (strdup)");
+ return ACL_ERROR;