From cffaed83e87bde81378b2be74192193850d0e03a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Aug 2017 00:37:02 +0900 Subject: [PATCH] core: add missing properties in D-Bus API Closes #6466. --- src/core/dbus-execute.c | 459 ++++++++++++++++++++++++++++++++++++- src/shared/bus-unit-util.c | 272 +++++++++++++++++++++- 2 files changed, 717 insertions(+), 14 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 12348d3423..bd4e113bec 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -27,8 +27,10 @@ #include "alloc-util.h" #include "bus-util.h" #include "capability-util.h" +#include "cap-list.h" #include "dbus-execute.h" #include "env-util.h" +#include "errno-list.h" #include "execute.h" #include "fd-util.h" #include "fileio.h" @@ -43,6 +45,7 @@ #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "securebits-util.h" #include "strv.h" #include "syslog-util.h" #include "unit-printf.h" @@ -1028,6 +1031,41 @@ int bus_exec_context_set_transient_property( } return 1; + + } else if (streq(name, "SupplementaryGroups")) { + _cleanup_strv_free_ char **l = NULL; + char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + STRV_FOREACH(p, l) { + if (!isempty(*p) && !valid_user_group_name_or_id(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supplementary group names"); + } + + if (mode != UNIT_CHECK) { + if (strv_length(l) == 0) { + c->supplementary_groups = strv_free(c->supplementary_groups); + unit_write_drop_in_private_format(u, mode, name, "%s=", name); + } else { + _cleanup_free_ char *joined = NULL; + + r = strv_extend_strv(&c->supplementary_groups, l, true); + if (r < 0) + return -ENOMEM; + + joined = strv_join(c->supplementary_groups, " "); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined); + } + } + + return 1; + } else if (streq(name, "SyslogIdentifier")) { const char *id; @@ -1077,6 +1115,361 @@ int bus_exec_context_set_transient_property( unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i", facility); } + return 1; + } else if (streq(name, "SecureBits")) { + int n; + + r = sd_bus_message_read(message, "i", &n); + if (r < 0) + return r; + + if (!secure_bits_is_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid secure bits"); + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *str = NULL; + + c->secure_bits = n; + r = secure_bits_to_string_alloc(n, &str); + if (r < 0) + return r; + + unit_write_drop_in_private_format(u, mode, name, "SecureBits=%s", str); + } + + return 1; + } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) { + uint64_t n; + + r = sd_bus_message_read(message, "t", &n); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *str = NULL; + + if (streq(name, "CapabilityBoundingSet")) + c->capability_bounding_set = n; + else /* "AmbientCapabilities" */ + c->capability_ambient_set = n; + + r = capability_set_to_string_alloc(n, &str); + if (r < 0) + return r; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str); + } + + return 1; + + } else if (streq(name, "Personality")) { + const char *s; + unsigned long p; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + p = personality_from_string(s); + if (p == PERSONALITY_INVALID) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid personality"); + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *str = NULL; + + c->personality = p; + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s); + } + + return 1; + +#ifdef HAVE_SECCOMP + + } else if (streq(name, "SystemCallFilter")) { + int whitelist; + _cleanup_strv_free_ char **l; + + r = sd_bus_message_enter_container(message, 'r', "bas"); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "b", &whitelist); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (strv_length(l) == 0) { + c->syscall_whitelist = false; + c->syscall_filter = set_free(c->syscall_filter); + } else { + char **s; + + c->syscall_whitelist = whitelist; + + r = set_ensure_allocated(&c->syscall_filter, NULL); + if (r < 0) + return r; + + STRV_FOREACH(s, l) { + if (**s == '@') { + const SyscallFilterSet *set; + const char *i; + + set = syscall_filter_set_find(*s); + if (!set) + return -EINVAL; + + NULSTR_FOREACH(i, set->value) { + int id; + + id = seccomp_syscall_resolve_name(i); + if (id == __NR_SCMP_ERROR) + return -EINVAL; + + r = set_put(c->address_families, INT_TO_PTR(id + 1)); + if (r < 0) + return r; + } + + } else { + int id; + + id = seccomp_syscall_resolve_name(*s); + if (id == __NR_SCMP_ERROR) + return -EINVAL; + + r = set_put(c->address_families, INT_TO_PTR(id + 1)); + if (r < 0) + return r; + } + } + } + + joined = strv_join(l, " "); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "SystemCallFilter=%s%s", whitelist ? "" : "~", joined); + } + + return 1; + + } else if (streq(name, "SystemCallArchitectures")) { + _cleanup_strv_free_ char **l = NULL; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (strv_length(l) == 0) + c->syscall_archs = set_free(c->syscall_archs); + else { + char **s; + + r = set_ensure_allocated(&c->syscall_archs, NULL); + if (r < 0) + return r; + + STRV_FOREACH(s, l) { + uint32_t a; + + r = seccomp_arch_from_string(*s, &a); + if (r < 0) + return r; + + r = set_put(c->syscall_archs, UINT32_TO_PTR(a + 1)); + if (r < 0) + return r; + } + + } + + joined = strv_join(l, " "); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined); + } + + return 1; + + } else if (streq(name, "SystemCallErrorNumber")) { + int32_t n; + const char *str; + + r = sd_bus_message_read(message, "i", &n); + if (r < 0) + return r; + + str = errno_to_name(n); + if (!str) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SystemCallErrorNumber"); + + if (mode != UNIT_CHECK) { + c->syscall_errno = n; + + unit_write_drop_in_private_format(u, mode, name, "SystemCallErrorNumber=%s", str); + } + + return 1; + + } else if (streq(name, "RestrictAddressFamilies")) { + int whitelist; + _cleanup_strv_free_ char **l; + + r = sd_bus_message_enter_container(message, 'r', "bas"); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "b", &whitelist); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (strv_length(l) == 0) { + c->address_families_whitelist = false; + c->address_families = set_free(c->address_families); + } else { + char **s; + + c->address_families_whitelist = whitelist; + + r = set_ensure_allocated(&c->address_families, NULL); + if (r < 0) + return r; + + STRV_FOREACH(s, l) { + int af; + + af = af_from_name(*s); + if (af <= 0) + return -EINVAL; + + r = set_put(c->address_families, INT_TO_PTR(af)); + if (r < 0) + return r; + } + } + + joined = strv_join(l, " "); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "RestrictAddressFamilies=%s%s", whitelist ? "" : "~", joined); + } + + return 1; +#endif + + } else if (streq(name, "CPUSchedulingPolicy")) { + int32_t n; + + r = sd_bus_message_read(message, "i", &n); + if (r < 0) + return r; + + if (!sched_policy_is_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy"); + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *str = NULL; + + c->cpu_sched_policy = n; + r = sched_policy_to_string_alloc(n, &str); + if (r < 0) + return r; + + unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPolicy=%s", str); + } + + return 1; + + } else if (streq(name, "CPUSchedulingPriority")) { + int32_t n; + + r = sd_bus_message_read(message, "i", &n); + if (r < 0) + return r; + + if (!ioprio_priority_is_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority"); + + if (mode != UNIT_CHECK) { + c->cpu_sched_priority = n; + unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPriority=%i", n); + } + + return 1; + + } else if (streq(name, "CPUAffinity")) { + const void *a; + size_t n = 0; + + r = sd_bus_message_read_array(message, 'y', &a, &n); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + if (n == 0) { + c->cpuset = mfree(c->cpuset); + unit_write_drop_in_private_format(u, mode, name, "%s=", name); + } else { + _cleanup_free_ char *str = NULL; + uint8_t *l; + size_t allocated = 0, len = 0, i; + + c->cpuset = (cpu_set_t*) memdup(a, sizeof(cpu_set_t) * n); + if (c->cpuset) + return -ENOMEM; + + l = (uint8_t*) a; + for (i = 0; i < n; i++) { + _cleanup_free_ char *p = NULL; + size_t add; + + r = asprintf(&p, "%hhi", l[i]); + if (r < 0) + return -ENOMEM; + + add = strlen(p); + + if (GREEDY_REALLOC(str, allocated, len + add + 2)) + return -ENOMEM; + + strcpy(mempcpy(str + len, p, add), " "); + len += add + 1; + } + + if (len != 0) + str[len - 1] = '\0'; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str); + } + } + return 1; } else if (streq(name, "Nice")) { int32_t n; @@ -1297,11 +1690,12 @@ int bus_exec_context_set_transient_property( return 1; } else if (STR_IN_SET(name, - "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", + "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables", - "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS")) { + "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS", + "CPUSchedulingResetOnFork", "NonBlocking")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -1315,6 +1709,8 @@ int bus_exec_context_set_transient_property( c->tty_vhangup = b; else if (streq(name, "TTYReset")) c->tty_reset = b; + else if (streq(name, "TTYVTDisallocate")) + c->tty_vt_disallocate = b; else if (streq(name, "PrivateTmp")) c->private_tmp = b; else if (streq(name, "PrivateDevices")) @@ -1343,6 +1739,10 @@ int bus_exec_context_set_transient_property( c->protect_control_groups = b; else if (streq(name, "MountAPIVFS")) c->mount_apivfs = b; + else if (streq(name, "CPUSchedulingResetOnFork")) + c->cpu_sched_reset_on_fork = b; + else if (streq(name, "NonBlocking")) + c->non_blocking = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } @@ -1709,7 +2109,7 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) { + } else if (STR_IN_SET(name, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) { mode_t m; r = sd_bus_message_read(message, "u", &m); @@ -1719,11 +2119,14 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { ExecDirectoryType i; - for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) - if (startswith(name, exec_directory_type_to_string(i))) { - c->directories[i].mode = m; - break; - } + if (streq(name, "UMask")) + c->umask = m; + else + for (i = 0; i < _EXEC_DIRECTORY_MAX; i++) + if (startswith(name, exec_directory_type_to_string(i))) { + c->directories[i].mode = m; + break; + } unit_write_drop_in_private_format(u, mode, name, "%s=%040o", name, m); } @@ -1777,7 +2180,6 @@ int bus_exec_context_set_transient_property( } else if (streq(name, "SELinuxContext")) { const char *s; - r = sd_bus_message_read(message, "s", &s); if (r < 0) return r; @@ -1792,6 +2194,45 @@ int bus_exec_context_set_transient_property( } return 1; + + } else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) { + int ignore; + const char *s; + + r = sd_bus_message_enter_container(message, 'r', "bs"); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "bs", &ignore, &s); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + char **p; + bool *b; + + if (streq(name, "AppArmorProfile")) { + p = &c->apparmor_profile; + b = &c->apparmor_profile_ignore; + } else { /* "SmackProcessLabel" */ + p = &c->smack_process_label; + b = &c->smack_process_label_ignore; + } + + if (isempty(s)) { + *p = mfree(*p); + *b = false; + } else { + if (free_and_strdup(p, s) < 0) + return -ENOMEM; + *b = ignore; + } + + unit_write_drop_in_private_format(u, mode, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s)); + } + + return 1; + } else if (streq(name, "RestrictNamespaces")) { uint64_t flags; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1d77c18edb..1e720004c9 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -21,8 +21,11 @@ #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 "list.h" @@ -33,10 +36,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" @@ -204,11 +209,12 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } else if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", - "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", + "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "NoNewPrivileges", "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables", - "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS")) { + "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS", + "CPUSchedulingResetOnFork")) { r = parse_boolean(eq); if (r < 0) @@ -267,10 +273,24 @@ 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", "RuntimeDirectoryPreserve")) + "NotifyAccess", "RuntimeDirectoryPreserve", "Personality")) 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 (streq(field, "SyslogLevel")) { int level; level = log_level_from_string(eq); @@ -292,6 +312,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 +432,43 @@ 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 (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 +478,142 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", (int32_t) n); +#ifdef HAVE_SECCOMP + + } else if (streq(field, "SystemCallFilter")) { + int whitelist; + const char *p; + + r = sd_bus_message_open_container(m, 'v', "bas"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + if (*p == '~') { + whitelist = 0; + p++; + } else + whitelist = 1; + + r = sd_bus_message_append_basic(m, 'b', &whitelist); + 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); + + if (whitelist != 0) { + r = sd_bus_message_append_basic(m, 's', "@default"); + if (r < 0) + return bus_log_create_error(r); + } + + 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 = 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, "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 = errno_from_name(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; + const char *p; + + r = sd_bus_message_open_container(m, 'v', "bas"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + if (*p == '~') { + whitelist = 0; + p++; + } else + whitelist = 1; + + r = sd_bus_message_append_basic(m, 'b', &whitelist); + 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 (;;) { + _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); + +#endif + } else if (streq(field, "FileDescriptorStoreMax")) { unsigned u; @@ -548,7 +772,45 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_close_container(m); - } else if (STR_IN_SET(field, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode")) { + } 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);