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:
parent
9bfc0df113
commit
c465a29f24
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
};
|
||||
|
||||
|
@ -49,6 +49,9 @@ typedef enum ConditionType {
|
||||
|
||||
CONDITION_NULL,
|
||||
|
||||
CONDITION_USER,
|
||||
CONDITION_GROUP,
|
||||
|
||||
_CONDITION_TYPE_MAX,
|
||||
_CONDITION_TYPE_INVALID = -1
|
||||
} ConditionType;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user