1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

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
This commit is contained in:
Felipe Sateler 2017-04-08 20:32:13 -03:00
parent 9bfc0df113
commit c465a29f24
5 changed files with 223 additions and 0 deletions

View File

@ -820,6 +820,8 @@
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
<term><varname>ConditionFileNotEmpty=</varname></term>
<term><varname>ConditionFileIsExecutable=</varname></term>
<term><varname>ConditionUser=</varname></term>
<term><varname>ConditionGroup=</varname></term>
<!-- We do not document ConditionNull=
here, as it is not particularly
@ -1031,6 +1033,18 @@
whether a certain path exists, is a regular file and marked
executable.</para>
<para><varname>ConditionUser=</varname> takes a numeric
<literal>UID</literal> or a UNIX user name. This condition
may be used to check whether the service manager is running
as the given real or effective user. This option is not
useful for system services, as the system manager exclusively
runs as the root user, and thus the test result is constant.</para>
<para><varname>ConditionGroup=</varname> is similar
to <varname>ConditionUser=</varname> but verifies that the
service manager's real or effective group, or any of its
auxiliary groups match the specified group or GID.</para>
<para>If multiple conditions are specified, the unit will be
executed if all of them apply (i.e. a logical AND is applied).
Condition checks can be prefixed with a pipe symbol (|) in
@ -1067,6 +1081,8 @@
<term><varname>AssertDirectoryNotEmpty=</varname></term>
<term><varname>AssertFileNotEmpty=</varname></term>
<term><varname>AssertFileIsExecutable=</varname></term>
<term><varname>AssertUser=</varname></term>
<term><varname>AssertGroup=</varname></term>
<listitem><para>Similar to the <varname>ConditionArchitecture=</varname>,
<varname>ConditionVirtualization=</varname>, …, condition settings described above, these settings add

View File

@ -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)

View File

@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
@ -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"
};

View File

@ -49,6 +49,9 @@ typedef enum ConditionType {
CONDITION_NULL,
CONDITION_USER,
CONDITION_GROUP,
_CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1
} ConditionType;

View File

@ -17,6 +17,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#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;
}