chiark / gitweb /
shared/acl-util: add mask only when needed, always add base ACLs
[elogind.git] / src / tmpfiles / tmpfiles.c
index 7081b4dc57eb5d1b03fa6a87c56b38c2844fcb91..7edeeb742840ffbe96ed32a7b0e8c8b8873ee121 100644 (file)
@@ -76,10 +76,12 @@ typedef enum ItemType {
         CREATE_CHAR_DEVICE = 'c',
         CREATE_BLOCK_DEVICE = 'b',
         COPY_FILES = 'C',
-        SET_XATTR = 't',
-        SET_ACL = 'a',
 
         /* These ones take globs */
+        SET_XATTR = 't',
+        RECURSIVE_SET_XATTR = 'T',
+        SET_ACL = 'a',
+        RECURSIVE_SET_ACL = 'A',
         WRITE_FILE = 'w',
         IGNORE_PATH = 'x',
         IGNORE_DIRECTORY_PATH = 'X',
@@ -151,7 +153,11 @@ static bool needs_glob(ItemType t) {
                       RECURSIVE_REMOVE_PATH,
                       ADJUST_MODE,
                       RELABEL_PATH,
-                      RECURSIVE_RELABEL_PATH);
+                      RECURSIVE_RELABEL_PATH,
+                      SET_XATTR,
+                      RECURSIVE_SET_XATTR,
+                      SET_ACL,
+                      RECURSIVE_SET_ACL);
 }
 
 static bool takes_ownership(ItemType t) {
@@ -486,7 +492,7 @@ finish:
         return r;
 }
 
-static int item_set_perms(Item *i, const char *path) {
+static int path_set_perms(Item *i, const char *path) {
         struct stat st;
         bool st_valid;
 
@@ -568,7 +574,7 @@ static int get_xattrs_from_arg(Item *i) {
         return r;
 }
 
-static int item_set_xattrs(Item *i, const char *path) {
+static int path_set_xattrs(Item *i, const char *path) {
         char **name, **value;
 
         assert(i);
@@ -594,7 +600,9 @@ static int get_acls_from_arg(Item *item) {
 
         assert(item);
 
-        r = parse_acl(item->argument, &item->acl_access, &item->acl_default);
+        /* If force (= modify) is set, we will not modify the acl
+         * afterwards, so the mask can be added now if necessary. */
+        r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
         if (r < 0)
                 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
                                   item->argument);
@@ -605,7 +613,46 @@ static int get_acls_from_arg(Item *item) {
         return 0;
 }
 
-static int item_set_acl(Item *item, const char *path) {
+static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
+        _cleanup_(acl_freep) acl_t dup = NULL;
+        int r;
+
+        if (modify) {
+                r = acls_for_file(path, type, acl, &dup);
+                if (r < 0)
+                        return r;
+
+                r = calc_acl_mask_if_needed(&dup);
+                if (r < 0)
+                        return r;
+        } else {
+                dup = acl_dup(acl);
+                if (!dup)
+                        return -errno;
+
+                /* the mask was already added earlier if needed */
+        }
+
+        r = add_base_acls_if_needed(&dup, path);
+        if (r < 0)
+                return r;
+
+        r = acl_set_file(path, type, dup);
+        if (r < 0) {
+                _cleanup_(acl_free_charpp) char *t;
+
+                r = -errno;
+                t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
+                log_error_errno(r,
+                                "Setting %s ACL \"%s\" on %s failed: %m",
+                                type == ACL_TYPE_ACCESS ? "access" : "default",
+                                strna(t), path);
+        }
+
+        return r;
+}
+
+static int path_set_acls(Item *item, const char *path) {
 #ifdef HAVE_ACL
         int r;
 
@@ -613,27 +660,15 @@ static int item_set_acl(Item *item, const char *path) {
         assert(path);
 
         if (item->acl_access) {
-                r = acl_set_file(path, ACL_TYPE_ACCESS, item->acl_access);
-                if (r < 0) {
-                        _cleanup_(acl_free_charpp) char *t;
-
-                        t = acl_to_any_text(item->acl_access, NULL, ',', TEXT_ABBREVIATE);
-                        return log_error_errno(errno,
-                                               "Setting access ACL \"%s\" on %s failed: %m",
-                                               strna(t), path);
-                }
+                r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
+                if (r < 0)
+                        return r;
         }
 
         if (item->acl_default) {
-                r = acl_set_file(path, ACL_TYPE_DEFAULT, item->acl_default);
-                if (r < 0) {
-                        _cleanup_(acl_free_charpp) char *t;
-
-                        t = acl_to_any_text(item->acl_default, NULL, ',', TEXT_ABBREVIATE);
-                        return log_error_errno(errno,
-                                               "Setting default ACL \"%s\" on %s failed: %m",
-                                               strna(t), path);
-                }
+                r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
+                if (r < 0)
+                        return r;
         }
 #endif
 
@@ -693,14 +728,16 @@ static int write_one_file(Item *i, const char *path) {
                 return -EEXIST;
         }
 
-        r = item_set_perms(i, path);
+        r = path_set_perms(i, path);
         if (r < 0)
                 return r;
 
         return 0;
 }
 
-static int item_set_perms_children(Item *i, const char *path) {
+typedef int (*action_t)(Item *, const char *);
+
+static int item_do_children(Item *i, const char *path, action_t action) {
         _cleanup_closedir_ DIR *d;
         int r = 0;
 
@@ -735,12 +772,12 @@ static int item_set_perms_children(Item *i, const char *path) {
                 if (!p)
                         return -ENOMEM;
 
-                q = item_set_perms(i, p);
+                q = action(i, p);
                 if (q < 0 && q != -ENOENT && r == 0)
                         r = q;
 
                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
-                        q = item_set_perms_children(i, p);
+                        q = item_do_children(i, p, action);
                         if (q < 0 && r == 0)
                                 r = q;
                 }
@@ -749,42 +786,26 @@ static int item_set_perms_children(Item *i, const char *path) {
         return r;
 }
 
-static int item_set_perms_recursive(Item *i, const char *path) {
-        int r, q;
-
-        assert(i);
-        assert(path);
-
-        r = item_set_perms(i, path);
-        if (r < 0)
-                return r;
-
-        q = item_set_perms_children(i, path);
-        if (q < 0 && r == 0)
-                r = q;
-
-        return r;
-}
-
-static int glob_item(Item *i, int (*action)(Item *, const char *)) {
+static int glob_item(Item *i, action_t action, bool recursive) {
         _cleanup_globfree_ glob_t g = {};
         int r = 0, k;
         char **fn;
 
         errno = 0;
         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
-        if (k != 0 && k != GLOB_NOMATCH) {
-                if (errno == 0)
-                        errno = EIO;
-
-                log_error_errno(errno, "glob(%s) failed: %m", i->path);
-                return -errno;
-        }
+        if (k != 0 && k != GLOB_NOMATCH)
+                return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
 
         STRV_FOREACH(fn, g.gl_pathv) {
                 k = action(i, *fn);
                 if (k < 0 && r == 0)
                         r = k;
+
+                if (recursive) {
+                        k = item_do_children(i, *fn, action);
+                        if (k < 0 && r == 0)
+                                r = k;
+                }
         }
 
         return r;
@@ -831,14 +852,14 @@ static int create_item(Item *i) {
                         }
                 }
 
-                r = item_set_perms(i, i->path);
+                r = path_set_perms(i, i->path);
                 if (r < 0)
                         return r;
 
                 break;
 
         case WRITE_FILE:
-                r = glob_item(i, write_one_file);
+                r = glob_item(i, write_one_file, false);
                 if (r < 0)
                         return r;
 
@@ -875,7 +896,7 @@ static int create_item(Item *i) {
                         }
                 }
 
-                r = item_set_perms(i, i->path);
+                r = path_set_perms(i, i->path);
                 if (r < 0)
                         return r;
 
@@ -915,7 +936,7 @@ static int create_item(Item *i) {
                         }
                 }
 
-                r = item_set_perms(i, i->path);
+                r = path_set_perms(i, i->path);
                 if (r < 0)
                         return r;
 
@@ -1006,7 +1027,7 @@ static int create_item(Item *i) {
                         }
                 }
 
-                r = item_set_perms(i, i->path);
+                r = path_set_perms(i, i->path);
                 if (r < 0)
                         return r;
 
@@ -1015,29 +1036,40 @@ static int create_item(Item *i) {
 
         case ADJUST_MODE:
         case RELABEL_PATH:
-
-                r = glob_item(i, item_set_perms);
+                r = glob_item(i, path_set_perms, false);
                 if (r < 0)
                         return r;
                 break;
 
         case RECURSIVE_RELABEL_PATH:
-
-                r = glob_item(i, item_set_perms_recursive);
+                r = glob_item(i, path_set_perms, true);
                 if (r < 0)
                         return r;
                 break;
 
         case SET_XATTR:
-                r = item_set_xattrs(i, i->path);
+                r = glob_item(i, path_set_xattrs, false);
+                if (r < 0)
+                        return r;
+                break;
+
+        case RECURSIVE_SET_XATTR:
+                r = glob_item(i, path_set_xattrs, true);
                 if (r < 0)
                         return r;
                 break;
 
         case SET_ACL:
-                r = item_set_acl(i, i->path);
+                r = glob_item(i, path_set_acls, false);
+                if (r < 0)
+                        return r;
+                break;
+
+        case RECURSIVE_SET_ACL:
+                r = glob_item(i, path_set_acls, true);
                 if (r < 0)
                         return r;
+                break;
         }
 
         log_debug("%s created successfully.", i->path);
@@ -1068,7 +1100,9 @@ static int remove_item_instance(Item *i, const char *instance) {
         case WRITE_FILE:
         case COPY_FILES:
         case SET_XATTR:
+        case RECURSIVE_SET_XATTR:
         case SET_ACL:
+        case RECURSIVE_SET_ACL:
                 break;
 
         case REMOVE_PATH:
@@ -1114,13 +1148,15 @@ static int remove_item(Item *i) {
         case WRITE_FILE:
         case COPY_FILES:
         case SET_XATTR:
+        case RECURSIVE_SET_XATTR:
         case SET_ACL:
+        case RECURSIVE_SET_ACL:
                 break;
 
         case REMOVE_PATH:
         case TRUNCATE_DIRECTORY:
         case RECURSIVE_REMOVE_PATH:
-                r = glob_item(i, remove_item_instance);
+                r = glob_item(i, remove_item_instance, false);
                 break;
         }
 
@@ -1187,7 +1223,7 @@ static int clean_item(Item *i) {
                 clean_item_instance(i, i->path);
                 break;
         case IGNORE_DIRECTORY_PATH:
-                r = glob_item(i, clean_item_instance);
+                r = glob_item(i, clean_item_instance, false);
                 break;
         default:
                 break;
@@ -1458,6 +1494,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         case SET_XATTR:
+        case RECURSIVE_SET_XATTR:
                 if (!i.argument) {
                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
                         return -EBADMSG;
@@ -1468,6 +1505,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 break;
 
         case SET_ACL:
+        case RECURSIVE_SET_ACL:
                 if (!i.argument) {
                         log_error("[%s:%u] Set ACLs requires argument.", fname, line);
                         return -EBADMSG;