mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #24370 from keszybz/sysusers-equivs
Use /bin/bash for root shell and suppress some warnings from sysusers
This commit is contained in:
@@ -35,23 +35,22 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-sysusers</command> creates system users and
|
||||
groups, based on the file format and location specified in
|
||||
<para><command>systemd-sysusers</command> creates system users and groups, based on files in the format
|
||||
described in
|
||||
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
||||
<para>If invoked with no arguments, it applies all directives from all files
|
||||
found in the directories specified by
|
||||
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
When invoked with positional arguments, if option
|
||||
<option>--replace=<replaceable>PATH</replaceable></option> is specified, arguments
|
||||
specified on the command line are used instead of the configuration file
|
||||
<replaceable>PATH</replaceable>. Otherwise, just the configuration specified by
|
||||
the command line arguments is executed. The string <literal>-</literal> may be
|
||||
specified instead of a filename to instruct <command>systemd-sysusers</command>
|
||||
to read the configuration from standard input. If only the basename of a file is
|
||||
specified, all configuration directories are searched for a matching file and
|
||||
the file found that has the highest priority is executed.</para>
|
||||
<para>If invoked with no arguments, it applies all directives from all files found in the directories
|
||||
specified by
|
||||
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. When
|
||||
invoked with positional arguments, if option <option>--replace=<replaceable>PATH</replaceable></option>
|
||||
is specified, arguments specified on the command line are used instead of the configuration file
|
||||
<replaceable>PATH</replaceable>. Otherwise, just the configuration specified by the command line
|
||||
arguments is executed. The string <literal>-</literal> may be specified instead of a filename to instruct
|
||||
<command>systemd-sysusers</command> to read the configuration from standard input. If the argument is a
|
||||
relative path, all configuration directories are searched for a matching file and the file found that has
|
||||
the highest priority is executed. If the argument is an absolute path, that file is used directly without
|
||||
searching of the configuration directories.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@@ -2108,7 +2108,7 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
|
||||
<row>
|
||||
<entry><literal>%s</literal></entry>
|
||||
<entry>User shell</entry>
|
||||
<entry>This is the shell of the user running the service manager instance. In case of the system manager this resolves to <literal>/bin/sh</literal>.</entry>
|
||||
<entry>This is the shell of the user running the service manager instance.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>%S</literal></entry>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase-symlinks.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@@ -136,7 +137,6 @@ char *getusername_malloc(void) {
|
||||
}
|
||||
|
||||
bool is_nologin_shell(const char *shell) {
|
||||
|
||||
return PATH_IN_SET(shell,
|
||||
/* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
|
||||
* message and exits. Different distributions place the binary at different places though,
|
||||
@@ -154,6 +154,21 @@ bool is_nologin_shell(const char *shell) {
|
||||
"/usr/bin/true");
|
||||
}
|
||||
|
||||
const char* default_root_shell(const char *root) {
|
||||
/* We want to use the preferred shell, i.e. DEFAULT_USER_SHELL, which usually
|
||||
* will be /bin/bash. Fall back to /bin/sh if DEFAULT_USER_SHELL is not found,
|
||||
* or any access errors. */
|
||||
|
||||
int r = chase_symlinks(DEFAULT_USER_SHELL, root, CHASE_PREFIX_ROOT, NULL, NULL);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to look up shell '%s%s%s': %m",
|
||||
strempty(root), root ? "/" : "", DEFAULT_USER_SHELL);
|
||||
if (r > 0)
|
||||
return DEFAULT_USER_SHELL;
|
||||
|
||||
return "/bin/sh";
|
||||
}
|
||||
|
||||
static int synthesize_user_creds(
|
||||
const char **username,
|
||||
uid_t *uid, gid_t *gid,
|
||||
@@ -176,13 +191,13 @@ static int synthesize_user_creds(
|
||||
*home = "/root";
|
||||
|
||||
if (shell)
|
||||
*shell = "/bin/sh";
|
||||
*shell = default_root_shell(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (synthesize_nobody() &&
|
||||
STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
|
||||
if (STR_IN_SET(*username, NOBODY_USER_NAME, "65534") &&
|
||||
synthesize_nobody()) {
|
||||
*username = NOBODY_USER_NAME;
|
||||
|
||||
if (uid)
|
||||
@@ -326,8 +341,8 @@ int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (synthesize_nobody() &&
|
||||
STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
|
||||
if (STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534") &&
|
||||
synthesize_nobody()) {
|
||||
*groupname = NOBODY_GROUP_NAME;
|
||||
|
||||
if (gid)
|
||||
@@ -373,8 +388,7 @@ char* uid_to_name(uid_t uid) {
|
||||
/* Shortcut things to avoid NSS lookups */
|
||||
if (uid == 0)
|
||||
return strdup("root");
|
||||
if (synthesize_nobody() &&
|
||||
uid == UID_NOBODY)
|
||||
if (uid == UID_NOBODY && synthesize_nobody())
|
||||
return strdup(NOBODY_USER_NAME);
|
||||
|
||||
if (uid_is_valid(uid)) {
|
||||
@@ -417,8 +431,7 @@ char* gid_to_name(gid_t gid) {
|
||||
|
||||
if (gid == 0)
|
||||
return strdup("root");
|
||||
if (synthesize_nobody() &&
|
||||
gid == GID_NOBODY)
|
||||
if (gid == GID_NOBODY && synthesize_nobody())
|
||||
return strdup(NOBODY_GROUP_NAME);
|
||||
|
||||
if (gid_is_valid(gid)) {
|
||||
@@ -556,43 +569,29 @@ int getgroups_alloc(gid_t** gids) {
|
||||
return ngroups;
|
||||
}
|
||||
|
||||
int get_home_dir(char **_h) {
|
||||
int get_home_dir(char **ret) {
|
||||
struct passwd *p;
|
||||
const char *e;
|
||||
char *h;
|
||||
uid_t u;
|
||||
|
||||
assert(_h);
|
||||
assert(ret);
|
||||
|
||||
/* Take the user specified one */
|
||||
e = secure_getenv("HOME");
|
||||
if (e && path_is_valid(e) && path_is_absolute(e)) {
|
||||
h = strdup(e);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
*_h = path_simplify(h);
|
||||
return 0;
|
||||
}
|
||||
if (e && path_is_valid(e) && path_is_absolute(e))
|
||||
goto found;
|
||||
|
||||
/* Hardcode home directory for root and nobody to avoid NSS */
|
||||
u = getuid();
|
||||
if (u == 0) {
|
||||
h = strdup("/root");
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
*_h = h;
|
||||
return 0;
|
||||
e = "/root";
|
||||
goto found;
|
||||
}
|
||||
if (synthesize_nobody() &&
|
||||
u == UID_NOBODY) {
|
||||
h = strdup("/");
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
*_h = h;
|
||||
return 0;
|
||||
if (u == UID_NOBODY && synthesize_nobody()) {
|
||||
e = "/";
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Check the database... */
|
||||
@@ -600,56 +599,42 @@ int get_home_dir(char **_h) {
|
||||
p = getpwuid(u);
|
||||
if (!p)
|
||||
return errno_or_else(ESRCH);
|
||||
e = p->pw_dir;
|
||||
|
||||
if (!path_is_valid(p->pw_dir) ||
|
||||
!path_is_absolute(p->pw_dir))
|
||||
if (!path_is_valid(e) || !path_is_absolute(e))
|
||||
return -EINVAL;
|
||||
|
||||
h = strdup(p->pw_dir);
|
||||
found:
|
||||
h = strdup(e);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
*_h = path_simplify(h);
|
||||
*ret = path_simplify(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_shell(char **_s) {
|
||||
int get_shell(char **ret) {
|
||||
struct passwd *p;
|
||||
const char *e;
|
||||
char *s;
|
||||
uid_t u;
|
||||
|
||||
assert(_s);
|
||||
assert(ret);
|
||||
|
||||
/* Take the user specified one */
|
||||
e = secure_getenv("SHELL");
|
||||
if (e && path_is_valid(e) && path_is_absolute(e)) {
|
||||
s = strdup(e);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*_s = path_simplify(s);
|
||||
return 0;
|
||||
}
|
||||
if (e && path_is_valid(e) && path_is_absolute(e))
|
||||
goto found;
|
||||
|
||||
/* Hardcode shell for root and nobody to avoid NSS */
|
||||
u = getuid();
|
||||
if (u == 0) {
|
||||
s = strdup("/bin/sh");
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*_s = s;
|
||||
return 0;
|
||||
e = default_root_shell(NULL);
|
||||
goto found;
|
||||
}
|
||||
if (synthesize_nobody() &&
|
||||
u == UID_NOBODY) {
|
||||
s = strdup(NOLOGIN);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*_s = s;
|
||||
return 0;
|
||||
if (u == UID_NOBODY && synthesize_nobody()) {
|
||||
e = NOLOGIN;
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Check the database... */
|
||||
@@ -657,16 +642,17 @@ int get_shell(char **_s) {
|
||||
p = getpwuid(u);
|
||||
if (!p)
|
||||
return errno_or_else(ESRCH);
|
||||
e = p->pw_shell;
|
||||
|
||||
if (!path_is_valid(p->pw_shell) ||
|
||||
!path_is_absolute(p->pw_shell))
|
||||
if (!path_is_valid(e) || !path_is_absolute(e))
|
||||
return -EINVAL;
|
||||
|
||||
s = strdup(p->pw_shell);
|
||||
found:
|
||||
s = strdup(e);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*_s = path_simplify(s);
|
||||
*ret = path_simplify(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t
|
||||
int getgroups_alloc(gid_t** gids);
|
||||
|
||||
int get_home_dir(char **ret);
|
||||
int get_shell(char **_ret);
|
||||
int get_shell(char **ret);
|
||||
|
||||
int reset_uid_gid(void);
|
||||
|
||||
@@ -130,6 +130,7 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
|
||||
#endif
|
||||
|
||||
bool is_nologin_shell(const char *shell);
|
||||
const char* default_root_shell(const char *root);
|
||||
|
||||
int is_this_me(const char *username);
|
||||
|
||||
|
||||
@@ -755,7 +755,7 @@ static int write_root_passwd(const char *passwd_path, const char *password, cons
|
||||
.pw_gid = 0,
|
||||
.pw_gecos = (char *) "Super User",
|
||||
.pw_dir = (char *) "/root",
|
||||
.pw_shell = (char *) (shell ?: "/bin/sh"),
|
||||
.pw_shell = (char *) (shell ?: default_root_shell(arg_root)),
|
||||
};
|
||||
|
||||
if (errno != ENOENT)
|
||||
|
||||
@@ -26,7 +26,7 @@ static const struct passwd root_passwd = {
|
||||
.pw_gid = 0,
|
||||
.pw_gecos = (char*) "Super User",
|
||||
.pw_dir = (char*) "/root",
|
||||
.pw_shell = (char*) "/bin/sh",
|
||||
.pw_shell = NULL,
|
||||
};
|
||||
|
||||
static const struct spwd root_spwd = {
|
||||
@@ -142,24 +142,25 @@ NSS_INITGROUPS_PROTOTYPE(systemd);
|
||||
static enum nss_status copy_synthesized_passwd(
|
||||
struct passwd *dest,
|
||||
const struct passwd *src,
|
||||
const char *fallback_shell,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
size_t required;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
assert(src->pw_name);
|
||||
assert(src->pw_passwd);
|
||||
assert(src->pw_gecos);
|
||||
assert(src->pw_dir);
|
||||
assert(src->pw_shell);
|
||||
|
||||
required = strlen(src->pw_name) + 1;
|
||||
required += strlen(src->pw_passwd) + 1;
|
||||
required += strlen(src->pw_gecos) + 1;
|
||||
required += strlen(src->pw_dir) + 1;
|
||||
required += strlen(src->pw_shell) + 1;
|
||||
const char *shell = ASSERT_PTR(src->pw_shell ?: fallback_shell);
|
||||
|
||||
size_t required =
|
||||
strlen(src->pw_name) + 1 +
|
||||
strlen(src->pw_passwd) + 1 +
|
||||
strlen(src->pw_gecos) + 1 +
|
||||
strlen(src->pw_dir) + 1 +
|
||||
strlen(shell) + 1;
|
||||
|
||||
if (buflen < required) {
|
||||
*errnop = ERANGE;
|
||||
@@ -176,7 +177,7 @@ static enum nss_status copy_synthesized_passwd(
|
||||
dest->pw_gecos = stpcpy(dest->pw_passwd, src->pw_passwd) + 1;
|
||||
dest->pw_dir = stpcpy(dest->pw_gecos, src->pw_gecos) + 1;
|
||||
dest->pw_shell = stpcpy(dest->pw_dir, src->pw_dir) + 1;
|
||||
strcpy(dest->pw_shell, src->pw_shell);
|
||||
strcpy(dest->pw_shell, shell);
|
||||
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -187,15 +188,14 @@ static enum nss_status copy_synthesized_spwd(
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
size_t required;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
assert(src->sp_namp);
|
||||
assert(src->sp_pwdp);
|
||||
|
||||
required = strlen(src->sp_namp) + 1;
|
||||
required += strlen(src->sp_pwdp) + 1;
|
||||
size_t required =
|
||||
strlen(src->sp_namp) + 1 +
|
||||
strlen(src->sp_pwdp) + 1;
|
||||
|
||||
if (buflen < required) {
|
||||
*errnop = ERANGE;
|
||||
@@ -220,8 +220,6 @@ static enum nss_status copy_synthesized_group(
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
size_t required;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
assert(src->gr_name);
|
||||
@@ -229,9 +227,10 @@ static enum nss_status copy_synthesized_group(
|
||||
assert(src->gr_mem);
|
||||
assert(!*src->gr_mem); /* Our synthesized records' gr_mem is always just NULL... */
|
||||
|
||||
required = strlen(src->gr_name) + 1;
|
||||
required += strlen(src->gr_passwd) + 1;
|
||||
required += sizeof(char*); /* ...but that NULL still needs to be stored into the buffer! */
|
||||
size_t required =
|
||||
strlen(src->gr_name) + 1 +
|
||||
strlen(src->gr_passwd) + 1 +
|
||||
sizeof(char*); /* ...but that NULL still needs to be stored into the buffer! */
|
||||
|
||||
if (buflen < ALIGN(required)) {
|
||||
*errnop = ERANGE;
|
||||
@@ -257,15 +256,14 @@ static enum nss_status copy_synthesized_sgrp(
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop) {
|
||||
|
||||
size_t required;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
assert(src->sg_namp);
|
||||
assert(src->sg_passwd);
|
||||
|
||||
required = strlen(src->sg_namp) + 1;
|
||||
required += strlen(src->sg_passwd) + 1;
|
||||
size_t required =
|
||||
strlen(src->sg_namp) + 1 +
|
||||
strlen(src->sg_passwd) + 1;
|
||||
|
||||
if (buflen < required) {
|
||||
*errnop = ERANGE;
|
||||
@@ -310,13 +308,17 @@ enum nss_status _nss_systemd_getpwnam_r(
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
|
||||
|
||||
if (streq(name, root_passwd.pw_name))
|
||||
return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
|
||||
return copy_synthesized_passwd(pwd, &root_passwd,
|
||||
default_root_shell(NULL),
|
||||
buffer, buflen, errnop);
|
||||
|
||||
if (streq(name, nobody_passwd.pw_name)) {
|
||||
if (!synthesize_nobody())
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
|
||||
return copy_synthesized_passwd(pwd, &nobody_passwd,
|
||||
NULL,
|
||||
buffer, buflen, errnop);
|
||||
}
|
||||
|
||||
} else if (STR_IN_SET(name, root_passwd.pw_name, nobody_passwd.pw_name))
|
||||
@@ -354,13 +356,17 @@ enum nss_status _nss_systemd_getpwuid_r(
|
||||
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
|
||||
|
||||
if (uid == root_passwd.pw_uid)
|
||||
return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
|
||||
return copy_synthesized_passwd(pwd, &root_passwd,
|
||||
default_root_shell(NULL),
|
||||
buffer, buflen, errnop);
|
||||
|
||||
if (uid == nobody_passwd.pw_uid) {
|
||||
if (!synthesize_nobody())
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
|
||||
return copy_synthesized_passwd(pwd, &nobody_passwd,
|
||||
NULL,
|
||||
buffer, buflen, errnop);
|
||||
}
|
||||
|
||||
} else if (uid == root_passwd.pw_uid || uid == nobody_passwd.pw_uid)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -347,8 +347,8 @@ static void test_get_user_creds_one(const char *id, const char *name, uid_t uid,
|
||||
}
|
||||
|
||||
TEST(get_user_creds) {
|
||||
test_get_user_creds_one("root", "root", 0, 0, "/root", "/bin/sh");
|
||||
test_get_user_creds_one("0", "root", 0, 0, "/root", "/bin/sh");
|
||||
test_get_user_creds_one("root", "root", 0, 0, "/root", DEFAULT_USER_SHELL);
|
||||
test_get_user_creds_one("0", "root", 0, 0, "/root", DEFAULT_USER_SHELL);
|
||||
test_get_user_creds_one(NOBODY_USER_NAME, NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN);
|
||||
test_get_user_creds_one("65534", NOBODY_USER_NAME, UID_NOBODY, GID_NOBODY, "/", NOLOGIN);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ ExecStart=sh -c 'test %U = $$(id -u)'
|
||||
ExecStart=sh -c 'test %g = $$(id -gn)'
|
||||
ExecStart=sh -c 'test %G = $$(id -g)'
|
||||
ExecStart=test %h = /root
|
||||
ExecStart=sh -c 'test %s = /bin/sh'
|
||||
ExecStart=sh -c 'test -x %s'
|
||||
ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
|
||||
ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
|
||||
ExecStart=sh -c 'test %H = $$(uname -n)'
|
||||
|
||||
@@ -23,7 +23,7 @@ ExecStart=sh -c 'test %U = $$(id -u)'
|
||||
ExecStart=sh -c 'test %g = $$(id -gn)'
|
||||
ExecStart=sh -c 'test %G = $$(id -g)'
|
||||
ExecStart=test %h = /root
|
||||
ExecStart=sh -c 'test %s = /bin/sh'
|
||||
ExecStart=sh -c 'test -x %s'
|
||||
ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)'
|
||||
ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')'
|
||||
ExecStart=sh -c 'test %H = $$(uname -n)'
|
||||
|
||||
@@ -152,7 +152,7 @@ for f in $(ls -1 $SOURCE/unhappy-*.input | sort -V); do
|
||||
echo "*** Running test $f"
|
||||
prepare_testdir ${f%.input}
|
||||
cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
|
||||
$SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/err
|
||||
$SYSUSERS --root=$TESTDIR 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >$TESTDIR/err
|
||||
if ! diff -u $TESTDIR/err ${f%.*}.expected-err; then
|
||||
echo "**** Unexpected error output for $f"
|
||||
cat $TESTDIR/err
|
||||
|
||||
@@ -1 +1 @@
|
||||
Failed to parse UID: '9999999999': Numerical result out of range
|
||||
Failed to parse UID: '9999999999': Numerical result out of range
|
||||
|
||||
Reference in New Issue
Block a user