diff cli-auth.c @ 297:79bf1023cf11 agent-client

propagate from branch 'au.asn.ucc.matt.dropbear' (head 0501e6f661b5415eb76f3b312d183c3adfbfb712) to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 01038174ec27245b51bd43a66c01ad930880f67b)
author Matt Johnston <matt@ucc.asn.au>
date Tue, 21 Mar 2006 16:20:59 +0000
parents 475a818dd6e7
children 64abb124763d baea1d43e7eb
line wrap: on
line diff
--- a/cli-auth.c	Mon Jul 18 14:32:52 2005 +0000
+++ b/cli-auth.c	Tue Mar 21 16:20:59 2006 +0000
@@ -32,7 +32,6 @@
 #include "packet.h"
 #include "runopts.h"
 
-
 void cli_authinitialise() {
 
 	memset(&ses.authstate, 0, sizeof(ses.authstate));
@@ -99,6 +98,40 @@
 	TRACE(("leave recv_msg_userauth_banner"))
 }
 
+/* This handles the message-specific types which
+ * all have a value of 60. These are
+ * SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
+ * SSH_MSG_USERAUTH_PK_OK, &
+ * SSH_MSG_USERAUTH_INFO_REQUEST. */
+void recv_msg_userauth_specific_60() {
+
+#ifdef ENABLE_CLI_PUBKEY_AUTH
+	if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
+		recv_msg_userauth_pk_ok();
+		return;
+	}
+#endif
+
+#ifdef ENABLE_CLI_INTERACT_AUTH
+	if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
+		recv_msg_userauth_info_request();
+		return;
+	}
+#endif
+
+#ifdef ENABLE_CLI_PASSWORD_AUTH
+	if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
+		/* Eventually there could be proper password-changing
+		 * support. However currently few servers seem to
+		 * implement it, and password auth is last-resort
+		 * regardless - keyboard-interactive is more likely
+		 * to be used anyway. */
+		dropbear_close("Your password has expired.");
+	}
+#endif
+
+	dropbear_exit("Unexpected userauth packet");
+}
 
 void recv_msg_userauth_failure() {
 
@@ -113,8 +146,7 @@
 
 	if (cli_ses.state != USERAUTH_REQ_SENT) {
 		/* Perhaps we should be more fatal? */
-		TRACE(("But we didn't send a userauth request!!!!!!"))
-		return;
+		dropbear_exit("Unexpected userauth failure");
 	}
 
 #ifdef ENABLE_CLI_PUBKEY_AUTH
@@ -125,6 +157,19 @@
 	}
 #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;
+	}
+#endif
+
+	cli_ses.lastauthtype = AUTH_TYPE_NONE;
+
 	methods = buf_getstring(ses.payload, &methlen);
 
 	partial = buf_getbool(ses.payload);
@@ -157,6 +202,12 @@
 				ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
 			}
 #endif
+#ifdef ENABLE_CLI_INTERACT_AUTH
+			if (strncmp(AUTH_METHOD_INTERACT, tok,
+				AUTH_METHOD_INTERACT_LEN) == 0) {
+				ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
+			}
+#endif
 #ifdef ENABLE_CLI_PASSWORD_AUTH
 			if (strncmp(AUTH_METHOD_PASSWORD, tok,
 				AUTH_METHOD_PASSWORD_LEN) == 0) {
@@ -180,6 +231,7 @@
 	TRACE(("received msg_userauth_success"))
 	ses.authstate.authdone = 1;
 	cli_ses.state = USERAUTH_SUCCESS_RCVD;
+	cli_ses.lastauthtype = AUTH_TYPE_NONE;
 }
 
 void cli_auth_try() {
@@ -189,7 +241,8 @@
 
 	CHECKCLEARTOWRITE();
 	
-	/* XXX We hardcode that we try a pubkey first */
+	/* Order to try is pubkey, interactive, password.
+	 * As soon as "finished" is set for one, we don't do any more. */
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 	if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
 		finished = cli_auth_pubkey();
@@ -197,16 +250,46 @@
 	}
 #endif
 
+#ifdef ENABLE_CLI_INTERACT_AUTH
+	if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
+		if (cli_ses.auth_interact_failed) {
+			finished = 0;
+		} else {
+			cli_auth_interactive();
+			cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
+			finished = 1;
+		}
+	}
+#endif
+
 #ifdef ENABLE_CLI_PASSWORD_AUTH
 	if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
-		finished = cli_auth_password();
+		cli_auth_password();
+		finished = 1;
 		cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
 	}
 #endif
 
+	TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
+
 	if (!finished) {
 		dropbear_exit("No auth methods could be used.");
 	}
 
 	TRACE(("leave cli_auth_try"))
 }
+
+/* A helper for getpass() that exits if the user cancels. The returned
+ * password is statically allocated by getpass() */
+char* getpass_or_cancel()
+{
+	char* password = NULL;
+
+	password = getpass("Password: ");
+
+	/* 0x03 is a ctrl-c character in the buffer. */
+	if (password == NULL || strchr(password, '\3') != NULL) {
+		dropbear_close("Interrupted.");
+	}
+	return password;
+}