AC_PREREQ([2.68])
-AC_INIT([apply-default-acl], [0.3.1], [michael@orlitzky.com])
+AC_INIT([apply-default-acl], [0.4.0], [michael@orlitzky.com])
AM_INIT_AUTOMAKE([-Wall foreign no-dist-gzip dist-xz])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_CONFIG_SRCDIR([src/apply-default-acl.c])
.SH SYNOPSIS
-\fBapply-default-acl\fR [\fB-rx\fR] \fIpath\fR [\fIpath2 ...\fR]
+\fBapply-default-acl\fR [\fB-r\fR] \fIpath\fR [\fIpath2 ...\fR]
.SH DESCRIPTION
links are followed; symbolic links are ignored in all path components
to avoid a dangerous race condition.
.P
-By default, a heuristic is used to determine whether or not the
-execute bit is masked on \fIpath\fR. If \fIpath\fR is not a directory,
-and no user or group has \fBeffective\fR execute permissions on
-\fIpath\fR, then the execute bit will not masked. Otherwise, it is
-left alone. In effect we pretend that the \fBx\fR permission acts like
+A heuristic is used to determine whether or not the execute bits are
+removed from \fIpath\fR. If \fIpath\fR is a directory or if some user
+or group has \fBeffective\fR execute permissions on \fIpath\fR, then
+the execute bits will be left alone. Otherwise, they will be
+removed. In effect we pretend that the \fBx\fR permission acts like
the \fBX\fR (note the case difference) permission of \fBsetfacl\fR.
-.P
-This behavior can be modified with the \fB--no-exec-mask\fR flag.
.SH OPTIONS
.IP \fB\-\-recursive\fR,\ \fB\-r\fR
\fBfoo\fR is in another directory \fBbar\fR which has a default ACL,
then \fBbar\fR's default ACL will be applied to \fBfoo\fR before the
contents of \fBfoo\fR are processed.
-.IP \fB\-\-no-exec-mask\fR,\ \fB\-x\fR
-Apply the default ACL literally; that is, don't use a heuristic to
-decide whether or not to mask the execute bit. This usually results in
-looser-than-necessary execute permissions.
.SH ALGORITHM
.IP "I. Argument validation" 0.4i
.RS
.IP "a. If any part of the target path contains a symlink" 0.4i
Return failure
-.IP "b. If there's no default ACL to apply"
+.IP "b. If there is no default ACL to apply"
Return success
.IP "c. If the target is not a (non-hardlink) regular file or directory"
Return failure
Return success
.IP "d. If the target was executable by anyone"
Return success
-.IP "e. If \fB--no-exec-mask\fR was given"
-Return success
-.IP "f. Unset the user/group/other/mask execute bits"
-.IP "g. Return success"
+.IP "e. Unset the user/group/other/mask execute bits"
+.IP "f. Return success"
.RE
.P
The action of apply-default ACL largely mimics what the kernel would
compare
-# A slightly modified test #1 to make sure it works right.
+# A slightly modified version of the first test, to make sure it works.
((TESTNUM++))
TARGET="${TESTDIR}"/foo
touch "${TARGET}"
# The --recursive mode should work normally if the argument is a
-# normal file. See Test #1.
+# normal file. See the first test.
((TESTNUM++))
TARGET="${TESTDIR}"/foo
setfacl -d -m user::r-- "${TESTDIR}"
-# Test #16's setup repeated with the --no-exec-mask flag.
-#
-((TESTNUM++))
-TARGET="${TESTDIR}"/foo
-touch "${TARGET}"
-chmod 644 "${TARGET}"
-# The directory allows execute for user, group, and other, so the file
-# should actually inherit them regardless of its initial mode when the
-# --no-exec-mask flag is passed.
-setfacl -d -m user:${USERS[0]}:rwx "${TESTDIR}"
-
-$BIN --no-exec-mask "${TARGET}"
-
-EXPECTED=$(cat <<EOF
-user::rwx
-user:${USERS[0]}:rwx
-group::r-x
-mask::rwx
-other::r-x
-EOF
-)
-
-ACTUAL=$(getfacl --omit-header "${TARGET}")
-compare
-
-
-
-# Test #20 repeated recursively to make sure the flags play nice
-# together.
-((TESTNUM++))
-PARENT_DIR="${TESTDIR}"/foo
-TARGET="${PARENT_DIR}"/bar
-mkdir "${PARENT_DIR}"
-touch "${TARGET}"
-chmod 644 "${TARGET}"
-setfacl -d -m user:${USERS[0]}:rwx "${TESTDIR}"
-
-$BIN --recursive --no-exec-mask "${PARENT_DIR}"
-
-EXPECTED=$(cat <<EOF
-user::rwx
-user:${USERS[0]}:rwx
-group::r-x
-mask::rwx
-other::r-x
-EOF
-)
-
-ACTUAL=$(getfacl --omit-header "${TARGET}")
-compare
-
# Make sure a mask with an execute bit doesn't count as being
# executable.
compare
-# Same as test #2, except we pass multiple files on the command
-# line and check the result of the first one.
+# Same as the second test, except we pass multiple files on the
+# command line and check the result of the first one.
((TESTNUM++))
setfacl -d -m user::r-- "${TESTDIR}"
setfacl -d -m group::r-- "${TESTDIR}"
EXPECTED="test/nonexistent: No such file or directory"
compare
+
# Same as the previous test, but with --recursive.
((TESTNUM++))
ACTUAL=$( "${BIN}" --recursive test/nonexistent 2>&1 )
EXPECTED="test/nonexistent: No such file or directory"
compare
+
# If we call apply-default-acl on more than one file, it should report any
# that don't exist (but proceed to operate on the others).
((TESTNUM++))
compare
-# Ensure that symlinks are not followed in subdirectories
-# (recursively).
+# Ensure that symlinks are not followed in subdirectories (recursively).
((TESTNUM++))
TARGET="${TESTDIR}/bar"
touch "${TARGET}"
include_HEADERS = libadacl.h
# The apply_default_acl_ex() function was dropped in v0.2.0,
-# and the "recursive" parameter was added in v0.3.0.
-libadacl_la_LDFLAGS = -version-info 2:0:0
+# and the "recursive" parameter was added in v0.3.0,
+# and the "no_exec_mask" parameter was dropped in v0.4.0.
+libadacl_la_LDFLAGS = -version-info 3:0:0
bin_PROGRAMS = apply-default-acl
apply_default_acl_LDADD = libadacl.la
printf("Flags:\n");
printf(" -h, --help Print this help message\n");
printf(" -r, --recursive Act on any given directories recursively\n");
- printf(" -x, --no-exec-mask Apply execute permissions unconditionally\n");
return;
}
}
bool recursive = false;
- bool no_exec_mask = false;
struct option long_options[] = {
/* These options set a flag. */
{"help", no_argument, NULL, 'h'},
{"recursive", no_argument, NULL, 'r'},
- {"no-exec-mask", no_argument, NULL, 'x'},
{NULL, 0, NULL, 0}
};
case 'r':
recursive = true;
break;
- case 'x':
- no_exec_mask = true;
- break;
default:
usage(argv[0]);
return EXIT_FAILURE;
continue;
}
- reapp_result = apply_default_acl(target, no_exec_mask, recursive);
+ reapp_result = apply_default_acl(target, recursive);
if (result == EXIT_SUCCESS && reapp_result == ACL_FAILURE) {
/* We don't want to turn an error into a (less-severe) failure. */
* @param fd
* The file descriptor that should inherit its parent's default ACL.
*
- * @param no_exec_mask
- * The value (either true or false) of the --no-exec-mask flag.
- *
* @param recursive
* Should we recurse into subdirectories?
*
*/
int apply_default_acl_fds(int parent_fd,
int fd,
- bool no_exec_mask,
bool recursive) {
int result = ACL_SUCCESS;
}
- /* Default to not masking the exec bit; i.e. applying the default
- ACL literally. If --no-exec-mask was not specified, then we try
- to "guess" whether or not to mask the exec bit. This behavior
- is modeled after the capital 'X' perms of setfacl. */
- bool allow_exec = true;
+ /* Next We try to guess whether or not to strip the execute bits.
+ * This behavior is modeled after the capital 'X' perms of setfacl.
+ */
+ int ace_result = any_can_execute(fd, &s);
- if (!no_exec_mask) {
- /* Never mask the execute bit on directories. */
- int ace_result = any_can_execute(fd,&s) || S_ISDIR(s.st_mode);
+ if (ace_result == ACL_ERROR) {
+ perror("apply_default_acl_fds (any_can_execute)");
+ result = ACL_ERROR;
+ goto cleanup;
+ }
- if (ace_result == ACL_ERROR) {
- perror("apply_default_acl_fds (any_can_execute)");
- result = ACL_ERROR;
- goto cleanup;
- }
+ /* Never mask the execute bit on directories. */
+ bool allow_exec = (bool)ace_result || S_ISDIR(s.st_mode);
- allow_exec = (bool)ace_result;
- }
/* If it's a directory, inherit the parent's default. */
if (S_ISDIR(s.st_mode)) {
continue;
}
}
- switch (apply_default_acl_fds(fd, new_fd, no_exec_mask, recursive)) {
+ switch (apply_default_acl_fds(fd, new_fd, recursive)) {
/* Don't overwrite an error result with success/failure. */
case ACL_FAILURE:
if (result == ACL_SUCCESS) {
* @param path
* The path whose ACL we would like to reset to its default.
*
- * @param no_exec_mask
- * The value (either true or false) of the --no-exec-mask flag.
- *
* @param recursive
* Should we recurse into subdirectories?
*
* - @c ACL_FAILURE - If symlinks or hard links are encountered.
* - @c ACL_ERROR - Unexpected library error.
*/
-int apply_default_acl(const char* path, bool no_exec_mask, bool recursive) {
+int apply_default_acl(const char* path, bool recursive) {
if (path == NULL) {
errno = EINVAL;
}
}
- result = apply_default_acl_fds(parent_fd, fd, no_exec_mask, recursive);
+ result = apply_default_acl_fds(parent_fd, fd, recursive);
cleanup:
free(dirname_path_copy);
#define ACL_FAILURE 0
#define ACL_SUCCESS 1
-int apply_default_acl(const char* path, bool no_exec_mask, bool recursive);
+int apply_default_acl(const char* path, bool recursive);