chiark / gitweb /
tmpfiles, man: Add xattr support to tmpfiles
authorMaciej Wereski <m.wereski@partner.samsung.com>
Thu, 4 Dec 2014 09:32:10 +0000 (10:32 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 4 Dec 2014 19:21:45 +0000 (20:21 +0100)
This patch makes it possible to set extended attributes on files created
by tmpfiles. This can be especially used to set SMACK security labels on
volatile files and directories.

It is done by adding new line of type "t". Such line should contain
attributes in Argument field, using following format:

name=value

All other fields are ignored.

If value contains spaces, then it must be surrounded by quotation marks.
User can also put quotation mark in value by escaping it with backslash.

Example:
D /var/run/cups - - - -
t /var/run/cups - - - - security.SMACK64=printing

man/tmpfiles.d.xml
src/tmpfiles/tmpfiles.c

index 1b14d69a91dfceee88c0fdd74b50686f653f3cfa..4f2e6406a882807da2166e02356af173d28dc76c 100644 (file)
@@ -343,6 +343,25 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
                                         normal path
                                         names.</para></listitem>
                                 </varlistentry>
                                         normal path
                                         names.</para></listitem>
                                 </varlistentry>
+
+                                <varlistentry>
+                                        <term><varname>t</varname></term>
+                                        <listitem><para>Set extended
+                                        attributes on item. It may be
+                                        used in conjunction with other
+                                        types (only <varname>d</varname>,
+                                        <varname>D</varname>, <varname>f</varname>,
+                                        <varname>F</varname>, <varname>L</varname>,
+                                        <varname>p</varname>, <varname>c</varname>,
+                                        <varname>b</varname>, makes sense).
+                                        If used as a standalone line, then
+                                        <command>systemd-tmpfiles</command>
+                                        will try to set extended
+                                        attributes on specified path.
+                                        This can be especially used to set
+                                        SMACK labels.
+                                        </para></listitem>
+                                </varlistentry>
                         </variablelist>
 
                         <para>If the exclamation mark is used, this
                         </variablelist>
 
                         <para>If the exclamation mark is used, this
@@ -430,7 +449,7 @@ r! /tmp/.X[0-9]*-lock</programlisting>
                         will not be modified. This parameter is
                         ignored for <varname>x</varname>,
                         <varname>r</varname>, <varname>R</varname>,
                         will not be modified. This parameter is
                         ignored for <varname>x</varname>,
                         <varname>r</varname>, <varname>R</varname>,
-                        <varname>L</varname> lines.</para>
+                        <varname>L</varname>, <varname>t</varname> lines.</para>
 
                         <para>Optionally, if prefixed with
                         <literal>~</literal>, the access mode is masked
 
                         <para>Optionally, if prefixed with
                         <literal>~</literal>, the access mode is masked
@@ -462,8 +481,8 @@ r! /tmp/.X[0-9]*-lock</programlisting>
                         ownership will not be modified. These
                         parameters are ignored for
                         <varname>x</varname>, <varname>r</varname>,
                         ownership will not be modified. These
                         parameters are ignored for
                         <varname>x</varname>, <varname>r</varname>,
-                        <varname>R</varname>, <varname>L</varname>
-                        lines.</para>
+                        <varname>R</varname>, <varname>L</varname>,
+                        <varname>t</varname> lines.</para>
                 </refsect2>
 
                 <refsect2>
                 </refsect2>
 
                 <refsect2>
@@ -527,8 +546,8 @@ r! /tmp/.X[0-9]*-lock</programlisting>
                         specify a short string that is written to the
                         file, suffixed by a newline. For
                         <varname>C</varname>, specifies the source file
                         specify a short string that is written to the
                         file, suffixed by a newline. For
                         <varname>C</varname>, specifies the source file
-                        or directory. Ignored for all other
-                        lines.</para>
+                        or directory. For <varname>t</varname> determines
+                        extended attributes to be set. Ignored for all other lines.</para>
                 </refsect2>
 
         </refsect1>
                 </refsect2>
 
         </refsect1>
@@ -540,7 +559,8 @@ r! /tmp/.X[0-9]*-lock</programlisting>
                         <para><command>screen</command> needs two directories created at boot with specific modes and ownership.</para>
 
                         <programlisting>d /run/screens  1777 root root 10d
                         <para><command>screen</command> needs two directories created at boot with specific modes and ownership.</para>
 
                         <programlisting>d /run/screens  1777 root root 10d
-d /run/uscreens 0755 root root 10d12h</programlisting>
+d /run/uscreens 0755 root root 10d12h
+t /run/screen - - - - user.name="John Smith" security.SMACK64=screen</programlisting>
                 </example>
                 <example>
                         <title>/etc/tmpfiles.d/abrt.conf example</title>
                 </example>
                 <example>
                         <title>/etc/tmpfiles.d/abrt.conf example</title>
index d60c57793b12872365b0c6ab234990889d7be1d4..d40bd96f1b4169fc1f6c55cfcb0eeec42fefc342 100644 (file)
@@ -39,6 +39,7 @@
 #include <glob.h>
 #include <fnmatch.h>
 #include <sys/capability.h>
 #include <glob.h>
 #include <fnmatch.h>
 #include <sys/capability.h>
+#include <sys/xattr.h>
 
 #include "log.h"
 #include "util.h"
 
 #include "log.h"
 #include "util.h"
@@ -71,6 +72,7 @@ typedef enum ItemType {
         CREATE_CHAR_DEVICE = 'c',
         CREATE_BLOCK_DEVICE = 'b',
         COPY_FILES = 'C',
         CREATE_CHAR_DEVICE = 'c',
         CREATE_BLOCK_DEVICE = 'b',
         COPY_FILES = 'C',
+        SET_XATTR = 't',
 
         /* These ones take globs */
         WRITE_FILE = 'w',
 
         /* These ones take globs */
         WRITE_FILE = 'w',
@@ -88,6 +90,7 @@ typedef struct Item {
 
         char *path;
         char *argument;
 
         char *path;
         char *argument;
+        char **xattrs;
         uid_t uid;
         gid_t gid;
         mode_t mode;
         uid_t uid;
         gid_t gid;
         mode_t mode;
@@ -487,6 +490,67 @@ static int item_set_perms(Item *i, const char *path) {
         return label_fix(path, false, false);
 }
 
         return label_fix(path, false, false);
 }
 
+static int get_xattrs_from_arg(Item *i) {
+        char *xattr;
+        const char *p;
+        int r;
+
+        assert(i);
+
+        if (!i->argument) {
+                log_error("%s: Argument can't be empty!", i->path);
+                return -EBADMSG;
+        }
+        p = i->argument;
+
+        while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
+                _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
+                r = split_pair(xattr, "=", &name, &value);
+                if (r < 0) {
+                        log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
+                        free(xattr);
+                        continue;
+                }
+                free(xattr);
+                if (streq(name, "") || streq(value, "")) {
+                        log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
+                        continue;
+                }
+                tmp = unquote(value, "\"");
+                if (!tmp)
+                        return log_oom();
+                free(value);
+                value = cunescape(tmp);
+                if (!value)
+                        return log_oom();
+                if (strv_consume_pair(&i->xattrs, name, value) < 0)
+                        return log_oom();
+                name = value = NULL;
+        }
+
+        return r;
+}
+
+static int item_set_xattrs(Item *i, const char *path) {
+        char **name, **value;
+
+        assert(i);
+        assert(path);
+
+        if (strv_isempty(i->xattrs))
+                return 0;
+
+        STRV_FOREACH_PAIR(name, value, i->xattrs) {
+                int n;
+                n = strlen(*value);
+                if (lsetxattr(path, *name, *value, n, 0) < 0) {
+                        log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
+                        return -errno;
+                }
+        }
+        return 0;
+}
+
 static int write_one_file(Item *i, const char *path) {
         _cleanup_close_ int fd = -1;
         int flags, r = 0;
 static int write_one_file(Item *i, const char *path) {
         _cleanup_close_ int fd = -1;
         int flags, r = 0;
@@ -544,6 +608,10 @@ static int write_one_file(Item *i, const char *path) {
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+        r = item_set_xattrs(i, i->path);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
         return 0;
 }
 
@@ -716,6 +784,10 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
                 if (r < 0)
                         return r;
 
+                r = item_set_xattrs(i, i->path);
+                if (r < 0)
+                        return r;
+
                 break;
 
         case CREATE_FIFO:
                 break;
 
         case CREATE_FIFO:
@@ -756,6 +828,10 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
                 if (r < 0)
                         return r;
 
+                r = item_set_xattrs(i, i->path);
+                if (r < 0)
+                        return r;
+
                 break;
 
         case CREATE_SYMLINK:
                 break;
 
         case CREATE_SYMLINK:
@@ -787,6 +863,10 @@ static int create_item(Item *i) {
                         }
                 }
 
                         }
                 }
 
+                r = item_set_xattrs(i, i->path);
+                if (r < 0)
+                       return r;
+
                 break;
 
         case CREATE_BLOCK_DEVICE:
                 break;
 
         case CREATE_BLOCK_DEVICE:
@@ -847,6 +927,10 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
                 if (r < 0)
                         return r;
 
+                r = item_set_xattrs(i, i->path);
+                if (r < 0)
+                        return r;
+
                 break;
         }
 
                 break;
         }
 
@@ -863,7 +947,12 @@ static int create_item(Item *i) {
                 r = glob_item(i, item_set_perms_recursive);
                 if (r < 0)
                         return r;
                 r = glob_item(i, item_set_perms_recursive);
                 if (r < 0)
                         return r;
+                break;
 
 
+        case SET_XATTR:
+                r = item_set_xattrs(i, i->path);
+                if (r < 0)
+                        return r;
                 break;
         }
 
                 break;
         }
 
@@ -893,6 +982,7 @@ static int remove_item_instance(Item *i, const char *instance) {
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
         case COPY_FILES:
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
         case COPY_FILES:
+        case SET_XATTR:
                 break;
 
         case REMOVE_PATH:
                 break;
 
         case REMOVE_PATH:
@@ -936,6 +1026,7 @@ static int remove_item(Item *i) {
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
         case COPY_FILES:
         case RECURSIVE_RELABEL_PATH:
         case WRITE_FILE:
         case COPY_FILES:
+        case SET_XATTR:
                 break;
 
         case REMOVE_PATH:
                 break;
 
         case REMOVE_PATH:
@@ -1059,6 +1150,7 @@ static void item_free(Item *i) {
 
         free(i->path);
         free(i->argument);
 
         free(i->path);
         free(i->argument);
+        strv_free(i->xattrs);
         free(i);
 }
 
         free(i);
 }
 
@@ -1257,6 +1349,16 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 break;
         }
 
                 break;
         }
 
+        case SET_XATTR:
+                if (!i->argument) {
+                        log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
+                        return -EBADMSG;
+                }
+                r = get_xattrs_from_arg(i);
+                if (r < 0)
+                        return r;
+                break;
+
         default:
                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
                 return -EBADMSG;
         default:
                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
                 return -EBADMSG;
@@ -1350,18 +1452,35 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         existing = hashmap_get(h, i->path);
         if (existing) {
 
         existing = hashmap_get(h, i->path);
         if (existing) {
-
-                /* Two identical items are fine */
-                if (!item_equal(existing, i))
-                        log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
-
-                return 0;
+                if (i->type == SET_XATTR) {
+                        r = strv_extend_strv(&existing->xattrs, i->xattrs);
+                        if (r < 0)
+                                return log_oom();
+                        return 0;
+                } else if (existing->type == SET_XATTR) {
+                        r = strv_extend_strv(&i->xattrs, existing->xattrs);
+                        if (r < 0)
+                                return log_oom();
+                        r = hashmap_replace(h, i->path, i);
+                        if (r < 0) {
+                                log_error("Failed to replace item for %s.", i->path);
+                                return r;
+                        }
+                        item_free(existing);
+                } else {
+                        /* Two identical items are fine */
+                        if (!item_equal(existing, i))
+                                log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
+                        return 0;
+                }
+        } else {
+                r = hashmap_put(h, i->path, i);
+                if (r < 0) {
+                        log_error("Failed to insert item %s: %s", i->path, strerror(-r));
+                        return r;
+                }
         }
 
         }
 
-        r = hashmap_put(h, i->path, i);
-        if (r < 0)
-                return log_error_errno(r, "Failed to insert item %s: %m", i->path);
-
         i = NULL; /* avoid cleanup */
 
         return 0;
         i = NULL; /* avoid cleanup */
 
         return 0;