diff cli-auth.c @ 883:ff597bf2cfb0

DROPBEAR_CLI_AUTH_IMMEDIATE fixed, now enabled by default
author Matt Johnston <matt@ucc.asn.au>
date Fri, 17 Jan 2014 21:39:27 +0800
parents 619b1ed837fd
children 7032deca6b90
line wrap: on
line diff
--- a/cli-auth.c	Wed Dec 11 21:50:33 2013 +0800
+++ b/cli-auth.c	Fri Jan 17 21:39:27 2014 +0800
@@ -41,16 +41,6 @@
 /* Send a "none" auth request to get available methods */
 void cli_auth_getmethods() {
 	TRACE(("enter cli_auth_getmethods"))
-#ifdef CLI_IMMEDIATE_AUTH
-	ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
-    if (getenv(DROPBEAR_PASSWORD_ENV)) {
-		ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
-	}
-	if (cli_auth_try() == DROPBEAR_SUCCESS) {
-		TRACE(("skipped initial none auth query"))
-		return;
-	}
-#endif
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
 	buf_putstring(ses.writepayload, cli_opts.username, 
@@ -60,6 +50,18 @@
 	buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
 
 	encrypt_packet();
+
+#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH
+	ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
+    if (getenv(DROPBEAR_PASSWORD_ENV)) {
+		ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
+	}
+	if (cli_auth_try() == DROPBEAR_SUCCESS) {
+		TRACE(("skipped initial none auth query"))
+		/* Note that there will be two auth responses in-flight */
+		cli_ses.ignore_next_auth_response = 1;
+	}
+#endif
 	TRACE(("leave cli_auth_getmethods"))
 }
 
@@ -150,31 +152,46 @@
 	TRACE(("<- MSG_USERAUTH_FAILURE"))
 	TRACE(("enter recv_msg_userauth_failure"))
 
+	if (ses.authstate.authdone) {
+		TRACE(("leave recv_msg_userauth_failure, already authdone."))
+		return;
+	}
+
 	if (cli_ses.state != USERAUTH_REQ_SENT) {
 		/* Perhaps we should be more fatal? */
 		dropbear_exit("Unexpected userauth failure");
 	}
 
+	/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for 
+	the "none" auth request, and then a response to the immediate auth request. 
+	We need to be careful handling them. */
+	if (cli_ses.ignore_next_auth_response) {
+		TRACE(("ignore next response, state set to USERAUTH_REQ_SENT"))
+		cli_ses.state = USERAUTH_REQ_SENT;
+	} else  {
+		cli_ses.state = USERAUTH_FAIL_RCVD;
+		cli_ses.lastauthtype = AUTH_TYPE_NONE;
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	/* If it was a pubkey auth request, we should cross that key 
-	 * off the list. */
-	if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
-		cli_pubkeyfail();
-	}
+		/* If it was a pubkey auth request, we should cross that key 
+		 * off the list. */
+		if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
+			cli_pubkeyfail();
+		}
 #endif
 
 #ifdef ENABLE_CLI_INTERACT_AUTH
-	/* If we get a failure message for keyboard interactive without
-	 * receiving any request info packet, then we don't bother trying
-	 * keyboard interactive again */
-	if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
-			&& !cli_ses.interact_request_received) {
-		TRACE(("setting auth_interact_failed = 1"))
-		cli_ses.auth_interact_failed = 1;
+		/* If we get a failure message for keyboard interactive without
+		 * receiving any request info packet, then we don't bother trying
+		 * keyboard interactive again */
+		if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
+				&& !cli_ses.interact_request_received) {
+			TRACE(("setting auth_interact_failed = 1"))
+			cli_ses.auth_interact_failed = 1;
+		}
+#endif
 	}
-#endif
 
-	cli_ses.lastauthtype = AUTH_TYPE_NONE;
+	cli_ses.ignore_next_auth_response = 0;
 
 	methods = buf_getstring(ses.payload, &methlen);
 
@@ -227,13 +244,14 @@
 	}
 
 	m_free(methods);
-
-	cli_ses.state = USERAUTH_FAIL_RCVD;
 		
 	TRACE(("leave recv_msg_userauth_failure"))
 }
 
 void recv_msg_userauth_success() {
+	/* This function can validly get called multiple times
+	if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
+
 	TRACE(("received msg_userauth_success"))
 	/* Note: in delayed-zlib mode, setting authdone here 
 	 * will enable compression in the transport layer */