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:
@@ -97,7 +97,12 @@ static int specifier_last_component(char specifier, const void *data, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
|
||||
int install_name_printf(
|
||||
UnitFileScope scope,
|
||||
const UnitFileInstallInfo *i,
|
||||
const char *format,
|
||||
const char *root,
|
||||
char **ret) {
|
||||
/* This is similar to unit_name_printf() */
|
||||
|
||||
const Specifier table[] = {
|
||||
@@ -109,7 +114,7 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const
|
||||
|
||||
COMMON_SYSTEM_SPECIFIERS,
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
COMMON_CREDS_SPECIFIERS(scope),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,4 +4,9 @@
|
||||
#include "install.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret);
|
||||
int install_name_printf(
|
||||
UnitFileScope scope,
|
||||
const UnitFileInstallInfo *i,
|
||||
const char *format,
|
||||
const char *root,
|
||||
char **ret);
|
||||
|
||||
@@ -1157,7 +1157,7 @@ static int config_parse_also(
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = install_name_printf(info, word, info->root, &printed);
|
||||
r = install_name_printf(ctx->scope, info, word, info->root, &printed);
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to resolve unit name in Also=\"%s\": %m", word);
|
||||
@@ -1188,6 +1188,7 @@ static int config_parse_default_instance(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
InstallContext *ctx = ASSERT_PTR(data);
|
||||
UnitFileInstallInfo *info = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *printed = NULL;
|
||||
int r;
|
||||
@@ -1205,7 +1206,7 @@ static int config_parse_default_instance(
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"DefaultInstance= only makes sense for template units, ignoring.");
|
||||
|
||||
r = install_name_printf(info, rvalue, info->root, &printed);
|
||||
r = install_name_printf(ctx->scope, info, rvalue, info->root, &printed);
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue);
|
||||
@@ -1772,7 +1773,7 @@ static int install_info_symlink_alias(
|
||||
STRV_FOREACH(s, info->aliases) {
|
||||
_cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL;
|
||||
|
||||
q = install_name_printf(info, *s, info->root, &dst);
|
||||
q = install_name_printf(scope, info, *s, info->root, &dst);
|
||||
if (q < 0) {
|
||||
unit_file_changes_add(changes, n_changes, q, *s, NULL);
|
||||
return q;
|
||||
@@ -1858,7 +1859,7 @@ static int install_info_symlink_wants(
|
||||
STRV_FOREACH(s, list) {
|
||||
_cleanup_free_ char *path = NULL, *dst = NULL;
|
||||
|
||||
q = install_name_printf(info, *s, info->root, &dst);
|
||||
q = install_name_printf(scope, info, *s, info->root, &dst);
|
||||
if (q < 0) {
|
||||
unit_file_changes_add(changes, n_changes, q, *s, NULL);
|
||||
return q;
|
||||
|
||||
+36
-8
@@ -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;
|
||||
|
||||
@@ -84,11 +84,11 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co
|
||||
{ 'w', specifier_os_version_id, NULL }, \
|
||||
{ 'W', specifier_os_variant_id, NULL }
|
||||
|
||||
#define COMMON_CREDS_SPECIFIERS \
|
||||
{ 'g', specifier_group_name, NULL }, \
|
||||
{ 'G', specifier_group_id, NULL }, \
|
||||
{ 'u', specifier_user_name, NULL }, \
|
||||
{ 'U', specifier_user_id, NULL }
|
||||
#define COMMON_CREDS_SPECIFIERS(scope) \
|
||||
{ 'g', specifier_group_name, INT_TO_PTR(scope) }, \
|
||||
{ 'G', specifier_group_id, INT_TO_PTR(scope) }, \
|
||||
{ 'u', specifier_user_name, INT_TO_PTR(scope) }, \
|
||||
{ 'U', specifier_user_id, INT_TO_PTR(scope) }
|
||||
|
||||
#define COMMON_TMP_SPECIFIERS \
|
||||
{ 'T', specifier_tmp_dir, NULL }, \
|
||||
|
||||
Reference in New Issue
Block a user