components/openssh/patches/015-pam_conversation_fix.patch
author Tomas Kuthan <tomas.kuthan@oracle.com>
Tue, 20 Sep 2016 03:54:40 -0700
changeset 6931 f6f7269f85a9
parent 6930 31ef2580c45d
permissions -rw-r--r--
24597931 PAM_BUGFIX by-passes fake password for timing attack avoidance

#
# This patch contains an important bug fix for the PAM password userauth
# conversation function. This bug fix was contributed back to the upstream in 
# 2009, but it was not accepted by the upstream.  For more information, see
# https://bugzilla.mindrot.org/show_bug.cgi?id=1681.
#
--- orig/auth-pam.c	Mon Aug 15 16:16:17 2016
+++ new/auth-pam.c	Mon Aug 15 16:26:40 2016
@@ -1138,11 +1138,13 @@
 	free(env);
 }
 
+#ifndef PAM_BUGFIX
 /*
  * "Blind" conversation function for password authentication.  Assumes that
  * echo-off prompts are for the password and stores messages for later
  * display.
  */
+#endif
 static int
 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
     struct pam_response **resp, void *data)
@@ -1164,6 +1166,17 @@
 	for (i = 0; i < n; ++i) {
 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
 		case PAM_PROMPT_ECHO_OFF:
+#ifdef PAM_BUGFIX
+                       /*
+                        * PAM conversation function for the password userauth
+                        * method (non-interactive) really cannot do any 
+                        * prompting.  We set the PAM_AUTHTOK item in 
+                        * sshpam_auth_passwd()to avoid conversation. If some
+                        * modules still try to converse, then the password
+                        * userauth will fail.
+                        */
+                        goto fail;
+#else
 			if (sshpam_password == NULL)
 				goto fail;
 			if ((reply[i].resp = strdup(sshpam_password)) == NULL)
@@ -1170,6 +1183,7 @@
 				goto fail;
 			reply[i].resp_retcode = PAM_SUCCESS;
 			break;
+#endif
 		case PAM_ERROR_MSG:
 		case PAM_TEXT_INFO:
 			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
@@ -1205,6 +1219,9 @@
 int
 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
 {
+#ifdef PAM_BUGFIX
+        int set_item_rtn;
+#endif
 	int flags = (options.permit_empty_passwd == 0 ?
 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
 	char *fake = NULL;
@@ -1225,6 +1242,15 @@
 	    options.permit_root_login != PERMIT_YES))
 		sshpam_password = fake = fake_password(password);
 
+#ifdef PAM_BUGFIX
+        sshpam_err = pam_set_item(sshpam_handle, PAM_AUTHTOK, sshpam_password);
+        if (sshpam_err != PAM_SUCCESS) {
+                debug("PAM: %s: failed to set PAM_AUTHTOK: %s", __func__,
+                    pam_strerror(sshpam_handle, sshpam_err));
+                return 0;
+        }
+#endif
+
 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
 	    (const void *)&passwd_conv);
 	if (sshpam_err != PAM_SUCCESS)
@@ -1236,6 +1262,16 @@
 	free(fake);
 	if (sshpam_err == PAM_MAXTRIES)
 		sshpam_set_maxtries_reached(1);
+
+#ifdef PAM_BUGFIX
+        set_item_rtn = pam_set_item(sshpam_handle, PAM_AUTHTOK, NULL);
+        if (set_item_rtn != PAM_SUCCESS) {
+                debug("PAM: %s: failed to set PAM_AUTHTOK: %s", __func__,
+                    pam_strerror(sshpam_handle, set_item_rtn));
+                return 0;
+        }
+#endif
+
 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
 		debug("PAM: password authentication accepted for %.100s",
 		    authctxt->user);