summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-08-19 16:43:45 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-08-24 10:02:46 +0200
commit8a7adccbdb23ae6fee82840ef41d17d5e568a8f2 (patch)
tree43c2e7748cf432e98c640b2984385a70960db36e /src
parent5f465fda4ec9f1e70a1bb993944ea92b2469b0db (diff)
downloadsystemd-8a7adccbdb23ae6fee82840ef41d17d5e568a8f2.tar.gz
various: try to use DEFAULT_USER_SHELL for root too
/bin/sh as a shell is punishing. There is no good reason to make the occasional root login unpleasant. Since /bin/sh is usually /bin/bash in compat mode, i.e. if one is available, the other will be too, /bin/bash is almost as good as a default. But to avoid a regression in the situation where /bin/bash (or DEFAULT_USER_SHELL) is not installed, we check with access() and fall back to /bin/sh. This should make this change in behaviour less risky. (FWIW, e.g. Fedora/RHEL use /bin/bash as default for root.) This is a follow-up of sorts for 53350c7bbade8c5f357aa3d1029ef9b2208ea675, which added the default-user-shell option, but most likely with the idea of using /bin/bash less ;) Fixes #24369.
Diffstat (limited to 'src')
-rw-r--r--src/basic/user-util.c21
-rw-r--r--src/basic/user-util.h1
-rw-r--r--src/firstboot/firstboot.c2
-rw-r--r--src/nss-systemd/nss-systemd.c60
-rw-r--r--src/sysusers/sysusers.c2
-rw-r--r--src/test/test-user-util.c4
6 files changed, 56 insertions, 34 deletions
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 16185332f9..37ccb667b2 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -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,7 +191,7 @@ static int synthesize_user_creds(
*home = "/root";
if (shell)
- *shell = "/bin/sh";
+ *shell = default_root_shell(NULL);
return 0;
}
@@ -635,7 +650,7 @@ int get_shell(char **_s) {
/* Hardcode shell for root and nobody to avoid NSS */
u = getuid();
if (u == 0) {
- s = strdup("/bin/sh");
+ s = strdup(default_root_shell(NULL));
if (!s)
return -ENOMEM;
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
index e1692c4f66..c8f0758541 100644
--- a/src/basic/user-util.h
+++ b/src/basic/user-util.h
@@ -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);
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 9169129a68..fd9954b54d 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -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)
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index e24828450f..75d749e736 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -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)
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 5eb67ea084..393d2cc0fc 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -398,7 +398,7 @@ static const char* pick_shell(const Item *i) {
if (i->shell)
return i->shell;
if (i->uid_set && i->uid == 0)
- return "/bin/sh";
+ return default_root_shell(arg_root);
return NOLOGIN;
}
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 907de54eaa..48d9b1e0fb 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -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);
}