5113bc
From a08c1a6aadaa27e4070fe58242d55464d6c7a3e7 Mon Sep 17 00:00:00 2001
5113bc
From: Karel Zak <kzak@redhat.com>
5113bc
Date: Mon, 25 May 2015 15:30:52 +0200
5113bc
Subject: [PATCH 164/173] sulogin: improve support for locked root account
5113bc
5113bc
Some installations and distributions don't use a root account password
5113bc
for security reasons and use sudo instead. In that case, asking for the
5113bc
password makes no sense, and it is not even considered as valid as it's just
5113bc
"*" or "!".
5113bc
5113bc
In these cases --force is required to just start a root shell and no
5113bc
ask for password.
5113bc
5113bc
I don't think it's a good idea to automatically start root shell when
5113bc
locked account is detected. It's possible that the machine is on
5113bc
public place and for example Ubuntu uses root account disabled by
5113bc
default (and also Fedora when installed by yum/dnf without anaconda).
5113bc
5113bc
The --force option forces admins to think about it...
5113bc
5113bc
The distro maintainers can also use --force in their initscripts or
5113bc
systemd emergency.service if they believe that promiscuous setting is
5113bc
the right thing for the distro.
5113bc
5113bc
Addresses: https://bugs.debian.org/326678
5113bc
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1561200
5113bc
Upstream: http://github.com/karelzak/util-linux/commit/7ff1162e67164cb4ece19dd809c26272461aa254
5113bc
Signed-off-by: Karel Zak <kzak@redhat.com>
5113bc
---
5113bc
 login-utils/sulogin.8 | 13 +++++++++----
5113bc
 login-utils/sulogin.c | 48 ++++++++++++++++++++++++++++++++++--------------
5113bc
 2 files changed, 43 insertions(+), 18 deletions(-)
5113bc
5113bc
diff --git a/login-utils/sulogin.8 b/login-utils/sulogin.8
5113bc
index b9dec165c..702487985 100644
5113bc
--- a/login-utils/sulogin.8
5113bc
+++ b/login-utils/sulogin.8
5113bc
@@ -35,8 +35,10 @@ Give root password for system maintenance
5113bc
 .br
5113bc
 (or type Control\-D for normal startup):
5113bc
 .PP
5113bc
-.I sulogin
5113bc
-will be connected to the current terminal, or to the optional tty device that
5113bc
+If the root account is locked and --force is specified, no password is required.
5113bc
+.PP
5113bc
+.B sulogin
5113bc
+will be connected to the current terminal, or to the optional \fItty\fR device that
5113bc
 can be specified on the command line (typically
5113bc
 .BR /dev/console ).
5113bc
 .PP
5113bc
@@ -50,8 +52,11 @@ from the system fails, manually examine
5113bc
 .I /etc/passwd
5113bc
 and
5113bc
 .I /etc/shadow
5113bc
-to get the password.  If they are damaged or nonexistent, sulogin will start
5113bc
-a root shell without asking for a password.
5113bc
+to get the password.  If these files are damaged or nonexistent, or when
5113bc
+root account is locked by '!' or '*' at the begin of the password then
5113bc
+.B sulogin
5113bc
+will \fBstart a root shell without asking for a password\fP.
5113bc
+.PP
5113bc
 .IP
5113bc
 Only use the
5113bc
 .B \-e
5113bc
diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
5113bc
index 6d03bc5ae..a17b91d71 100644
5113bc
--- a/login-utils/sulogin.c
5113bc
+++ b/login-utils/sulogin.c
5113bc
@@ -81,6 +81,13 @@ static volatile sig_atomic_t sigchild;
5113bc
 # define IUCLC		0
5113bc
 #endif
5113bc
 
5113bc
+static int locked_account_password(const char *passwd)
5113bc
+{
5113bc
+	if (passwd && (*passwd == '*' || *passwd == '!'))
5113bc
+		return 1;
5113bc
+	return 0;
5113bc
+}
5113bc
+
5113bc
 /*
5113bc
  * Fix the tty modes and set reasonable defaults.
5113bc
  */
5113bc
@@ -423,7 +430,6 @@ static struct passwd *getrootpwent(int try_manually)
5113bc
 		p = line;
5113bc
 		break;
5113bc
 	}
5113bc
-
5113bc
 	fclose(fp);
5113bc
 
5113bc
 	/*
5113bc
@@ -460,7 +466,8 @@ static struct passwd *getrootpwent(int try_manually)
5113bc
 		warnx(_("%s: no entry for root"), _PATH_SHADOW_PASSWD);
5113bc
 		*pwd.pw_passwd = '\0';
5113bc
 	}
5113bc
-	if (!valid(pwd.pw_passwd)) {
5113bc
+	/* locked accont passwords are valid too */
5113bc
+	if (!locked_account_password(pwd.pw_passwd) && !valid(pwd.pw_passwd)) {
5113bc
 		warnx(_("%s: root password garbled"), _PATH_SHADOW_PASSWD);
5113bc
 		*pwd.pw_passwd = '\0';
5113bc
 	}
5113bc
@@ -470,7 +477,7 @@ static struct passwd *getrootpwent(int try_manually)
5113bc
 /*
5113bc
  * Ask by prompt for the password.
5113bc
  */
5113bc
-static void doprompt(const char *crypted, struct console *con)
5113bc
+static void doprompt(const char *crypted, struct console *con, int deny)
5113bc
 {
5113bc
 	struct termios tty;
5113bc
 
5113bc
@@ -487,18 +494,25 @@ static void doprompt(const char *crypted, struct console *con)
5113bc
 		if  ((con->file = fdopen(con->fd, "r+")) == (FILE*)0)
5113bc
 			goto err;
5113bc
 	}
5113bc
+
5113bc
+	if (deny)
5113bc
+		fprintf(con->file, _("\nCannot open access to console, the root account is locked.\n"
5113bc
+				     "See sulogin(8) man page for more details.\n\n"
5113bc
+				     "Press Enter to continue.\n"));
5113bc
+	else {
5113bc
 #if defined(USE_ONELINE)
5113bc
-	if (crypted[0])
5113bc
-		fprintf(con->file, _("Give root password for login: "));
5113bc
-	else
5113bc
-		fprintf(con->file, _("Press enter for login: "));
5113bc
+		if (crypted[0] && !locked_account_password(crypted))
5113bc
+			fprintf(con->file, _("Give root password for login: "));
5113bc
+		else
5113bc
+			fprintf(con->file, _("Press Enter for login: "));
5113bc
 #else
5113bc
-	if (crypted[0])
5113bc
-		fprintf(con->file, _("Give root password for maintenance\n"));
5113bc
-	else
5113bc
-		fprintf(con->file, _("Press enter for maintenance"));
5113bc
-	fprintf(con->file, _("(or type Control-D to continue): "));
5113bc
+		if (crypted[0] && !locked_account_password(crypted))
5113bc
+			fprintf(con->file, _("Give root password for maintenance\n"));
5113bc
+		else
5113bc
+			fprintf(con->file, _("Press Enter for maintenance\n"));
5113bc
+		fprintf(con->file, _("(or press Control-D to continue): "));
5113bc
 #endif
5113bc
+	}
5113bc
 	fflush(con->file);
5113bc
 err:
5113bc
 	if (con->flags & CON_SERIAL)
5113bc
@@ -914,6 +928,7 @@ int main(int argc, char **argv)
5113bc
 		goto nofork;
5113bc
 	}
5113bc
 
5113bc
+
5113bc
 	mask_signal(SIGCHLD, chld_handler, &saved_sigchld);
5113bc
 	do {
5113bc
 		con = list_entry(ptr, struct console, entry);
5113bc
@@ -930,12 +945,17 @@ int main(int argc, char **argv)
5113bc
 				const char *passwd = pwd->pw_passwd;
5113bc
 				const char *answer;
5113bc
 				int failed = 0, doshell = 0;
5113bc
+				int deny = !opt_e && locked_account_password(pwd->pw_passwd);
5113bc
+
5113bc
+				doprompt(passwd, con, deny);
5113bc
 
5113bc
-				doprompt(passwd, con);
5113bc
 				if ((answer = getpasswd(con)) == NULL)
5113bc
 					break;
5113bc
+				if (deny)
5113bc
+					exit(EXIT_FAILURE);
5113bc
 
5113bc
-				if (passwd[0] == '\0')
5113bc
+				/* no password or locked account */
5113bc
+				if (!passwd[0] || locked_account_password(passwd))
5113bc
 					doshell++;
5113bc
 				else {
5113bc
 					const char *cryptbuf;
5113bc
-- 
5113bc
2.14.4
5113bc