From cb04d3cb6b3899b5386f940a385d08c66dcd0da1 Mon Sep 17 00:00:00 2001
From: mancha <mancha1@hush.com>
Date: Fri, 31 Jan 2014
Subject: Handle new crypt() behavior in glibc 2.17+

Starting with glibc 2.17 (eglibc 2.17), crypt() fails with EINVAL
(w/ NULL return) if the salt violates specifications. Additionally,
on FIPS-140 enabled Linux systems, DES/MD5-encrypted passwords
passed to crypt() fail with EPERM (w/ NULL return).

If using glibc's crypt(), check return value to avoid a possible
NULL pointer dereference.

Note: gdm 2.20.11 is the last version that support non-PAM 
      authentication which is why it is the latest stable
      maintained for Slackware Linux via slackbuilds.org.

---
 daemon/verify-crypt.c  |   13 ++++++++++---
 daemon/verify-shadow.c |   13 ++++++++++---
 2 files changed, 20 insertions(+), 6 deletions(-)

--- a/daemon/verify-crypt.c
+++ b/daemon/verify-crypt.c
@@ -104,7 +104,7 @@ gdm_verify_user (GdmDisplay *d,
 		 const char *username,
 		 gboolean allow_retry)
 {
-	gchar *login, *passwd, *ppasswd;
+	gchar *login, *passwd, *ppasswd, *cpasswd;
 	struct passwd *pwent;
 #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS)	\
 	|| defined (HAVE_LOGINRESTRICTIONS)
@@ -190,8 +190,10 @@ gdm_verify_user (GdmDisplay *d,
 	}
 
 	/* Check whether password is valid */
-	if (ppasswd == NULL || (ppasswd[0] != '\0' &&
-				strcmp (crypt (passwd, ppasswd), ppasswd) != 0)) {
+	cpasswd = ppasswd ? g_strdup(crypt (passwd, ppasswd)) : NULL;
+	if (ppasswd == NULL || cpasswd == NULL ||
+				(ppasswd[0] != '\0' &&
+				 strcmp (cpasswd, ppasswd) != 0)) {
 		gdm_sleep_no_signal (gdm_daemon_config_get_value_int (GDM_KEY_RETRY_DELAY));
 		gdm_debug ("Couldn't authenticate user");
 
@@ -200,6 +202,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -217,6 +220,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -233,6 +237,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		if (message != NULL)
 			free (message);
 		return NULL;
@@ -259,6 +264,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -266,6 +272,7 @@ gdm_verify_user (GdmDisplay *d,
 
 	g_free (passwd);
 	g_free (ppasswd);
+	g_free (cpasswd);
 
 	if ( ! gdm_slave_check_user_wants_to_log_in (login)) {
 		g_free (login);
--- a/daemon/verify-shadow.c
+++ b/daemon/verify-shadow.c
@@ -105,7 +105,7 @@ gdm_verify_user (GdmDisplay *d,
 		 const char *username,
 		 gboolean allow_retry)
 {
-	gchar *login, *passwd, *ppasswd;
+	gchar *login, *passwd, *ppasswd, *cpasswd;
 	struct passwd *pwent;
 	struct spwd *sp;
 #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS)	\
@@ -211,8 +211,10 @@ gdm_verify_user (GdmDisplay *d,
 	}
 
 	/* Check whether password is valid */
-	if (ppasswd == NULL || (ppasswd[0] != '\0' &&
-				strcmp (crypt (passwd, ppasswd), ppasswd) != 0)) {
+	cpasswd = ppasswd ? g_strdup(crypt (passwd, ppasswd)) : NULL;
+	if (ppasswd == NULL || cpasswd == NULL || 
+				(ppasswd[0] != '\0' &&
+				 strcmp (cpasswd, ppasswd) != 0)) {
 		gdm_sleep_no_signal (gdm_daemon_config_get_value_int (GDM_KEY_RETRY_DELAY));
 		gdm_debug ("Couldn't authenticate user");
 
@@ -221,6 +223,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -238,6 +241,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -254,6 +258,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		if (message != NULL)
 			free (message);
 		return NULL;
@@ -280,6 +285,7 @@ gdm_verify_user (GdmDisplay *d,
 		g_free (login);
 		g_free (passwd);
 		g_free (ppasswd);
+		g_free (cpasswd);
 		return NULL;
 	}
 
@@ -287,6 +293,7 @@ gdm_verify_user (GdmDisplay *d,
 
 	g_free (passwd);
 	g_free (ppasswd);
+	g_free (cpasswd);
 
 	if ( ! gdm_slave_check_user_wants_to_log_in (login)) {
 		g_free (login);
