shared/specifier: fix %u/%U/%g/%G when called as unprivileged user

We would resolve those specifiers to the calling user/group. This is mostly OK
when done in the manager, because the manager generally operates as root
in system mode, and a non-root in user mode. It would still be wrong if
called with --test though. But in systemctl, this would be generally wrong,
since we can call 'systemctl --system' as a normal user, either for testing
or even for actual operation with '--root=…'.

When operating in --global mode, %u/%U/%g/%G should return an error.

The information whether we're operating in system mode, user mode, or global
mode is passed as the data pointer to specifier_group_name(), specifier_user_name(),
specifier_group_id(), specifier_user_id(). We can't use userdata, because
it's already used for other things.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2022-03-29 16:17:56 +02:00
parent 4a84db4c0c
commit 172e9cc3ee
11 changed files with 150 additions and 99 deletions
+36 -8
View File
@@ -22,6 +22,7 @@
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
#include "unit-file.h"
#include "user-util.h"
/*
@@ -309,11 +310,15 @@ int specifier_os_image_version(char specifier, const void *data, const char *roo
}
int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
UnitFileScope scope = PTR_TO_INT(data);
char *t;
assert(ret);
t = gid_to_name(getgid());
if (scope == UNIT_FILE_GLOBAL)
return -EINVAL;
t = gid_to_name(scope == UNIT_FILE_USER ? getgid() : 0);
if (!t)
return -ENOMEM;
@@ -322,27 +327,42 @@ int specifier_group_name(char specifier, const void *data, const char *root, con
}
int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
UnitFileScope scope = PTR_TO_INT(data);
gid_t gid;
assert(ret);
if (asprintf(ret, UID_FMT, getgid()) < 0)
if (scope == UNIT_FILE_GLOBAL)
return -EINVAL;
gid = scope == UNIT_FILE_USER ? getgid() : 0;
if (asprintf(ret, UID_FMT, gid) < 0)
return -ENOMEM;
return 0;
}
int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
UnitFileScope scope = PTR_TO_INT(data);
uid_t uid;
char *t;
assert(ret);
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
* to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
if (scope == UNIT_FILE_GLOBAL)
return -EINVAL;
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
* specifer_user_id() below.
uid = scope == UNIT_FILE_USER ? getuid() : 0;
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want
* to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain
* consistent with specifer_user_id() below.
*/
t = uid_to_name(getuid());
t = uid_to_name(uid);
if (!t)
return -ENOMEM;
@@ -351,9 +371,17 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons
}
int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
UnitFileScope scope = PTR_TO_INT(data);
uid_t uid;
assert(ret);
if (asprintf(ret, UID_FMT, getuid()) < 0)
if (scope == UNIT_FILE_GLOBAL)
return -EINVAL;
uid = scope == UNIT_FILE_USER ? getuid() : 0;
if (asprintf(ret, UID_FMT, uid) < 0)
return -ENOMEM;
return 0;