From c465a29f24403c7583a96eb90a1fe4f5b7f9b5a9 Mon Sep 17 00:00:00 2001 From: Felipe Sateler Date: Sat, 8 Apr 2017 20:32:13 -0300 Subject: core: add ConditionUser and ConditionGroup This adds two options that are useful for user units. In particular, it is useful to check ConditionUser=!0 to not start for the root user. Closes: #5187 --- src/core/load-fragment-gperf.gperf.m4 | 4 + src/shared/condition.c | 59 ++++++++++++++ src/shared/condition.h | 3 + src/test/test-condition.c | 141 ++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) (limited to 'src') diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 97adbdd7bb..4f17fa892b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -221,6 +221,8 @@ Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_S Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, conditions) Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions) Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, conditions) +Unit.ConditionUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, conditions) +Unit.ConditionGroup, config_parse_unit_condition_string, CONDITION_GROUP, offsetof(Unit, conditions) Unit.ConditionNull, config_parse_unit_condition_null, 0, offsetof(Unit, conditions) Unit.AssertPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, asserts) Unit.AssertPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, asserts) @@ -240,6 +242,8 @@ Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_S Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, asserts) Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts) Unit.AssertACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, asserts) +Unit.AssertUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, asserts) +Unit.AssertGroup, config_parse_unit_condition_string, CONDITION_GROUP, offsetof(Unit, asserts) Unit.AssertNull, config_parse_unit_condition_null, 0, offsetof(Unit, asserts) m4_dnl Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) diff --git a/src/shared/condition.c b/src/shared/condition.c index 0b77d2c22d..7320b53492 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ #include "stat-util.h" #include "string-table.h" #include "string-util.h" +#include "user-util.h" #include "util.h" #include "virt.h" @@ -138,6 +140,57 @@ static int condition_test_kernel_command_line(Condition *c) { return false; } +static int condition_test_user(Condition *c) { + uid_t id; + int r; + _cleanup_free_ char *username = NULL; + const char *u; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_USER); + + r = parse_uid(c->parameter, &id); + if (r >= 0) + return id == getuid() || id == geteuid(); + + username = getusername_malloc(); + if (!username) + return -ENOMEM; + + if (streq(username, c->parameter)) + return 1; + + if (getpid() == 1) + return streq(c->parameter, "root"); + + u = c->parameter; + r = get_user_creds(&u, &id, NULL, NULL, NULL); + if (r < 0) + return 0; + + return id == getuid() || id == geteuid(); +} + +static int condition_test_group(Condition *c) { + gid_t id; + int r; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_GROUP); + + r = parse_gid(c->parameter, &id); + if (r >= 0) + return in_gid(id); + + /* Avoid any NSS lookups if we are PID1 */ + if (getpid() == 1) + return streq(c->parameter, "root"); + + return in_group(c->parameter) > 0; +} + static int condition_test_virtualization(Condition *c) { int b, v; @@ -475,6 +528,8 @@ int condition_test(Condition *c) { [CONDITION_ARCHITECTURE] = condition_test_architecture, [CONDITION_NEEDS_UPDATE] = condition_test_needs_update, [CONDITION_FIRST_BOOT] = condition_test_first_boot, + [CONDITION_USER] = condition_test_user, + [CONDITION_GROUP] = condition_test_group, [CONDITION_NULL] = condition_test_null, }; @@ -538,6 +593,8 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty", [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty", [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable", + [CONDITION_USER] = "ConditionUser", + [CONDITION_GROUP] = "ConditionGroup", [CONDITION_NULL] = "ConditionNull" }; @@ -562,6 +619,8 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty", [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty", [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable", + [CONDITION_USER] = "AssertUser", + [CONDITION_GROUP] = "AssertGroup", [CONDITION_NULL] = "AssertNull" }; diff --git a/src/shared/condition.h b/src/shared/condition.h index bdda04b770..d0b592bc43 100644 --- a/src/shared/condition.h +++ b/src/shared/condition.h @@ -49,6 +49,9 @@ typedef enum ConditionType { CONDITION_NULL, + CONDITION_USER, + CONDITION_GROUP, + _CONDITION_TYPE_MAX, _CONDITION_TYPE_INVALID = -1 } ConditionType; diff --git a/src/test/test-condition.c b/src/test/test-condition.c index dd985f5863..790716e1dc 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -17,6 +17,10 @@ along with systemd; If not, see . ***/ +#include +#include +#include + #include "sd-id128.h" #include "alloc-util.h" @@ -34,6 +38,7 @@ #include "strv.h" #include "virt.h" #include "util.h" +#include "user-util.h" static void test_condition_test_path(void) { Condition *condition; @@ -323,6 +328,140 @@ static void test_condition_test_virtualization(void) { } } +static void test_condition_test_user(void) { + Condition *condition; + char* uid; + char* username; + int r; + + condition = condition_new(CONDITION_USER, "garbage oifdsjfoidsjoj", false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=garbage → %i", r); + assert_se(r == 0); + condition_free(condition); + + assert_se(asprintf(&uid, "%"PRIu32, UINT32_C(0xFFFF)) > 0); + condition = condition_new(CONDITION_USER, uid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=%s → %i", uid, r); + assert_se(r == 0); + condition_free(condition); + free(uid); + + assert_se(asprintf(&uid, "%u", (unsigned)getuid()) > 0); + condition = condition_new(CONDITION_USER, uid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=%s → %i", uid, r); + assert_se(r > 0); + condition_free(condition); + free(uid); + + assert_se(asprintf(&uid, "%u", (unsigned)getuid()+1) > 0); + condition = condition_new(CONDITION_USER, uid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=%s → %i", uid, r); + assert_se(r == 0); + condition_free(condition); + free(uid); + + username = getusername_malloc(); + assert_se(username); + condition = condition_new(CONDITION_USER, username, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=%s → %i", username, r); + assert_se(r > 0); + condition_free(condition); + free(username); + + username = (char*)(geteuid() == 0 ? NOBODY_USER_NAME : "root"); + condition = condition_new(CONDITION_USER, username, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionUser=%s → %i", username, r); + assert_se(r == 0); + condition_free(condition); +} + +static void test_condition_test_group(void) { + Condition *condition; + char* gid; + char* groupname; + gid_t *gids, max_gid; + int ngroups_max, r, i; + + assert_se(0 < asprintf(&gid, "%u", UINT32_C(0xFFFF))); + condition = condition_new(CONDITION_GROUP, gid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", gid, r); + assert_se(r == 0); + condition_free(condition); + free(gid); + + assert_se(0 < asprintf(&gid, "%u", getgid())); + condition = condition_new(CONDITION_GROUP, gid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", gid, r); + assert_se(r > 0); + condition_free(condition); + free(gid); + + ngroups_max = sysconf(_SC_NGROUPS_MAX); + assert(ngroups_max > 0); + + gids = alloca(sizeof(gid_t) * ngroups_max); + + r = getgroups(ngroups_max, gids); + assert(r >= 0); + + max_gid = getgid(); + for (i = 0; i < r; i++) { + assert_se(0 < asprintf(&gid, "%u", gids[i])); + condition = condition_new(CONDITION_GROUP, gid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", gid, r); + assert_se(r > 0); + condition_free(condition); + free(gid); + max_gid = gids[i] > max_gid ? gids[i] : max_gid; + + groupname = gid_to_name(gids[i]); + assert_se(groupname); + condition = condition_new(CONDITION_GROUP, groupname, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", groupname, r); + assert_se(r > 0); + condition_free(condition); + free(groupname); + max_gid = gids[i] > max_gid ? gids[i] : max_gid; + } + + assert_se(0 < asprintf(&gid, "%u", max_gid+1)); + condition = condition_new(CONDITION_GROUP, gid, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", gid, r); + assert_se(r == 0); + condition_free(condition); + free(gid); + + groupname = (char*)(geteuid() == 0 ? NOBODY_GROUP_NAME : "root"); + condition = condition_new(CONDITION_GROUP, groupname, false, false); + assert_se(condition); + r = condition_test(condition); + log_info("ConditionGroup=%s → %i", groupname, r); + assert_se(r == 0); + condition_free(condition); +} + int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); log_parse_environment(); @@ -336,6 +475,8 @@ int main(int argc, char *argv[]) { test_condition_test_null(); test_condition_test_security(); test_condition_test_virtualization(); + test_condition_test_user(); + test_condition_test_group(); return 0; } -- cgit v1.2.1