changeset 278:e109fb08b8ee

merge of 4cbdd6e0a0d8c061075b9ed7609a06c4547f67d3 and 5d396842815593611f0d61762440145d1fc74d5a
author Matt Johnston <matt@ucc.asn.au>
date Wed, 08 Mar 2006 12:53:09 +0000
parents 3cea9d789cca (current diff) 7f9adaf85fca (diff)
children 1f5ec029dfe8
files common-channel.c
diffstat 15 files changed, 118 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/auth.h	Wed Mar 08 12:09:02 2006 +0000
+++ b/auth.h	Wed Mar 08 12:53:09 2006 +0000
@@ -52,6 +52,7 @@
 void cli_auth_password();
 int cli_auth_pubkey();
 void cli_auth_interactive();
+char* getpass_or_cancel();
 
 
 #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
--- a/cli-auth.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/cli-auth.c	Wed Mar 08 12:53:09 2006 +0000
@@ -278,3 +278,18 @@
 
 	TRACE(("leave cli_auth_try"))
 }
+
+/* A helper for getpass() that exits if the user cancels. The returned
+ * password is statically allocated by getpass() */
+char* getpass_or_cancel()
+{
+	char* password = NULL;
+
+	password = getpass("Password: ");
+
+	/* 0x03 is a ctrl-c character in the buffer. */
+	if (password == NULL || strchr(password, '\3') != NULL) {
+		dropbear_close("Interrupted.");
+	}
+	return password;
+}
--- a/cli-authinteract.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/cli-authinteract.c	Wed Mar 08 12:53:09 2006 +0000
@@ -115,7 +115,7 @@
 		echo = buf_getbool(ses.payload);
 
 		if (!echo) {
-			unsigned char* p = getpass(prompt);
+			unsigned char* p = getpass_or_cancel(prompt);
 			response = m_strdup(p);
 			m_burn(p, strlen(p));
 		} else {
--- a/cli-authpasswd.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/cli-authpasswd.c	Wed Mar 08 12:53:09 2006 +0000
@@ -125,10 +125,7 @@
 		password = gui_getpass("Password: ");
 	else
 #endif
-		password = getpass("Password: ");
-
-	if (password == NULL)
-		return 0;
+		password = getpass_or_cancel("Password: ");
 
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
 
--- a/cli-session.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/cli-session.c	Wed Mar 08 12:53:09 2006 +0000
@@ -76,12 +76,14 @@
 
 void cli_session(int sock, char* remotehost) {
 
+	seedrandom();
+
 	crypto_init();
+
 	common_session_init(sock, remotehost);
 
 	chaninitialise(cli_chantypes);
 
-
 	/* Set up cli_ses vars */
 	cli_session_init();
 
@@ -91,12 +93,8 @@
 	/* Exchange identification */
 	session_identification();
 
-	seedrandom();
-
 	send_msg_kexinit();
 
-	/* XXX here we do stuff differently */
-
 	session_loop(cli_sessionloop);
 
 	/* Not reached */
--- a/common-channel.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/common-channel.c	Wed Mar 08 12:53:09 2006 +0000
@@ -376,7 +376,7 @@
 	cbuf_incrread(cbuf, len);
 	channel->recvdonelen += len;
 
-	if (fd == channel->writefd && len == maxlen && channel->recveof) { 
+	if (fd == channel->writefd && cbuf_getused(cbuf) == 0 && channel->recveof) { 
 		/* Check if we're closing up */
 		closewritefd(channel);
 		TRACE(("leave writechannel: recveof set"))
--- a/common-session.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/common-session.c	Wed Mar 08 12:53:09 2006 +0000
@@ -232,10 +232,8 @@
 		dropbear_exit("Error writing ident string");
 	}
 
-	/* We allow up to 9 lines before the actual version string, to
-	 * account for wrappers/cruft etc. According to the spec only the client
-	 * needs to handle this, but no harm in letting the server handle it too */
-	for (i = 0; i < 10; i++) {
+    /* If they send more than 50 lines, something is wrong */
+	for (i = 0; i < 50; i++) {
 		len = ident_readln(ses.sock, linebuf, sizeof(linebuf));
 
 		if (len < 0 && errno != EINTR) {
@@ -259,6 +257,12 @@
 		memcpy(ses.remoteident, linebuf, len);
 	}
 
+    /* Shall assume that 2.x will be backwards compatible. */
+    if (strncmp(ses.remoteident, "SSH-2.", 6) != 0
+            && strncmp(ses.remoteident, "SSH-1.99-", 9) != 0) {
+        dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
+    }
+
 	TRACE(("remoteident: %s", ses.remoteident))
 
 }
--- a/random.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/random.c	Wed Mar 08 12:53:09 2006 +0000
@@ -30,8 +30,8 @@
 static int donerandinit = 0;
 
 /* this is used to generate unique output from the same hashpool */
-static unsigned int counter = 0;
-#define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */
+static uint32_t counter = 0;
+#define MAX_COUNTER 1<<31 /* the max value for the counter, so it won't loop */
 
 static unsigned char hashpool[SHA1_HASH_SIZE];
 
@@ -132,7 +132,8 @@
 
 	hash_state hs;
 
-	/* initialise so compilers will be happy about hashing it */
+	/* initialise so that things won't warn about
+     * hashing an undefined buffer */
 	if (!donerandinit) {
 		m_burn(hashpool, sizeof(hashpool));
 	}
@@ -150,6 +151,30 @@
 	donerandinit = 1;
 }
 
+/* hash the current random pool with some unique identifiers
+ * for this process and point-in-time. this is used to separate
+ * the random pools for fork()ed processes. */
+void reseedrandom() {
+
+    pid_t pid;
+    struct timeval tv;
+
+	if (!donerandinit) {
+		dropbear_exit("seedrandom not done");
+	}
+
+    pid = getpid();
+    gettimeofday(&tv, NULL);
+
+	hash_state hs;
+	unsigned char hash[SHA1_HASH_SIZE];
+	sha1_init(&hs);
+	sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
+	sha1_process(&hs, (void*)&pid, sizeof(pid));
+	sha1_process(&hs, (void*)&tv, sizeof(tv));
+	sha1_done(&hs, hashpool);
+}
+
 /* return len bytes of pseudo-random data */
 void genrandom(unsigned char* buf, unsigned int len) {
 
--- a/random.h	Wed Mar 08 12:09:02 2006 +0000
+++ b/random.h	Wed Mar 08 12:53:09 2006 +0000
@@ -28,6 +28,7 @@
 struct mp_int;
 
 void seedrandom();
+void reseedrandom();
 void genrandom(unsigned char* buf, int len);
 void addrandom(unsigned char* buf, int len);
 void gen_random_mpint(mp_int *max, mp_int *rand);
--- a/scp.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/scp.c	Wed Mar 08 12:53:09 2006 +0000
@@ -166,8 +166,22 @@
 	close(reserved[0]);
 	close(reserved[1]);
 
+    // uClinux needs to build the args here before vforking,
+    // otherwise we do it later on.
+#ifdef __uClinux__
+	args.list[0] = ssh_program;
+	if (remuser != NULL)
+		addargs(&args, "-l%s", remuser);
+	addargs(&args, "%s", host);
+	addargs(&args, "%s", cmd);
+#endif /* __uClinux__ */
+
 	/* Fork a child to execute the command on the remote host using ssh. */
+#ifdef __uClinux__
+	do_cmd_pid = vfork();
+#else
 	do_cmd_pid = fork();
+#endif /* __uClinux__ */
 	if (do_cmd_pid == 0) {
 		/* Child. */
 		close(pin[1]);
@@ -177,6 +191,7 @@
 		close(pin[0]);
 		close(pout[1]);
 
+#ifndef __uClinux__
 		args.list[0] = ssh_program;
 		if (remuser != NULL) {
 			addargs(&args, "-l");
@@ -184,6 +199,7 @@
 		}
 		addargs(&args, "%s", host);
 		addargs(&args, "%s", cmd);
+#endif
 
 		execvp(ssh_program, args.list);
 		perror(ssh_program);
@@ -192,6 +208,22 @@
 		fprintf(stderr, "Fatal error: fork: %s\n", strerror(errno));
 		exit(1);
 	}
+
+#ifdef __uClinux__
+	/* clean up command */
+	/* pop cmd */
+	free(args->list[--args->num]);
+	args->list[args->num]=NULL;
+	/* pop host */
+	free(args->list[--args->num-1]);
+	args->list[args->num]=NULL;
+	/* pop user */
+	if (remuser != NULL) {
+		free(args->list[--args->num-1]);
+		args->list[args->num]=NULL;
+	}
+#endif /* __uClinux__
+	  
 	/* Parent.  Close the other side, and return the local side. */
 	close(pin[0]);
 	*fdout = pin[1];
--- a/svr-chansession.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/svr-chansession.c	Wed Mar 08 12:53:09 2006 +0000
@@ -623,7 +623,12 @@
 	if (pipe(errfds) != 0)
 		return DROPBEAR_FAILURE;
 
+#ifdef __uClinux__
+	pid = vfork();
+#else
 	pid = fork();
+#endif
+
 	if (pid < 0)
 		return DROPBEAR_FAILURE;
 
@@ -714,7 +719,11 @@
 		return DROPBEAR_FAILURE;
 	}
 	
+#ifdef __uClinux__
+	pid = vfork();
+#else
 	pid = fork();
+#endif
 	if (pid < 0)
 		return DROPBEAR_FAILURE;
 
@@ -828,12 +837,16 @@
 	char * baseshell = NULL;
 	unsigned int i;
 
+    /* with uClinux we'll have vfork()ed, so don't want to overwrite the
+     * hostkey. can't think of a workaround to clear it */
+#ifndef __uClinux__
 	/* wipe the hostkey */
 	sign_key_free(svr_opts.hostkey);
 	svr_opts.hostkey = NULL;
 
 	/* overwrite the prng state */
-	seedrandom();
+	reseedrandom();
+#endif
 
 	/* close file descriptors except stdin/stdout/stderr
 	 * Need to be sure FDs are closed here to avoid reading files as root */
--- a/svr-main.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/svr-main.c	Wed Mar 08 12:53:09 2006 +0000
@@ -83,7 +83,7 @@
 	int remoteaddrlen;
 	char * addrstring = NULL;
 
-	/* Set up handlers, syslog */
+	/* Set up handlers, syslog, seed random */
 	commonsetup();
 
 	remoteaddrlen = sizeof(remoteaddr);
@@ -359,6 +359,8 @@
 	/* Now we can setup the hostkeys - needs to be after logging is on,
 	 * otherwise we might end up blatting error messages to the socket */
 	loadhostkeys();
+
+    seedrandom();
 }
 
 /* Set up listening sockets for all the requested ports */
--- a/svr-runopts.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/svr-runopts.c	Wed Mar 08 12:53:09 2006 +0000
@@ -105,8 +105,12 @@
 	svr_opts.inetdmode = 0;
 	svr_opts.portcount = 0;
 	svr_opts.hostkey = NULL;
+#ifdef ENABLE_SVR_LOCALTCPFWD
 	svr_opts.nolocaltcp = 0;
+#endif
+#ifdef ENABLE_SVR_REMOTETCPFWD
 	svr_opts.noremotetcp = 0;
+#endif
 	/* not yet
 	opts.ipv4 = 1;
 	opts.ipv6 = 1;
@@ -154,12 +158,12 @@
 					svr_opts.usingsyslog = 0;
 					break;
 #endif
-#ifndef DISABLE_LOCALTCPFWD
+#ifdef ENABLE_SVR_LOCALTCPFWD
 				case 'j':
 					svr_opts.nolocaltcp = 1;
 					break;
 #endif
-#ifndef DISABLE_REMOTETCPFWD
+#ifdef ENABLE_SVR_REMOTETCPFWD
 				case 'k':
 					svr_opts.noremotetcp = 1;
 					break;
--- a/svr-session.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/svr-session.c	Wed Mar 08 12:53:09 2006 +0000
@@ -78,7 +78,9 @@
 		char* remotehost, char *addrstring) {
 
 	struct timeval timeout;
-	
+
+    reseedrandom();
+
 	crypto_init();
 	common_session_init(sock, remotehost);
 
@@ -110,8 +112,6 @@
 	/* exchange identification, version etc */
 	session_identification();
 
-	seedrandom();
-
 	/* start off with key exchange */
 	send_msg_kexinit();
 
--- a/svr-tcpfwd.c	Wed Mar 08 12:09:02 2006 +0000
+++ b/svr-tcpfwd.c	Wed Mar 08 12:53:09 2006 +0000
@@ -80,7 +80,7 @@
 	reqname = buf_getstring(ses.payload, &namelen);
 	wantreply = buf_getbool(ses.payload);
 
-	if (namelen > MAXNAMLEN) {
+	if (namelen > MAX_NAME_LEN) {
 		TRACE(("name len is wrong: %d", namelen))
 		goto out;
 	}