X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fcore%2Fload-fragment.c;h=a4e39a84eab5982fb13d4d72d6e68402f18916b3;hb=c05f3c8ff8961c1431014b684586df3c9fbf791b;hp=15d392cdde3521f5aaf0f685265b4c81b6efa576;hpb=53f47dfc7b0b1e31878f7a17848fd925b1ab3c03;p=thirdparty%2Fsystemd.git diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 15d392cdde3..a4e39a84eab 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -22,7 +22,7 @@ #include #include #include -#ifdef HAVE_SECCOMP +#if HAVE_SECCOMP #include #endif #include @@ -54,10 +54,11 @@ #include "path-util.h" #include "process-util.h" #include "rlimit-util.h" -#ifdef HAVE_SECCOMP +#if HAVE_SECCOMP #include "seccomp-util.h" #endif #include "securebits.h" +#include "securebits-util.h" #include "signal-util.h" #include "stat-util.h" #include "string-util.h" @@ -282,6 +283,11 @@ int config_parse_unit_path_strv_printf( assert(rvalue); assert(u); + if (isempty(rvalue)) { + *x = strv_free(*x); + return 0; + } + for (p = rvalue;;) { _cleanup_free_ char *word = NULL, *k = NULL; @@ -607,7 +613,8 @@ int config_parse_exec( p = rvalue; do { _cleanup_free_ char *path = NULL, *firstword = NULL; - bool separate_argv0 = false, ignore = false, privileged = false; + ExecCommandFlags flags = 0; + bool ignore = false, separate_argv0 = false; _cleanup_free_ ExecCommand *nce = NULL; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; @@ -621,18 +628,31 @@ int config_parse_exec( f = firstword; for (;;) { - /* We accept an absolute path as first argument. - * If it's prefixed with - and the path doesn't exist, - * we ignore it instead of erroring out; - * if it's prefixed with @, we allow overriding of argv[0]; - * and if it's prefixed with +, it will be run with full privileges */ - if (*f == '-' && !ignore) + /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't + * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of + * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if + * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if + * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient + * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most + * other sandboxing, with some special exceptions for changing UID. + * + * The idea is that '!!' may be used to write services that can take benefit of systemd's + * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to + * privilege dropping within the daemon if the kernel does not offer that. */ + + if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) { + flags |= EXEC_COMMAND_IGNORE_FAILURE; ignore = true; - else if (*f == '@' && !separate_argv0) + } else if (*f == '@' && !separate_argv0) separate_argv0 = true; - else if (*f == '+' && !privileged) - privileged = true; - else + else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) + flags |= EXEC_COMMAND_FULLY_PRIVILEGED; + else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) + flags |= EXEC_COMMAND_NO_SETUID; + else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) { + flags &= ~EXEC_COMMAND_NO_SETUID; + flags |= EXEC_COMMAND_AMBIENT_MAGIC; + } else break; f++; } @@ -751,8 +771,7 @@ int config_parse_exec( nce->argv = n; nce->path = path; - nce->ignore = ignore; - nce->privileged = privileged; + nce->flags = flags; exec_command_append_list(e, nce); @@ -1094,7 +1113,6 @@ int config_parse_exec_secure_bits(const char *unit, void *userdata) { ExecContext *c = data; - const char *p; int r; assert(filename); @@ -1108,38 +1126,18 @@ int config_parse_exec_secure_bits(const char *unit, return 0; } - for (p = rvalue;;) { - _cleanup_free_ char *word = NULL; + r = secure_bits_from_string(rvalue); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } + c->secure_bits = r; - if (streq(word, "keep-caps")) - c->secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1< replace */ - *capability_set = sum; - else + /* "", "~" or uninitialized data -> replace */ + *capability_set = invert ? ~sum : sum; + else { /* previous data -> merge */ - *capability_set |= sum; + if (invert) + *capability_set &= ~sum; + else + *capability_set |= sum; + } return 0; } @@ -1250,7 +1234,7 @@ int config_parse_limit( return 0; } -#ifdef HAVE_SYSV_COMPAT +#if HAVE_SYSV_COMPAT int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, @@ -1972,15 +1956,7 @@ int config_parse_user_group_strv( assert(u); if (isempty(rvalue)) { - char **empty; - - empty = new0(char*, 1); - if (!empty) - return log_oom(); - - strv_free(*users); - *users = empty; - + *users = strv_free(*users); return 0; } @@ -2019,115 +1995,6 @@ int config_parse_user_group_strv( return 0; } -int config_parse_busname_service( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - BusName *n = data; - int r; - Unit *x; - _cleanup_free_ char *p = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = unit_name_printf(UNIT(n), rvalue, &p); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); - return 0; - } - - if (!endswith(p, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue); - return 0; - } - - r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); - return 0; - } - - unit_ref_set(&n->service, x); - - return 0; -} - -DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access"); - -int config_parse_bus_policy( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_free_ BusNamePolicy *p = NULL; - _cleanup_free_ char *id_str = NULL; - BusName *busname = data; - char *access_str; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - p = new0(BusNamePolicy, 1); - if (!p) - return log_oom(); - - if (streq(lvalue, "AllowUser")) - p->type = BUSNAME_POLICY_TYPE_USER; - else if (streq(lvalue, "AllowGroup")) - p->type = BUSNAME_POLICY_TYPE_GROUP; - else - assert_not_reached("Unknown lvalue"); - - id_str = strdup(rvalue); - if (!id_str) - return log_oom(); - - access_str = strpbrk(id_str, WHITESPACE); - if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue); - return 0; - } - - *access_str = '\0'; - access_str++; - access_str += strspn(access_str, WHITESPACE); - - p->access = bus_policy_access_from_string(access_str); - if (p->access < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str); - return 0; - } - - p->name = id_str; - id_str = NULL; - - LIST_PREPEND(policy, busname->policy, p); - p = NULL; - - return 0; -} - int config_parse_working_directory( const char *unit, const char *filename, @@ -2238,16 +2105,17 @@ int config_parse_unit_env_file(const char *unit, return 0; } -int config_parse_environ(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_environ( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Unit *u = userdata; char ***env = data; @@ -2283,7 +2151,7 @@ int config_parse_environ(const char *unit, r = unit_full_printf(u, word, &k); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to resolve specifiers, ignoring: %s", k); + "Failed to resolve specifiers, ignoring: %s", word); continue; } } else { @@ -2300,25 +2168,28 @@ int config_parse_environ(const char *unit, r = strv_env_replace(env, k); if (r < 0) return log_oom(); + k = NULL; } } -int config_parse_pass_environ(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_pass_environ( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { const char *whole_rvalue = rvalue; - char*** passenv = data; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; + char*** passenv = data; + Unit *u = userdata; int r; assert(filename); @@ -2333,7 +2204,7 @@ int config_parse_pass_environ(const char *unit, } for (;;) { - _cleanup_free_ char *word = NULL; + _cleanup_free_ char *word = NULL, *k = NULL; r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES); if (r == 0) @@ -2346,17 +2217,30 @@ int config_parse_pass_environ(const char *unit, break; } - if (!env_name_is_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid environment name for %s, ignoring: %s", lvalue, word); + if (u) { + r = unit_full_printf(u, word, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to resolve specifiers, ignoring: %s", word); + continue; + } + } else { + k = word; + word = NULL; + } + + if (!env_name_is_valid(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid environment name for %s, ignoring: %s", lvalue, k); continue; } if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) return log_oom(); - n[nlen++] = word; + + n[nlen++] = k; n[nlen] = NULL; - word = NULL; + k = NULL; } if (n) { @@ -2368,6 +2252,85 @@ int config_parse_pass_environ(const char *unit, return 0; } +int config_parse_unset_environ( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_strv_free_ char **n = NULL; + const char *whole_rvalue = rvalue; + size_t nlen = 0, nbufsize = 0; + char*** unsetenv = data; + Unit *u = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *unsetenv = strv_free(*unsetenv); + return 0; + } + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue); + break; + } + + if (u) { + r = unit_full_printf(u, word, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to resolve specifiers, ignoring: %s", word); + continue; + } + } else { + k = word; + word = NULL; + } + + if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid environment name or assignment %s, ignoring: %s", lvalue, k); + continue; + } + + if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) + return log_oom(); + + n[nlen++] = k; + n[nlen] = NULL; + k = NULL; + } + + if (n) { + r = strv_extend_strv(unsetenv, n, true); + if (r < 0) + return r; + } + + return 0; +} + int config_parse_ip_tos(const char *unit, const char *filename, unsigned line, @@ -2660,7 +2623,7 @@ int config_parse_documentation(const char *unit, return r; } -#ifdef HAVE_SECCOMP +#if HAVE_SECCOMP static int syscall_filter_parse_one( const char *unit, @@ -3703,7 +3666,7 @@ int config_parse_job_mode_isolate( DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode"); -int config_parse_runtime_directory( +int config_parse_exec_directories( const char *unit, const char *filename, unsigned line, @@ -3735,8 +3698,6 @@ int config_parse_runtime_directory( _cleanup_free_ char *word = NULL, *k = NULL; r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r == 0) - return 0; if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -3744,6 +3705,8 @@ int config_parse_runtime_directory( "Invalid syntax, ignoring: %s", rvalue); return 0; } + if (r == 0) + return 0; r = unit_full_printf(u, word, &k); if (r < 0) { @@ -3752,9 +3715,9 @@ int config_parse_runtime_directory( continue; } - if (!filename_is_valid(k)) { + if (!path_is_safe(k) || path_is_absolute(k)) { log_syntax(unit, LOG_ERR, filename, line, 0, - "Runtime directory is not valid, ignoring assignment: %s", rvalue); + "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue); continue; } @@ -4180,6 +4143,80 @@ int config_parse_protect_system( return 0; } +DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode"); + +int config_parse_job_timeout_sec( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = data; + usec_t usec; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = parse_sec_fix_0(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue); + return 0; + } + + /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old + * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should + * count. */ + + if (!u->job_running_timeout_set) + u->job_running_timeout = usec; + + u->job_timeout = usec; + + return 0; +} + +int config_parse_job_running_timeout_sec( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = data; + usec_t usec; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = parse_sec_fix_0(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue); + return 0; + } + + u->job_running_timeout = usec; + u->job_running_timeout_set = true; + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { @@ -4519,7 +4556,7 @@ void unit_dump_config_items(FILE *f) { const ConfigParserCallback callback; const char *rvalue; } table[] = { -#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR) +#if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR { config_parse_warn_compat, "NOTSUPPORTED" }, #endif { config_parse_int, "INTEGER" }, @@ -4552,7 +4589,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_exec, "PATH [ARGUMENT [...]]" }, { config_parse_service_type, "SERVICETYPE" }, { config_parse_service_restart, "SERVICERESTART" }, -#ifdef HAVE_SYSV_COMPAT +#if HAVE_SYSV_COMPAT { config_parse_sysv_priority, "SYSVPRIORITY" }, #endif { config_parse_kill_mode, "KILLMODE" }, @@ -4582,7 +4619,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_set_status, "STATUS" }, { config_parse_service_sockets, "SOCKETS" }, { config_parse_environ, "ENVIRON" }, -#ifdef HAVE_SECCOMP +#if HAVE_SECCOMP { config_parse_syscall_filter, "SYSCALLS" }, { config_parse_syscall_archs, "ARCHS" }, { config_parse_syscall_errno, "ERRNO" }, @@ -4602,7 +4639,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_blockio_device_weight, "DEVICEWEIGHT" }, { config_parse_long, "LONG" }, { config_parse_socket_service, "SERVICE" }, -#ifdef HAVE_SELINUX +#if HAVE_SELINUX { config_parse_exec_selinux_context, "LABEL" }, #endif { config_parse_job_mode, "MODE" },