X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=blobdiff_plain;f=src%2Fshared%2Fbus-unit-util.c;h=87e2e597e29ac85f2573863c02dc04986fbd8929;hp=7e446cbc84ddebf8caf977986752461a51695051;hb=53e1b683907c2f12330f00feb9630150196f064d;hpb=3cdd4e487e828bb45a83e06c6c76f6aa27b9c7e0 diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 7e446cbc84d..87e2e597e29 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -21,10 +22,15 @@ #include "bus-internal.h" #include "bus-unit-util.h" #include "bus-util.h" +#include "cap-list.h" #include "cgroup-util.h" +#include "cpu-set-util.h" #include "env-util.h" +#include "errno-list.h" #include "escape.h" #include "hashmap.h" +#include "hostname-util.h" +#include "in-addr-util.h" #include "list.h" #include "locale-util.h" #include "mount-util.h" @@ -33,10 +39,12 @@ #include "path-util.h" #include "process-util.h" #include "rlimit-util.h" +#include "securebits-util.h" #include "signal-util.h" #include "string-util.h" #include "syslog-util.h" #include "terminal-util.h" +#include "user-util.h" #include "utf8.h" #include "util.h" @@ -61,6 +69,31 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { &u->job_path); } +static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) { + int r; + + assert(m); + assert(prefix); + + r = sd_bus_message_open_container(m, 'r', "iayu"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "i", family); + if (r < 0) + return r; + + r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family)); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "u", prefixlen); + if (r < 0) + return r; + + return sd_bus_message_close_container(m); +} + int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { const char *eq, *field; UnitDependency dep; @@ -124,6 +157,31 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", n, "t", t); goto finish; + } else if (streq(field, "LogExtraFields")) { + + r = sd_bus_message_append(m, "s", "LogExtraFields"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'v', "aay"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'a', "ay"); + if (r < 0) + goto finish; + + r = sd_bus_message_append_array(m, 'y', eq, strlen(eq)); + if (r < 0) + goto finish; + + r = sd_bus_message_close_container(m); + if (r < 0) + goto finish; + + r = sd_bus_message_close_container(m); + goto finish; + } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { uint64_t bytes; @@ -151,6 +209,51 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", field, "t", bytes); goto finish; + + } else if (streq(field, "Delegate")) { + + r = parse_boolean(eq); + if (r < 0) { + const char *p = eq; + + r = sd_bus_message_append(m, "s", "DelegateControllers"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + goto finish; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Invalid syntax: %s", eq); + + r = sd_bus_message_append(m, "s", word); + if (r < 0) + goto finish; + } + + r = sd_bus_message_close_container(m); + if (r < 0) + goto finish; + + r = sd_bus_message_close_container(m); + } else + r = sd_bus_message_append(m, "sv", "Delegate", "b", r); + + goto finish; + } else if (streq(field, "TasksMax")) { uint64_t t; @@ -202,13 +305,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); } else if (STR_IN_SET(field, - "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting", - "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", - "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", - "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "NoNewPrivileges", - "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute", - "RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables", - "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS")) { + "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", + "TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", + "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", + "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", + "NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse", + "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", + "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS", + "CPUSchedulingResetOnFork", "LockPersonality")) { r = parse_boolean(eq); if (r < 0) @@ -267,10 +371,25 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "Description", "Slice", "Type", "WorkingDirectory", "RootDirectory", "SyslogIdentifier", "ProtectSystem", "ProtectHome", "SELinuxContext", "Restart", "RootImage", - "NotifyAccess")) + "NotifyAccess", "RuntimeDirectoryPreserve", "Personality", + "KeyringMode", "CollectMode")) r = sd_bus_message_append(m, "v", "s", eq); - else if (streq(field, "SyslogLevel")) { + else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) { + bool ignore; + const char *s; + + if (eq[0] == '-') { + ignore = true; + s = eq + 1; + } else { + ignore = false; + s = eq; + } + + r = sd_bus_message_append(m, "v", "(bs)", ignore, s); + + } else if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax")) { int level; level = log_level_from_string(eq); @@ -292,6 +411,37 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", facility); + } else if (streq(field, "SecureBits")) { + + r = secure_bits_from_string(eq); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", r); + + } else if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) { + uint64_t sum = 0; + bool invert = false; + const char *p; + + p = eq; + if (*p == '~') { + invert = true; + p++; + } + + r = capability_set_from_string(p, &sum); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + sum = invert ? ~sum : sum; + + r = sd_bus_message_append(m, "v", "t", sum); + } else if (streq(field, "DeviceAllow")) { if (isempty(eq)) @@ -381,6 +531,135 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "a(st)", 1, path, u); } + } else if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(iayu)", 0); + else { + unsigned char prefixlen; + union in_addr_union prefix = {}; + int family; + + r = sd_bus_message_open_container(m, 'v', "a(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + if (streq(eq, "any")) { + /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */ + + r = bus_append_ip_address_access(m, AF_INET, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + } else if (is_localhost(eq)) { + /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */ + + prefix.in.s_addr = htobe32(0x7f000000); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128); + if (r < 0) + return r; + + } else if (streq(eq, "link-local")) { + + /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */ + + prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 16); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xfe800000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64); + if (r < 0) + return bus_log_create_error(r); + + } else if (streq(eq, "multicast")) { + + /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */ + + prefix.in.s_addr = htobe32((UINT32_C(224) << 24)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 4); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xff000000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + } else { + r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen); + if (r < 0) + return log_error_errno(r, "Failed to parse IP address prefix: %s", eq); + + r = bus_append_ip_address_access(m, family, &prefix, prefixlen); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + } else if (streq(field, "CPUSchedulingPolicy")) { + int n; + + n = sched_policy_from_string(eq); + if (n < 0) + return log_error_errno(r, "Failed to parse CPUSchedulingPolicy: %s", eq); + + r = sd_bus_message_append(m, "v", "i", (int32_t) n); + + } else if (streq(field, "CPUSchedulingPriority")) { + int n; + + r = safe_atoi(eq, &n); + if (r < 0) + return log_error_errno(r, "Failed to parse CPUSchedulingPriority: %s", eq); + if (!sched_priority_is_valid(n)) + return log_error_errno(r, "Invalid CPUSchedulingPriority: %s", eq); + + r = sd_bus_message_append(m, "v", "i", (int32_t) n); + + } else if (streq(field, "CPUAffinity")) { + _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; + int ncpus; + + ncpus = parse_cpu_set(eq, &cpuset); + if (ncpus < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + + r = sd_bus_message_open_container(m, 'v', "ay"); + if (r < 0) + return bus_log_create_error(r); + + if (cpuset) + sd_bus_message_append_array(m, 'y', cpuset, CPU_ALLOC_SIZE(ncpus)); + + r = sd_bus_message_close_container(m); + } else if (streq(field, "Nice")) { int n; @@ -390,6 +669,153 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", (int32_t) n); +#if HAVE_SECCOMP + + } else if (streq(field, "SystemCallFilter")) { + int whitelist; + _cleanup_strv_free_ char **l = NULL; + const char *p; + + p = eq; + if (*p == '~') { + whitelist = 0; + p++; + } else + whitelist = 1; + + if (whitelist != 0) { + r = strv_extend(&l, "@default"); + if (r < 0) + return log_oom(); + } + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + if (r == 0) + break; + + r = strv_extend(&l, word); + if (r < 0) + return log_oom(); + } + + r = sd_bus_message_open_container(m, 'v', "(bas)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'r', "bas"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 'b', &whitelist); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, l); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + } else if (streq(field, "SystemCallArchitectures")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + for (p = eq;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + if (r == 0) + break; + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (streq(field, "SystemCallErrorNumber")) { + int n; + + n = parse_errno(eq); + if (n <= 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + + r = sd_bus_message_append(m, "v", "i", (int32_t) n); + + } else if (streq(field, "RestrictAddressFamilies")) { + int whitelist; + _cleanup_strv_free_ char **l = NULL; + const char *p = eq; + + if (*p == '~') { + whitelist = 0; + p++; + } else + whitelist = 1; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + if (r == 0) + break; + + r = strv_extend(&l, word); + if (r < 0) + return log_oom(); + } + + r = sd_bus_message_open_container(m, 'v', "(bas)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'r', "bas"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 'b', &whitelist); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, l); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); +#endif } else if (streq(field, "FileDescriptorStoreMax")) { unsigned u; @@ -399,7 +825,25 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "u", (uint32_t) u); - } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) { + } else if (streq(field, "IOSchedulingClass")) { + int c; + + c = ioprio_class_from_string(eq); + if (c < 0) + return log_error_errno(r, "Failed to parse IO scheduling class: %s", eq); + + r = sd_bus_message_append(m, "v", "i", (int32_t) c); + + } else if (streq(field, "IOSchedulingPriority")) { + int q; + + r = ioprio_parse_priority(eq, &q); + if (r < 0) + return log_error_errno(r, "Failed to parse IO scheduling priority: %s", eq); + + r = sd_bus_message_append(m, "v", "i", (int32_t) q); + + } else if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment")) { const char *p; r = sd_bus_message_open_container(m, 'v', "as"); @@ -426,6 +870,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen log_error("Invalid environment assignment: %s", word); return -EINVAL; } + } else if (streq(field, "UnsetEnvironment")) { + if (!env_assignment_is_valid(word) && !env_name_is_valid(word)) { + log_error("Invalid environment name or assignment: %s", word); + return -EINVAL; + } } else { /* PassEnvironment */ if (!env_name_is_valid(word)) { log_error("Invalid environment variable name: %s", word); @@ -530,7 +979,54 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_close_container(m); - } else if (streq(field, "RuntimeDirectory")) { + } else if (streq(field, "SupplementaryGroups")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + for (p = eq;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + if (r == 0) + break; + + if (!valid_user_group_name_or_id(word)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (STR_IN_SET(field, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) { + mode_t mode; + + r = parse_mode(eq, &mode); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s", field, eq); + + r = sd_bus_message_append(m, "v", "u", mode); + + } else if (STR_IN_SET(field, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) { const char *p; r = sd_bus_message_open_container(m, 'v', "as"); @@ -545,9 +1041,10 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) + return log_oom(); if (r < 0) return log_error_errno(r, "Failed to parse %s value %s", field, eq); - if (r == 0) break; @@ -838,6 +1335,9 @@ static int bus_job_get_service_result(BusWaitForJobs *d, char **result) { assert(d->name); assert(result); + if (!endswith(d->name, ".service")) + return -EINVAL; + dbus_path = unit_dbus_path_from_name(d->name); if (!dbus_path) return -ENOMEM; @@ -872,7 +1372,7 @@ static void log_job_error_with_service_result(const char* service, const char *r service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH); - if (extra_args) { + if (!strv_isempty((char**) extra_args)) { _cleanup_free_ char *t; t = strv_join((char**) extra_args, " "); @@ -935,14 +1435,14 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* log_error("Operation on or unit type of %s not supported on this system.", strna(d->name)); else if (streq(d->result, "collected")) log_error("Queued job for %s was garbage collected.", strna(d->name)); - else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { + else if (!STR_IN_SET(d->result, "done", "skipped")) { if (d->name) { - int q; _cleanup_free_ char *result = NULL; + int q; q = bus_job_get_service_result(d, &result); if (q < 0) - log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name); + log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name); log_job_error_with_service_result(d->name, result, extra_args); } else @@ -962,7 +1462,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* r = -EPROTO; else if (streq(d->result, "unsupported")) r = -EOPNOTSUPP; - else if (!streq(d->result, "done") && !streq(d->result, "skipped")) + else if (!STR_IN_SET(d->result, "done", "skipped")) r = -EIO; return r; @@ -1053,7 +1553,7 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un if (r < 0) return bus_log_parse_error(r); - unit_file_dump_changes(0, NULL, *changes, *n_changes, false); + unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet); return 0; }