[hackers] [PATCHv2] passwd, login: Support empty passwords

From: Drew DeVault <sir_AT_cmpwn.com>
Date: Sun, 14 Jan 2018 22:45:55 -0500

These are useful for daemon users, etc.
---
Sorry for the noise. Initially I just updated my original patch without
much thought and sent it along, but when I tested it more, I found out
that it was total dogshit. This patch actually works and (hopefully)
doesn't introduce blatantly obvious security holes.
 libutil/passwd.c | 38 ++++++++++++++++++++++----------------
 login.c          | 13 +++++++++----
 passwd.c         | 28 +++++++++++++++++++++++-----
 passwd.h         |  3 ++-
 4 files changed, 56 insertions(+), 26 deletions(-)
diff --git a/libutil/passwd.c b/libutil/passwd.c
index 0798225..d60000c 100644
--- a/libutil/passwd.c
+++ b/libutil/passwd.c
_AT_@ -14,10 +14,9 @@
 #include "../text.h"
 #include "../util.h"
 
-/* Returns -1 on error, 0 for incorrect password
- * and 1 if all went OK */
-int
-pw_check(const struct passwd *pw, const char *pass)
+/* Returns NULL on error or a string pointer if all went OK */
+const char *
+pw_get(const struct passwd *pw)
 {
 	char *cryptpass, *p;
 	struct spwd *spw;
_AT_@ -25,14 +24,7 @@ pw_check(const struct passwd *pw, const char *pass)
 	p = pw->pw_passwd;
 	if (p[0] == '!' || p[0] == '*') {
 		weprintf("denied\n");
-		return -1;
-	}
-
-	if (pw->pw_passwd[0] == '\0') {
-		if (pass[0] == '\0')
-			return 1;
-		weprintf("incorrect password\n");
-		return 0;
+		return NULL;
 	}
 
 	if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
_AT_@ -43,21 +35,35 @@ pw_check(const struct passwd *pw, const char *pass)
 				weprintf("getspnam: %s:", pw->pw_name);
 			else
 				weprintf("who are you?\n");
-			return -1;
+			return NULL;
 		}
 		p = spw->sp_pwdp;
 		if (p[0] == '!' || p[0] == '*') {
 			weprintf("denied\n");
-			return -1;
+			return NULL;
 		}
+		return p;
+	}
+}
+
+/* Returns -1 on error, 0 for incorrect password
+ * and 1 if all went OK */
+int
+pw_check(const char *hash, const char *pass)
+{
+	char *cryptpass;
+
+	if (!hash || hash[0] == '!' || hash[0] == '*') {
+		weprintf("denied\n");
+		return -1;
 	}
 
-	cryptpass = crypt(pass, p);
+	cryptpass = crypt(pass, hash);
 	if (!cryptpass) {
 		weprintf("crypt:");
 		return -1;
 	}
-	if (strcmp(cryptpass, p) != 0) {
+	if (strcmp(cryptpass, hash) != 0) {
 		weprintf("incorrect password\n");
 		return 0;
 	}
diff --git a/login.c b/login.c
index 25a59e4..3490632 100644
--- a/login.c
+++ b/login.c
_AT_@ -107,11 +107,16 @@ main(int argc, char *argv[])
 	/* Flush pending input */
 	ioctl(0, TCFLSH, (void *)0);
 
-	pass = getpass("Password: ");
-	if (!pass)
-		eprintf("getpass:");
-	if (pw_check(pw, pass) <= 0)
+	const char *hash = pw_get(pw);
+	if (!hash)
 		exit(1);
+	else if (*hash) {
+		pass = getpass("Password: ");
+		if (!pass)
+			eprintf("getpass:");
+		if (pw_check(hash, pass) <= 0)
+			exit(1);
+	}
 
 	tty = ttyname(0);
 	if (!tty)
diff --git a/passwd.c b/passwd.c
index 52b70a8..cd70c64 100644
--- a/passwd.c
+++ b/passwd.c
_AT_@ -164,9 +164,12 @@ main(int argc, char *argv[])
 	struct passwd *pw;
 	struct spwd *spw = NULL;
 	FILE *fp = NULL;
-	int r = -1, status = 1;
+	int r = -1, status = 1, fdel = 0;
 
 	ARGBEGIN {
+	case 'd':
+		fdel = 1;
+		break;
 	default:
 		usage();
 	} ARGEND;
_AT_@ -216,6 +219,14 @@ main(int argc, char *argv[])
 			prevhash = pw->pw_passwd;
 	}
 
+	printf("%s\n", prevhash);
+	if (!*prevhash) {
+		if (pw->pw_uid == getuid())
+			goto newpass;
+		else
+			eprintf("denied\n");
+	}
+
 	printf("Changing password for %s\n", pw->pw_name);
 	inpass = getpass("Old password: ");
 	if (!inpass)
_AT_@ -230,10 +241,15 @@ main(int argc, char *argv[])
 		eprintf("incorrect password\n");
 
 newpass:
-	inpass = getpass("Enter new password: ");
+	if (fdel) {
+		cryptpass3 = estrdup("");
+		goto writepass;
+	} else {
+		inpass = getpass("Enter new password: ");
+	}
 	if (!inpass)
 		eprintf("getpass:");
-	if (inpass[0] == '\0')
+	if (inpass[0] == '\0' && !fdel)
 		eprintf("no password supplied\n");
 	p = crypt(inpass, prevhash);
 	if (!p)
_AT_@ -249,10 +265,11 @@ newpass:
 	/* Flush pending input */
 	ioctl(0, TCFLSH, (void *)0);
 
-	inpass = getpass("Retype new password: ");
+	if (!fdel)
+		inpass = getpass("Retype new password: ");
 	if (!inpass)
 		eprintf("getpass:");
-	if (inpass[0] == '\0')
+	if (inpass[0] == '\0' && !fdel)
 		eprintf("no password supplied\n");
 	p = crypt(inpass, salt);
 	if (!p)
_AT_@ -261,6 +278,7 @@ newpass:
 	if (strcmp(cryptpass2, cryptpass3) != 0)
 		eprintf("passwords don't match\n");
 
+writepass:
 	fp = spw_get_file(pw->pw_name);
 	if (fp) {
 		r = spw_write_file(fp, spw, cryptpass3);
diff --git a/passwd.h b/passwd.h
index ec8286b..f39a826 100644
--- a/passwd.h
+++ b/passwd.h
_AT_@ -1,4 +1,5 @@
 /* See LICENSE file for copyright and license details. */
 /* passwd.c */
-int pw_check(const struct passwd *, const char *);
+const char *pw_get(const struct passwd *);
+int pw_check(const char *, const char *);
 int pw_init(void);
-- 
2.15.0
Received on Mon Jan 15 2018 - 04:45:55 CET

This archive was generated by hypermail 2.3.0 : Mon Jan 15 2018 - 04:48:22 CET