Blob Blame History Raw
From a7453aeeb398d6cbb7a709c4e2a1d75905220fff Mon Sep 17 00:00:00 2001
From: Stanislav Zidek <szidek@redhat.com>
Date: Fri, 16 Apr 2021 19:14:18 +0200
Subject: [PATCH] pam_userdb: Prevent garbage characters from db

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791965
---
 modules/pam_userdb/pam_userdb.8.xml |  3 +-
 modules/pam_userdb/pam_userdb.c     | 56 +++++++++++++++++------------
 2 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/modules/pam_userdb/pam_userdb.8.xml b/modules/pam_userdb/pam_userdb.8.xml
index fa628ada..bce92850 100644
--- a/modules/pam_userdb/pam_userdb.8.xml
+++ b/modules/pam_userdb/pam_userdb.8.xml
@@ -100,7 +100,8 @@
         </term>
         <listitem>
           <para>
-            Print debug information.
+            Print debug information. Note that password hashes, both from db
+            and computed, will be printed to syslog.
           </para>
         </listitem>
       </varlistentry>
diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c
index dc2ca232..d59801bf 100644
--- a/modules/pam_userdb/pam_userdb.c
+++ b/modules/pam_userdb/pam_userdb.c
@@ -194,7 +194,7 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode,
     }
 
     if (data.dptr != NULL) {
-	int compare = 0;
+	int compare = -2;
 
 	if (ctrl & PAM_KEY_ONLY_ARG)
 	  {
@@ -209,36 +209,48 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode,
 	  char *cryptpw = NULL;
 
 	  if (data.dsize < 13) {
-	    compare = -2;
+	    /* hash is too short */
+	    pam_syslog(pamh, LOG_INFO, "password hash in database is too short");
 	  } else if (ctrl & PAM_ICASE_ARG) {
-	    compare = -2;
+	    pam_syslog(pamh, LOG_INFO,
+	       "case-insensitive comparison only works with plaintext passwords");
 	  } else {
+	    /* libdb is not guaranteed to produce null terminated strings */
+	    char *pwhash = strndup(data.dptr, data.dsize);
+
+	    if (pwhash == NULL) {
+	      pam_syslog(pamh, LOG_CRIT, "strndup failed: data.dptr");
+	    } else {
 #ifdef HAVE_CRYPT_R
-	    struct crypt_data *cdata = NULL;
-	    cdata = malloc(sizeof(*cdata));
-	    if (cdata != NULL) {
-		cdata->initialized = 0;
-		cryptpw = crypt_r(pass, data.dptr, cdata);
-	    }
+	      struct crypt_data *cdata = NULL;
+	      cdata = malloc(sizeof(*cdata));
+	      if (cdata == NULL) {
+	        pam_syslog(pamh, LOG_CRIT, "malloc failed: struct crypt_data");
+	      } else {
+	        cdata->initialized = 0;
+	        cryptpw = crypt_r(pass, pwhash, cdata);
+	      }
 #else
-	    cryptpw = crypt (pass, data.dptr);
+	      cryptpw = crypt (pass, pwhash);
 #endif
-	    if (cryptpw && strlen(cryptpw) == (size_t)data.dsize) {
-	      compare = memcmp(data.dptr, cryptpw, data.dsize);
-	    } else {
-	      compare = -2;
-	      if (ctrl & PAM_DEBUG_ARG) {
-		if (cryptpw)
-		  pam_syslog(pamh, LOG_INFO, "lengths of computed and stored hashes differ");
-		else
-		  pam_syslog(pamh, LOG_INFO, "crypt() returned NULL");
+	      if (cryptpw && strlen(cryptpw) == (size_t)data.dsize) {
+	        compare = memcmp(data.dptr, cryptpw, data.dsize);
+	      } else {
+	        if (ctrl & PAM_DEBUG_ARG) {
+	          if (cryptpw) {
+	            pam_syslog(pamh, LOG_INFO, "lengths of computed and stored hashes differ");
+	            pam_syslog(pamh, LOG_INFO, "computed hash: %s", cryptpw);
+	          } else {
+	            pam_syslog(pamh, LOG_ERR, "crypt() returned NULL");
+	          }
+	        }
 	      }
-	    }
 #ifdef HAVE_CRYPT_R
-	    free(cdata);
+	      free(cdata);
 #endif
+	    }
+	    free(pwhash);
 	  }
-
 	} else {
 
 	  /* Unknown password encryption method -
-- 
2.30.2