The unified diff between revisions [7403c6fd..] and [3d8098cb..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "CHANGES"
#  from [20a98abde556c8534b4b8dbc1f22344ff46bb437]
#    to [6abc3fce3a2c017cf6acbb9802538acdc124f913]
#
# patch "Makefile.in"
#  from [2680062057a83519d987ef4b06f85533b87b1ab7]
#    to [4be8bcfc6c1a68ca515d55ad95fa09cb6cdae56f]
#
# patch "TODO"
#  from [50ee35bff72e972e85237c9ffa8a291ae5b60643]
#    to [3f82959bf798a1e75ec6472c5e3d47ebd84444ed]
#
# patch "algo.h"
#  from [fafc3a506408d2419de5102daf467c4e19a16e51]
#    to [099e54015c956d2a6f1c765eac70eecce0223608]
#
# patch "auth.h"
#  from [ff1ddd99ccdd09f16eabf2e22e5384dabf33543d]
#    to [aac1a55d01be93e35ab5b0281b9760f8c8ec79d1]
#
# patch "bignum.c"
#  from [8364cbabf0e7d51729bce8bfcb1107491c607314]
#    to [7254934652c463035add2847a4c88620f21a4146]
#
# patch "bignum.h"
#  from [9ed48eb17ed0aa1325bf5ec41eac5982d45e1b08]
#    to [aa809160f87a1519a4e835321cbbc3aaba13ded1]
#
# patch "channel.h"
#  from [2616df4031a05a3fea394b765fd1004944677ef5]
#    to [f0285633bae6fc082951524deaa3ada0061ebff4]
#
# patch "cli-authpubkey.c"
#  from [c288cbc134f450b4d74c9d3cc76974f9d9b7b391]
#    to [f4b6c66351e60851c73405d8ecf4676557f0da30]
#
# patch "cli-runopts.c"
#  from [b8faf5f20ca149fb9e661d18f97bb50c97ce3ea5]
#    to [79955079fc49e1b252055d125874535d52b5914b]
#
# patch "cli-session.c"
#  from [456ed9269b52604e2d0c8aa700ba987974d0fd7b]
#    to [e088b599dbdbd93930ff21e6bebe7dcbfbf66ed3]
#
# patch "cli-tcpfwd.c"
#  from [7158c409b3543e5242181549f553aa8feef45e34]
#    to [d8d52da1d269d157d91e9731508a3b8beba444c2]
#
# patch "common-algo.c"
#  from [ed536db796983916b20d9d7ceb67315d640175e9]
#    to [37d9d05401ab9d81872628b05045b6437296e78b]
#
# patch "common-channel.c"
#  from [20cff6c269bc3c5bf298c5b68a243898d02d538b]
#    to [522b3539ac8ac8feb32efd8c3e7a0490e51b29c3]
#
# patch "common-kex.c"
#  from [9788bd7db05be84eb9abdaa8f0f72c95e10a0d8d]
#    to [960bfda8deaa204b5866f14647f3cd86d262d93f]
#
# patch "dbutil.c"
#  from [68e915623c2cefbdef21e766aa05158f43f11758]
#    to [9440c0ae5ca45076f63b0f295585bfaeb82dd57c]
#
# patch "dbutil.h"
#  from [511a4175c74ed8a8fdc48cdd4468b385f63435b6]
#    to [3806a1758a9a15ee7a1e3b75e3a49c0d27a7343a]
#
# patch "debian/changelog"
#  from [e211468167e6fe1e3b06d9fee2f6ad08e84a48f5]
#    to [0b48636591f4a2c83a575882f346ddc5b3d8bf06]
#
# patch "debian/dropbear.prerm"
#  from [53ede32224237c8417c6b756c8fb308140d668b0]
#    to [c3c2968d21e5e7824f20c1b5c41cabf9d6dda076]
#
# patch "dss.c"
#  from [05beaaaa9c0eed14b7b865979aeb9c9dbaca1220]
#    to [e72e0ab248024c0d858b55fdd382a414aeb31317]
#
# patch "gendss.c"
#  from [b44a5aee6a454aa841f650ba0c3b79ff791725c3]
#    to [e74baeb5db4ddfbcc8b5f45c0b0deb8b16c45ef7]
#
# patch "genrsa.c"
#  from [42466cccb885588edc6f5e6545156441322dbc23]
#    to [e6709602978123e50233339e9e68059b8c8f9a61]
#
# patch "includes.h"
#  from [58e45295174f4b43470ccc8561f180e05d22049a]
#    to [cb0e389740b51fc33f98b8c29c9f2ffe7cd11bc2]
#
# patch "options.h"
#  from [582a50c5552632be3c6cb63dab088be1c530eb4a]
#    to [688a5f91a3863a143f476719dbe445d3e5dd4050]
#
# patch "packet.c"
#  from [9bd7730b6e469787f0a5229bc4ba5e695449fc7a]
#    to [93ffb969c3097b6fe2c9f50cf80716ca0f209295]
#
# patch "random.c"
#  from [310a24216932705d6c33fd40a1bf51caf0b682af]
#    to [6b27327c1fd2cc9eca918be77a997c93404ab00d]
#
# patch "random.h"
#  from [fff5cc49d5b349a7e2e41d2b92c901181300b099]
#    to [128a6e472a5e4900a7458ceda877961affa43c24]
#
# patch "rsa.c"
#  from [292a51fb0389c6cd8718a58566f46be58126ba86]
#    to [a5bd0348ccf9497600f633057ec6028e8cf3c329]
#
# patch "runopts.h"
#  from [b41d55b72bd1703f3be932422efc2838fa0c2a29]
#    to [866a99e2213c6a2602a649a2915471ef4b39770a]
#
# patch "session.h"
#  from [8b1677ad8f52c19aa94571211683d6ef04de2d6a]
#    to [0e62967a248214d43a774911bfa4a0c503f0da17]
#
# patch "signkey.c"
#  from [4f2fd1d9fe4d738300816324138e2287c1948c32]
#    to [0b42ca44158bc9c2057064ddf12aa3ab11fb76b4]
#
# patch "svr-authpam.c"
#  from [48afbf9c99df79c7ba65ddbed8180fc4e2036386]
#    to [d2e49b9902777338e827e1935b24457b86fce347]
#
# patch "svr-chansession.c"
#  from [116db08f0e91f74f1372770790ce4615a9110bc4]
#    to [14640c883f2d3f5a07cb5614102eeb7762aa9b79]
#
============================================================
--- CHANGES	20a98abde556c8534b4b8dbc1f22344ff46bb437
+++ CHANGES	6abc3fce3a2c017cf6acbb9802538acdc124f913
@@ -1,3 +1,35 @@
+0.46 - Sat July 9 2005
+
+- Fix long-standing bug which caused connections to be closed if an ssh-agent
+  socket was no longer available
+
+- Print a warning if we seem to be blocking on /dev/random
+  (suggested by Paul Fox)
+
+- Fixed a memory leak in DSS code (thanks to Boris Berezovsky for the patch)
+
+- dbclient -L no longer segfaults, allocate correct buffer size (thanks
+  to David Cook for reporting it, and Christopher Faylor for independently
+  sending in a patch)
+
+- Added RSA blinding to signing code (suggested by Dan Kaminsky)
+
+- Rearranged bignum reading/random generation code
+
+- Reset the non-blocking status on stderr and stdout as well as stdin,
+  fixes a problem where the shell running dbclient will exit (thanks to
+  Brent Roman for reporting it)
+
+- Fix so that all file descriptors are closed so the child shell doesn't
+  inherit descriptors (thanks to Linden May for the patch)
+
+- Change signkey.c to avoid gcc 4 generating incorrect code
+
+- After both sides of a file descriptor have been shutdown(), close()
+  it to avoid leaking descriptors (thanks to Ari Hyttinen for a patch)
+
+- Update to LibTomCrypt 1.05 and LibTomMath 0.35
+
 0.45 - Mon March 7 2005

 - Makefile no longer appends 'static' to statically linked binaries
============================================================
--- Makefile.in	2680062057a83519d987ef4b06f85533b87b1ab7
+++ Makefile.in	4be8bcfc6c1a68ca515d55ad95fa09cb6cdae56f
@@ -69,7 +69,7 @@ INSTALL=@INSTALL@
 RANLIB=@RANLIB@
 STRIP=@STRIP@
 INSTALL=@INSTALL@
-CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@
+CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ @CFLAGS@
 LIBS=$(LTC) $(LTM) @LIBS@ -lucc
 LDFLAGS=@LDFLAGS@

============================================================
--- TODO	50ee35bff72e972e85237c9ffa8a291ae5b60643
+++ TODO	3f82959bf798a1e75ec6472c5e3d47ebd84444ed
@@ -2,12 +2,12 @@ Things which might need doing:

 Things which might need doing:

+- default private dbclient keys
+
 - Make options.h generated from configure perhaps?

 - Improved queueing of unauthed connections

-- fix agent fwd problems
-
 - handle /etc/environment in AIX

 - check that there aren't timing issues with valid/invalid user authentication
@@ -15,9 +15,9 @@ Things which might need doing:

 - Binding to different interfaces

-- possible RSA blinding? need to check whether this is vuln to timing attacks
 - check PRNG
-- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
+- CTR mode
+- SSH_MSG_IGNORE sending to improve CBC security
 - DH Group Exchange possibly, or just add group14 (whatever it's called today)

 - fix scp.c for IRIX
============================================================
--- algo.h	fafc3a506408d2419de5102daf467c4e19a16e51
+++ algo.h	099e54015c956d2a6f1c765eac70eecce0223608
@@ -51,13 +51,13 @@ struct dropbear_cipher {
 extern const struct dropbear_hash dropbear_nohash;

 struct dropbear_cipher {
-	const struct _cipher_descriptor *cipherdesc;
+	const struct ltc_cipher_descriptor *cipherdesc;
 	unsigned long keysize;
 	unsigned char blocksize;
 };

 struct dropbear_hash {
-	const struct _hash_descriptor *hashdesc;
+	const struct ltc_hash_descriptor *hashdesc;
 	unsigned long keysize;
 	unsigned char hashsize;
 };
============================================================
--- auth.h	ff1ddd99ccdd09f16eabf2e22e5384dabf33543d
+++ auth.h	aac1a55d01be93e35ab5b0281b9760f8c8ec79d1
@@ -84,13 +84,13 @@ struct AuthState {

 };

-struct PubkeyList;
-/* A singly linked list of pubkeys */
-struct PubkeyList {
+struct SignKeyList;
+/* A singly linked list of signing keys */
+struct SignKeyList {

 	sign_key *key;
 	int type; /* The type of key */
-	struct PubkeyList *next;
+	struct SignKeyList *next;
 	/* filename? or the buffer? for encrypted keys, so we can later get
 	 * the private key portion */

============================================================
--- bignum.c	8364cbabf0e7d51729bce8bfcb1107491c607314
+++ bignum.c	7254934652c463035add2847a4c88620f21a4146
@@ -52,9 +52,9 @@ void m_mp_init_multi(mp_int *mp, ...)
     va_end(args);
 }

-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) {
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {

-	if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) {
+	if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
 		dropbear_exit("mem alloc error");
 	}
 }
============================================================
--- bignum.h	9ed48eb17ed0aa1325bf5ec41eac5982d45e1b08
+++ bignum.h	aa809160f87a1519a4e835321cbbc3aaba13ded1
@@ -29,7 +29,7 @@ void m_mp_init_multi(mp_int *mp, ...);

 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...);
-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len);
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
 void sha1_process_mp(hash_state *hs, mp_int *mp);

 #endif /* _BIGNUM_H_ */
============================================================
--- channel.h	2616df4031a05a3fea394b765fd1004944677ef5
+++ channel.h	f0285633bae6fc082951524deaa3ada0061ebff4
@@ -119,7 +119,7 @@ void common_recv_msg_channel_data(struct
 		circbuffer * buf);

 #ifdef DROPBEAR_CLIENT
-const struct ChanType clichansess;
+extern const struct ChanType clichansess;
 #endif

 #if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
============================================================
--- cli-authpubkey.c	c288cbc134f450b4d74c9d3cc76974f9d9b7b391
+++ cli-authpubkey.c	f4b6c66351e60851c73405d8ecf4676557f0da30
@@ -38,29 +38,29 @@ void cli_pubkeyfail() {
  * We use it to remove the key we tried from the list */
 void cli_pubkeyfail() {

-	struct PubkeyList *keyitem;
-	struct PubkeyList **previtem;
+	struct SignKeyList *keyitem;
+	struct SignKeyList **previtem;

 	TRACE(("enter cli_pubkeyfail"))
-	previtem = &cli_opts.pubkeys;
+	previtem = &cli_opts.privkeys;

 	/* Find the key we failed with, and remove it */
-	for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
-		if (keyitem == cli_ses.lastpubkey) {
+	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
+		if (keyitem == cli_ses.lastprivkey) {
 			*previtem = keyitem->next;
 		}
 		previtem = &keyitem;
 	}

-	sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
-	m_free(cli_ses.lastpubkey);
+	sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
+	m_free(cli_ses.lastprivkey);

 	TRACE(("leave cli_pubkeyfail"))
 }

 void recv_msg_userauth_pk_ok() {

-	struct PubkeyList *keyitem;
+	struct SignKeyList *keyitem;
 	buffer* keybuf;
 	char* algotype = NULL;
 	unsigned int algolen;
@@ -80,7 +80,7 @@ void recv_msg_userauth_pk_ok() {

 	/* Iterate through our keys, find which one it was that matched, and
 	 * send a real request with that key */
-	for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {

 		if (keyitem->type != keytype) {
 			/* Types differed */
@@ -172,11 +172,11 @@ int cli_auth_pubkey() {

 	TRACE(("enter cli_auth_pubkey"))

-	if (cli_opts.pubkeys != NULL) {
+	if (cli_opts.privkeys != NULL) {
 		/* Send a trial request */
-		send_msg_userauth_pubkey(cli_opts.pubkeys->key,
-				cli_opts.pubkeys->type, 0);
-		cli_ses.lastpubkey = cli_opts.pubkeys;
+		send_msg_userauth_pubkey(cli_opts.privkeys->key,
+				cli_opts.privkeys->type, 0);
+		cli_ses.lastprivkey = cli_opts.privkeys;
 		TRACE(("leave cli_auth_pubkey-success"))
 		return 1;
 	} else {
============================================================
--- cli-runopts.c	b8faf5f20ca149fb9e661d18f97bb50c97ce3ea5
+++ cli-runopts.c	79955079fc49e1b252055d125874535d52b5914b
@@ -89,7 +89,7 @@ void cli_getopts(int argc, char ** argv)
 	cli_opts.cmd = NULL;
 	cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	cli_opts.pubkeys = NULL;
+	cli_opts.privkeys = NULL;
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
 	cli_opts.localfwds = NULL;
@@ -271,7 +271,7 @@ static void loadidentityfile(const char*
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 static void loadidentityfile(const char* filename) {

-	struct PubkeyList * nextkey;
+	struct SignKeyList * nextkey;
 	sign_key *key;
 	int keytype;

@@ -284,11 +284,11 @@ static void loadidentityfile(const char*

 	} else {

-		nextkey = (struct PubkeyList*)m_malloc(sizeof(struct PubkeyList));
+		nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
 		nextkey->key = key;
-		nextkey->next = cli_opts.pubkeys;
+		nextkey->next = cli_opts.privkeys;
 		nextkey->type = keytype;
-		cli_opts.pubkeys = nextkey;
+		cli_opts.privkeys = nextkey;
 	}
 }
 #endif
============================================================
--- cli-session.c	456ed9269b52604e2d0c8aa700ba987974d0fd7b
+++ cli-session.c	e088b599dbdbd93930ff21e6bebe7dcbfbf66ed3
@@ -126,7 +126,7 @@ static void cli_session_init() {
 									  specific exit status */

 	/* Auth */
-	cli_ses.lastpubkey = NULL;
+	cli_ses.lastprivkey = NULL;
 	cli_ses.lastauthtype = 0;

 	/* For printing "remote host closed" for the user */
============================================================
--- cli-tcpfwd.c	7158c409b3543e5242181549f553aa8feef45e34
+++ cli-tcpfwd.c	d8d52da1d269d157d91e9731508a3b8beba444c2
@@ -94,7 +94,7 @@ static int cli_localtcp(unsigned int lis
 	TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
 				remoteport));

-	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
+	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
 	tcpinfo->sendaddr = m_strdup(remoteaddr);
 	tcpinfo->sendport = remoteport;
 	tcpinfo->listenport = listenport;
============================================================
--- common-algo.c	ed536db796983916b20d9d7ceb67315d640175e9
+++ common-algo.c	37d9d05401ab9d81872628b05045b6437296e78b
@@ -125,7 +125,7 @@ void crypto_init() {
  * This should be run before using any of the ciphers/hashes */
 void crypto_init() {

-	const struct _cipher_descriptor *regciphers[] = {
+	const struct ltc_cipher_descriptor *regciphers[] = {
 #ifdef DROPBEAR_AES128_CBC
 		&aes_desc,
 #endif
@@ -141,7 +141,7 @@ void crypto_init() {
 		NULL
 	};

-	const struct _hash_descriptor *reghashes[] = {
+	const struct ltc_hash_descriptor *reghashes[] = {
 		/* we need sha1 for hostkey stuff regardless */
 		&sha1_desc,
 #ifdef DROPBEAR_MD5_HMAC
============================================================
--- common-channel.c	20cff6c269bc3c5bf298c5b68a243898d02d538b
+++ common-channel.c	522b3539ac8ac8feb32efd8c3e7a0490e51b29c3
@@ -964,7 +964,8 @@ void recv_msg_channel_open_confirmation(
 	channel->transwindow = buf_getint(ses.payload);
 	channel->transmaxpacket = buf_getint(ses.payload);

-	TRACE(("new chan remote %d localho %d", channel->remotechan, chan))
+	TRACE(("new chan remote %d local %d",
+				channel->remotechan, channel->index))

 	/* Run the inithandler callback */
 	if (channel->type->inithandler) {
@@ -1018,6 +1019,7 @@ static void closechanfd(struct Channel *

 	/* XXX server */
 	if (channel->type->sepfds) {
+		TRACE(("shutdown((%d), %d)", fd, how))
 		shutdown(fd, how);
 		if (how == 0) {
 			closeout = 1;
@@ -1042,4 +1044,11 @@ static void closechanfd(struct Channel *
 	if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
 		channel->errfd = FD_CLOSED;
 	}
+
+	/* if we called shutdown on it and all references are gone, then we
+	 * need to close() it to stop it lingering */
+	if (channel->type->sepfds && channel->outfd == FD_CLOSED
+		&& channel->infd == FD_CLOSED && channel->errfd == FD_CLOSED) {
+		close(fd);
+	}
 }
============================================================
--- common-kex.c	9788bd7db05be84eb9abdaa8f0f72c95e10a0d8d
+++ common-kex.c	960bfda8deaa204b5866f14647f3cd86d262d93f
@@ -469,18 +469,13 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_i
 	DEF_MP_INT(dh_p);
 	DEF_MP_INT(dh_q);
 	DEF_MP_INT(dh_g);
-	unsigned char randbuf[DH_P_LEN];
-	int dh_q_len;

 	TRACE(("enter send_msg_kexdh_reply"))

 	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);

 	/* read the prime and generator*/
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);

 	if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
@@ -495,17 +490,9 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_i
 		dropbear_exit("Diffie-Hellman error");
 	}

-	dh_q_len = mp_unsigned_bin_size(&dh_q);
+	/* Generate a private portion 0 < dh_priv < dh_q */
+	gen_random_mpint(&dh_q, dh_priv);

-	/* calculate our random value dh_y */
-	do {
-		assert((unsigned int)dh_q_len <= sizeof(randbuf));
-		genrandom(randbuf, dh_q_len);
-		if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) {
-			dropbear_exit("Diffie-Hellman error");
-		}
-	} while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT);
-
 	/* f = g^y mod p */
 	if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
@@ -526,10 +513,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, m

 	/* read the prime and generator*/
 	mp_init(&dh_p);
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);

 	/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
 	if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
============================================================
--- dbutil.c	68e915623c2cefbdef21e766aa05158f43f11758
+++ dbutil.c	9440c0ae5ca45076f63b0f295585bfaeb82dd57c
@@ -430,10 +430,11 @@ char* getaddrhostname(struct sockaddr_st
 }

 #ifdef DEBUG_TRACE
-void printhex(unsigned char* buf, int len) {
+void printhex(const char * label, const unsigned char * buf, int len) {

 	int i;

+	fprintf(stderr, "%s\n", label);
 	for (i = 0; i < len; i++) {
 		fprintf(stderr, "%02x", buf[i]);
 		if (i % 16 == 15) {
============================================================
--- dbutil.h	511a4175c74ed8a8fdc48cdd4468b385f63435b6
+++ dbutil.h	3806a1758a9a15ee7a1e3b75e3a49c0d27a7343a
@@ -41,7 +41,7 @@ void dropbear_trace(const char* format,
 void dropbear_log(int priority, const char* format, ...);
 #ifdef DEBUG_TRACE
 void dropbear_trace(const char* format, ...);
-void printhex(unsigned char* buf, int len);
+void printhex(const char * label, const unsigned char * buf, int len);
 extern int debug_trace;
 #endif
 char * stripcontrol(const char * text);
============================================================
--- debian/changelog	e211468167e6fe1e3b06d9fee2f6ad08e84a48f5
+++ debian/changelog	0b48636591f4a2c83a575882f346ddc5b3d8bf06
@@ -1,9 +1,19 @@
-dropbear (0.45-dispensable1) unstable; urgency=low
+dropbear (0.46-0.1) unstable; urgency=medium

-  * Turned PAM on.
+  * New upstream release, various fixes.

- -- Matt Johnston <matt@ucc.asn.au>  Fri, 15 Apr 2005 18:00:88 +0800
+ -- Matt Johnston <matt@ucc.asn.au>  Fri, 8 July 2005 21:32:55 +0800

+dropbear (0.45-3) unstable; urgency=low
+
+  * debian/dropbear.init: init script prints human readable message in case
+    it's disabled (closes: #309099).
+  * debian/dropbear.postinst: configure: restart service through init script
+    instead of start.
+  * debian/dropbear.prerm: set -u -> set -e.
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 25 May 2005 22:38:17 +0000
+
 dropbear (0.45-2) unstable; urgency=low

   * Matt Johnston:
============================================================
--- debian/dropbear.prerm	53ede32224237c8417c6b756c8fb308140d668b0
+++ debian/dropbear.prerm	c3c2968d21e5e7824f20c1b5c41cabf9d6dda076
@@ -1,5 +1,5 @@
 #!/bin/sh
-set -u
+set -e

 test "$1" = 'remove' || test "$1" = 'deconfigure' || exit 0
 if test -x /etc/init.d/cokedropbear; then
============================================================
--- dss.c	05beaaaa9c0eed14b7b865979aeb9c9dbaca1220
+++ dss.c	e72e0ab248024c0d858b55fdd382a414aeb31317
@@ -190,10 +190,8 @@ int buf_dss_verify(buffer* buf, dss_key
 	/* create the signature - s' and r' are the received signatures in buf */
 	/* w = (s')-1 mod q */
 	/* let val1 = s' */
-	if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
+
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, s' >= q"))
 		goto out;
@@ -205,9 +203,8 @@ int buf_dss_verify(buffer* buf, dss_key

 	/* u1 = ((SHA(M')w) mod q */
 	/* let val1 = SHA(M') = msghash */
-	if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
+
 	/* let val3 = u1 = ((SHA(M')w) mod q */
 	if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
 		goto out;
@@ -215,10 +212,7 @@ int buf_dss_verify(buffer* buf, dss_key

 	/* u2 = ((r')w) mod q */
 	/* let val1 = r' */
-	if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, r' >= q"))
 		goto out;
@@ -306,8 +300,6 @@ void buf_put_dss_sign(buffer* buf, dss_k
 	unsigned char *privkeytmp;
 	unsigned char proto_k[SHA512_HASH_SIZE];
 	DEF_MP_INT(dss_protok);
-#else
-	unsigned char kbuf[SHA1_HASH_SIZE];
 #endif
 	DEF_MP_INT(dss_k);
 	DEF_MP_INT(dss_m);
@@ -345,22 +337,16 @@ void buf_put_dss_sign(buffer* buf, dss_k

 	/* generate k */
 	m_mp_init(&dss_protok);
-	bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
+	bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
 	mp_mod(&dss_protok, key->q, &dss_k);
 	mp_clear(&dss_protok);
 	m_burn(proto_k, SHA512_HASH_SIZE);
 #else /* DSS_PROTOK not defined*/
-	do {
-		genrandom(kbuf, SHA1_HASH_SIZE);
-		if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
-			dropbear_exit("dss error");
-		}
-	} while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
-	m_burn(kbuf, SHA1_HASH_SIZE);
+	gen_random_mpint(key->q, &dss_k);
 #endif

 	/* now generate the actual signature */
-	bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
+	bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);

 	/* g^k mod p */
 	if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) !=  MP_OKAY) {
@@ -419,7 +405,7 @@ void buf_put_dss_sign(buffer* buf, dss_k
 	mp_clear(&dss_s);
 	buf_incrwritepos(buf, writelen);

-	mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s,
+	mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
 			&dss_m, NULL);

 	/* create the signature to return */
============================================================
--- gendss.c	b44a5aee6a454aa841f650ba0c3b79ff791725c3
+++ gendss.c	e74baeb5db4ddfbcc8b5f45c0b0deb8b16c45ef7
@@ -77,10 +77,7 @@ static void getq(dss_key *key) {
 	buf[0] |= 0x80; /* top bit high */
 	buf[QSIZE-1] |= 0x01; /* bottom bit high */

-	if (mp_read_unsigned_bin(key->q, buf, QSIZE) != MP_OKAY) {
-		fprintf(stderr, "dss key generation failed\n");
-		exit(1);
-	}
+	bytes_to_mp(key->q, buf, QSIZE);

 	/* 18 rounds are required according to HAC */
 	if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
@@ -116,10 +113,7 @@ static void getp(dss_key *key, unsigned
 		buf[0] |= 0x80; /* set the top bit high */

 		/* X is a random mp_int */
-		if (mp_read_unsigned_bin(&tempX, buf, size) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(&tempX, buf, size);

 		/* C = X mod 2q */
 		if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
@@ -147,6 +141,7 @@ static void getp(dss_key *key, unsigned
 	} while (!result);

 	mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
+	m_burn(buf, size);
 	m_free(buf);
 }

@@ -189,22 +184,7 @@ static void getx(dss_key *key) {

 static void getx(dss_key *key) {

-	DEF_MP_INT(val);
-	char buf[QSIZE];
-
-	m_mp_init(&val);
-
-	do {
-		genrandom(buf, QSIZE);
-
-		if (mp_read_unsigned_bin(&val, buf, QSIZE) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-		}
-	} while ((mp_cmp_d(&val, 1) == MP_GT) && (mp_cmp(&val, key->q) == MP_LT));
-
-	mp_copy(&val, key->x);
-	mp_clear(&val);
-
+	gen_random_mpint(key->q, key->x);
 }

 static void gety(dss_key *key) {
============================================================
--- genrsa.c	42466cccb885588edc6f5e6545156441322dbc23
+++ genrsa.c	e6709602978123e50233339e9e68059b8c8f9a61
@@ -108,10 +108,7 @@ static void getrsaprime(mp_int* prime, m
 		genrandom(buf, size+1);
 		buf[0] |= 0x80; /* MSB set */

-		if (mp_read_unsigned_bin(prime, buf, size+1) != MP_OKAY) {
-			fprintf(stderr, "rsa generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(prime, buf, size+1);

 		/* find the next integer which is prime, 8 round of miller-rabin */
 		if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
============================================================
--- includes.h	58e45295174f4b43470ccc8561f180e05d22049a
+++ includes.h	cb0e389740b51fc33f98b8c29c9f2ffe7cd11bc2
@@ -111,7 +111,7 @@
 #include <libgen.h>
 #endif

-#include "libtomcrypt/mycrypt.h"
+#include "libtomcrypt/src/headers/tomcrypt.h"
 #include "libtommath/tommath.h"

 #include "compat.h"
============================================================
--- options.h	582a50c5552632be3c6cb63dab088be1c530eb4a
+++ options.h	688a5f91a3863a143f476719dbe445d3e5dd4050
@@ -90,6 +90,11 @@ etc) slower (perhaps by 50%). Recommende
 #define DROPBEAR_RSA
 #define DROPBEAR_DSS

+/* RSA can be vulnerable to timing attacks which use the time required for
+ * signing to guess the private key. Blinding avoids this attack, though makes
+ * signing operations slightly slower. */
+#define RSA_BLINDING
+
 /* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
  * rather than just from the random byte source. Undefining this will save you
  * ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
@@ -189,7 +194,7 @@ etc) slower (perhaps by 50%). Recommende
  *******************************************************************/

 #ifndef DROPBEAR_VERSION
-#define DROPBEAR_VERSION "0.45-dispensable1"
+#define DROPBEAR_VERSION "0.46"
 #endif

 #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -313,14 +318,6 @@ etc) slower (perhaps by 50%). Recommende
 #define DISABLE_AGENTFWD
 #endif

-#ifndef ENABLE_LOCALTCPFWD
-#define DISABLE_TCPDIRECT
-#endif
-
-#ifndef ENABLE_REMOTETCPFWD
-#define DISABLE_REMOTETCPFWD
-#endif
-
 #if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
 #define ENABLE_CLI_ANYTCPFWD
 #endif
@@ -329,7 +326,8 @@ etc) slower (perhaps by 50%). Recommende
 #define DROPBEAR_TCP_ACCEPT
 #endif

-#if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \
+#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) || \
+	defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_SVR_LOCALTCPFWD) || \
 	defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD)
 #define USING_LISTENERS
 #endif
============================================================
--- packet.c	9bd7730b6e469787f0a5229bc4ba5e695449fc7a
+++ packet.c	93ffb969c3097b6fe2c9f50cf80716ca0f209295
@@ -206,6 +206,7 @@ static void read_packet_init() {
 		/* decrypt it */
 		if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
 					buf_getwriteptr(ses.decryptreadbuf,blocksize),
+					blocksize,
 					&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
 			dropbear_exit("error decrypting");
 		}
@@ -259,6 +260,7 @@ void decrypt_packet() {
 		while (ses.readbuf->pos < ses.readbuf->len - macsize) {
 			if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
 						buf_getwriteptr(ses.decryptreadbuf, blocksize),
+						blocksize,
 						&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
 				dropbear_exit("error decrypting");
 			}
@@ -496,6 +498,7 @@ void encrypt_packet() {
 		while (clearwritebuf->pos < clearwritebuf->len) {
 			if (cbc_encrypt(buf_getptr(clearwritebuf, blocksize),
 						buf_getwriteptr(writebuf, blocksize),
+						blocksize,
 						&ses.keys->trans_symmetric_struct) != CRYPT_OK) {
 				dropbear_exit("error encrypting");
 			}
============================================================
--- random.c	310a24216932705d6c33fd40a1bf51caf0b682af
+++ random.c	6b27327c1fd2cc9eca918be77a997c93404ab00d
@@ -25,14 +25,15 @@
 #include "includes.h"
 #include "buffer.h"
 #include "dbutil.h"
+#include "bignum.h"

-int donerandinit = 0;
+static int donerandinit = 0;

 /* this is used to generate unique output from the same hashpool */
-unsigned int counter = 0;
+static unsigned int counter = 0;
 #define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */

-unsigned char hashpool[SHA1_HASH_SIZE];
+static unsigned char hashpool[SHA1_HASH_SIZE];

 #define INIT_SEED_SIZE 32 /* 256 bits */

@@ -50,6 +51,7 @@ static void readrand(unsigned char* buf,

 static void readrand(unsigned char* buf, unsigned int buflen) {

+	static int already_blocked = 0;
 	int readfd;
 	unsigned int readpos;
 	int readlen;
@@ -92,6 +94,24 @@ static void readrand(unsigned char* buf,
 	/* read the actual random data */
 	readpos = 0;
 	do {
+		if (!already_blocked)
+		{
+			int ret;
+			struct timeval timeout;
+			fd_set read_fds;
+
+			timeout.tv_sec = 2; /* two seconds should be enough */
+			timeout.tv_usec = 0;
+
+			FD_ZERO(&read_fds);
+			FD_SET(readfd, &read_fds);
+			ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
+			if (ret == 0)
+			{
+				dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source.");
+				already_blocked = 1;
+			}
+		}
 		readlen = read(readfd, &buf[readpos], buflen - readpos);
 		if (readlen <= 0) {
 			if (readlen < 0 && errno == EINTR) {
@@ -159,3 +179,38 @@ void genrandom(unsigned char* buf, unsig
 	}
 	m_burn(hash, sizeof(hash));
 }
+
+/* Generates a random mp_int.
+ * max is a *mp_int specifying an upper bound.
+ * rand must be an initialised *mp_int for the result.
+ * the result rand satisfies:  0 < rand < max
+ * */
+void gen_random_mpint(mp_int *max, mp_int *rand) {
+
+	unsigned char *randbuf = NULL;
+	unsigned int len = 0;
+	const char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
+
+	const int size_bits = mp_count_bits(max);
+
+	len = size_bits / 8;
+	if ((size_bits % 8) != 0) {
+		len += 1;
+	}
+
+	randbuf = (unsigned char*)m_malloc(len);
+	do {
+		genrandom(randbuf, len);
+		/* Mask out the unrequired bits - mp_read_unsigned_bin expects
+		 * MSB first.*/
+		randbuf[0] &= masks[size_bits % 8];
+
+		bytes_to_mp(rand, randbuf, len);
+
+		/* keep regenerating until we get one satisfying
+		 * 0 < rand < max    */
+	} while ( ( (max != NULL) && (mp_cmp(rand, max) != MP_LT) )
+			|| (mp_cmp_d(rand, 0) != MP_GT) );
+	m_burn(randbuf, len);
+	m_free(randbuf);
+}
============================================================
--- random.h	fff5cc49d5b349a7e2e41d2b92c901181300b099
+++ random.h	128a6e472a5e4900a7458ceda877961affa43c24
@@ -25,8 +25,11 @@
 #ifndef _RANDOM_H_
 #define _RANDOM_H_

+struct mp_int;
+
 void seedrandom();
 void genrandom(unsigned char* buf, int len);
 void addrandom(unsigned char* buf, int len);
+void gen_random_mpint(mp_int *max, mp_int *rand);

 #endif /* _RANDOM_H_ */
============================================================
--- rsa.c	292a51fb0389c6cd8718a58566f46be58126ba86
+++ rsa.c	a5bd0348ccf9497600f633057ec6028e8cf3c329
@@ -38,8 +38,9 @@

 #ifdef DROPBEAR_RSA

-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len);
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len,
+		mp_int * rsa_em);

 /* Load a public rsa key from a buffer, initialising the values.
  * The key will have the same format as buf_put_rsa_key.
@@ -203,14 +204,14 @@ int buf_rsa_verify(buffer * buf, rsa_key
 	unsigned int slen;
 	DEF_MP_INT(rsa_s);
 	DEF_MP_INT(rsa_mdash);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_em);
 	int ret = DROPBEAR_FAILURE;

 	TRACE(("enter buf_rsa_verify"))

 	assert(key != NULL);

-	m_mp_init_multi(&rsa_mdash, &rsa_s, NULL);
+	m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);

 	slen = buf_getint(buf);
 	if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
@@ -231,29 +232,25 @@ int buf_rsa_verify(buffer * buf, rsa_key
 	}

 	/* create the magic PKCS padded value */
-	rsa_em = rsa_pad_em(key, data, len);
+	rsa_pad_em(key, data, len, &rsa_em);

 	if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
 		TRACE(("failed exptmod rsa_s"))
 		goto out;
 	}

-	if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
+	if (mp_cmp(&rsa_em, &rsa_mdash) == MP_EQ) {
 		/* signature is valid */
 		TRACE(("success!"))
 		ret = DROPBEAR_SUCCESS;
 	}

 out:
-	if (rsa_em) {
-		mp_clear(rsa_em);
-		m_free(rsa_em);
-	}
-	mp_clear_multi(&rsa_mdash, &rsa_s, NULL);
+	mp_clear_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
 	TRACE(("leave buf_rsa_verify: ret %d", ret))
 	return ret;
-
 }
+
 #endif /* DROPBEAR_SIGNKEY_VERIFY */

 /* Sign the data presented with key, writing the signature contents
@@ -264,22 +261,55 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
 	unsigned int nsize, ssize;
 	unsigned int i;
 	DEF_MP_INT(rsa_s);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_tmp1);
+	DEF_MP_INT(rsa_tmp2);
+	DEF_MP_INT(rsa_tmp3);
+	unsigned char *tmpbuf;

 	TRACE(("enter buf_put_rsa_sign"))
 	assert(key != NULL);

-	rsa_em = rsa_pad_em(key, data, len);
+	m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);

-	m_mp_init(&rsa_s);
+	rsa_pad_em(key, data, len, &rsa_tmp1);

 	/* the actual signing of the padded data */
+
+#ifdef RSA_BLINDING
+
+	/* With blinding, s = (r^(-1))((em)*r^e)^d mod n */
+
+	/* generate the r blinding value */
+	/* rsa_tmp2 is r */
+	gen_random_mpint(key->n, &rsa_tmp2);
+
+	/* rsa_tmp1 is em */
+	/* em' = em * r^e mod n */
+
+	mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/
+	mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3);
+	mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2);
+
+	/* rsa_tmp2 is em' */
+	/* s' = (em')^d mod n */
+	mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1);
+
+	/* rsa_tmp1 is s' */
+	/* rsa_tmp3 is r^(-1) mod n */
+	/* s = (s')r^(-1) mod n */
+	mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s);
+
+#else
+
 	/* s = em^d mod n */
-	if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
+	/* rsa_tmp1 is em */
+	if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) {
 		dropbear_exit("rsa error");
 	}
-	mp_clear(rsa_em);
-	m_free(rsa_em);
+
+#endif /* RSA_BLINDING */
+
+	mp_clear_multi(&rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);

 	/* create the signature to return */
 	buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
@@ -302,7 +332,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
 	mp_clear(&rsa_s);

 #if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
-	printhex(buf->data, buf->len);
+	printhex("RSA sig", buf->data, buf->len);
 #endif


@@ -318,19 +348,22 @@ void buf_put_rsa_sign(buffer* buf, rsa_k
  *
  * prefix is the ASN1 designator prefix,
  * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14
+ *
+ * rsa_em must be a pointer to an initialised mp_int.
  */
-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len) {
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len,
+		mp_int * rsa_em) {

 	/* ASN1 designator (including the 0x00 preceding) */
-	const char rsa_asn1_magic[] =
+	const unsigned char rsa_asn1_magic[] =
 		{0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
 		 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
-#define RSA_ASN1_MAGIC_LEN 16
+	const unsigned int RSA_ASN1_MAGIC_LEN = 16;
+
 	buffer * rsa_EM = NULL;
 	hash_state hs;
 	unsigned int nsize;
-	mp_int * rsa_em = NULL;

 	assert(key != NULL);
 	assert(data != NULL);
@@ -358,16 +391,9 @@ static mp_int * rsa_pad_em(rsa_key * key

 	/* Create the mp_int from the encoded bytes */
 	buf_setpos(rsa_EM, 0);
-	rsa_em = (mp_int*)m_malloc(sizeof(mp_int));
-	m_mp_init(rsa_em);
-	if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
-				rsa_EM->size) != MP_OKAY) {
-		dropbear_exit("rsa error");
-	}
+	bytes_to_mp(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
+			rsa_EM->size);
 	buf_free(rsa_EM);
-
-	return rsa_em;
-
 }

 #endif /* DROPBEAR_RSA */
============================================================
--- runopts.h	b41d55b72bd1703f3be932422efc2838fa0c2a29
+++ runopts.h	866a99e2213c6a2602a649a2915471ef4b39770a
@@ -95,7 +95,7 @@ typedef struct cli_runopts {
 	char *cmd;
 	int wantpty;
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
+	struct SignKeyList *privkeys; /* Keys to use for public-key auth */
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 	struct TCPFwdList * remotefwds;
============================================================
--- session.h	8b1677ad8f52c19aa94571211683d6ef04de2d6a
+++ session.h	0e62967a248214d43a774911bfa4a0c503f0da17
@@ -211,7 +211,6 @@ struct clientsession {
 	mp_int *dh_e, *dh_x; /* Used during KEX */
 	cli_kex_state kex_state; /* Used for progressing KEX */
 	cli_state state; /* Used to progress auth/channelsession etc */
-	int something; /* XXX */
 	unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */

 	int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */
@@ -227,7 +226,7 @@ struct clientsession {

 	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
 						 for the last type of auth we tried */
-	struct PubkeyList *lastpubkey;
+	struct SignKeyList *lastprivkey;

 	int retval; /* What the command exit status was - we emulate it */
 #if 0
============================================================
--- signkey.c	4f2fd1d9fe4d738300816324138e2287c1948c32
+++ signkey.c	0b42ca44158bc9c2057064ddf12aa3ab11fb76b4
@@ -279,7 +279,7 @@ static char * sign_key_md5_fingerprint(u
 	char * ret;
 	hash_state hs;
 	unsigned char hash[MD5_HASH_SIZE];
-	unsigned int h, i;
+	unsigned int i;
 	unsigned int buflen;

 	md5_init(&hs);
@@ -296,10 +296,11 @@ static char * sign_key_md5_fingerprint(u
 	memset(ret, 'Z', buflen);
 	strcpy(ret, "md5 ");

-	for (i = 4, h = 0; i < buflen; i+=3, h++) {
-		ret[i] = hexdig(hash[h] >> 4);
-		ret[i+1] = hexdig(hash[h] & 0x0f);
-		ret[i+2] = ':';
+	for (i = 0; i < MD5_HASH_SIZE; i++) {
+		unsigned int pos = 4 + i*3;
+		ret[pos] = hexdig(hash[i] >> 4);
+		ret[pos+1] = hexdig(hash[i] & 0x0f);
+		ret[pos+2] = ':';
 	}
 	ret[buflen-1] = 0x0;

@@ -313,7 +314,7 @@ static char * sign_key_sha1_fingerprint(
 	char * ret;
 	hash_state hs;
 	unsigned char hash[SHA1_HASH_SIZE];
-	unsigned int h, i;
+	unsigned int i;
 	unsigned int buflen;

 	sha1_init(&hs);
@@ -329,10 +330,11 @@ static char * sign_key_sha1_fingerprint(

 	strcpy(ret, "sha1 ");

-	for (i = 5, h = 0; i < buflen; i+=3, h++) {
-		ret[i] = hexdig(hash[h] >> 4);
-		ret[i+1] = hexdig(hash[h] & 0x0f);
-		ret[i+2] = ':';
+	for (i = 0; i < SHA1_HASH_SIZE; i++) {
+		unsigned int pos = 5 + 3*i;
+		ret[pos] = hexdig(hash[i] >> 4);
+		ret[pos+1] = hexdig(hash[i] & 0x0f);
+		ret[pos+2] = ':';
 	}
 	ret[buflen-1] = 0x0;

============================================================
--- svr-authpam.c	48afbf9c99df79c7ba65ddbed8180fc4e2036386
+++ svr-authpam.c	d2e49b9902777338e827e1935b24457b86fce347
@@ -54,34 +54,58 @@ pamConvFunc(int num_msg,
 	int rc = PAM_SUCCESS;
 	struct pam_response* resp = NULL;
 	struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr;
+	unsigned int msg_len = 0;
+	unsigned int i = 0;

 	const char* message = (*msg)->msg;

+	// make a copy we can strip
+	char * compare_message = m_strdup(message);
+
 	TRACE(("enter pamConvFunc"))

 	if (num_msg != 1) {
 		/* If you're getting here - Dropbear probably can't support your pam
 		 * modules. This whole file is a bit of a hack around lack of
-		 * asynchronocity in PAM anyway */
+		 * asynchronocity in PAM anyway. */
 		dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported.");
 		return PAM_CONV_ERR;
 	}

 	TRACE(("msg_style is %d", (*msg)->msg_style))
-	if (message) {
-		TRACE(("message is '%s'", message))
+	if (compare_message) {
+		TRACE(("message is '%s'", compare_message))
 	} else {
 		TRACE(("null message"))
 	}

+
+	// Make the string lowercase.
+	msg_len = strlen(compare_message);
+	for (i = 0; i < msg_len; i++) {
+		compare_message[i] = tolower(compare_message[i]);
+	}
+
+	// If the string ends with ": ", remove the space.
+	// ie "login: " vs "login:"
+	if (msg_len > 2
+			&& compare_message[msg_len-2] == ':'
+			&& compare_message[msg_len-1] == ' ') {
+		compare_message[msg_len-1] = '\0';
+	}
+
 	switch((*msg)->msg_style) {

 		case PAM_PROMPT_ECHO_OFF:

-			if (strcmp(message, "Password:") != 0) {
-					TRACE(("PAM_PROMPT_ECHO_OFF: unrecognized prompt"))
-					rc = PAM_CONV_ERR;
-					break;
+			if (!(strcmp(compare_message, "password:") == 0)) {
+				// We don't recognise the prompt as asking for a password,
+				// so can't handle it. Add more above as required for
+				// different pam modules/implementations
+				dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
+						compare_message);
+				rc = PAM_CONV_ERR;
+				break;
 			}

 			/* You have to read the PAM module-writers' docs (do we look like
@@ -99,10 +123,13 @@ pamConvFunc(int num_msg,

 		case PAM_PROMPT_ECHO_ON:

-			if ((strcmp(message, "login: " ) != 0)
-					&& (strcmp(message, "login:" ) != 0)
-					&& (strcmp(message, "Please enter username: " ) != 0)) {
-				TRACE(("PAM_PROMPT_ECHO_ON: unrecognized prompt"))
+			if (!((strcmp(compare_message, "login:" ) == 0)
+				|| (strcmp(compare_message, "please enter username:") == 0))) {
+				// We don't recognise the prompt as asking for a username,
+				// so can't handle it. Add more above as required for
+				// different pam modules/implementations
+				dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
+						compare_message);
 				rc = PAM_CONV_ERR;
 				break;
 			}
@@ -125,6 +152,7 @@ pamConvFunc(int num_msg,
 			break;
 	}

+	m_free(compare_message);
 	TRACE(("leave pamConvFunc, rc %d", rc))

 	return rc;
============================================================
--- svr-chansession.c	116db08f0e91f74f1372770790ce4615a9110bc4
+++ svr-chansession.c	14640c883f2d3f5a07cb5614102eeb7762aa9b79
@@ -837,7 +837,7 @@ static void execchild(struct ChanSess *c

 	/* close file descriptors except stdin/stdout/stderr
 	 * Need to be sure FDs are closed here to avoid reading files as root */
-	for (i = 3; i < (unsigned int)ses.maxfd; i++) {
+	for (i = 3; i <= (unsigned int)ses.maxfd; i++) {
 		if (m_close(i) == DROPBEAR_FAILURE) {
 			dropbear_exit("Error closing file desc");
 		}
@@ -862,8 +862,10 @@ static void execchild(struct ChanSess *c

 		if ((setgid(ses.authstate.pw->pw_gid) < 0) ||
 			(initgroups(ses.authstate.pw->pw_name,
-						ses.authstate.pw->pw_gid) < 0) ||
-			(setuid(ses.authstate.pw->pw_uid) < 0)) {
+						ses.authstate.pw->pw_gid) < 0)) {
+			dropbear_exit("error changing user group");
+		}
+		if (setuid(ses.authstate.pw->pw_uid) < 0) {
 			dropbear_exit("error changing user");
 		}
 	} else {