ACTUAL=`getfacl --omit-header "${TARGET}"`
compare
+
+
+
+# Test #16's setup repeated with the --no-exec-mask flag.
+#
+TESTNUM=20
+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:mail:rwx "${TESTDIR}"
+
+$BIN --no-exec-mask "${TARGET}"
+
+EXPECTED=$(cat <<EOF
+user::rwx
+user:mail: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=21
+PARENT_DIR="${TESTDIR}"/foo
+TARGET="${PARENT_DIR}"/bar
+mkdir "${PARENT_DIR}"
+touch "${TARGET}"
+chmod 644 "${TARGET}"
+setfacl -d -m user:mail:rwx "${TESTDIR}"
+
+$BIN --recursive --no-exec-mask "${PARENT_DIR}"
+
+EXPECTED=$(cat <<EOF
+user::rwx
+user:mail:rwx
+group::r-x
+mask::rwx
+other::r-x
+EOF
+)
+
+ACTUAL=`getfacl --omit-header "${TARGET}"`
+compare
+
#include <sys/acl.h>
+/* Command-line options */
+static bool no_exec_mask = false;
+
+
mode_t get_mode(const char* path) {
/*
* Get the mode bits from path.
/* Really apply the default ACL by looping through it. Returns one
* for success, zero for failure (i.e. no ACL), and -1 on unexpected
* errors.
+
*/
if (path == NULL) {
return 0;
return 0;
}
- int ace_result = any_can_execute_or_dir(path);
- if (ace_result == -1) {
+ /* 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. */
+ bool allow_exec = true;
+
+ if (!no_exec_mask) {
+ int ace_result = any_can_execute_or_dir(path);
+
+ if (ace_result == -1) {
perror("apply_default_acl (any_can_execute_or_dir)");
return -1;
}
-
- bool allow_exec = (bool)ace_result;
+ allow_exec = (bool)ace_result;
+ }
acl_t defacl = acl_get_file(parent, ACL_TYPE_DEFAULT);
tag == ACL_USER_OBJ ||
tag == ACL_GROUP_OBJ ||
tag == ACL_OTHER) {
+
if (!allow_exec) {
/* The mask doesn't affect acl_user_obj, acl_group_obj (in
minimal ACLs) or acl_other entries, so if execute should be
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;
}
int apply_default_acl_nftw(const char *target,
- const struct stat *s,
- int info,
- struct FTW *ftw) {
+ const struct stat *s,
+ int info,
+ struct FTW *ftw) {
/* A wrapper around the apply_default_acl() function for use with
* nftw(). We need to adjust the return value so that nftw() doesn't
* think we've failed.
return EXIT_FAILURE;
}
-
bool recursive = false;
+ /* bool no_exec_mask is declared static/global */
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}
};
int opt = 0;
- while ((opt = getopt_long(argc, argv, "hr", long_options, NULL)) != -1) {
+ while ((opt = getopt_long(argc, argv, "hrx", long_options, NULL)) != -1) {
switch (opt) {
case 'h':
usage(argv[0]);
case 'r':
recursive = true;
break;
+ case 'x':
+ no_exec_mask = true;
+ break;
default:
usage(argv[0]);
return EXIT_FAILURE;