From 99d9cf500b30c77107bf8477dd55831626f9beaf Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Fri, 29 Mar 2013 23:29:48 +0800
Subject: [PATCH] Add kexguess2 behaviour

--HG--
branch : kexguess
---
 algo.h        | 14 ++++++++++++--
 cli-algo.c    | 32 +++++++++++++++++++++++++++-----
 common-algo.c |  1 +
 common-kex.c  | 21 ++++++++++++---------
 debug.h       |  4 ++--
 kex.h         |  1 +
 options.h     |  4 ++--
 session.h     |  1 +
 svr-algo.c    | 32 ++++++++++++++++++++++++++++----
 9 files changed, 86 insertions(+), 24 deletions(-)

diff --git a/algo.h b/algo.h
index ad57037f..755cfcdf 100644
--- a/algo.h
+++ b/algo.h
@@ -83,10 +83,20 @@ void crypto_init();
 int have_algo(char* algo, size_t algolen, algo_type algos[]);
 void buf_put_algolist(buffer * buf, algo_type localalgos[]);
 
+enum kexguess2_used {
+	KEXGUESS2_LOOK,
+	KEXGUESS2_NO,
+	KEXGUESS2_YES,
+};
+
+#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
+#define KEXGUESS2_ALGO_ID 99
+
+
 algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess);
+		enum kexguess2_used *kexguess2, int *goodguess);
 algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess);
+		enum kexguess2_used *kexguess2, int *goodguess);
 
 #ifdef ENABLE_USER_ALGO_LIST
 int check_user_algos(const char* user_algo_list, algo_type * algos, 
diff --git a/cli-algo.c b/cli-algo.c
index 09da41a3..ec8c541f 100644
--- a/cli-algo.c
+++ b/cli-algo.c
@@ -34,7 +34,7 @@
  * that is also on the server's list.
  */
 algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess) {
+		enum kexguess2_used *kexguess2, int *goodguess) {
 
 	unsigned char * algolist = NULL;
 	unsigned char * remotealgos[MAX_PROPOSED_ALGO];
@@ -42,7 +42,9 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
 	unsigned int count, i, j;
 	algo_type * ret = NULL;
 
-	*goodguess = 0;
+	if (goodguess) {
+		*goodguess = 0;
+	}
 
 	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
 	algolist = buf_getstring(buf, &len);
@@ -72,6 +74,19 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
 		}
 	}
 
+	if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
+		for (i = 0; i < count; i++)
+		{
+			if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) {
+				*kexguess2 = KEXGUESS2_YES;
+				break;
+			}
+		}
+		if (*kexguess2 == KEXGUESS2_LOOK) {
+			*kexguess2 = KEXGUESS2_NO;
+		}
+	}
+
 	/* iterate and find the first match */
 
 	for (j = 0; localalgos[j].name != NULL; j++) {
@@ -81,9 +96,16 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
 				if (len == strlen(remotealgos[i]) 
 						&& strncmp(localalgos[j].name, 
 							remotealgos[i], len) == 0) {
-					if (i == 0 && j == 0) {
-						/* was a good guess */
-						*goodguess = 1;
+					if (goodguess && kexguess2) {
+						if (*kexguess2 == KEXGUESS2_YES) {
+							if (j == 0) {
+								*goodguess = 1;
+							}
+						} else {
+							if (i == 0 && j == 0) {
+								*goodguess = 1;
+							}
+						}
 					}
 					ret = &localalgos[j];
 					goto out;
diff --git a/common-algo.c b/common-algo.c
index 4a14651e..46dbe74f 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -215,6 +215,7 @@ algo_type sshhostkey[] = {
 algo_type sshkex[] = {
 	{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
 	{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
+	{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
 	{NULL, 0, NULL, 0, NULL}
 };
 
diff --git a/common-kex.c b/common-kex.c
index e4b4c023..0640b9f8 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -692,18 +692,21 @@ static void read_kex_algos() {
 
 	memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
 
+	enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
+
 	/* kex_algorithms */
-	algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
+	algo = ses.buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
 	allgood &= goodguess;
-	if (algo == NULL) {
+	if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
 		erralgo = "kex";
 		goto error;
 	}
+	TRACE(("kexguess2 %d", kexguess2))
 	TRACE(("kex algo %s", algo->name))
 	ses.newkeys->algo_kex = algo->val;
 
 	/* server_host_key_algorithms */
-	algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
+	algo = ses.buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
 	allgood &= goodguess;
 	if (algo == NULL) {
 		erralgo = "hostkey";
@@ -713,7 +716,7 @@ static void read_kex_algos() {
 	ses.newkeys->algo_hostkey = algo->val;
 
 	/* encryption_algorithms_client_to_server */
-	c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
+	c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL);
 	if (c2s_cipher_algo == NULL) {
 		erralgo = "enc c->s";
 		goto error;
@@ -721,7 +724,7 @@ static void read_kex_algos() {
 	TRACE(("enc c2s is  %s", c2s_cipher_algo->name))
 
 	/* encryption_algorithms_server_to_client */
-	s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
+	s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, NULL, NULL);
 	if (s2c_cipher_algo == NULL) {
 		erralgo = "enc s->c";
 		goto error;
@@ -729,7 +732,7 @@ static void read_kex_algos() {
 	TRACE(("enc s2c is  %s", s2c_cipher_algo->name))
 
 	/* mac_algorithms_client_to_server */
-	c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
+	c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL);
 	if (c2s_hash_algo == NULL) {
 		erralgo = "mac c->s";
 		goto error;
@@ -737,7 +740,7 @@ static void read_kex_algos() {
 	TRACE(("hash c2s is  %s", c2s_hash_algo->name))
 
 	/* mac_algorithms_server_to_client */
-	s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
+	s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, NULL, NULL);
 	if (s2c_hash_algo == NULL) {
 		erralgo = "mac s->c";
 		goto error;
@@ -745,7 +748,7 @@ static void read_kex_algos() {
 	TRACE(("hash s2c is  %s", s2c_hash_algo->name))
 
 	/* compression_algorithms_client_to_server */
-	c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
+	c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
 	if (c2s_comp_algo == NULL) {
 		erralgo = "comp c->s";
 		goto error;
@@ -753,7 +756,7 @@ static void read_kex_algos() {
 	TRACE(("hash c2s is  %s", c2s_comp_algo->name))
 
 	/* compression_algorithms_server_to_client */
-	s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
+	s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
 	if (s2c_comp_algo == NULL) {
 		erralgo = "comp s->c";
 		goto error;
diff --git a/debug.h b/debug.h
index b20e6850..02c100f9 100644
--- a/debug.h
+++ b/debug.h
@@ -39,7 +39,7 @@
  * Caution: Don't use this in an unfriendly environment (ie unfirewalled),
  * since the printing may not sanitise strings etc. This will add a reasonable
  * amount to your executable size. */
-/*#define DEBUG_TRACE */
+#define DEBUG_TRACE
 
 /* All functions writing to the cleartext payload buffer call
  * CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -69,7 +69,7 @@
 
 /* To debug with GDB it is easier to run with no forking of child processes.
    You will need to pass "-F" as well. */
-/* #define DEBUG_NOFORK */
+#define DEBUG_NOFORK
 
 
 /* For testing as non-root on shadowed systems, include the crypt of a password
diff --git a/kex.h b/kex.h
index dc5f46bc..72430e96 100644
--- a/kex.h
+++ b/kex.h
@@ -66,6 +66,7 @@ struct KEXState {
 
 };
 
+
 #define MAX_KEXHASHBUF 2000
 
 #endif /* _KEX_H_ */
diff --git a/options.h b/options.h
index c52d6c24..71d39ccd 100644
--- a/options.h
+++ b/options.h
@@ -174,9 +174,9 @@ much traffic. */
  * PAM challenge/response.
  * You can't enable both PASSWORD and PAM. */
 
-#define ENABLE_SVR_PASSWORD_AUTH
+//#define ENABLE_SVR_PASSWORD_AUTH
 /* PAM requires ./configure --enable-pam */
-/*#define ENABLE_SVR_PAM_AUTH*/
+#define ENABLE_SVR_PAM_AUTH
 #define ENABLE_SVR_PUBKEY_AUTH
 
 /* Whether to take public key options in 
diff --git a/session.h b/session.h
index 6b106f5c..3b9e957e 100644
--- a/session.h
+++ b/session.h
@@ -170,6 +170,7 @@ struct sshsession {
 	struct packetlist *reply_queue_head, *reply_queue_tail;
 
 	algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
+			enum kexguess2_used *kexguess2,
 			int *goodguess); /* The function to use to choose which algorithm
 								to use from the ones presented by the remote
 								side. Is specific to the client/server mode,
diff --git a/svr-algo.c b/svr-algo.c
index f8f90559..620cfeb9 100644
--- a/svr-algo.c
+++ b/svr-algo.c
@@ -33,7 +33,7 @@
  * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
  * guessed correctly */
 algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess)
+		enum kexguess2_used *kexguess2, int *goodguess)
 {
 
 	unsigned char * algolist = NULL;
@@ -42,7 +42,9 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
 	unsigned int count, i, j;
 	algo_type * ret = NULL;
 
-	*goodguess = 0;
+	if (goodguess) {
+		*goodguess = 0;
+	}
 
 	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
 	algolist = buf_getstring(buf, &len);
@@ -73,6 +75,19 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
 		}
 	}
 
+	if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
+		for (i = 0; i < count; i++)
+		{
+			if (strcmp(remotealgos[i], KEXGUESS2_ALGO_NAME) == 0) {
+				*kexguess2 = KEXGUESS2_YES;
+				break;
+			}
+		}
+		if (*kexguess2 == KEXGUESS2_LOOK) {
+			*kexguess2 = KEXGUESS2_NO;
+		}
+	}
+
 	/* iterate and find the first match */
 	for (i = 0; i < count; i++) {
 
@@ -83,8 +98,17 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
 				if (len == strlen(localalgos[j].name) &&
 						strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
 					/* set if it was a good guess */
-					if (i == 0 && j == 0) {
-						*goodguess = 1;
+					if (goodguess && kexguess2) {
+						if (*kexguess2 == KEXGUESS2_YES) {
+							if (i == 0) {
+								*goodguess = 1;
+							}
+
+						} else {
+							if (i == 0 && j == 0) {
+								*goodguess = 1;
+							}
+						}
 					}
 					/* set the algo to return */
 					ret = &localalgos[j];
-- 
GitLab