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
@@ -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;
@@ -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') {
@@ -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
@@ -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
@@ -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;
@@ -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)
@@ -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)
@@ -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)
@@ -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
@@ -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


Reply via email to