struct stat s;
int result = stat(path, &s);
-
+
if (result == 0) {
return s.st_mode;
}
}
-bool has_default_acl(const char* path) {
- /* Return true if the given path has a default ACL, false
- otherwise. */
+int has_default_tag_acl(const char* path, acl_tag_t tag_type) {
+ /* Returns one if the given path has a default ACL for the supplied
+ tag, zero if it doesn't, and -1 on error. */
acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT);
-
- if (defacl == (acl_t)NULL) {
- return false;
- }
-
- /* Used to store the entry if it exists, even though we don't care
- what it is. */
- acl_entry_t dummy;
-
- int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &dummy);
-
- if (result == 1) {
- /* There's a first entry in the default ACL. */
- return true;
- }
- else if (result == 0) {
- return false;
- }
- else {
- perror("has_default_acl");
- return false;
- }
-}
-
-
-bool has_default_tag_acl(const char* path, acl_tag_t tag_type) {
- /* Return true if the given path has a default ACL for the supplied
- tag, false otherwise. */
- acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT);
-
if (defacl == (acl_t)NULL) {
- return false;
+ return 0;
}
acl_entry_t entry;
while (result == 1) {
acl_tag_t tag = ACL_UNDEFINED_TAG;
int tag_result = acl_get_tag_type(entry, &tag);
-
+
if (tag_result == -1) {
- perror("has_default_tag_acl - acl_get_tag_type");
- return false;
+ perror("has_default_tag_acl (acl_get_tag_type)");
+ return -1;
}
else {
if (tag == tag_type) {
- return true;
+ return 1;
}
}
-
+
result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
}
-
- return false;
+
+ if (result == -1) {
+ perror("has_default_tag_acl (acl_get_entry)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int has_minimal_default_acl(const char* path) {
+ /* An ACL is minimal if and only if it has no mask. Return 1 if it's
+ minimal, zero if it isn't, and -1 on errors. */
+ int has_dm = has_default_tag_acl(path, ACL_MASK);
+
+ if (has_dm == 0) {
+ return 1;
+ }
+ else if (has_dm == 1) {
+ return 0;
+ }
+ else {
+ perror("has_minimal_default_acl");
+ return -1;
+ }
}
-bool has_default_user_obj_acl(const char* path) {
+int has_default_user_obj_acl(const char* path) {
return has_default_tag_acl(path, ACL_USER_OBJ);
}
-bool has_default_group_obj_acl(const char* path) {
+int has_default_group_obj_acl(const char* path) {
return has_default_tag_acl(path, ACL_GROUP_OBJ);
}
-bool has_default_other_acl(const char* path) {
+int has_default_other_acl(const char* path) {
return has_default_tag_acl(path, ACL_OTHER);
}
-bool get_default_tag_permset(const char* path,
+int get_default_tag_permset(const char* path,
acl_tag_t tag_type,
acl_permset_t* output_perms) {
- /* Returns true if successful or false on error */
+ /* Returns one if successful, zero when the ACL doesn't exist, and
+ -1 on unexpected errors. */
acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT);
-
+
if (defacl == (acl_t)NULL) {
/* Follow the acl_foo convention of -1 == error. */
errno = EINVAL;
- return false;
+ return 0;
}
acl_entry_t entry;
while (result == 1) {
acl_tag_t tag = ACL_UNDEFINED_TAG;
int tag_result = acl_get_tag_type(entry, &tag);
-
+
if (tag_result == -1) {
- perror("get_default_tag_permset");
- return false;
+ perror("get_default_tag_permset (acl_get_tag_type)");
+ return -1;
}
else {
if (tag == tag_type) {
/* We found the right tag, now get the permset. */
int ps_result = acl_get_permset(entry, output_perms);
+ if (ps_result == -1) {
+ perror("get_default_tag_permset (acl_get_permset)");
+ }
+
if (ps_result == 0) {
- return true;
+ return 1;
}
else {
- return false;
+ return 0;
}
}
}
-
+
result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
}
- errno = EINVAL;
- return false;
-}
-
-bool get_default_user_obj_permset(const char* path,
- acl_permset_t* output_perms) {
- return get_default_tag_permset(path, ACL_USER_OBJ, output_perms);
-}
-
-bool get_default_group_obj_permset(const char* path,
- acl_permset_t* output_perms) {
- return get_default_tag_permset(path, ACL_GROUP_OBJ, output_perms);
-}
+ /* This catches both the initial acl_get_entry and the ones at the
+ end of the loop. */
+ if (result == -1) {
+ perror("get_default_tag_permset (acl_get_entry)");
+ return -1;
+ }
-bool get_default_other_permset(const char* path,
- acl_permset_t* output_perms) {
- return get_default_tag_permset(path, ACL_OTHER, output_perms);
+ return 0;
}
-
-bool has_default_tag_perm(const char* path,
+int has_default_tag_perm(const char* path,
acl_tag_t tag,
acl_perm_t perm) {
- /* Check path to see if tag has perm. */
+ /* Check path to see if tag has the given perm. Returns one if it
+ does, zero if it doesn't (or there's no ACL), and -1 on unexpected
+ errors. */
if (!has_default_tag_acl(path, tag)) {
- return false;
+ return 0;
}
-
+
acl_permset_t permset;
bool ps_result = get_default_tag_permset(path, tag, &permset);
- if (!ps_result) {
- return false;
+ if (ps_result != 1) {
+ /* Failure or error. */
+ return ps_result;
}
int p_result = acl_get_perm(permset, perm);
- if (p_result == 1) {
- return true;
- }
- else {
- return false;
+ if (p_result == -1) {
+ perror("has_default_tag_perm (acl_get_perm)");
}
+
+ return p_result;
}
-bool has_default_user_obj_read(const char* path) {
+int has_default_user_obj_read(const char* path) {
return has_default_tag_perm(path, ACL_USER_OBJ, ACL_READ);
}
-bool has_default_user_obj_write(const char* path) {
+int has_default_user_obj_write(const char* path) {
return has_default_tag_perm(path, ACL_USER_OBJ, ACL_WRITE);
}
-bool has_default_user_obj_execute(const char* path) {
+int has_default_user_obj_execute(const char* path) {
return has_default_tag_perm(path, ACL_USER_OBJ, ACL_EXECUTE);
}
-bool has_default_group_obj_read(const char* path) {
+int has_default_group_obj_read(const char* path) {
return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_READ);
}
-bool has_default_group_obj_write(const char* path) {
+int has_default_group_obj_write(const char* path) {
return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_WRITE);
}
-bool has_default_group_obj_execute(const char* path) {
+int has_default_group_obj_execute(const char* path) {
return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_EXECUTE);
}
-bool has_default_other_read(const char* path) {
+int has_default_other_read(const char* path) {
return has_default_tag_perm(path, ACL_OTHER, ACL_READ);
}
-bool has_default_other_write(const char* path) {
+int has_default_other_write(const char* path) {
return has_default_tag_perm(path, ACL_OTHER, ACL_WRITE);
}
-bool has_default_other_execute(const char* path) {
+int has_default_other_execute(const char* path) {
return has_default_tag_perm(path, ACL_OTHER, ACL_EXECUTE);
}
-bool has_default_mask_read(const char* path) {
+int has_default_mask_read(const char* path) {
return has_default_tag_perm(path, ACL_MASK, ACL_READ);
}
-bool has_default_mask_write(const char* path) {
+int has_default_mask_write(const char* path) {
return has_default_tag_perm(path, ACL_MASK, ACL_WRITE);
}
-bool has_default_mask_execute(const char* path) {
+int has_default_mask_execute(const char* path) {
return has_default_tag_perm(path, ACL_MASK, ACL_EXECUTE);
}
-bool reapply_default_acl(const char* path) {
+int reapply_default_acl(const char* path) {
/* If this is a normal file or directory (i.e. that has just been
created), we proceed to find its parent directory which will have
- a default ACL. */
+ a default ACL.
+
+ Returns one for success, zero for failure (i.e. no ACL), and -1
+ on unexpected errors. */
if (path == NULL) {
- return false;
+ return 0;
}
if (!is_regular_file(path) && !is_directory(path)) {
- return false;
+ return 0;
}
/* dirname mangles its argument */
char* parent = dirname(path_copy);
if (!is_directory(parent)) {
/* Make sure dirname() did what we think it did. */
- return false;
+ return 0;
}
/* This is the original mode of path. We will simply add permissions
to it, and then later reapply the result via chmod. */
mode_t path_mode = get_mode(path);
-
+
/* If parent has a default user ACL, apply it to path via chmod. */
if (has_default_user_obj_read(parent)) {
path_mode |= S_IRUSR;
}
-
+
if (has_default_user_obj_write(parent)) {
path_mode |= S_IWUSR;
}
if (has_default_other_read(parent)) {
path_mode |= S_IROTH;
}
-
+
if (has_default_other_write(parent)) {
path_mode |= S_IWOTH;
}
}
}
- /* For the group bits, we'll use the ACL's mask instead of the group
- object bits. If the default ACL had a group entry, it should
- already have propagated (but might be masked). */
- if (has_default_mask_read(parent)) {
- path_mode |= S_IRGRP;
- }
-
- if (has_default_mask_write(parent)) {
- path_mode |= S_IWGRP;
+ if (has_minimal_default_acl(parent)) {
+ /* With a minimal ACL, we'll repeat for the group bits what we
+ already did for the owner/other bits. */
+ if (has_default_group_obj_read(parent)) {
+ path_mode |= S_IRGRP;
+ }
+
+ if (has_default_group_obj_write(parent)) {
+ path_mode |= S_IWGRP;
+ }
+
+ if (has_default_group_obj_acl(parent)) {
+ if (!has_default_group_obj_execute(parent)) {
+ /* It has a group ACL, but no group execute is granted. */
+ path_mode &= ~S_IXGRP;
+ }
+ }
}
+ else {
+ /* The parent has an extended ACL. Extended ACLs use the mask
+ entry. */
+
+ /* For the group bits, we'll use the ACL's mask instead of the group
+ object bits. If the default ACL had a group entry, it should
+ already have propagated (but might be masked). */
+ if (has_default_mask_read(parent)) {
+ path_mode |= S_IRGRP;
+ }
- /* Honor the mask execute unconditionally. */
- if (has_default_mask_execute(parent)) {
- if (mode_has_perm(path_mode, S_IXGRP)) {
+ if (has_default_mask_write(parent)) {
+ path_mode |= S_IWGRP;
+ }
+
+ /* Honor the mask execute unconditionally. */
+ if (has_default_mask_execute(parent)) {
+ /* This just adds the group execute bit, and doesn't actually
+ grant group execute permissions. */
path_mode |= S_IXGRP;
}
+
+ if (!mode_has_perm(path_mode, S_IXGRP)) {
+ /* The group ACL entry should already have been inherited from the
+ default ACL. If the source was not group executable, we want to
+ modify the destination so that it is not group executable
+ either. In the presence of ACLs, the group permissions come not
+ from the mode bits, but from the group:: ACL entry. So, to do
+ this, we remove the group::x entry. */
+ if (has_default_group_obj_execute(path)) {
+ /* remove_default_group_obj_execute(path);*/
+ }
+ }
}
- int result = chmod(path, path_mode);
- if (result == 0) {
- return true;
+ int chmod_result = chmod(path, path_mode);
+ if (chmod_result == 0) {
+ return 1;
}
else {
- return false;
+ return 0;
}
}
int main(int argc, char* argv[]) {
const char* target = argv[1];
-
+
bool result = reapply_default_acl(target);
if (result) {