X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftmpfiles%2Ftmpfiles.c;h=3c8993e8942f7b6736cac91d9a958021621941bc;hb=50d9e46dbb8400d4570781728c63b151d9ca982b;hp=c44dfaf1d22dd3c17df6e58d9ddc1e84a0cad1d9;hpb=3f93da987961c139215d3a55fd25496310537d1b;p=elogind.git diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index c44dfaf1d..3c8993e89 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -57,6 +57,7 @@ #include "copy.h" #include "selinux-util.h" #include "btrfs-util.h" +#include "acl-util.h" /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates * them in the file system. This is intended to be used to create @@ -75,9 +76,12 @@ typedef enum ItemType { CREATE_CHAR_DEVICE = 'c', CREATE_BLOCK_DEVICE = 'b', COPY_FILES = 'C', - SET_XATTR = 't', /* 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', @@ -94,6 +98,10 @@ typedef struct Item { char *path; char *argument; char **xattrs; +#ifdef HAVE_ACL + acl_t acl_access; + acl_t acl_default; +#endif uid_t uid; gid_t gid; mode_t mode; @@ -145,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) { @@ -480,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; @@ -562,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); @@ -581,6 +593,75 @@ static int item_set_xattrs(Item *i, const char *path) { return 0; } +static int get_acls_from_arg(Item *item) { +#ifdef HAVE_ACL + int r; + _cleanup_(acl_freep) acl_t a = NULL, d = NULL; + + assert(item); + + /* 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); +#else + log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring"); +#endif + + 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; + + assert(item); + assert(path); + + if (item->acl_access) { + r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force); + if (r < 0) + return r; + } + + if (item->acl_default) { + r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force); + if (r < 0) + return r; + } +#endif + + return 0; +} + static int write_one_file(Item *i, const char *path) { _cleanup_close_ int fd = -1; int flags, r = 0; @@ -634,14 +715,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; @@ -676,12 +759,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; } @@ -690,42 +773,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; @@ -772,14 +839,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; @@ -816,7 +883,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; @@ -856,7 +923,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; @@ -947,7 +1014,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; @@ -956,21 +1023,37 @@ 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 = 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; @@ -1004,6 +1087,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: @@ -1049,12 +1135,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; } @@ -1121,7 +1210,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; @@ -1190,6 +1279,11 @@ static void item_free_contents(Item *i) { free(i->path); free(i->argument); strv_free(i->xattrs); + +#ifdef HAVE_ACL + acl_free(i->acl_access); + acl_free(i->acl_default); +#endif } static void item_array_free(ItemArray *a) { @@ -1387,6 +1481,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; @@ -1396,6 +1491,17 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return r; break; + case SET_ACL: + case RECURSIVE_SET_ACL: + if (!i.argument) { + log_error("[%s:%u] Set ACLs requires argument.", fname, line); + return -EBADMSG; + } + r = get_acls_from_arg(&i); + if (r < 0) + return r; + break; + default: log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type); return -EBADMSG;