}
-int any_can_execute(const char* path) {
- /* Returns 1 if any ACL entry has execute access, 0 if none do, and
+int acl_execute_masked(const char* path) {
+ /* Returns 1 i the given path has an ACL mask which denies
+ execute. Returns 0 if it does not (or if it has no ACL/mask at
+ all), and -1 on error. */
+
+ acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
+
+ if (acl == (acl_t)NULL) {
+ return 0;
+ }
+
+ /* Our return value. */
+ int result = 0;
+
+ acl_entry_t entry;
+ int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+
+ while (ge_result == 1) {
+ acl_tag_t tag = ACL_UNDEFINED_TAG;
+ int tag_result = acl_get_tag_type(entry, &tag);
+
+ if (tag_result == -1) {
+ perror("acl_execute_masked (acl_get_tag_type)");
+ result = -1;
+ goto cleanup;
+ }
+
+ if (tag == ACL_MASK) {
+ /* This is the mask entry, get its permissions, and see if
+ execute is specified. */
+ acl_permset_t permset;
+
+ int ps_result = acl_get_permset(entry, &permset);
+ if (ps_result == -1) {
+ perror("acl_execute_masked (acl_get_permset)");
+ result = -1;
+ goto cleanup;
+ }
+
+ int gp_result = acl_get_perm(permset, ACL_EXECUTE);
+ if (gp_result == -1) {
+ perror("acl_execute_masked (acl_get_perm)");
+ result = -1;
+ goto cleanup;
+ }
+
+ if (gp_result == 0) {
+ /* No execute bit set in the mask; execute not allowed. */
+ return 1;
+ }
+ }
+
+ ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ }
+
+ cleanup:
+ acl_free(acl);
+ return result;
+}
+
+
+int any_can_execute_or_dir(const char* path) {
+ /* If the given path is a directory, returns 1. Otherwise, returns 1
+ * if any ACL entry has EFFECTIVE execute access, 0 if none do, and
* -1 on error.
+ *
+ * This is meant to somewhat mimic setfacl's handling of the capital
+ * 'X' perm, which allows execute access if the target is a
+ * directory or someone can already execute it. We differ in that we
+ * check the effective execute rather than just the execute bits.
*/
+
+ if (is_directory(path)) {
+ /* That was easy... */
+ return 1;
+ }
+
acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
if (acl == (acl_t)NULL) {
int ps_result = acl_get_permset(entry, &permset);
if (ps_result == -1) {
- perror("any_can_execute (acl_get_permset)");
+ perror("any_can_execute_or_dir (acl_get_permset)");
result = -1;
goto cleanup;
}
int gp_result = acl_get_perm(permset, ACL_EXECUTE);
if (gp_result == -1) {
- perror("any_can_execute (acl_get_perm)");
+ perror("any_can_execute_or_dir (acl_get_perm)");
result = -1;
goto cleanup;
}
if (gp_result == 1) {
- result = 1;
- goto cleanup;
+ /* Only return one if this execute bit is not masked. */
+ if (acl_execute_masked(path) != 1) {
+ result = 1;
+ goto cleanup;
+ }
}
ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
}
if (ge_result == -1) {
- perror("any_can_execute (acl_get_entry)");
+ perror("any_can_execute_or_dir (acl_get_entry)");
result = -1;
goto cleanup;
}
return 0;
}
- int ace_result = any_can_execute(path);
+ int ace_result = any_can_execute_or_dir(path);
if (ace_result == -1) {
- perror("apply_default_acl (any_can_execute)");
+ perror("apply_default_acl (any_can_execute_or_dir)");
return -1;
}
int tag_result = acl_get_tag_type(entry, &tag);
if (tag_result == -1) {
- perror("has_default_tag_acl (acl_get_tag_type)");
+ perror("apply_default_acl (acl_get_tag_type)");
result = -1;
goto cleanup;
}