From 335681ca8e39144fa19814f7ba10d0fe760e4055 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Apr 2017 12:57:04 +0200 Subject: su: FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY When this feature is enabled, blank passwords are not accepted by su unless the user is on a secure TTY defined in /etc/securetty. This resembles the default PAM configuration of some Linux distros which specify the nullok_secure option for pam_unix.so. Based on patch by Kaarle Ritvanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/correct_password.c | 4 ++-- loginutils/su.c | 27 ++++++++++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 6b33ffa..b889dd7 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1486,6 +1486,7 @@ int check_securetty(const char *short_tty) FAST_FUNC; #else static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } #endif +#define CHECKPASS_PW_HAS_EMPTY_PASSWORD 2 int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; int ask_and_check_password(const struct passwd *pw) FAST_FUNC; diff --git a/libbb/correct_password.c b/libbb/correct_password.c index 513c930..3436edc 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -88,7 +88,7 @@ int FAST_FUNC check_password(const struct passwd *pw, const char *plaintext) /* Ask the user for a password. - * Return 1 without asking if PW has an empty password. + * Return CHECKPASS_PW_HAS_EMPTY_PASSWORD without asking if PW has an empty password. * Return -1 on EOF, error while reading input, or timeout. * Return 1 if the user gives the correct password for entry PW, * 0 if not. @@ -105,7 +105,7 @@ int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, pw_pass = get_passwd(pw, buffer); if (!pw_pass[0]) /* empty password field? */ - return 1; + return CHECKPASS_PW_HAS_EMPTY_PASSWORD; plaintext = bb_ask(STDIN_FILENO, timeout, prompt); if (!plaintext) { diff --git a/loginutils/su.c b/loginutils/su.c index d04b85f..f2cd799 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -23,6 +23,11 @@ //config: bool "If user's shell is not in /etc/shells, disallow -s PROG" //config: default y //config: depends on SU +//config: +//config:config FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY +//config: bool "Disallow blank passwords from TTYs other than specified in /etc/securetty" +//config: default n +//config: depends on SU //applet:/* Needs to be run by root or be suid root - needs to change uid and gid: */ //applet:IF_SU(APPLET(su, BB_DIR_BIN, BB_SUID_REQUIRE)) @@ -79,6 +84,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) char user_buf[64]; #endif const char *old_user; + int r; /* Note: we don't use "'+': stop at first non-option" idiom here. * For su, "SCRIPT ARGS" or "-c CMD ARGS" do not stop option parsing: @@ -99,6 +105,11 @@ int su_main(int argc UNUSED_PARAM, char **argv) argv++; } + tty = xmalloc_ttyname(STDIN_FILENO); + if (!tty) + tty = "none"; + tty = skip_dev_pfx(tty); + if (ENABLE_FEATURE_SU_SYSLOG) { /* The utmp entry (via getlogin) is probably the best way to * identify the user, especially if someone su's from a su-shell. @@ -112,20 +123,26 @@ int su_main(int argc UNUSED_PARAM, char **argv) pw = getpwuid(cur_uid); old_user = pw ? xstrdup(pw->pw_name) : ""; } - tty = xmalloc_ttyname(2); - if (!tty) { - tty = "none"; - } openlog(applet_name, 0, LOG_AUTH); } pw = xgetpwnam(opt_username); - if (cur_uid == 0 || ask_and_check_password(pw) > 0) { + r = 1; + if (cur_uid != 0) + r = ask_and_check_password(pw); + if (r > 0) { + if (ENABLE_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY + && r == CHECKPASS_PW_HAS_EMPTY_PASSWORD + && !check_securetty(tty) + ) { + goto fail; + } if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); } else { + fail: if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '-', tty, old_user, opt_username); -- cgit v1.1