changeset 773:a9f2a6ae4eb5

merge
author Matt Johnston <matt@ucc.asn.au>
date Sun, 14 Apr 2013 22:49:19 +0800
parents 7fc0aeada79c (current diff) a389a2a7aa96 (diff)
children e8b2ca448928
files cli-algo.c cli-kex.c cli-service.c configure.in svr-algo.c
diffstat 46 files changed, 1363 insertions(+), 1262 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Sun Apr 14 22:49:10 2013 +0800
+++ b/.hgsigs	Sun Apr 14 22:49:19 2013 +0800
@@ -1,3 +1,4 @@
 aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
 3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
 85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
+9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
--- a/.hgtags	Sun Apr 14 22:49:10 2013 +0800
+++ b/.hgtags	Sun Apr 14 22:49:19 2013 +0800
@@ -35,3 +35,4 @@
 0000000000000000000000000000000000000000 t:ltc-0.95-orig
 d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
 0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
+1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
--- a/Makefile.in	Sun Apr 14 22:49:10 2013 +0800
+++ b/Makefile.in	Sun Apr 14 22:49:19 2013 +0800
@@ -28,13 +28,13 @@
 		queue.o \
 		atomicio.o compat.o  fake-rfc2553.o 
 
-SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
+SVROBJS=svr-kex.o svr-auth.o sshpty.o \
 		svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
 		svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
 		svr-tcpfwd.o svr-authpam.o
 
-CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
-		cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
+CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
+		cli-session.o cli-runopts.o cli-chansession.o \
 		cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
 		cli-agentfwd.o list.o
 
--- a/algo.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/algo.h	Sun Apr 14 22:49:19 2013 +0800
@@ -83,10 +83,18 @@
 int have_algo(char* algo, size_t algolen, algo_type algos[]);
 void buf_put_algolist(buffer * buf, algo_type localalgos[]);
 
-algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess);
-algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess);
+enum kexguess2_used {
+	KEXGUESS2_LOOK,
+	KEXGUESS2_NO,
+	KEXGUESS2_YES,
+};
+
+#define KEXGUESS2_ALGO_NAME "[email protected]"
+#define KEXGUESS2_ALGO_ID 99
+
+
+algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
+		enum kexguess2_used *kexguess2, int *goodguess);
 
 #ifdef ENABLE_USER_ALGO_LIST
 int check_user_algos(const char* user_algo_list, algo_type * algos, 
--- a/auth.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/auth.h	Sun Apr 14 22:49:19 2013 +0800
@@ -67,7 +67,7 @@
 void recv_msg_userauth_info_request();
 void cli_get_user();
 void cli_auth_getmethods();
-void cli_auth_try();
+int cli_auth_try();
 void recv_msg_userauth_banner();
 void cli_pubkeyfail();
 void cli_auth_password();
--- a/bignum.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/bignum.h	Sun Apr 14 22:49:19 2013 +0800
@@ -26,9 +26,10 @@
 #define _BIGNUM_H_
 
 #include "includes.h"
+#include "dbutil.h"
 
 void m_mp_init(mp_int *mp);
-void m_mp_init_multi(mp_int *mp, ...);
+void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
 void sha1_process_mp(hash_state *hs, mp_int *mp);
 
--- a/buffer.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/buffer.c	Sun Apr 14 22:49:19 2013 +0800
@@ -282,7 +282,7 @@
 void buf_putmpint(buffer* buf, mp_int * mp) {
 
 	unsigned int len, pad = 0;
-	TRACE(("enter buf_putmpint"))
+	TRACE2(("enter buf_putmpint"))
 
 	dropbear_assert(mp != NULL);
 
@@ -318,7 +318,7 @@
 		buf_incrwritepos(buf, len-pad);
 	}
 
-	TRACE(("leave buf_putmpint"))
+	TRACE2(("leave buf_putmpint"))
 }
 
 /* Retrieve an mp_int from the buffer.
--- a/channel.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/channel.h	Sun Apr 14 22:49:19 2013 +0800
@@ -83,8 +83,10 @@
 
 	int flushing;
 
+	/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
+	void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
+
 	const struct ChanType* type;
-
 };
 
 struct ChanType {
--- a/cli-agentfwd.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-agentfwd.c	Sun Apr 14 22:49:19 2013 +0800
@@ -156,8 +156,6 @@
 		goto out;
 	}
 	
-	TRACE(("agent_request readlen is %d", readlen))
-
 	buf_resize(inbuf, readlen);
 	buf_setpos(inbuf, 0);
 	ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
@@ -167,7 +165,6 @@
 	}
 	buf_incrwritepos(inbuf, readlen);
 	buf_setpos(inbuf, 0);
-	TRACE(("agent_request success, length %d", readlen))
 
 out:
 	if (payload)
--- a/cli-algo.c	Sun Apr 14 22:49:10 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Dropbear - a SSH2 server
- * SSH client implementation
- * 
- * Copyright (c) 2002,2003 Matt Johnston
- * Copyright (c) 2004 by Mihnea Stoenescu
- * All rights reserved.
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
-
-#include "algo.h"
-#include "dbutil.h"
-
-
-/*
- * The chosen [encryption | MAC | compression] algorithm to each 
- * direction MUST be the first algorithm  on the client's list
- * that is also on the server's list.
- */
-algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
-		int *goodguess) {
-
-	unsigned char * algolist = NULL;
-	unsigned char * remotealgos[MAX_PROPOSED_ALGO];
-	unsigned int len;
-	unsigned int count, i, j;
-	algo_type * ret = NULL;
-
-	*goodguess = 0;
-
-	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
-	algolist = buf_getstring(buf, &len);
-	TRACE(("cli_buf_match_algo: %s", algolist))
-	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
-		goto out; /* just a sanity check, no other use */
-	}
-
-	/* remotealgos will contain a list of the strings parsed out */
-	/* We will have at least one string (even if it's just "") */
-	remotealgos[0] = algolist;
-	count = 1;
-	/* Iterate through, replacing ','s with NULs, to split it into
-	 * words. */
-	for (i = 0; i < len; i++) {
-		if (algolist[i] == '\0') {
-			/* someone is trying something strange */
-			goto out;
-		}
-		if (algolist[i] == ',') {
-			algolist[i] = '\0';
-			remotealgos[count] = &algolist[i+1];
-			count++;
-		}
-		if (count >= MAX_PROPOSED_ALGO) {
-			break;
-		}
-	}
-
-	/* iterate and find the first match */
-
-	for (j = 0; localalgos[j].name != NULL; j++) {
-		if (localalgos[j].usable) {
-		len = strlen(localalgos[j].name);
-			for (i = 0; i < count; i++) {
-				if (len == strlen(remotealgos[i]) 
-						&& strncmp(localalgos[j].name, 
-							remotealgos[i], len) == 0) {
-					if (i == 0 && j == 0) {
-						/* was a good guess */
-						*goodguess = 1;
-					}
-					ret = &localalgos[j];
-					goto out;
-				}
-			}
-		}
-	}
-
-out:
-	m_free(algolist);
-	return ret;
-}
-
--- a/cli-auth.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-auth.c	Sun Apr 14 22:49:19 2013 +0800
@@ -40,11 +40,18 @@
 
 /* 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, 
 			strlen(cli_opts.username));
@@ -54,7 +61,6 @@
 
 	encrypt_packet();
 	TRACE(("leave cli_auth_getmethods"))
-
 }
 
 void recv_msg_userauth_banner() {
@@ -240,7 +246,7 @@
 #endif
 }
 
-void cli_auth_try() {
+int cli_auth_try() {
 
 	int finished = 0;
 	TRACE(("enter cli_auth_try"))
@@ -256,37 +262,40 @@
 	}
 #endif
 
-#ifdef ENABLE_CLI_INTERACT_AUTH
-	if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
-		fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
-	} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
-		if (cli_ses.auth_interact_failed) {
-			finished = 0;
+#ifdef ENABLE_CLI_PASSWORD_AUTH
+	if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
+		if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
+			fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
 		} else {
-			cli_auth_interactive();
-			cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
+			cli_auth_password();
 			finished = 1;
+			cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
 		}
 	}
 #endif
 
-#ifdef ENABLE_CLI_PASSWORD_AUTH
-	if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
-		fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
-	} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
-		cli_auth_password();
-		finished = 1;
-		cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
+#ifdef ENABLE_CLI_INTERACT_AUTH
+	if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
+		if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
+			fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
+		} else {
+			if (!cli_ses.auth_interact_failed) {
+				cli_auth_interactive();
+				cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
+				finished = 1;
+			}
+		}
 	}
 #endif
 
 	TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
 
-	if (!finished) {
-		dropbear_exit("No auth methods could be used.");
+	if (finished) {
+		TRACE(("leave cli_auth_try success"))
+		return DROPBEAR_SUCCESS;
 	}
-
-	TRACE(("leave cli_auth_try"))
+	TRACE(("leave cli_auth_try failure"))
+	return DROPBEAR_FAILURE;
 }
 
 /* A helper for getpass() that exits if the user cancels. The returned
--- a/cli-chansession.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-chansession.c	Sun Apr 14 22:49:19 2013 +0800
@@ -38,9 +38,10 @@
 static void cli_closechansess(struct Channel *channel);
 static int cli_initchansess(struct Channel *channel);
 static void cli_chansessreq(struct Channel *channel);
-
 static void send_chansess_pty_req(struct Channel *channel);
 static void send_chansess_shell_req(struct Channel *channel);
+static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
+
 
 static void cli_tty_setup();
 
@@ -81,14 +82,12 @@
 
 /* If the main session goes, we close it up */
 static void cli_closechansess(struct Channel *UNUSED(channel)) {
+	cli_tty_cleanup(); /* Restore tty modes etc */
 
 	/* This channel hasn't gone yet, so we have > 1 */
 	if (ses.chancount > 1) {
 		dropbear_log(LOG_INFO, "Waiting for other channels to close...");
 	}
-
-	cli_tty_cleanup(); /* Restore tty modes etc */
-
 }
 
 void cli_start_send_channel_request(struct Channel *channel, 
@@ -374,7 +373,9 @@
 
 	if (cli_opts.wantpty) {
 		cli_tty_setup();
-	}
+		channel->read_mangler = cli_escape_handler;
+		cli_ses.last_char = '\r';
+	}	
 
 	return 0; /* Success */
 }
@@ -429,3 +430,59 @@
 	TRACE(("leave cli_send_chansess_request"))
 
 }
+
+// returns 1 if the character should be consumed, 0 to pass through
+static int
+do_escape(unsigned char c) {
+	switch (c) {
+		case '.':
+			dropbear_exit("Terminated");
+			return 1;
+			break;
+		case 0x1a:
+			// ctrl-z
+			cli_tty_cleanup();
+			kill(getpid(), SIGTSTP);
+			// after continuation
+			cli_tty_setup();
+			cli_ses.winchange = 1;
+			return 1;
+			break;
+	}
+	return 0;
+}
+
+static
+void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
+	char c;
+	int skip_char = 0;
+
+	// only handle escape characters if they are read one at a time. simplifies
+	// the code and avoids nasty people putting ~. at the start of a line to paste 
+	if (*len != 1) {
+		cli_ses.last_char = 0x0;
+		return;
+	}
+
+	c = buf[0];
+
+	if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
+		skip_char = do_escape(c);
+		cli_ses.last_char = 0x0;
+	} else {
+		if (c == DROPBEAR_ESCAPE_CHAR) {
+			if (cli_ses.last_char == '\r') {
+				cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
+				skip_char = 1;
+			} else {
+				cli_ses.last_char = 0x0;
+			}
+		} else {
+			cli_ses.last_char = c;
+		}
+	}
+
+	if (skip_char) {
+		*len = 0;
+	}
+}
--- a/cli-kex.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-kex.c	Sun Apr 14 22:49:19 2013 +0800
@@ -42,18 +42,27 @@
 #define MAX_KNOWNHOSTS_LINE 4500
 
 void send_msg_kexdh_init() {
+	TRACE(("send_msg_kexdh_init()"))	
+	if ((cli_ses.dh_e && cli_ses.dh_x 
+				&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
+		TRACE(("reusing existing dh_e from first_kex_packet_follows"))
+	} else {
+		if (!cli_ses.dh_e || !cli_ses.dh_e) {
+			cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
+			cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
+			m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
+		}
 
-	cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
-	cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
-	m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
-
-	gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
+		gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
+		cli_ses.dh_val_algo = ses.newkeys->algo_kex;
+	}
 
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
 	buf_putmpint(ses.writepayload, cli_ses.dh_e);
 	encrypt_packet();
-	ses.requirenext = SSH_MSG_KEXDH_REPLY;
+	// XXX fixme
+	//ses.requirenext = SSH_MSG_KEXDH_REPLY;
 }
 
 /* Handle a diffie-hellman key exchange reply. */
@@ -98,6 +107,7 @@
 	mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
 	m_free(cli_ses.dh_e);
 	m_free(cli_ses.dh_x);
+	cli_ses.dh_val_algo = DROPBEAR_KEX_NONE;
 
 	if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) 
 			!= DROPBEAR_SUCCESS) {
@@ -251,7 +261,6 @@
 		/* Compare hostnames */
 		if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
 					hostlen) != 0) {
-			TRACE(("hosts don't match"))
 			continue;
 		}
 
@@ -314,7 +323,6 @@
 		buf_putbytes(line, algoname, algolen);
 		buf_putbyte(line, ' ');
 		len = line->size - line->pos;
-		TRACE(("keybloblen %d, len %d", keybloblen, len))
 		/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
 		 * will die horribly in the case anyway */
 		base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
--- a/cli-main.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-main.c	Sun Apr 14 22:49:19 2013 +0800
@@ -98,8 +98,7 @@
 	}
 
 	/* Do the cleanup first, since then the terminal will be reset */
-	cli_session_cleanup();
-	common_session_cleanup();
+	session_cleanup();
 
 	_dropbear_log(LOG_INFO, fmtbuf, param);
 
--- a/cli-service.c	Sun Apr 14 22:49:10 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Dropbear SSH
- * 
- * Copyright (c) 2002,2003 Matt Johnston
- * Copyright (c) 2004 by Mihnea Stoenescu
- * All rights reserved.
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
-
-#include "includes.h"
-#include "service.h"
-#include "dbutil.h"
-#include "packet.h"
-#include "buffer.h"
-#include "session.h"
-#include "ssh.h"
-
-void send_msg_service_request(char* servicename) {
-
-	TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
-
-	CHECKCLEARTOWRITE();
-
-	buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
-	buf_putstring(ses.writepayload, servicename, strlen(servicename));
-
-	encrypt_packet();
-	TRACE(("leave send_msg_service_request"))
-}
-
-/* This just sets up the state variables right for the main client session loop
- * to deal with */
-void recv_msg_service_accept() {
-
-	unsigned char* servicename;
-	unsigned int len;
-
-	TRACE(("enter recv_msg_service_accept"))
-
-	servicename = buf_getstring(ses.payload, &len);
-
-	/* ssh-userauth */
-	if (cli_ses.state == SERVICE_AUTH_REQ_SENT
-			&& len == SSH_SERVICE_USERAUTH_LEN
-			&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
-
-		cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
-		m_free(servicename);
-		TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
-		return;
-	}
-
-	/* ssh-connection */
-	if (cli_ses.state == SERVICE_CONN_REQ_SENT
-			&& len == SSH_SERVICE_CONNECTION_LEN 
-			&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
-
-		if (ses.authstate.authdone != 1) {
-			dropbear_exit("Request for connection before auth");
-		}
-
-		cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
-		m_free(servicename);
-		TRACE(("leave recv_msg_service_accept: done ssh-connection"))
-		return;
-	}
-
-	dropbear_exit("Unrecognised service accept");
-}
--- a/cli-session.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/cli-session.c	Sun Apr 14 22:49:19 2013 +0800
@@ -41,6 +41,8 @@
 static void cli_sessionloop();
 static void cli_session_init();
 static void cli_finished();
+static void recv_msg_service_accept(void);
+static void cli_session_cleanup(void);
 
 struct clientsession cli_ses; /* GLOBAL */
 
@@ -99,7 +101,7 @@
 	sessinitdone = 1;
 
 	/* Exchange identification */
-	session_identification();
+	send_session_identification();
 
 	send_msg_kexinit();
 
@@ -109,6 +111,12 @@
 
 }
 
+#ifdef USE_KEX_FIRST_FOLLOWS
+static void cli_send_kex_first_guess() {
+	send_msg_kexdh_init();
+}
+#endif
+
 static void cli_session_init() {
 
 	cli_ses.state = STATE_NOTHING;
@@ -142,37 +150,61 @@
 
 	/* For printing "remote host closed" for the user */
 	ses.remoteclosed = cli_remoteclosed;
-	ses.buf_match_algo = cli_buf_match_algo;
+
+	ses.extra_session_cleanup = cli_session_cleanup;
 
 	/* packet handlers */
 	ses.packettypes = cli_packettypes;
 
 	ses.isserver = 0;
+
+#ifdef USE_KEX_FIRST_FOLLOWS
+	ses.send_kex_first_guess = cli_send_kex_first_guess;
+#endif
+
+}
+
+static void send_msg_service_request(char* servicename) {
+
+	TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
+
+	CHECKCLEARTOWRITE();
+
+	buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
+	buf_putstring(ses.writepayload, servicename, strlen(servicename));
+
+	encrypt_packet();
+	TRACE(("leave send_msg_service_request"))
+}
+
+static void recv_msg_service_accept(void) {
+	// do nothing, if it failed then the server MUST have disconnected
 }
 
 /* This function drives the progress of the session - it initiates KEX,
  * service, userauth and channel requests */
 static void cli_sessionloop() {
 
-	TRACE(("enter cli_sessionloop"))
+	TRACE2(("enter cli_sessionloop"))
 
-	if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
-		cli_ses.kex_state = KEXINIT_RCVD;
+	if (ses.lastpacket == 0) {
+		TRACE2(("exit cli_sessionloop: no real packets yet"))
+		return;
 	}
 
-	if (cli_ses.kex_state == KEXINIT_RCVD) {
-
+	if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
 		/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
 		 * negotiation would have failed. */
-		send_msg_kexdh_init();
-		cli_ses.kex_state = KEXDH_INIT_SENT;
+		if (!ses.kexstate.our_first_follows_matches) {
+			send_msg_kexdh_init();
+		}
+		cli_ses.kex_state = KEXDH_INIT_SENT;			
 		TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
 		return;
 	}
 
 	/* A KEX has finished, so we should go back to our KEX_NOTHING state */
-	if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
-			&& ses.kexstate.sentkexinit == 0) {
+	if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
 		cli_ses.kex_state = KEX_NOTHING;
 	}
 
@@ -182,10 +214,10 @@
 		return;
 	}
 
-	/* We should exit if we haven't donefirstkex: we shouldn't reach here
-	 * in normal operation */
 	if (ses.kexstate.donefirstkex == 0) {
-		TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
+		/* We might reach here if we have partial packet reads or have
+		 * received SSG_MSG_IGNORE etc. Just skip it */
+		TRACE2(("donefirstkex false\n"))
 		return;
 	}
 
@@ -195,19 +227,15 @@
 			/* We've got the transport layer sorted, we now need to request
 			 * userauth */
 			send_msg_service_request(SSH_SERVICE_USERAUTH);
-			cli_ses.state = SERVICE_AUTH_REQ_SENT;
-			TRACE(("leave cli_sessionloop: sent userauth service req"))
-			return;
-
-		/* userauth code */
-		case SERVICE_AUTH_ACCEPT_RCVD:
 			cli_auth_getmethods();
 			cli_ses.state = USERAUTH_REQ_SENT;
 			TRACE(("leave cli_sessionloop: sent userauth methods req"))
 			return;
 			
 		case USERAUTH_FAIL_RCVD:
-			cli_auth_try();
+			if (cli_auth_try() == DROPBEAR_FAILURE) {
+				dropbear_exit("No auth methods could be used.");
+			}
 			cli_ses.state = USERAUTH_REQ_SENT;
 			TRACE(("leave cli_sessionloop: cli_auth_try"))
 			return;
@@ -238,13 +266,6 @@
 				}
 			}
 			
-#ifdef ENABLE_CLI_LOCALTCPFWD
-			setup_localtcp();
-#endif
-#ifdef ENABLE_CLI_REMOTETCPFWD
-			setup_remotetcp();
-#endif
-
 #ifdef ENABLE_CLI_NETCAT
 			if (cli_opts.netcat_host) {
 				cli_send_netcat_request();
@@ -253,6 +274,14 @@
 			if (!cli_opts.no_cmd) {
 				cli_send_chansess_request();
 			}
+
+#ifdef ENABLE_CLI_LOCALTCPFWD
+			setup_localtcp();
+#endif
+#ifdef ENABLE_CLI_REMOTETCPFWD
+			setup_remotetcp();
+#endif
+
 			TRACE(("leave cli_sessionloop: running"))
 			cli_ses.state = SESSION_RUNNING;
 			return;
@@ -274,11 +303,11 @@
 		break;
 	}
 
-	TRACE(("leave cli_sessionloop: fell out"))
+	TRACE2(("leave cli_sessionloop: fell out"))
 
 }
 
-void cli_session_cleanup() {
+static void cli_session_cleanup(void) {
 
 	if (!sessinitdone) {
 		return;
@@ -296,8 +325,7 @@
 
 static void cli_finished() {
 
-	cli_session_cleanup();
-	common_session_cleanup();
+	session_cleanup();
 	fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
 			cli_opts.remotehost, cli_opts.remoteport);
 	exit(cli_ses.retval);
--- a/common-algo.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/common-algo.c	Sun Apr 14 22:49:19 2013 +0800
@@ -24,6 +24,7 @@
  * SOFTWARE. */
 
 #include "algo.h"
+#include "session.h"
 #include "dbutil.h"
 
 /* This file (algo.c) organises the ciphers which can be used, and is used to
@@ -215,6 +216,9 @@
 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},
+#ifdef USE_KEXGUESS2
+	{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
+#endif
 	{NULL, 0, NULL, 0, NULL}
 };
 
@@ -307,6 +311,122 @@
 	buf_free(algolist);
 }
 
+/* match the first algorithm in the comma-separated list in buf which is
+ * also in localalgos[], or return NULL on failure.
+ * (*goodguess) is set to 1 if the preferred client/server algos match,
+ * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
+ * guessed correctly */
+algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
+		enum kexguess2_used *kexguess2, int *goodguess)
+{
+
+	unsigned char * algolist = NULL;
+	const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
+	unsigned int len;
+	unsigned int remotecount, localcount, clicount, servcount, i, j;
+	algo_type * ret = NULL;
+	const unsigned char **clinames, **servnames;
+
+	if (goodguess) {
+		*goodguess = 0;
+	}
+
+	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
+	algolist = buf_getstring(buf, &len);
+	TRACE(("buf_match_algo: %s", algolist))
+	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
+		goto out;
+	}
+
+	/* remotenames will contain a list of the strings parsed out */
+	/* We will have at least one string (even if it's just "") */
+	remotenames[0] = algolist;
+	remotecount = 1;
+	for (i = 0; i < len; i++) {
+		if (algolist[i] == '\0') {
+			/* someone is trying something strange */
+			goto out;
+		}
+		if (algolist[i] == ',') {
+			algolist[i] = '\0';
+			remotenames[remotecount] = &algolist[i+1];
+			remotecount++;
+		}
+		if (remotecount >= MAX_PROPOSED_ALGO) {
+			break;
+		}
+	}
+	if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
+		for (i = 0; i < remotecount; i++)
+		{
+			if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
+				*kexguess2 = KEXGUESS2_YES;
+				break;
+			}
+		}
+		if (*kexguess2 == KEXGUESS2_LOOK) {
+			*kexguess2 = KEXGUESS2_NO;
+		}
+	}
+
+	for (i = 0; localalgos[i].name != NULL; i++) {
+		if (localalgos[i].usable) {
+			localnames[i] = localalgos[i].name;
+		} else {
+			localnames[i] = NULL;
+		}
+	}
+	localcount = i;
+
+	if (IS_DROPBEAR_SERVER) {
+		clinames = remotenames;
+		clicount = remotecount;
+		servnames = localnames;
+		servcount = localcount;
+	} else {
+		clinames = localnames;
+		clicount = localcount;
+		servnames = remotenames;
+		servcount = remotecount;
+	}
+
+	/* iterate and find the first match */
+	for (i = 0; i < clicount; i++) {
+		for (j = 0; j < servcount; j++) {
+			if (!(servnames[j] && clinames[i])) {
+				// unusable algos are NULL
+				continue;
+			}
+			if (strcmp(servnames[j], clinames[i]) == 0) {
+				/* set if it was a good guess */
+				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 */
+				if (IS_DROPBEAR_SERVER) {
+					ret = &localalgos[j];
+				} else {
+					ret = &localalgos[i];
+				}
+				goto out;
+			}
+		}
+	}
+
+out:
+	m_free(algolist);
+	return ret;
+}
+
 #ifdef DROPBEAR_NONE_CIPHER
 
 void
--- a/common-channel.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/common-channel.c	Sun Apr 14 22:49:19 2013 +0800
@@ -273,10 +273,10 @@
 static void check_close(struct Channel *channel) {
 	int close_allowed = 0;
 
-	TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
+	TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
 				channel->writefd, channel->readfd,
 				channel->errfd, channel->sent_close, channel->recv_close))
-	TRACE(("writebuf size %d extrabuf size %d",
+	TRACE2(("writebuf size %d extrabuf size %d",
 				channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
 				channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
 
@@ -561,7 +561,11 @@
 	TRACE(("CLOSE errfd %d", channel->errfd))
 	close(channel->errfd);
 
-	channel->typedata = NULL;
+	if (!channel->close_handler_done
+		&& channel->type->closehandler) {
+		channel->type->closehandler(channel);
+		channel->close_handler_done = 1;
+	}
 
 	ses.channels[channel->index] = NULL;
 	m_free(channel);
@@ -625,7 +629,7 @@
 	 * exttype if is extended */
 	maxlen = MIN(maxlen, 
 			ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
-	TRACE(("maxlen %d", maxlen))
+	TRACE(("maxlen %zd", maxlen))
 	if (maxlen == 0) {
 		TRACE(("leave send_msg_channel_data: no window"))
 		return;
@@ -643,6 +647,7 @@
 
 	/* read the data */
 	len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
+
 	if (len <= 0) {
 		if (len == 0 || errno != EINTR) {
 			/* This will also get hit in the case of EAGAIN. The only
@@ -650,12 +655,22 @@
 			in which case it can be treated the same as EOF */
 			close_chan_fd(channel, fd, SHUT_RD);
 		}
-		ses.writepayload->len = ses.writepayload->pos = 0;
+		buf_setpos(ses.writepayload, 0);
+		buf_setlen(ses.writepayload, 0);
 		TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d", 
 					len, errno, fd))
 		return;
 	}
 
+	if (channel->read_mangler) {
+		channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
+		if (len == 0) {
+			buf_setpos(ses.writepayload, 0);
+			buf_setlen(ses.writepayload, 0);
+			return;
+		}
+	}
+
 	TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
 	buf_incrwritepos(ses.writepayload, len);
 	/* ... real size here */
--- a/common-kex.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/common-kex.c	Sun Apr 14 22:49:19 2013 +0800
@@ -80,9 +80,10 @@
 static const int DH_G_VAL = 2;
 
 static void kexinitialise();
-void gen_new_keys();
+static void gen_new_keys();
 #ifndef DISABLE_ZLIB
-static void gen_new_zstreams();
+static void gen_new_zstream_recv();
+static void gen_new_zstream_trans();
 #endif
 static void read_kex_algos();
 /* helper function for gen_new_keys */
@@ -131,8 +132,8 @@
 	/* languages_server_to_client */
 	buf_putstring(ses.writepayload, "", 0);
 
-	/* first_kex_packet_follows - unimplemented for now */
-	buf_putbyte(ses.writepayload, 0x00);
+	/* first_kex_packet_follows */
+	buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
 
 	/* reserved unit32 */
 	buf_putint(ses.writepayload, 0);
@@ -144,16 +145,56 @@
 	encrypt_packet();
 	ses.dataallowed = 0; /* don't send other packets during kex */
 
+	ses.kexstate.sentkexinit = 1;
+
+	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+
+	if (ses.send_kex_first_guess) {
+		ses.newkeys->algo_kex = sshkex[0].val;
+		ses.newkeys->algo_hostkey = sshhostkey[0].val;
+		ses.send_kex_first_guess();
+	}
+
 	TRACE(("DATAALLOWED=0"))
 	TRACE(("-> KEXINIT"))
-	ses.kexstate.sentkexinit = 1;
+
 }
 
-/* *** NOTE regarding (send|recv)_msg_newkeys *** 
- * Changed by mihnea from the original kex.c to set dataallowed after a 
- * completed key exchange, no matter the order in which it was performed.
- * This enables client mode without affecting server functionality.
- */
+static void switch_keys() {
+	TRACE2(("enter switch_keys"))
+	if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
+		dropbear_exit("Unexpected newkeys message");
+	}
+
+	if (!ses.keys) {
+		ses.keys = m_malloc(sizeof(*ses.newkeys));
+	}
+	if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
+		TRACE(("switch_keys recv"))
+		gen_new_zstream_recv();
+		ses.keys->recv = ses.newkeys->recv;
+		m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
+		ses.newkeys->recv.valid = 0;
+	}
+	if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
+		TRACE(("switch_keys trans"))
+		gen_new_zstream_trans();
+		ses.keys->trans = ses.newkeys->trans;
+		m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
+		ses.newkeys->trans.valid = 0;
+	}
+	if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
+	{
+		TRACE(("switch_keys done"))
+		ses.keys->algo_kex = ses.newkeys->algo_kex;
+		ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
+		ses.keys->allow_compress = 0;
+		m_free(ses.newkeys);
+		ses.newkeys = NULL;
+		kexinitialise();
+	}
+	TRACE2(("leave switch_keys"))
+}
 
 /* Bring new keys into use after a key exchange, and let the client know*/
 void send_msg_newkeys() {
@@ -164,44 +205,25 @@
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
 	encrypt_packet();
+
 	
-
 	/* set up our state */
-	if (ses.kexstate.recvnewkeys) {
-		TRACE(("while RECVNEWKEYS=1"))
-		gen_new_keys();
-		kexinitialise(); /* we've finished with this kex */
-		TRACE((" -> DATAALLOWED=1"))
-		ses.dataallowed = 1; /* we can send other packets again now */
-		ses.kexstate.donefirstkex = 1;
-	} else {
-		ses.kexstate.sentnewkeys = 1;
-		TRACE(("SENTNEWKEYS=1"))
-	}
+	ses.kexstate.sentnewkeys = 1;
+	ses.kexstate.donefirstkex = 1;
+	ses.dataallowed = 1; /* we can send other packets again now */
+	gen_new_keys();
+	switch_keys();
 
-	TRACE(("-> MSG_NEWKEYS"))
 	TRACE(("leave send_msg_newkeys"))
 }
 
 /* Bring the new keys into use after a key exchange */
 void recv_msg_newkeys() {
 
-	TRACE(("<- MSG_NEWKEYS"))
 	TRACE(("enter recv_msg_newkeys"))
 
-	/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
-	 * switch to the new keys */
-	if (ses.kexstate.sentnewkeys) {
-		TRACE(("while SENTNEWKEYS=1"))
-		gen_new_keys();
-		kexinitialise(); /* we've finished with this kex */
-	    TRACE((" -> DATAALLOWED=1"))
-	    ses.dataallowed = 1; /* we can send other packets again now */
-		ses.kexstate.donefirstkex = 1;
-	} else {
-		TRACE(("RECVNEWKEYS=1"))
-		ses.kexstate.recvnewkeys = 1;
-	}
+	ses.kexstate.recvnewkeys = 1;
+	switch_keys();
 	
 	TRACE(("leave recv_msg_newkeys"))
 }
@@ -236,11 +258,13 @@
 	ses.kexstate.sentnewkeys = 0;
 
 	/* first_packet_follows */
-	ses.kexstate.firstfollows = 0;
+	ses.kexstate.them_firstfollows = 0;
 
 	ses.kexstate.datatrans = 0;
 	ses.kexstate.datarecv = 0;
 
+	ses.kexstate.our_first_follows_matches = 0;
+
 	ses.kexstate.lastkextime = time(NULL);
 
 }
@@ -281,8 +305,7 @@
  * ses.newkeys is the new set of keys which are generated, these are only
  * taken into use after both sides have sent a newkeys message */
 
-/* Originally from kex.c, generalized for cli/svr mode --mihnea */
-void gen_new_keys() {
+static void gen_new_keys() {
 
 	unsigned char C2S_IV[MAX_IV_LEN];
 	unsigned char C2S_key[MAX_KEY_LEN];
@@ -366,15 +389,9 @@
 		ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
 	}
 
-#ifndef DISABLE_ZLIB
-	gen_new_zstreams();
-#endif
-	
-	/* Switch over to the new keys */
-	m_burn(ses.keys, sizeof(struct key_context));
-	m_free(ses.keys);
-	ses.keys = ses.newkeys;
-	ses.newkeys = NULL;
+	/* Ready to switch over */
+	ses.newkeys->trans.valid = 1;
+	ses.newkeys->recv.valid = 1;
 
 	m_burn(C2S_IV, sizeof(C2S_IV));
 	m_burn(C2S_key, sizeof(C2S_key));
@@ -400,7 +417,7 @@
 
 /* Set up new zlib compression streams, close the old ones. Only
  * called from gen_new_keys() */
-static void gen_new_zstreams() {
+static void gen_new_zstream_recv() {
 
 	/* create new zstreams */
 	if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
@@ -415,6 +432,17 @@
 	} else {
 		ses.newkeys->recv.zstream = NULL;
 	}
+	/* clean up old keys */
+	if (ses.keys->recv.zstream != NULL) {
+		if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
+			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
+			dropbear_exit("Crypto error");
+		}
+		m_free(ses.keys->recv.zstream);
+	}
+}
+
+static void gen_new_zstream_trans() {
 
 	if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
 			|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
@@ -432,14 +460,6 @@
 		ses.newkeys->trans.zstream = NULL;
 	}
 
-	/* clean up old keys */
-	if (ses.keys->recv.zstream != NULL) {
-		if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
-			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
-			dropbear_exit("Crypto error");
-		}
-		m_free(ses.keys->recv.zstream);
-	}
 	if (ses.keys->trans.zstream != NULL) {
 		if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
 			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
@@ -555,7 +575,7 @@
 	DEF_MP_INT(dh_q);
 	DEF_MP_INT(dh_g);
 
-	TRACE(("enter send_msg_kexdh_reply"))
+	TRACE(("enter gen_kexdh_vals"))
 	
 	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
 
@@ -678,20 +698,27 @@
 
 	buf_incrpos(ses.payload, 16); /* start after the cookie */
 
-	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
+	memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
+
+#ifdef USE_KEXGUESS2
+	enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
+#else
+	enum kexguess2_used kexguess2 = KEXGUESS2_NO;
+#endif
 
 	/* kex_algorithms */
-	algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
+	algo = 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 = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
 	allgood &= goodguess;
 	if (algo == NULL) {
 		erralgo = "hostkey";
@@ -701,7 +728,7 @@
 	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 = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
 	if (c2s_cipher_algo == NULL) {
 		erralgo = "enc c->s";
 		goto error;
@@ -709,7 +736,7 @@
 	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 = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
 	if (s2c_cipher_algo == NULL) {
 		erralgo = "enc s->c";
 		goto error;
@@ -717,7 +744,7 @@
 	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 = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
 	if (c2s_hash_algo == NULL) {
 		erralgo = "mac c->s";
 		goto error;
@@ -725,7 +752,7 @@
 	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 = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
 	if (s2c_hash_algo == NULL) {
 		erralgo = "mac s->c";
 		goto error;
@@ -733,7 +760,7 @@
 	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 = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
 	if (c2s_comp_algo == NULL) {
 		erralgo = "comp c->s";
 		goto error;
@@ -741,7 +768,7 @@
 	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 = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
 	if (s2c_comp_algo == NULL) {
 		erralgo = "comp s->c";
 		goto error;
@@ -754,9 +781,10 @@
 	/* languages_server_to_client */
 	buf_eatstring(ses.payload);
 
-	/* first_kex_packet_follows */
+	/* their first_kex_packet_follows */
 	if (buf_getbool(ses.payload)) {
-		ses.kexstate.firstfollows = 1;
+		TRACE(("them kex firstfollows. allgood %d", allgood))
+		ses.kexstate.them_firstfollows = 1;
 		/* if the guess wasn't good, we ignore the packet sent */
 		if (!allgood) {
 			ses.ignorenext = 1;
@@ -799,6 +827,11 @@
 
 	/* reserved for future extensions */
 	buf_getint(ses.payload);
+
+	if (ses.send_kex_first_guess && allgood) {
+		TRACE(("our_first_follows_matches 1"))
+		ses.kexstate.our_first_follows_matches = 1;
+	}
 	return;
 
 error:
--- a/common-session.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/common-session.c	Sun Apr 14 22:49:19 2013 +0800
@@ -33,12 +33,12 @@
 #include "random.h"
 #include "kex.h"
 #include "channel.h"
-#include "atomicio.h"
 #include "runopts.h"
 
 static void checktimeouts();
 static long select_timeout();
 static int ident_readln(int fd, char* buf, int count);
+static void read_session_identification();
 
 struct sshsession ses; /* GLOBAL */
 
@@ -49,8 +49,6 @@
 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
 int exitflag = 0; /* GLOBAL */
 
-
-
 /* called only at the start of a session, set up initial state */
 void common_session_init(int sock_in, int sock_out) {
 
@@ -141,7 +139,10 @@
 		FD_ZERO(&writefd);
 		FD_ZERO(&readfd);
 		dropbear_assert(ses.payload == NULL);
-		if (ses.sock_in != -1) {
+
+		/* during initial setup we flush out the KEXINIT packet before
+		 * attempting to read the remote version string, which might block */
+		if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
 			FD_SET(ses.sock_in, &readfd);
 		}
 		if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -195,7 +196,12 @@
 
 		if (ses.sock_in != -1) {
 			if (FD_ISSET(ses.sock_in, &readfd)) {
-				read_packet();
+				if (!ses.remoteident) {
+					/* blocking read of the version string */
+					read_session_identification();
+				} else {
+					read_packet();
+				}
 			}
 			
 			/* Process the decrypted packet. After this, the read buffer
@@ -225,7 +231,7 @@
 }
 
 /* clean up a session on exit */
-void common_session_cleanup() {
+void session_cleanup() {
 	
 	TRACE(("enter session_cleanup"))
 	
@@ -234,6 +240,10 @@
 		TRACE(("leave session_cleanup: !sessinitdone"))
 		return;
 	}
+
+	if (ses.extra_session_cleanup) {
+		ses.extra_session_cleanup();
+	}
 	
 	m_free(ses.session_id);
 	m_burn(ses.keys, sizeof(struct key_context));
@@ -244,21 +254,20 @@
 	TRACE(("leave session_cleanup"))
 }
 
+void send_session_identification() {
+	buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
+	buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
+	buf_putbyte(writebuf, 0x0); // packet type
+	buf_setpos(writebuf, 0);
+	enqueue(&ses.writequeue, writebuf);
+}
 
-void session_identification() {
-
+static void read_session_identification() {
 	/* max length of 255 chars */
 	char linebuf[256];
 	int len = 0;
 	char done = 0;
 	int i;
-
-	/* write our version string, this blocks */
-	if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
-				strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
-		ses.remoteclosed();
-	}
-
 	/* If they send more than 50 lines, something is wrong */
 	for (i = 0; i < 50; i++) {
 		len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configure.ac	Sun Apr 14 22:49:19 2013 +0800
@@ -0,0 +1,702 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf and autoheader to produce a configure script.
+
+# This Autoconf file was cobbled from various locations. In particular, a bunch
+# of the platform checks have been taken straight from OpenSSH's configure.ac
+# Huge thanks to them for dealing with the horrible platform-specifics :)
+
+AC_PREREQ(2.50)
+AC_INIT(buffer.c)
+
+OLDCFLAGS=$CFLAGS
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+
+if test -z "$LD" ; then
+	LD=$CC
+fi
+AC_SUBST(LD)	
+
+if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
+	AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
+	CFLAGS="-Os -W -Wall"
+fi
+
+# large file support is useful for scp
+AC_SYS_LARGEFILE
+
+# Host specific options
+# this isn't a definitive list of hosts, they are just added as required
+AC_CANONICAL_HOST
+
+case "$host" in
+
+*-*-linux*)
+	no_ptmx_check=1
+	;;
+
+*-*-solaris*)
+	CFLAGS="$CFLAGS -I/usr/local/include"
+	LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
+	conf_lastlog_location="/var/adm/lastlog"
+	AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
+	sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
+	if test "$sol2ver" -ge 8; then
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(DISABLE_UTMP,,Disable utmp)
+		AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
+	else
+		AC_MSG_RESULT(no)
+	fi
+	AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
+	AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
+	;;
+
+*-*-aix*)
+	AC_DEFINE(AIX,,Using AIX)
+	# OpenSSH thinks it's broken. If it isn't, let me know.
+	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
+	;;
+	
+*-*-hpux*)
+	LIBS="$LIBS -lsec"
+	# It's probably broken.
+	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
+	;;
+*-dec-osf*)
+	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
+	;;
+esac
+
+AC_CHECK_TOOL(AR, ar, :)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+AC_CHECK_TOOL(INSTALL, install, :)
+
+dnl Can't use login() or logout() with uclibc
+AC_CHECK_DECL(__UCLIBC__, 
+	[
+	no_loginfunc_check=1
+	AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
+	],,,)
+
+# Checks for libraries.
+AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
+AC_SUBST(CRYPTLIB)	
+
+# Check if zlib is needed
+AC_ARG_WITH(zlib,
+	[  --with-zlib=PATH        Use zlib in PATH],
+	[
+		# option is given
+		if test -d "$withval/lib"; then
+			LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+		else
+			LDFLAGS="-L${withval} ${LDFLAGS}"
+		fi
+		if test -d "$withval/include"; then
+			CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
+		else
+			CPPFLAGS="-I${withval} ${CPPFLAGS}"
+		fi
+	]
+)
+
+AC_ARG_ENABLE(zlib,
+	[  --disable-zlib          Don't include zlib support],
+	[
+		if test "x$enableval" = "xno"; then
+			AC_DEFINE(DISABLE_ZLIB,, Use zlib)
+			AC_MSG_NOTICE(Disabling zlib)
+		else
+			AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
+			AC_MSG_NOTICE(Enabling zlib)
+		fi
+	],
+	[
+		# if not disabled, check for zlib
+		AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
+		AC_MSG_NOTICE(Enabling zlib)
+	]
+)
+
+# Check if pam is needed
+AC_ARG_WITH(pam,
+	[  --with-pam=PATH        Use pam in PATH],
+	[
+		# option is given
+		if test -d "$withval/lib"; then
+			LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+		else
+			LDFLAGS="-L${withval} ${LDFLAGS}"
+		fi
+		if test -d "$withval/include"; then
+			CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
+		else
+			CPPFLAGS="-I${withval} ${CPPFLAGS}"
+		fi
+	]
+)
+
+
+AC_ARG_ENABLE(pam,
+	[  --enable-pam          Try to include PAM support],
+	[
+		if test "x$enableval" = "xyes"; then
+			AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
+			AC_MSG_NOTICE(Enabling PAM)
+			AC_CHECK_FUNCS(pam_fail_delay)
+		else
+			AC_DEFINE(DISABLE_PAM,, Use PAM)
+			AC_MSG_NOTICE(Disabling PAM)
+		fi
+	],
+	[
+		# disable it by default
+		AC_DEFINE(DISABLE_PAM,, Use PAM)
+		AC_MSG_NOTICE(Disabling PAM)
+	]
+)
+
+AC_ARG_ENABLE(openpty,
+	[  --disable-openpty       Don't use openpty, use alternative method],
+	[
+		if test "x$enableval" = "xno"; then
+			AC_MSG_NOTICE(Not using openpty)
+		else
+			AC_MSG_NOTICE(Using openpty if available)
+			AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
+		fi
+	],
+	[
+		AC_MSG_NOTICE(Using openpty if available)
+		AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
+	]
+)
+		
+
+AC_ARG_ENABLE(syslog,
+	[  --disable-syslog        Don't include syslog support],
+	[
+		if test "x$enableval" = "xno"; then
+			AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
+			AC_MSG_NOTICE(Disabling syslog)
+		else
+			AC_MSG_NOTICE(Enabling syslog)
+		fi
+	],
+	[
+		AC_MSG_NOTICE(Enabling syslog)
+	]
+)
+
+AC_ARG_ENABLE(shadow,
+	[  --disable-shadow        Don't use shadow passwords (if available)],
+	[
+		if test "x$enableval" = "xno"; then
+			AC_MSG_NOTICE(Not using shadow passwords)
+		else
+			AC_CHECK_HEADERS([shadow.h])
+			AC_MSG_NOTICE(Using shadow passwords if available)
+		fi
+	],
+	[
+		AC_CHECK_HEADERS([shadow.h])
+		AC_MSG_NOTICE(Using shadow passwords if available)
+	]
+)
+			
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h, sys/uio.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
+AC_CHECK_TYPE([socklen_t], ,[
+	AC_MSG_CHECKING([for socklen_t equivalent])
+	AC_CACHE_VAL([curl_cv_socklen_t_equiv],
+	[
+	# Systems have either "struct sockaddr *" or
+	# "void *" as the second argument to getpeername
+	curl_cv_socklen_t_equiv=
+	for arg2 in "struct sockaddr" void; do
+		for t in int size_t unsigned long "unsigned long"; do
+		AC_TRY_COMPILE([
+			#include <sys/types.h>
+			#include <sys/socket.h>
+
+			int getpeername (int, $arg2 *, $t *);
+		],[
+			$t len;
+			getpeername(0,0,&len);
+		],[
+			curl_cv_socklen_t_equiv="$t"
+			break
+		])
+		done
+	done
+
+	if test "x$curl_cv_socklen_t_equiv" = x; then
+		AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
+	fi
+	])
+	AC_MSG_RESULT($curl_cv_socklen_t_equiv)
+	AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
+			[type to use in place of socklen_t if not defined])],
+	[#include <sys/types.h>
+	#include <sys/socket.h>])
+
+# for the fake-rfc2553 stuff - straight from OpenSSH
+
+AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
+	AC_TRY_COMPILE(
+		[
+#include <sys/types.h>
+#include <sys/socket.h>
+		],
+		[ struct sockaddr_storage s; ],
+		[ ac_cv_have_struct_sockaddr_storage="yes" ],
+		[ ac_cv_have_struct_sockaddr_storage="no" ]
+	)
+])
+if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
+	AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
+fi
+
+AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
+	AC_TRY_COMPILE(
+		[
+#include <sys/types.h>
+#include <netinet/in.h>
+		],
+		[ struct sockaddr_in6 s; s.sin6_family = 0; ],
+		[ ac_cv_have_struct_sockaddr_in6="yes" ],
+		[ ac_cv_have_struct_sockaddr_in6="no" ]
+	)
+])
+if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
+	AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6)
+fi
+
+AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
+	AC_TRY_COMPILE(
+		[
+#include <sys/types.h>
+#include <netinet/in.h>
+		],
+		[ struct in6_addr s; s.s6_addr[0] = 0; ],
+		[ ac_cv_have_struct_in6_addr="yes" ],
+		[ ac_cv_have_struct_in6_addr="no" ]
+	)
+])
+if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
+	AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr)
+fi
+
+AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
+	AC_TRY_COMPILE(
+		[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+		],
+		[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
+		[ ac_cv_have_struct_addrinfo="yes" ],
+		[ ac_cv_have_struct_addrinfo="no" ]
+	)
+])
+if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
+	AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo)
+fi
+
+
+# IRIX has a const char return value for gai_strerror()
+AC_CHECK_FUNCS(gai_strerror,[
+	AC_DEFINE(HAVE_GAI_STRERROR)
+	AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+const char *gai_strerror(int);],[
+char *str;
+
+str = gai_strerror(0);],[
+		AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
+		[Define if gai_strerror() returns const char *])])])
+
+# for loginrec.c
+
+AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
+#include <sys/types.h>
+#if HAVE_UTMP_H
+#include <utmp.h>
+#endif
+])
+
+AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
+#include <sys/types.h>
+#include <sys/socket.h>
+#if HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+])
+
+AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[
+#include <sys/types.h>
+#include <sys/socket.h>
+])
+
+AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
+AC_CHECK_FUNCS(utmpname)
+AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
+AC_CHECK_FUNCS(setutxent utmpxname)
+AC_CHECK_FUNCS(logout updwtmp logwtmp)
+
+AC_ARG_ENABLE(bundled-libtom,
+	[  --enable-bundled-libtom       Use bundled libtomcrypt/libtommath even if a system version exists],
+	[ 
+		BUNDLED_LIBTOM=1
+		AC_MSG_NOTICE(Forcing bundled libtom*)
+	],
+	[
+		BUNDLED_LIBTOM=0
+		AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
+		AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
+	]
+)
+
+if test $BUNDLED_LIBTOM = 1 ; then
+	AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom) 
+fi
+
+AC_SUBST(BUNDLED_LIBTOM)
+
+dnl Added from OpenSSH 3.6.1p2's configure.ac
+
+dnl allow user to disable some login recording features
+AC_ARG_ENABLE(lastlog,
+	[  --disable-lastlog       Disable use of lastlog even if detected [no]],
+	[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
+)
+AC_ARG_ENABLE(utmp,
+	[  --disable-utmp          Disable use of utmp even if detected [no]],
+	[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
+)
+AC_ARG_ENABLE(utmpx,
+	[  --disable-utmpx         Disable use of utmpx even if detected [no]],
+	[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
+)
+AC_ARG_ENABLE(wtmp,
+	[  --disable-wtmp          Disable use of wtmp even if detected [no]],
+	[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
+)
+AC_ARG_ENABLE(wtmpx,
+	[  --disable-wtmpx         Disable use of wtmpx even if detected [no]],
+	[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
+)
+AC_ARG_ENABLE(loginfunc,
+	[  --disable-loginfunc     Disable use of login() etc. [no]],
+	[ no_loginfunc_check=1
+	AC_MSG_NOTICE(Not using login() etc) ]
+)
+AC_ARG_ENABLE(pututline,
+	[  --disable-pututline     Disable use of pututline() etc. ([uw]tmp) [no]],
+	[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
+)
+AC_ARG_ENABLE(pututxline,
+	[  --disable-pututxline    Disable use of pututxline() etc. ([uw]tmpx) [no]],
+	[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
+)
+AC_ARG_WITH(lastlog,
+  [  --with-lastlog=FILE|DIR specify lastlog location [common locations]],
+	[
+		if test "x$withval" = "xno" ; then	
+			AC_DEFINE(DISABLE_LASTLOG)
+		else
+			conf_lastlog_location=$withval
+		fi
+	]
+)
+
+if test -z "$no_loginfunc_check"; then
+	dnl    Checks for libutil functions (login(), logout() etc, not openpty() )
+	AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
+	AC_CHECK_FUNCS(logout updwtmp logwtmp)
+fi
+
+dnl lastlog, [uw]tmpx? detection
+dnl  NOTE: set the paths in the platform section to avoid the
+dnl   need for command-line parameters
+dnl lastlog and [uw]tmp are subject to a file search if all else fails
+
+dnl lastlog detection
+dnl  NOTE: the code itself will detect if lastlog is a directory
+AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+#ifdef HAVE_LOGIN_H
+# include <login.h>
+#endif
+	],
+	[ char *lastlog = LASTLOG_FILE; ],
+	[ AC_MSG_RESULT(yes) ],
+	[
+		AC_MSG_RESULT(no)
+		AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
+		AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+		],
+		[ char *lastlog = _PATH_LASTLOG; ],
+		[ AC_MSG_RESULT(yes) ],
+		[
+			AC_MSG_RESULT(no)
+			system_lastlog_path=no
+		])
+	]
+)
+
+if test -z "$conf_lastlog_location"; then
+	if test x"$system_lastlog_path" = x"no" ; then
+		for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
+				if (test -d "$f" || test -f "$f") ; then
+					conf_lastlog_location=$f
+				fi
+		done
+		if test -z "$conf_lastlog_location"; then
+			AC_MSG_WARN([** Cannot find lastlog **])
+			dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
+		fi
+	fi
+fi
+
+if test -n "$conf_lastlog_location"; then
+	AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
+fi	
+
+dnl utmp detection
+AC_MSG_CHECKING([if your system defines UTMP_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+	],
+	[ char *utmp = UTMP_FILE; ],
+	[ AC_MSG_RESULT(yes) ],
+	[ AC_MSG_RESULT(no)
+	  system_utmp_path=no ]
+)
+if test -z "$conf_utmp_location"; then
+	if test x"$system_utmp_path" = x"no" ; then
+		for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
+			if test -f $f ; then
+				conf_utmp_location=$f
+			fi
+		done
+		if test -z "$conf_utmp_location"; then
+			AC_DEFINE(DISABLE_UTMP)
+		fi
+	fi
+fi
+if test -n "$conf_utmp_location"; then
+	AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
+fi	
+
+dnl wtmp detection
+AC_MSG_CHECKING([if your system defines WTMP_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+	],
+	[ char *wtmp = WTMP_FILE; ],
+	[ AC_MSG_RESULT(yes) ],
+	[ AC_MSG_RESULT(no)
+	  system_wtmp_path=no ]
+)
+if test -z "$conf_wtmp_location"; then
+	if test x"$system_wtmp_path" = x"no" ; then
+		for f in /usr/adm/wtmp /var/log/wtmp; do
+			if test -f $f ; then
+				conf_wtmp_location=$f
+			fi
+		done
+		if test -z "$conf_wtmp_location"; then
+			AC_DEFINE(DISABLE_WTMP)
+		fi
+	fi
+fi
+if test -n "$conf_wtmp_location"; then
+	AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
+fi	
+
+
+dnl utmpx detection - I don't know any system so perverse as to require
+dnl  utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
+dnl  there, though.
+AC_MSG_CHECKING([if your system defines UTMPX_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+	],
+	[ char *utmpx = UTMPX_FILE; ],
+	[ AC_MSG_RESULT(yes) ],
+	[ AC_MSG_RESULT(no)
+	  system_utmpx_path=no ]
+)
+if test -z "$conf_utmpx_location"; then
+	if test x"$system_utmpx_path" = x"no" ; then
+		AC_DEFINE(DISABLE_UTMPX)
+	fi
+else
+	AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
+fi	
+
+dnl wtmpx detection
+AC_MSG_CHECKING([if your system defines WTMPX_FILE])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+	],
+	[ char *wtmpx = WTMPX_FILE; ],
+	[ AC_MSG_RESULT(yes) ],
+	[ AC_MSG_RESULT(no)
+	  system_wtmpx_path=no ]
+)
+if test -z "$conf_wtmpx_location"; then
+	if test x"$system_wtmpx_path" = x"no" ; then
+		AC_DEFINE(DISABLE_WTMPX)
+	fi
+else
+	AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
+fi	
+
+# Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
+
+AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
+
+# Solaris needs ptmx
+if test -z "$no_ptmx_check" ; then
+	if test x"$cross_compiling" = x"no" ; then
+		AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
+	else
+		AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
+	fi
+fi
+
+if test -z "$no_ptc_check" ; then
+	if test x"$cross_compiling" = x"no" ; then
+		AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
+	else
+		AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
+	fi
+fi
+
+AC_EXEEXT
+
+# XXX there must be a nicer way to do this
+AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
+AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
+AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
+AS_MKDIR_P(libtomcrypt/src/encauth/ccm)
+AS_MKDIR_P(libtomcrypt/src/encauth/eax)
+AS_MKDIR_P(libtomcrypt/src/encauth/gcm)
+AS_MKDIR_P(libtomcrypt/src/encauth/ocb)
+AS_MKDIR_P(libtomcrypt/src/hashes)
+AS_MKDIR_P(libtomcrypt/src/hashes/chc)
+AS_MKDIR_P(libtomcrypt/src/hashes/helper)
+AS_MKDIR_P(libtomcrypt/src/hashes/sha2)
+AS_MKDIR_P(libtomcrypt/src/hashes/whirl)
+AS_MKDIR_P(libtomcrypt/src/mac/hmac)
+AS_MKDIR_P(libtomcrypt/src/mac/omac)
+AS_MKDIR_P(libtomcrypt/src/mac/pelican)
+AS_MKDIR_P(libtomcrypt/src/mac/pmac)
+AS_MKDIR_P(libtomcrypt/src/mac/f9)
+AS_MKDIR_P(libtomcrypt/src/mac/xcbc)
+AS_MKDIR_P(libtomcrypt/src/math/fp)
+AS_MKDIR_P(libtomcrypt/src/misc/base64)
+AS_MKDIR_P(libtomcrypt/src/misc/crypt)
+AS_MKDIR_P(libtomcrypt/src/misc/mpi)
+AS_MKDIR_P(libtomcrypt/src/misc/pkcs5)
+AS_MKDIR_P(libtomcrypt/src/modes/cbc)
+AS_MKDIR_P(libtomcrypt/src/modes/cfb)
+AS_MKDIR_P(libtomcrypt/src/modes/ctr)
+AS_MKDIR_P(libtomcrypt/src/modes/ecb)
+AS_MKDIR_P(libtomcrypt/src/modes/ofb)
+AS_MKDIR_P(libtomcrypt/src/modes/f8)
+AS_MKDIR_P(libtomcrypt/src/modes/lrw)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
+AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
+AS_MKDIR_P(libtomcrypt/src/pk/dh)
+AS_MKDIR_P(libtomcrypt/src/pk/dsa)
+AS_MKDIR_P(libtomcrypt/src/pk/ecc)
+AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
+AS_MKDIR_P(libtomcrypt/src/pk/rsa)
+AS_MKDIR_P(libtomcrypt/src/prng)
+AC_CONFIG_HEADER(config.h)
+AC_OUTPUT(Makefile)
+AC_OUTPUT(libtomcrypt/Makefile)
+AC_OUTPUT(libtommath/Makefile)
+
+AC_MSG_NOTICE()
+if test $BUNDLED_LIBTOM = 1 ; then
+AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
+else
+AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
+fi
+
+AC_MSG_NOTICE()
+AC_MSG_NOTICE(Now edit options.h to choose features.)
--- a/configure.in	Sun Apr 14 22:49:10 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,702 +0,0 @@
-#                                               -*- Autoconf -*-
-# Process this file with autoconf and autoheader to produce a configure script.
-
-# This Autoconf file was cobbled from various locations. In particular, a bunch
-# of the platform checks have been taken straight from OpenSSH's configure.ac
-# Huge thanks to them for dealing with the horrible platform-specifics :)
-
-AC_PREREQ(2.50)
-AC_INIT(buffer.c)
-
-OLDCFLAGS=$CFLAGS
-# Checks for programs.
-AC_PROG_CC
-AC_PROG_MAKE_SET
-
-if test -z "$LD" ; then
-	LD=$CC
-fi
-AC_SUBST(LD)	
-
-if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
-	AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
-	CFLAGS="-Os -W -Wall"
-fi
-
-# large file support is useful for scp
-AC_SYS_LARGEFILE
-
-# Host specific options
-# this isn't a definitive list of hosts, they are just added as required
-AC_CANONICAL_HOST
-
-case "$host" in
-
-*-*-linux*)
-	no_ptmx_check=1
-	;;
-
-*-*-solaris*)
-	CFLAGS="$CFLAGS -I/usr/local/include"
-	LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
-	conf_lastlog_location="/var/adm/lastlog"
-	AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
-	sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
-	if test "$sol2ver" -ge 8; then
-		AC_MSG_RESULT(yes)
-		AC_DEFINE(DISABLE_UTMP,,Disable utmp)
-		AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
-	else
-		AC_MSG_RESULT(no)
-	fi
-	AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
-	AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
-	;;
-
-*-*-aix*)
-	AC_DEFINE(AIX,,Using AIX)
-	# OpenSSH thinks it's broken. If it isn't, let me know.
-	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
-	;;
-	
-*-*-hpux*)
-	LIBS="$LIBS -lsec"
-	# It's probably broken.
-	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
-	;;
-*-dec-osf*)
-	AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo)
-	;;
-esac
-
-AC_CHECK_TOOL(AR, ar, :)
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-AC_CHECK_TOOL(STRIP, strip, :)
-AC_CHECK_TOOL(INSTALL, install, :)
-
-dnl Can't use login() or logout() with uclibc
-AC_CHECK_DECL(__UCLIBC__, 
-	[
-	no_loginfunc_check=1
-	AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
-	],,,)
-
-# Checks for libraries.
-AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
-AC_SUBST(CRYPTLIB)	
-
-# Check if zlib is needed
-AC_ARG_WITH(zlib,
-	[  --with-zlib=PATH        Use zlib in PATH],
-	[
-		# option is given
-		if test -d "$withval/lib"; then
-			LDFLAGS="-L${withval}/lib ${LDFLAGS}"
-		else
-			LDFLAGS="-L${withval} ${LDFLAGS}"
-		fi
-		if test -d "$withval/include"; then
-			CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
-		else
-			CPPFLAGS="-I${withval} ${CPPFLAGS}"
-		fi
-	]
-)
-
-AC_ARG_ENABLE(zlib,
-	[  --disable-zlib          Don't include zlib support],
-	[
-		if test "x$enableval" = "xno"; then
-			AC_DEFINE(DISABLE_ZLIB,, Use zlib)
-			AC_MSG_NOTICE(Disabling zlib)
-		else
-			AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
-			AC_MSG_NOTICE(Enabling zlib)
-		fi
-	],
-	[
-		# if not disabled, check for zlib
-		AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
-		AC_MSG_NOTICE(Enabling zlib)
-	]
-)
-
-# Check if pam is needed
-AC_ARG_WITH(pam,
-	[  --with-pam=PATH        Use pam in PATH],
-	[
-		# option is given
-		if test -d "$withval/lib"; then
-			LDFLAGS="-L${withval}/lib ${LDFLAGS}"
-		else
-			LDFLAGS="-L${withval} ${LDFLAGS}"
-		fi
-		if test -d "$withval/include"; then
-			CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
-		else
-			CPPFLAGS="-I${withval} ${CPPFLAGS}"
-		fi
-	]
-)
-
-
-AC_ARG_ENABLE(pam,
-	[  --enable-pam          Try to include PAM support],
-	[
-		if test "x$enableval" = "xyes"; then
-			AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
-			AC_MSG_NOTICE(Enabling PAM)
-			AC_CHECK_FUNCS(pam_fail_delay)
-		else
-			AC_DEFINE(DISABLE_PAM,, Use PAM)
-			AC_MSG_NOTICE(Disabling PAM)
-		fi
-	],
-	[
-		# disable it by default
-		AC_DEFINE(DISABLE_PAM,, Use PAM)
-		AC_MSG_NOTICE(Disabling PAM)
-	]
-)
-
-AC_ARG_ENABLE(openpty,
-	[  --disable-openpty       Don't use openpty, use alternative method],
-	[
-		if test "x$enableval" = "xno"; then
-			AC_MSG_NOTICE(Not using openpty)
-		else
-			AC_MSG_NOTICE(Using openpty if available)
-			AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
-		fi
-	],
-	[
-		AC_MSG_NOTICE(Using openpty if available)
-		AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
-	]
-)
-		
-
-AC_ARG_ENABLE(syslog,
-	[  --disable-syslog        Don't include syslog support],
-	[
-		if test "x$enableval" = "xno"; then
-			AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
-			AC_MSG_NOTICE(Disabling syslog)
-		else
-			AC_MSG_NOTICE(Enabling syslog)
-		fi
-	],
-	[
-		AC_MSG_NOTICE(Enabling syslog)
-	]
-)
-
-AC_ARG_ENABLE(shadow,
-	[  --disable-shadow        Don't use shadow passwords (if available)],
-	[
-		if test "x$enableval" = "xno"; then
-			AC_MSG_NOTICE(Not using shadow passwords)
-		else
-			AC_CHECK_HEADERS([shadow.h])
-			AC_MSG_NOTICE(Using shadow passwords if available)
-		fi
-	],
-	[
-		AC_CHECK_HEADERS([shadow.h])
-		AC_MSG_NOTICE(Using shadow passwords if available)
-	]
-)
-			
-
-# Checks for header files.
-AC_HEADER_STDC
-AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h])
-
-# Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
-AC_TYPE_UID_T
-AC_TYPE_MODE_T
-AC_TYPE_PID_T
-AC_TYPE_SIZE_T
-AC_HEADER_TIME
-
-AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
-AC_CHECK_TYPE([socklen_t], ,[
-	AC_MSG_CHECKING([for socklen_t equivalent])
-	AC_CACHE_VAL([curl_cv_socklen_t_equiv],
-	[
-	# Systems have either "struct sockaddr *" or
-	# "void *" as the second argument to getpeername
-	curl_cv_socklen_t_equiv=
-	for arg2 in "struct sockaddr" void; do
-		for t in int size_t unsigned long "unsigned long"; do
-		AC_TRY_COMPILE([
-			#include <sys/types.h>
-			#include <sys/socket.h>
-
-			int getpeername (int, $arg2 *, $t *);
-		],[
-			$t len;
-			getpeername(0,0,&len);
-		],[
-			curl_cv_socklen_t_equiv="$t"
-			break
-		])
-		done
-	done
-
-	if test "x$curl_cv_socklen_t_equiv" = x; then
-		AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
-	fi
-	])
-	AC_MSG_RESULT($curl_cv_socklen_t_equiv)
-	AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
-			[type to use in place of socklen_t if not defined])],
-	[#include <sys/types.h>
-	#include <sys/socket.h>])
-
-# for the fake-rfc2553 stuff - straight from OpenSSH
-
-AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
-	AC_TRY_COMPILE(
-		[
-#include <sys/types.h>
-#include <sys/socket.h>
-		],
-		[ struct sockaddr_storage s; ],
-		[ ac_cv_have_struct_sockaddr_storage="yes" ],
-		[ ac_cv_have_struct_sockaddr_storage="no" ]
-	)
-])
-if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
-	AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
-fi
-
-AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
-	AC_TRY_COMPILE(
-		[
-#include <sys/types.h>
-#include <netinet/in.h>
-		],
-		[ struct sockaddr_in6 s; s.sin6_family = 0; ],
-		[ ac_cv_have_struct_sockaddr_in6="yes" ],
-		[ ac_cv_have_struct_sockaddr_in6="no" ]
-	)
-])
-if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
-	AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6)
-fi
-
-AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
-	AC_TRY_COMPILE(
-		[
-#include <sys/types.h>
-#include <netinet/in.h>
-		],
-		[ struct in6_addr s; s.s6_addr[0] = 0; ],
-		[ ac_cv_have_struct_in6_addr="yes" ],
-		[ ac_cv_have_struct_in6_addr="no" ]
-	)
-])
-if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
-	AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr)
-fi
-
-AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
-	AC_TRY_COMPILE(
-		[
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-		],
-		[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
-		[ ac_cv_have_struct_addrinfo="yes" ],
-		[ ac_cv_have_struct_addrinfo="no" ]
-	)
-])
-if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
-	AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo)
-fi
-
-
-# IRIX has a const char return value for gai_strerror()
-AC_CHECK_FUNCS(gai_strerror,[
-	AC_DEFINE(HAVE_GAI_STRERROR)
-	AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-const char *gai_strerror(int);],[
-char *str;
-
-str = gai_strerror(0);],[
-		AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
-		[Define if gai_strerror() returns const char *])])])
-
-# for loginrec.c
-
-AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
-#include <sys/types.h>
-#if HAVE_UTMP_H
-#include <utmp.h>
-#endif
-])
-
-AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
-#include <sys/types.h>
-#include <sys/socket.h>
-#if HAVE_UTMPX_H
-#include <utmpx.h>
-#endif
-])
-
-AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],,,[
-#include <sys/types.h>
-#include <sys/socket.h>
-])
-
-AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
-AC_CHECK_FUNCS(utmpname)
-AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
-AC_CHECK_FUNCS(setutxent utmpxname)
-AC_CHECK_FUNCS(logout updwtmp logwtmp)
-
-AC_ARG_ENABLE(bundled-libtom,
-	[  --enable-bundled-libtom       Use bundled libtomcrypt/libtommath even if a system version exists],
-	[ 
-		BUNDLED_LIBTOM=1
-		AC_MSG_NOTICE(Forcing bundled libtom*)
-	],
-	[
-		BUNDLED_LIBTOM=0
-		AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
-		AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
-	]
-)
-
-if test $BUNDLED_LIBTOM = 1 ; then
-	AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom) 
-fi
-
-AC_SUBST(BUNDLED_LIBTOM)
-
-dnl Added from OpenSSH 3.6.1p2's configure.ac
-
-dnl allow user to disable some login recording features
-AC_ARG_ENABLE(lastlog,
-	[  --disable-lastlog       Disable use of lastlog even if detected [no]],
-	[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
-)
-AC_ARG_ENABLE(utmp,
-	[  --disable-utmp          Disable use of utmp even if detected [no]],
-	[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
-)
-AC_ARG_ENABLE(utmpx,
-	[  --disable-utmpx         Disable use of utmpx even if detected [no]],
-	[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
-)
-AC_ARG_ENABLE(wtmp,
-	[  --disable-wtmp          Disable use of wtmp even if detected [no]],
-	[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
-)
-AC_ARG_ENABLE(wtmpx,
-	[  --disable-wtmpx         Disable use of wtmpx even if detected [no]],
-	[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
-)
-AC_ARG_ENABLE(loginfunc,
-	[  --disable-loginfunc     Disable use of login() etc. [no]],
-	[ no_loginfunc_check=1
-	AC_MSG_NOTICE(Not using login() etc) ]
-)
-AC_ARG_ENABLE(pututline,
-	[  --disable-pututline     Disable use of pututline() etc. ([uw]tmp) [no]],
-	[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
-)
-AC_ARG_ENABLE(pututxline,
-	[  --disable-pututxline    Disable use of pututxline() etc. ([uw]tmpx) [no]],
-	[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
-)
-AC_ARG_WITH(lastlog,
-  [  --with-lastlog=FILE|DIR specify lastlog location [common locations]],
-	[
-		if test "x$withval" = "xno" ; then	
-			AC_DEFINE(DISABLE_LASTLOG)
-		else
-			conf_lastlog_location=$withval
-		fi
-	]
-)
-
-if test -z "$no_loginfunc_check"; then
-	dnl    Checks for libutil functions (login(), logout() etc, not openpty() )
-	AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
-	AC_CHECK_FUNCS(logout updwtmp logwtmp)
-fi
-
-dnl lastlog, [uw]tmpx? detection
-dnl  NOTE: set the paths in the platform section to avoid the
-dnl   need for command-line parameters
-dnl lastlog and [uw]tmp are subject to a file search if all else fails
-
-dnl lastlog detection
-dnl  NOTE: the code itself will detect if lastlog is a directory
-AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_LASTLOG_H
-#  include <lastlog.h>
-#endif
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-#ifdef HAVE_LOGIN_H
-# include <login.h>
-#endif
-	],
-	[ char *lastlog = LASTLOG_FILE; ],
-	[ AC_MSG_RESULT(yes) ],
-	[
-		AC_MSG_RESULT(no)
-		AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
-		AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_LASTLOG_H
-#  include <lastlog.h>
-#endif
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-		],
-		[ char *lastlog = _PATH_LASTLOG; ],
-		[ AC_MSG_RESULT(yes) ],
-		[
-			AC_MSG_RESULT(no)
-			system_lastlog_path=no
-		])
-	]
-)
-
-if test -z "$conf_lastlog_location"; then
-	if test x"$system_lastlog_path" = x"no" ; then
-		for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
-				if (test -d "$f" || test -f "$f") ; then
-					conf_lastlog_location=$f
-				fi
-		done
-		if test -z "$conf_lastlog_location"; then
-			AC_MSG_WARN([** Cannot find lastlog **])
-			dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
-		fi
-	fi
-fi
-
-if test -n "$conf_lastlog_location"; then
-	AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
-fi	
-
-dnl utmp detection
-AC_MSG_CHECKING([if your system defines UTMP_FILE])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-	],
-	[ char *utmp = UTMP_FILE; ],
-	[ AC_MSG_RESULT(yes) ],
-	[ AC_MSG_RESULT(no)
-	  system_utmp_path=no ]
-)
-if test -z "$conf_utmp_location"; then
-	if test x"$system_utmp_path" = x"no" ; then
-		for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
-			if test -f $f ; then
-				conf_utmp_location=$f
-			fi
-		done
-		if test -z "$conf_utmp_location"; then
-			AC_DEFINE(DISABLE_UTMP)
-		fi
-	fi
-fi
-if test -n "$conf_utmp_location"; then
-	AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
-fi	
-
-dnl wtmp detection
-AC_MSG_CHECKING([if your system defines WTMP_FILE])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-	],
-	[ char *wtmp = WTMP_FILE; ],
-	[ AC_MSG_RESULT(yes) ],
-	[ AC_MSG_RESULT(no)
-	  system_wtmp_path=no ]
-)
-if test -z "$conf_wtmp_location"; then
-	if test x"$system_wtmp_path" = x"no" ; then
-		for f in /usr/adm/wtmp /var/log/wtmp; do
-			if test -f $f ; then
-				conf_wtmp_location=$f
-			fi
-		done
-		if test -z "$conf_wtmp_location"; then
-			AC_DEFINE(DISABLE_WTMP)
-		fi
-	fi
-fi
-if test -n "$conf_wtmp_location"; then
-	AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
-fi	
-
-
-dnl utmpx detection - I don't know any system so perverse as to require
-dnl  utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
-dnl  there, though.
-AC_MSG_CHECKING([if your system defines UTMPX_FILE])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_UTMPX_H
-#include <utmpx.h>
-#endif
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-	],
-	[ char *utmpx = UTMPX_FILE; ],
-	[ AC_MSG_RESULT(yes) ],
-	[ AC_MSG_RESULT(no)
-	  system_utmpx_path=no ]
-)
-if test -z "$conf_utmpx_location"; then
-	if test x"$system_utmpx_path" = x"no" ; then
-		AC_DEFINE(DISABLE_UTMPX)
-	fi
-else
-	AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
-fi	
-
-dnl wtmpx detection
-AC_MSG_CHECKING([if your system defines WTMPX_FILE])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <utmp.h>
-#ifdef HAVE_UTMPX_H
-#include <utmpx.h>
-#endif
-#ifdef HAVE_PATHS_H
-#  include <paths.h>
-#endif
-	],
-	[ char *wtmpx = WTMPX_FILE; ],
-	[ AC_MSG_RESULT(yes) ],
-	[ AC_MSG_RESULT(no)
-	  system_wtmpx_path=no ]
-)
-if test -z "$conf_wtmpx_location"; then
-	if test x"$system_wtmpx_path" = x"no" ; then
-		AC_DEFINE(DISABLE_WTMPX)
-	fi
-else
-	AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
-fi	
-
-# Checks for library functions.
-AC_PROG_GCC_TRADITIONAL
-AC_FUNC_MEMCMP
-AC_FUNC_SELECT_ARGTYPES
-AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork])
-
-AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
-
-# Solaris needs ptmx
-if test -z "$no_ptmx_check" ; then
-	if test x"$cross_compiling" = x"no" ; then
-		AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
-	else
-		AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
-	fi
-fi
-
-if test -z "$no_ptc_check" ; then
-	if test x"$cross_compiling" = x"no" ; then
-		AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
-	else
-		AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
-	fi
-fi
-
-AC_EXEEXT
-
-# XXX there must be a nicer way to do this
-AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
-AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
-AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
-AS_MKDIR_P(libtomcrypt/src/encauth/ccm)
-AS_MKDIR_P(libtomcrypt/src/encauth/eax)
-AS_MKDIR_P(libtomcrypt/src/encauth/gcm)
-AS_MKDIR_P(libtomcrypt/src/encauth/ocb)
-AS_MKDIR_P(libtomcrypt/src/hashes)
-AS_MKDIR_P(libtomcrypt/src/hashes/chc)
-AS_MKDIR_P(libtomcrypt/src/hashes/helper)
-AS_MKDIR_P(libtomcrypt/src/hashes/sha2)
-AS_MKDIR_P(libtomcrypt/src/hashes/whirl)
-AS_MKDIR_P(libtomcrypt/src/mac/hmac)
-AS_MKDIR_P(libtomcrypt/src/mac/omac)
-AS_MKDIR_P(libtomcrypt/src/mac/pelican)
-AS_MKDIR_P(libtomcrypt/src/mac/pmac)
-AS_MKDIR_P(libtomcrypt/src/mac/f9)
-AS_MKDIR_P(libtomcrypt/src/mac/xcbc)
-AS_MKDIR_P(libtomcrypt/src/math/fp)
-AS_MKDIR_P(libtomcrypt/src/misc/base64)
-AS_MKDIR_P(libtomcrypt/src/misc/crypt)
-AS_MKDIR_P(libtomcrypt/src/misc/mpi)
-AS_MKDIR_P(libtomcrypt/src/misc/pkcs5)
-AS_MKDIR_P(libtomcrypt/src/modes/cbc)
-AS_MKDIR_P(libtomcrypt/src/modes/cfb)
-AS_MKDIR_P(libtomcrypt/src/modes/ctr)
-AS_MKDIR_P(libtomcrypt/src/modes/ecb)
-AS_MKDIR_P(libtomcrypt/src/modes/ofb)
-AS_MKDIR_P(libtomcrypt/src/modes/f8)
-AS_MKDIR_P(libtomcrypt/src/modes/lrw)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
-AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
-AS_MKDIR_P(libtomcrypt/src/pk/dh)
-AS_MKDIR_P(libtomcrypt/src/pk/dsa)
-AS_MKDIR_P(libtomcrypt/src/pk/ecc)
-AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
-AS_MKDIR_P(libtomcrypt/src/pk/rsa)
-AS_MKDIR_P(libtomcrypt/src/prng)
-AC_CONFIG_HEADER(config.h)
-AC_OUTPUT(Makefile)
-AC_OUTPUT(libtomcrypt/Makefile)
-AC_OUTPUT(libtommath/Makefile)
-
-AC_MSG_NOTICE()
-if test $BUNDLED_LIBTOM = 1 ; then
-AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
-else
-AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
-fi
-
-AC_MSG_NOTICE()
-AC_MSG_NOTICE(Now edit options.h to choose features.)
--- a/dbutil.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/dbutil.c	Sun Apr 14 22:49:19 2013 +0800
@@ -138,15 +138,39 @@
 
 #ifdef DEBUG_TRACE
 void dropbear_trace(const char* format, ...) {
-
 	va_list param;
+	struct timeval tv;
 
 	if (!debug_trace) {
 		return;
 	}
 
+	gettimeofday(&tv, NULL);
+
 	va_start(param, format);
-	fprintf(stderr, "TRACE (%d): ", getpid());
+	fprintf(stderr, "TRACE  (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
+	vfprintf(stderr, format, param);
+	fprintf(stderr, "\n");
+	va_end(param);
+}
+
+void dropbear_trace2(const char* format, ...) {
+	static int trace_env = -1;
+	va_list param;
+	struct timeval tv;
+
+	if (trace_env == -1) {
+		trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
+	}
+
+	if (!(debug_trace && trace_env)) {
+		return;
+	}
+
+	gettimeofday(&tv, NULL);
+
+	va_start(param, format);
+	fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
 	vfprintf(stderr, format, param);
 	fprintf(stderr, "\n");
 	va_end(param);
@@ -725,8 +749,6 @@
 
 	int c = EOF;
 
-	TRACE(("enter buf_getline"))
-
 	buf_setpos(line, 0);
 	buf_setlen(line, 0);
 
@@ -750,10 +772,8 @@
 
 	/* if we didn't read anything before EOF or error, exit */
 	if (c == EOF && line->pos == 0) {
-		TRACE(("leave buf_getline: failure"))
 		return DROPBEAR_FAILURE;
 	} else {
-		TRACE(("leave buf_getline: success"))
 		buf_setpos(line, 0);
 		return DROPBEAR_SUCCESS;
 	}
--- a/dbutil.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/dbutil.h	Sun Apr 14 22:49:19 2013 +0800
@@ -35,14 +35,12 @@
 
 #ifdef __GNUC__
 #define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args))) 
+#define ATTRIB_NORETURN __attribute__((noreturn))
+#define ATTRIB_SENTINEL __attribute__((sentinel))
 #else
 #define ATTRIB_PRINTF(fmt,args)
-#endif
-
-#ifdef __GNUC__
-#define ATTRIB_NORETURN __attribute__((noreturn))
-#else
 #define ATTRIB_NORETURN
+#define ATTRIB_SENTINEL
 #endif
 
 extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
@@ -57,6 +55,7 @@
 
 #ifdef DEBUG_TRACE
 void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
+void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
 void printhex(const char * label, const unsigned char * buf, int len);
 extern int debug_trace;
 #endif
--- a/debug.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/debug.h	Sun Apr 14 22:49:19 2013 +0800
@@ -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
@@ -63,8 +63,10 @@
 /* you don't need to touch this block */
 #ifdef DEBUG_TRACE
 #define TRACE(X) dropbear_trace X;
+#define TRACE2(X) dropbear_trace2 X;
 #else /*DEBUG_TRACE*/
 #define TRACE(X)
+#define TRACE2(X)
 #endif /*DEBUG_TRACE*/
 
 /* To debug with GDB it is easier to run with no forking of child processes.
--- a/dss.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/dss.c	Sun Apr 14 22:49:19 2013 +0800
@@ -101,9 +101,9 @@
 /* Clear and free the memory used by a public or private key */
 void dss_key_free(dropbear_dss_key *key) {
 
-	TRACE(("enter dsa_key_free"))
+	TRACE2(("enter dsa_key_free"))
 	if (key == NULL) {
-		TRACE(("enter dsa_key_free: key == NULL"))
+		TRACE2(("enter dsa_key_free: key == NULL"))
 		return;
 	}
 	if (key->p) {
@@ -127,7 +127,7 @@
 		m_free(key->x);
 	}
 	m_free(key);
-	TRACE(("leave dsa_key_free"))
+	TRACE2(("leave dsa_key_free"))
 }
 
 /* put the dss public key into the buffer in the required format:
--- a/includes.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/includes.h	Sun Apr 14 22:49:19 2013 +0800
@@ -120,6 +120,10 @@
 #include <libgen.h>
 #endif
 
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
 #ifdef BUNDLED_LIBTOM
 #include "libtomcrypt/src/headers/tomcrypt.h"
 #include "libtommath/tommath.h"
--- a/kex.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/kex.h	Sun Apr 14 22:49:19 2013 +0800
@@ -51,19 +51,22 @@
 
 	unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
 	unsigned recvkexinit : 1;
-	unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
+	unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */
 	unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
 	unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
 
 	unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
 								  ie the transport layer has been set up */
 
+	unsigned our_first_follows_matches : 1;
+
 	time_t lastkextime; /* time of the last kex */
 	unsigned int datatrans; /* data transmitted since last kex */
 	unsigned int datarecv; /* data received since last kex */
 
 };
 
+
 #define MAX_KEXHASHBUF 2000
 
 #endif /* _KEX_H_ */
--- a/options.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/options.h	Sun Apr 14 22:49:19 2013 +0800
@@ -153,7 +153,7 @@
 #endif
 
 /* Whether to do reverse DNS lookups. */
-#define DO_HOST_LOOKUP
+//#define DO_HOST_LOOKUP
 
 /* Whether to print the message of the day (MOTD). This doesn't add much code
  * size */
@@ -176,7 +176,7 @@
 
 #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 
--- a/packet.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/packet.c	Sun Apr 14 22:49:19 2013 +0800
@@ -55,10 +55,62 @@
 	buffer * writebuf = NULL;
 	time_t now;
 	unsigned packet_type;
+	int all_ignore = 1;
+#ifdef HAVE_WRITEV
+	struct iovec *iov = NULL;
+	int i;
+	struct Link *l;
+#endif
 	
-	TRACE(("enter write_packet"))
+	TRACE2(("enter write_packet"))
 	dropbear_assert(!isempty(&ses.writequeue));
 
+#ifdef HAVE_WRITEV
+	iov = m_malloc(sizeof(*iov) * ses.writequeue.count);
+	for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
+	{
+		writebuf = (buffer*)l->item;
+		packet_type = writebuf->data[writebuf->len-1];
+		len = writebuf->len - 1 - writebuf->pos;
+		dropbear_assert(len > 0);
+		all_ignore &= (packet_type == SSH_MSG_IGNORE);
+		TRACE2(("write_packet writev #%d  type %d len %d/%d", i, packet_type,
+				len, writebuf->len-1))
+		iov[i].iov_base = buf_getptr(writebuf, len);
+		iov[i].iov_len = len;
+	}
+	written = writev(ses.sock_out, iov, ses.writequeue.count);
+	if (written < 0) {
+		if (errno == EINTR) {
+			m_free(iov);
+			TRACE2(("leave writepacket: EINTR"))
+			return;
+		} else {
+			dropbear_exit("Error writing");
+		}
+	} 
+
+	if (written == 0) {
+		ses.remoteclosed();
+	}
+
+	while (written > 0) {
+		writebuf = (buffer*)examine(&ses.writequeue);
+		len = writebuf->len - 1 - writebuf->pos;
+		if (len > written) {
+			// partial buffer write
+			buf_incrpos(writebuf, written);
+			written = 0;
+		} else {
+			written -= len;
+			dequeue(&ses.writequeue);
+			buf_free(writebuf);
+		}
+	}
+
+	m_free(iov);
+
+#else
 	/* Get the next buffer in the queue of encrypted packets to write*/
 	writebuf = (buffer*)examine(&ses.writequeue);
 
@@ -72,19 +124,13 @@
 
 	if (written < 0) {
 		if (errno == EINTR) {
-			TRACE(("leave writepacket: EINTR"))
+			TRACE2(("leave writepacket: EINTR"))
 			return;
 		} else {
 			dropbear_exit("Error writing");
 		}
 	} 
-	
-	now = time(NULL);
-	ses.last_trx_packet_time = now;
-
-	if (packet_type != SSH_MSG_IGNORE) {
-		ses.last_packet_time = now;
-	}
+	all_ignore = (packet_type == SSH_MSG_IGNORE);
 
 	if (written == 0) {
 		ses.remoteclosed();
@@ -100,7 +146,15 @@
 		buf_incrpos(writebuf, written);
 	}
 
-	TRACE(("leave write_packet"))
+#endif
+	now = time(NULL);
+	ses.last_trx_packet_time = now;
+
+	if (!all_ignore) {
+		ses.last_packet_time = now;
+	}
+
+	TRACE2(("leave write_packet"))
 }
 
 /* Non-blocking function reading available portion of a packet into the
@@ -112,7 +166,7 @@
 	unsigned int maxlen;
 	unsigned char blocksize;
 
-	TRACE(("enter read_packet"))
+	TRACE2(("enter read_packet"))
 	blocksize = ses.keys->recv.algo_crypt->blocksize;
 	
 	if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
@@ -125,7 +179,7 @@
 
 		if (ret == DROPBEAR_FAILURE) {
 			/* didn't read enough to determine the length */
-			TRACE(("leave read_packet: packetinit done"))
+			TRACE2(("leave read_packet: packetinit done"))
 			return;
 		}
 	}
@@ -147,7 +201,7 @@
 
 		if (len < 0) {
 			if (errno == EINTR || errno == EAGAIN) {
-				TRACE(("leave read_packet: EINTR or EAGAIN"))
+				TRACE2(("leave read_packet: EINTR or EAGAIN"))
 				return;
 			} else {
 				dropbear_exit("Error reading: %s", strerror(errno));
@@ -163,7 +217,7 @@
 		/* The main select() loop process_packet() to
 		 * handle the packet contents... */
 	}
-	TRACE(("leave read_packet"))
+	TRACE2(("leave read_packet"))
 }
 
 /* Function used to read the initial portion of a packet, and determine the
@@ -197,7 +251,7 @@
 	}
 	if (slen < 0) {
 		if (errno == EINTR) {
-			TRACE(("leave read_packet_init: EINTR"))
+			TRACE2(("leave read_packet_init: EINTR"))
 			return DROPBEAR_FAILURE;
 		}
 		dropbear_exit("Error reading: %s", strerror(errno));
@@ -221,7 +275,7 @@
 	}
 	len = buf_getint(ses.readbuf) + 4 + macsize;
 
-	TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
+	TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
 
 
 	/* check packet length */
@@ -247,7 +301,7 @@
 	unsigned int padlen;
 	unsigned int len;
 
-	TRACE(("enter decrypt_packet"))
+	TRACE2(("enter decrypt_packet"))
 	blocksize = ses.keys->recv.algo_crypt->blocksize;
 	macsize = ses.keys->recv.algo_mac->hashsize;
 
@@ -304,7 +358,7 @@
 
 	ses.recvseq++;
 
-	TRACE(("leave decrypt_packet"))
+	TRACE2(("leave decrypt_packet"))
 }
 
 /* Checks the mac at the end of a decrypted readbuf.
@@ -314,7 +368,7 @@
 	unsigned char mac_bytes[MAX_MAC_LEN];
 	unsigned int mac_size, contents_len;
 	
-	mac_size = ses.keys->trans.algo_mac->hashsize;
+	mac_size = ses.keys->recv.algo_mac->hashsize;
 	contents_len = ses.readbuf->len - mac_size;
 
 	buf_setpos(ses.readbuf, 0);
@@ -403,7 +457,6 @@
 		ses.reply_queue_head = new_item;
 	}
 	ses.reply_queue_tail = new_item;
-	TRACE(("leave enqueue_reply_packet"))
 }
 
 void maybe_flush_reply_queue() {
@@ -440,24 +493,18 @@
 	unsigned int len, encrypt_buf_size;
 	unsigned char mac_bytes[MAX_MAC_LEN];
 	
-	TRACE(("enter encrypt_packet()"))
+	TRACE2(("enter encrypt_packet()"))
 
 	buf_setpos(ses.writepayload, 0);
 	packet_type = buf_getbyte(ses.writepayload);
 	buf_setpos(ses.writepayload, 0);
 
-	TRACE(("encrypt_packet type is %d", packet_type))
+	TRACE2(("encrypt_packet type is %d", packet_type))
 	
-	if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))
-			|| ses.kexstate.sentnewkeys) {
+	if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
 		/* During key exchange only particular packets are allowed.
 			Since this packet_type isn't OK we just enqueue it to send 
 			after the KEX, see maybe_flush_reply_queue */
-
-		/* We also enqueue packets here when we have sent a MSG_NEWKEYS
-		 * packet but are yet to received one. For simplicity we just switch
-		 * over all the keys at once. This is the 'ses.kexstate.sentnewkeys'
-		 * case. */
 		enqueue_reply_packet();
 		return;
 	}
@@ -559,7 +606,7 @@
 	ses.kexstate.datatrans += writebuf->len;
 	ses.transseq++;
 
-	TRACE(("leave encrypt_packet()"))
+	TRACE2(("leave encrypt_packet()"))
 }
 
 
@@ -572,8 +619,6 @@
 	unsigned long bufsize;
 	hmac_state hmac;
 
-	TRACE(("enter writemac"))
-
 	if (key_state->algo_mac->hashsize > 0) {
 		/* calculate the mac */
 		if (hmac_init(&hmac, 
@@ -602,7 +647,7 @@
 			dropbear_exit("HMAC error");
 		}
 	}
-	TRACE(("leave writemac"))
+	TRACE2(("leave writemac"))
 }
 
 #ifndef DISABLE_ZLIB
@@ -613,7 +658,7 @@
 	unsigned int endpos = src->pos + len;
 	int result;
 
-	TRACE(("enter buf_compress"))
+	TRACE2(("enter buf_compress"))
 
 	while (1) {
 
@@ -647,6 +692,6 @@
 		buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
 
 	}
-	TRACE(("leave buf_compress"))
+	TRACE2(("leave buf_compress"))
 }
 #endif
--- a/process-packet.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/process-packet.c	Sun Apr 14 22:49:19 2013 +0800
@@ -45,10 +45,10 @@
 	unsigned char type;
 	unsigned int i;
 
-	TRACE(("enter process_packet"))
+	TRACE2(("enter process_packet"))
 
 	type = buf_getbyte(ses.payload);
-	TRACE(("process_packet: packet type = %d", type))
+	TRACE(("process_packet: packet type = %d,  len %d", type, ses.payload->len))
 
 	ses.lastpacket = type;
 
@@ -123,7 +123,7 @@
 	buf_free(ses.payload);
 	ses.payload = NULL;
 
-	TRACE(("leave process_packet"))
+	TRACE2(("leave process_packet"))
 }
 
 
--- a/queue.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/queue.c	Sun Apr 14 22:49:19 2013 +0800
@@ -70,7 +70,6 @@
 
 	struct Link* newlink;
 
-	TRACE(("enter enqueue"))
 	newlink = (struct Link*)m_malloc(sizeof(struct Link));
 
 	newlink->item = item;
@@ -85,5 +84,4 @@
 		queue->head = newlink;
 	}
 	queue->count++;
-	TRACE(("leave enqueue"))
 }
--- a/queue.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/queue.h	Sun Apr 14 22:49:19 2013 +0800
@@ -36,7 +36,7 @@
 
 	struct Link* head;
 	struct Link* tail;
-	unsigned int count; /* safety value */
+	unsigned int count;
 
 };
 
--- a/random.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/random.c	Sun Apr 14 22:49:19 2013 +0800
@@ -157,6 +157,9 @@
 	/* This is opportunistic, don't worry about failure */
 	unsigned char buf[INIT_SEED_SIZE];
 	FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
+	if (!f) {
+		return;
+	}
 	genrandom(buf, sizeof(buf));
 	fwrite(buf, sizeof(buf), 1, f);
 	fclose(f);
--- a/rsa.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/rsa.c	Sun Apr 14 22:49:19 2013 +0800
@@ -139,10 +139,10 @@
 /* Clear and free the memory used by a public or private key */
 void rsa_key_free(dropbear_rsa_key *key) {
 
-	TRACE(("enter rsa_key_free"))
+	TRACE2(("enter rsa_key_free"))
 
 	if (key == NULL) {
-		TRACE(("leave rsa_key_free: key == NULL"))
+		TRACE2(("leave rsa_key_free: key == NULL"))
 		return;
 	}
 	if (key->d) {
@@ -166,7 +166,7 @@
 		m_free(key->q);
 	}
 	m_free(key);
-	TRACE(("leave rsa_key_free"))
+	TRACE2(("leave rsa_key_free"))
 }
 
 /* Put the public rsa key into the buffer in the required format:
--- a/scp.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/scp.c	Sun Apr 14 22:49:19 2013 +0800
@@ -230,7 +230,7 @@
 		close(pin[0]);
 		close(pout[1]);
 
-#ifdef USE_VFORK
+#ifndef USE_VFORK
 		arg_setup(host, remuser, cmd);
 #endif
 
--- a/scpmisc.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/scpmisc.c	Sun Apr 14 22:49:19 2013 +0800
@@ -40,6 +40,7 @@
 
 /*RCSID("OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp ");*/
 
+#define _GNU_SOURCE
 #include "includes.h"
 #include "scpmisc.h"
 
--- a/service.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/service.h	Sun Apr 14 22:49:19 2013 +0800
@@ -26,7 +26,5 @@
 #define _SERVICE_H_
 
 void recv_msg_service_request(); /* Server */
-void send_msg_service_request(); /* Client */
-void recv_msg_service_accept(); /* Client */
 
 #endif /* _SERVICE_H_ */
--- a/session.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/session.h	Sun Apr 14 22:49:19 2013 +0800
@@ -44,8 +44,8 @@
 
 void common_session_init(int sock_in, int sock_out);
 void session_loop(void(*loophandler)());
-void common_session_cleanup();
-void session_identification();
+void session_cleanup();
+void send_session_identification();
 void send_msg_ignore();
 
 const char* get_user_shell();
@@ -58,7 +58,6 @@
 
 /* Client */
 void cli_session(int sock_in, int sock_out);
-void cli_session_cleanup();
 void cleantext(unsigned char* dirtytext);
 
 /* crypto parameters that are stored individually for transmit and receive */
@@ -79,6 +78,7 @@
 #endif
 	} cipher_state;
 	unsigned char mackey[MAX_MAC_LEN];
+	int valid;
 };
 
 struct key_context {
@@ -111,7 +111,10 @@
 	int sock_in;
 	int sock_out;
 
-	unsigned char *remoteident;
+	/* remotehost will be initially NULL as we delay
+	 * reading the remote version string. it will be set
+	 * by the time any recv_() packet methods are called */
+	unsigned char *remoteident; 
 
 	int maxfd; /* the maximum file descriptor to check with select() */
 
@@ -169,15 +172,11 @@
 	   concluded (ie, while dataallowed was unset)*/
 	struct packetlist *reply_queue_head, *reply_queue_tail;
 
-	algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
-			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,
-								hence the function-pointer callback.*/
-
 	void(*remoteclosed)(); /* A callback to handle closure of the
 									  remote connection */
 
+	void(*extra_session_cleanup)(); /* client or server specific cleanup */
+	void(*send_kex_first_guess)();
 
 	struct AuthState authstate; /* Common amongst client and server, since most
 								   struct elements are common */
@@ -233,10 +232,6 @@
 
 typedef enum {
 	STATE_NOTHING,
-	SERVICE_AUTH_REQ_SENT,
-	SERVICE_AUTH_ACCEPT_RCVD,
-	SERVICE_CONN_REQ_SENT,
-	SERVICE_CONN_ACCEPT_RCVD,
 	USERAUTH_REQ_SENT,
 	USERAUTH_FAIL_RCVD,
 	USERAUTH_SUCCESS_RCVD,
@@ -246,6 +241,7 @@
 struct clientsession {
 
 	mp_int *dh_e, *dh_x; /* Used during KEX */
+	int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
 	cli_kex_state kex_state; /* Used for progressing KEX */
 	cli_state state; /* Used to progress auth/channelsession etc */
 	unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
@@ -259,6 +255,9 @@
 	int stderrcopy;
 	int stderrflags;
 
+	/* for escape char handling */
+	int last_char;
+
 	int winchange; /* Set to 1 when a windowchange signal happens */
 
 	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
--- a/signkey.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/signkey.c	Sun Apr 14 22:49:19 2013 +0800
@@ -98,7 +98,7 @@
 	int keytype;
 	int ret = DROPBEAR_FAILURE;
 
-	TRACE(("enter buf_get_pub_key"))
+	TRACE2(("enter buf_get_pub_key"))
 
 	ident = buf_getstring(buf, &len);
 	keytype = signkey_type_from_name(ident, len);
@@ -109,7 +109,7 @@
 		return DROPBEAR_FAILURE;
 	}
 	
-	TRACE(("buf_get_pub_key keytype is %d", keytype))
+	TRACE2(("buf_get_pub_key keytype is %d", keytype))
 
 	*type = keytype;
 
@@ -137,7 +137,7 @@
 	}
 #endif
 
-	TRACE(("leave buf_get_pub_key"))
+	TRACE2(("leave buf_get_pub_key"))
 
 	return ret;
 	
@@ -153,7 +153,7 @@
 	int keytype;
 	int ret = DROPBEAR_FAILURE;
 
-	TRACE(("enter buf_get_priv_key"))
+	TRACE2(("enter buf_get_priv_key"))
 
 	ident = buf_getstring(buf, &len);
 	keytype = signkey_type_from_name(ident, len);
@@ -190,7 +190,7 @@
 	}
 #endif
 
-	TRACE(("leave buf_get_priv_key"))
+	TRACE2(("leave buf_get_priv_key"))
 
 	return ret;
 	
@@ -201,7 +201,7 @@
 
 	buffer *pubkeys;
 
-	TRACE(("enter buf_put_pub_key"))
+	TRACE2(("enter buf_put_pub_key"))
 	pubkeys = buf_new(MAX_PUBKEY_SIZE);
 	
 #ifdef DROPBEAR_DSS
@@ -223,7 +223,7 @@
 			pubkeys->len);
 	
 	buf_free(pubkeys);
-	TRACE(("leave buf_put_pub_key"))
+	TRACE2(("leave buf_put_pub_key"))
 }
 
 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
@@ -251,7 +251,7 @@
 
 void sign_key_free(sign_key *key) {
 
-	TRACE(("enter sign_key_free"))
+	TRACE2(("enter sign_key_free"))
 
 #ifdef DROPBEAR_DSS
 	dss_key_free(key->dsskey);
@@ -265,7 +265,7 @@
 	m_free(key->filename);
 
 	m_free(key);
-	TRACE(("leave sign_key_free"))
+	TRACE2(("leave sign_key_free"))
 }
 
 static char hexdig(unsigned char x) {
--- a/svr-algo.c	Sun Apr 14 22:49:10 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Dropbear - a SSH2 server
- * SSH client implementation
- * 
- * Copyright (c) 2002,2003 Matt Johnston
- * Copyright (c) 2004 by Mihnea Stoenescu
- * All rights reserved.
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
-
-#include "algo.h"
-#include "dbutil.h"
-
-/* match the first algorithm in the comma-separated list in buf which is
- * also in localalgos[], or return NULL on failure.
- * (*goodguess) is set to 1 if the preferred client/server algos match,
- * 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)
-{
-
-	unsigned char * algolist = NULL;
-	unsigned char * remotealgos[MAX_PROPOSED_ALGO];
-	unsigned int len;
-	unsigned int count, i, j;
-	algo_type * ret = NULL;
-
-	*goodguess = 0;
-
-	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
-	algolist = buf_getstring(buf, &len);
-	/* Debug this */
-	TRACE(("buf_match_algo: %s", algolist))
-	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
-		goto out; /* just a sanity check, no other use */
-	}
-
-	/* remotealgos will contain a list of the strings parsed out */
-	/* We will have at least one string (even if it's just "") */
-	remotealgos[0] = algolist;
-	count = 1;
-	/* Iterate through, replacing ','s with NULs, to split it into
-	 * words. */
-	for (i = 0; i < len; i++) {
-		if (algolist[i] == '\0') {
-			/* someone is trying something strange */
-			goto out;
-		}
-		if (algolist[i] == ',') {
-			algolist[i] = '\0';
-			remotealgos[count] = &algolist[i+1];
-			count++;
-		}
-		if (count >= MAX_PROPOSED_ALGO) {
-			break;
-		}
-	}
-
-	/* iterate and find the first match */
-	for (i = 0; i < count; i++) {
-
-		len = strlen(remotealgos[i]);
-
-		for (j = 0; localalgos[j].name != NULL; j++) {
-			if (localalgos[j].usable) {
-				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;
-					}
-					/* set the algo to return */
-					ret = &localalgos[j];
-					goto out;
-				}
-			}
-		}
-	}
-
-out:
-	m_free(algolist);
-	return ret;
-}
--- a/svr-main.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/svr-main.c	Sun Apr 14 22:49:19 2013 +0800
@@ -271,7 +271,7 @@
 				goto out;
 			}
 
-			addrandom(&fork_ret, sizeof(fork_ret));
+			addrandom((void*)&fork_ret, sizeof(fork_ret));
 			
 			if (fork_ret > 0) {
 
--- a/svr-session.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/svr-session.c	Sun Apr 14 22:49:19 2013 +0800
@@ -72,6 +72,13 @@
 	NULL /* Null termination is mandatory. */
 };
 
+static void
+svr_session_cleanup(void)
+{
+	/* free potential public key options */
+	svr_pubkey_options_cleanup();
+}
+
 void svr_session(int sock, int childpipe) {
 	char *host, *port;
 	size_t len;
@@ -103,10 +110,10 @@
 
 	/* set up messages etc */
 	ses.remoteclosed = svr_remoteclosed;
+	ses.extra_session_cleanup = svr_session_cleanup;
 
 	/* packet handlers */
 	ses.packettypes = svr_packettypes;
-	ses.buf_match_algo = svr_buf_match_algo;
 
 	ses.isserver = 1;
 
@@ -114,7 +121,7 @@
 	sessinitdone = 1;
 
 	/* exchange identification, version etc */
-	session_identification();
+	send_session_identification();
 
 	/* start off with key exchange */
 	send_msg_kexinit();
@@ -160,11 +167,8 @@
 	if (svr_ses.server_pid == getpid())
 #endif
 	{
-		/* free potential public key options */
-		svr_pubkey_options_cleanup();
-
 		/* must be after we've done with username etc */
-		common_session_cleanup();
+		session_cleanup();
 	}
 
 	exit(exitcode);
--- a/svr-x11fwd.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/svr-x11fwd.c	Sun Apr 14 22:49:19 2013 +0800
@@ -175,7 +175,7 @@
 	m_free(chansess->x11authprot);
 	m_free(chansess->x11authcookie);
 
-	TRACE(("chansess %x", chansess))
+	TRACE(("chansess %p", chansess))
 	if (chansess->x11listener != NULL) {
 		remove_listener(chansess->x11listener);
 		chansess->x11listener = NULL;
--- a/sysoptions.h	Sun Apr 14 22:49:10 2013 +0800
+++ b/sysoptions.h	Sun Apr 14 22:49:19 2013 +0800
@@ -23,6 +23,15 @@
 #define AUTH_TIMEOUT 300 /* we choose 5 minutes */
 #endif
 
+/* A client should try and send an initial key exchange packet guessing
+ * the algorithm that will match - saves a round trip connecting, has little
+ * overhead if the guess was "wrong". */
+#define USE_KEX_FIRST_FOLLOWS
+/* Use protocol extension to allow "first follows" to succeed more frequently.
+ * This is currently Dropbear-specific but will gracefully fallback when connecting
+ * to other implementations. */
+#define USE_KEXGUESS2
+
 /* Minimum key sizes for DSS and RSA */
 #ifndef MIN_DSS_KEYLEN
 #define MIN_DSS_KEYLEN 512
@@ -54,13 +63,16 @@
 
 #define _PATH_CP "/bin/cp"
 
+#define DROPBEAR_ESCAPE_CHAR '~'
+
 /* success/failure defines */
 #define DROPBEAR_SUCCESS 0
 #define DROPBEAR_FAILURE -1
 
 /* various algorithm identifiers */
-#define DROPBEAR_KEX_DH_GROUP1 0
-#define DROPBEAR_KEX_DH_GROUP14 1
+#define DROPBEAR_KEX_NONE 0
+#define DROPBEAR_KEX_DH_GROUP1 1
+#define DROPBEAR_KEX_DH_GROUP14 2
 
 #define DROPBEAR_SIGNKEY_ANY 0
 #define DROPBEAR_SIGNKEY_RSA 1
@@ -186,6 +198,9 @@
 #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
 #endif
 
+/* Send an auth request straight away rather than trying "none" type to get a list */
+#define CLI_IMMEDIATE_AUTH
+
 /* Changing this is inadvisable, it appears to have problems
  * with flushing compressed data */
 #define DROPBEAR_ZLIB_MEM_LEVEL 8
--- a/termcodes.c	Sun Apr 14 22:49:10 2013 +0800
+++ b/termcodes.c	Sun Apr 14 22:49:19 2013 +0800
@@ -107,8 +107,14 @@
 #else
 		{0, 0},
 #endif
-		{0, 0}, /* 42 */
+		/* IUTF8 isn't standardised in rfc4254 but is likely soon.
+		 * Implemented by linux and darwin */
+#ifdef IUTF8
+		{IUTF8, TERMCODE_INPUT},
+#else
 		{0, 0},
+#endif
+		{0, 0}, /* 43 */
 		{0, 0},
 		{0, 0},
 		{0, 0},