chiark / gitweb /
tmpfiles: implement augmenting of existing ACLs
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 18 Jan 2015 10:02:47 +0000 (05:02 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 22 Jan 2015 06:14:53 +0000 (01:14 -0500)
This is much more useful in practice (equivalent to setfacl -m).

man/tmpfiles.d.xml
src/shared/acl-util.c
src/shared/acl-util.h
src/tmpfiles/tmpfiles.c

index ee33afc..957910d 100644 (file)
           to exclude paths from clean-up as controlled with the Age
           parameter. Note that lines of this type do not influence the
           effect of <varname>r</varname> or <varname>R</varname>
-          lines.  Lines of this type accept shell-style globs in place
+          lines. Lines of this type accept shell-style globs in place
           of normal path names.  </para></listitem>
         </varlistentry>
 
           not exclude the content if path is a directory, but only
           directory itself. Note that lines of this type do not
           influence the effect of <varname>r</varname> or
-          <varname>R</varname> lines.  Lines of this type accept
+          <varname>R</varname> lines. Lines of this type accept
           shell-style globs in place of normal path names.
           </para></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>a</varname></term>
-          <listitem><para>Set POSIX ACLs (access control lists).
-          Lines of this type accept shell-style globs in
-          place of normal path names. This can be useful for
-          allowing additional access to certain files.
-          </para></listitem>
+          <term><varname>a+</varname></term>
+          <listitem><para>Set POSIX ACLs (access control lists). If
+          suffixed with <varname>+</varname>, specified mask will be
+          added to existing
+          entries. <command>systemd-tmpfiles</command> does not
+          automatically add the required base entries for user and
+          group to the specified mask, so they must be specified
+          explicitly if <varname>+</varname> is not used. The
+          mask will be added if not specified explicitly.
+          Lines of this type accept shell-style globs in place
+          of normal path names. This can be useful for allowing
+          additional access to certain files.  </para></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>A</varname></term>
-          <listitem><para>Recursively set POSIX ACLs. Lines of this
-          type accept shell-style globs in place of normal path
-          names. This can be useful for allowing additional access to
-          certain files.</para></listitem>
+          <term><varname>A+</varname></term>
+          <listitem><para>Same as <varname>a</varname> and
+          <varname>a+</varname>, but recursive.</para></listitem>
         </varlistentry>
       </variablelist>
 
index 22bb844..950f472 100644 (file)
@@ -150,7 +150,7 @@ int search_acl_groups(char*** dst, const char* path, bool* belong) {
         return 0;
 }
 
-int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) {
+int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
         _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
         _cleanup_strv_free_ char **split;
         char **entry;
@@ -187,9 +187,11 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) {
                 if (!a_acl)
                         return -EINVAL;
 
-                r = calc_acl_mask_if_needed(&a_acl);
-                if (r < 0)
-                        return r;
+                if (want_mask) {
+                        r = calc_acl_mask_if_needed(&a_acl);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         if (!strv_isempty(d)) {
@@ -203,9 +205,11 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) {
                 if (!d_acl)
                         return -EINVAL;
 
-                r = calc_acl_mask_if_needed(&d_acl);
-                if (r < 0)
-                        return r;
+                if (want_mask) {
+                        r = calc_acl_mask_if_needed(&d_acl);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         *acl_access = a_acl;
@@ -213,3 +217,34 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) {
         a_acl = d_acl = NULL;
         return 0;
 }
+
+int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
+        _cleanup_(acl_freep) acl_t old;
+        acl_entry_t i;
+        int found, r;
+
+        old = acl_get_file(path, type);
+        if (!old)
+                return -errno;
+
+        for (found = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
+             found > 0;
+             found = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
+
+                acl_entry_t j;
+
+                if (acl_create_entry(&old, &j) < 0)
+                        return -errno;
+
+                if (acl_copy_entry(j, i) < 0)
+                        return -errno;
+        }
+
+        r = calc_acl_mask_if_needed(&old);
+        if (r < 0)
+                return r;
+
+        *acl = old;
+        old = NULL;
+        return 0;
+}
index 4133214..1ad4a2e 100644 (file)
@@ -32,7 +32,8 @@
 int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry);
 int calc_acl_mask_if_needed(acl_t *acl_p);
 int search_acl_groups(char*** dst, const char* path, bool* belong);
-int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default);
+int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask);
+int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);
 
 /* acl_free takes multiple argument types.
  * Multiple cleanup functions are necessary. */
index 44a0878..3c8993e 100644 (file)
@@ -600,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);
@@ -611,6 +613,32 @@ static int get_acls_from_arg(Item *item) {
         return 0;
 }
 
+static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
+        _cleanup_(acl_freep) acl_t cleanme = NULL;
+        int r;
+
+        if (modify) {
+                r = acls_for_file(path, type, acl, &cleanme);
+                if (r < 0)
+                        return r;
+                acl = cleanme;
+        };
+
+        r = acl_set_file(path, type, acl);
+        if (r < 0) {
+                _cleanup_(acl_free_charpp) char *t;
+
+                r = -errno;
+                t = acl_to_any_text(acl, 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;
@@ -619,27 +647,15 @@ static int path_set_acls(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