diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-03-28 16:44:19 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2018-03-29 15:45:02 +0200 |
commit | d04a93864dec3f7cd80018994be03dc82b30a474 (patch) | |
tree | 69bad694d9acda5428b369fb4478fec0790d4c16 /src/shared/install.c | |
parent | 244d2f07b49e3470d679fdd0f6ebd24fac8d5dc7 (diff) | |
download | systemd-d04a93864dec3f7cd80018994be03dc82b30a474.tar.gz |
install: don't enforce that .d/ dropin files (and their symlink chain elements) for units must have names that qualify as unit names
The names of drop-in files can be anything as long as they are suffixed
in ".conf", hence don't be stricter than necessary when validating the
names used in symlink chains of such drop-in files.
Also, drop-in files should not be ale to change the type of unit file
itself, i.e. not affect whether it is considered masked or an alias as a
whole.
This adds a flag SEARCH_DROPIN that is passed whenever we load a drop-in
rather the main unit file, and in that case loosen checks and behaviour
we otherwise enforce for the unit file itself. Specifically:
1. If SEARCH_DROPIN is passed we won't change the unit's info->type
field anymore, as that field (which can be REGULAR, MASKED, SYMLINK)
should not be affected by drop-ins, but only by the unit file itself.
2. If SEARCH_DROPIN is passed we will shortcut following of symlink
chains, and not validate the naming of each element in the chain,
since that's irrelevant for drop-ins, and only matters for the unit
file itself.
Or in other words, without this:
1. A symlink /etc/systemd/system/foobar.service.d/20-quux.conf →
/dev/null might have caused the whole of foobar.service to be
considered "masked".
2. A symlink /etc/systemd/system/foobar.service.d/20-quux.conf →
/tmp/miepf might have caused the whole loading of foobar.service to
fail as EINVAL, as "miepf" is not a valid unit name.
Diffstat (limited to 'src/shared/install.c')
-rw-r--r-- | src/shared/install.c | 98 |
1 files changed, 58 insertions, 40 deletions
diff --git a/src/shared/install.c b/src/shared/install.c index 7506018d41..477e15a4da 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -59,8 +59,9 @@ #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 typedef enum SearchFlags { - SEARCH_LOAD = 1, - SEARCH_FOLLOW_CONFIG_SYMLINKS = 2, + SEARCH_LOAD = 1U << 0, + SEARCH_FOLLOW_CONFIG_SYMLINKS = 1U << 1, + SEARCH_DROPIN = 1U << 2, } SearchFlags; typedef struct { @@ -1228,6 +1229,7 @@ static int unit_file_load( InstallContext *c, UnitFileInstallInfo *info, const char *path, + const char *root_dir, SearchFlags flags) { const ConfigTableItem items[] = { @@ -1248,40 +1250,57 @@ static int unit_file_load( assert(info); assert(path); - type = unit_name_to_type(info->name); - if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && - !unit_type_may_template(type)) - return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type)); + if (!(flags & SEARCH_DROPIN)) { + /* Loading or checking for the main unit file… */ - if (!(flags & SEARCH_LOAD)) { - r = lstat(path, &st); - if (r < 0) + type = unit_name_to_type(info->name); + if (type < 0) + return -EINVAL; + if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type)) { + log_error("Unit type %s cannot be templated.", unit_type_to_string(type)); + return -EINVAL; + } + + if (!(flags & SEARCH_LOAD)) { + r = lstat(path, &st); + if (r < 0) + return -errno; + + if (null_or_empty(&st)) + info->type = UNIT_FILE_TYPE_MASKED; + else if (S_ISREG(st.st_mode)) + info->type = UNIT_FILE_TYPE_REGULAR; + else if (S_ISLNK(st.st_mode)) + return -ELOOP; + else if (S_ISDIR(st.st_mode)) + return -EISDIR; + else + return -ENOTTY; + + return 0; + } + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) return -errno; + } else { + /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */ - if (null_or_empty(&st)) - info->type = UNIT_FILE_TYPE_MASKED; - else if (S_ISREG(st.st_mode)) - info->type = UNIT_FILE_TYPE_REGULAR; - else if (S_ISLNK(st.st_mode)) - return -ELOOP; - else if (S_ISDIR(st.st_mode)) - return -EISDIR; - else - return -ENOTTY; + if (!(flags & SEARCH_LOAD)) + return 0; - return 0; + fd = chase_symlinks_and_open(path, root_dir, 0, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); + if (fd < 0) + return fd; } - /* c is only needed if we actually load the file */ - assert(c); - - fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; if (fstat(fd, &st) < 0) return -errno; + if (null_or_empty(&st)) { - info->type = UNIT_FILE_TYPE_MASKED; + if ((flags & SEARCH_DROPIN) == 0) + info->type = UNIT_FILE_TYPE_MASKED; + return 0; } @@ -1294,6 +1313,9 @@ static int unit_file_load( return -errno; fd = -1; + /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */ + assert(c); + r = config_parse(info->name, path, f, NULL, config_item_table_lookup, items, @@ -1301,7 +1323,8 @@ static int unit_file_load( if (r < 0) return log_debug_errno(r, "Failed to parse %s: %m", info->name); - info->type = UNIT_FILE_TYPE_REGULAR; + if ((flags & SEARCH_DROPIN) == 0) + info->type = UNIT_FILE_TYPE_REGULAR; return (int) strv_length(info->aliases) + @@ -1319,8 +1342,8 @@ static int unit_file_load_or_readlink( _cleanup_free_ char *target = NULL; int r; - r = unit_file_load(c, info, path, flags); - if (r != -ELOOP) + r = unit_file_load(c, info, path, root_dir, flags); + if (r != -ELOOP || (flags & SEARCH_DROPIN)) return r; /* This is a symlink, let's read it. */ @@ -1383,16 +1406,12 @@ static int unit_file_search( const LookupPaths *paths, SearchFlags flags) { + const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL; + _cleanup_strv_free_ char **dirs = NULL, **files = NULL; _cleanup_free_ char *template = NULL; - _cleanup_strv_free_ char **dirs = NULL; - _cleanup_strv_free_ char **files = NULL; - const char *dropin_dir_name = NULL; - const char *dropin_template_dir_name = NULL; - - char **p; - int r; - int result; bool found_unit = false; + int r, result; + char **p; assert(info); assert(paths); @@ -1420,7 +1439,6 @@ static int unit_file_search( return -ENOMEM; r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); - if (r >= 0) { info->path = TAKE_PTR(path); result = r; @@ -1499,7 +1517,7 @@ static int unit_file_search( return log_debug_errno(r, "Failed to get list of conf files: %m"); STRV_FOREACH(p, files) { - r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags); + r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN); if (r < 0) return log_debug_errno(r, "Failed to load conf file %s: %m", *p); } |