diff common-session.c @ 1069:2fa71c3b2827 pam

merge pam branch up to date
author Matt Johnston <matt@ucc.asn.au>
date Mon, 16 Mar 2015 21:34:05 +0800
parents 9a6395ddb1b6 4c733310c21d
children 16379795f80b
line wrap: on
line diff
--- a/common-session.c	Fri Jan 23 22:32:49 2015 +0800
+++ b/common-session.c	Mon Mar 16 21:34:05 2015 +0800
@@ -34,6 +34,7 @@
 #include "kex.h"
 #include "channel.h"
 #include "runopts.h"
+#include "netio.h"
 
 static void checktimeouts();
 static long select_timeout();
@@ -53,6 +54,10 @@
 void common_session_init(int sock_in, int sock_out) {
 	time_t now;
 
+#ifdef DEBUG_TRACE
+	debug_start_net();
+#endif
+
 	TRACE(("enter session_init"))
 
 	ses.sock_in = sock_in;
@@ -150,8 +155,10 @@
 		FD_ZERO(&readfd);
 		dropbear_assert(ses.payload == NULL);
 
-		/* during initial setup we flush out the KEXINIT packet before
-		 * attempting to read the remote version string, which might block */
+		/* We delay reading from the input socket during initial setup until
+		after we have written out our initial KEXINIT packet (empty writequeue). 
+		This means our initial packet can be in-flight while we're doing a blocking
+		read for the remote ident */
 		if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
 			FD_SET(ses.sock_in, &readfd);
 		}
@@ -166,6 +173,9 @@
 		/* set up for channels which can be read/written */
 		setchannelfds(&readfd, &writefd);
 
+		/* Pending connections to test */
+		set_connect_fds(&writefd);
+
 		val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
 
 		if (exitflag) {
@@ -213,11 +223,13 @@
 				process_packet();
 			}
 		}
-		
+
 		/* if required, flush out any queued reply packets that
 		were being held up during a KEX */
 		maybe_flush_reply_queue();
 
+		handle_connect_fds(&writefd);
+
 		/* process pipes etc for the channels, ses.dataallowed == 0
 		 * during rekeying ) */
 		channelio(&readfd, &writefd);
@@ -239,6 +251,15 @@
 	ses.exit_recursion = 0;
 }
 
+static void cleanup_buf(buffer **buf) {
+	if (!*buf) {
+		return;
+	}
+	buf_burn(*buf);
+	buf_free(*buf);
+	*buf = NULL;
+}
+
 /* clean up a session on exit */
 void session_cleanup() {
 	
@@ -250,24 +271,47 @@
 		return;
 	}
 
+	/* Beware of changing order of functions here. */
+
+	/* Must be before extra_session_cleanup() */
+	chancleanup();
+
 	if (ses.extra_session_cleanup) {
 		ses.extra_session_cleanup();
 	}
 
-	chancleanup();
-	
-	/* Cleaning up keys must happen after other cleanup
-	functions which might queue packets */
-	if (ses.session_id) {
-		buf_burn(ses.session_id);
-		buf_free(ses.session_id);
-		ses.session_id = NULL;
+	/* After these are freed most functions will exit */
+#ifdef DROPBEAR_CLEANUP
+	/* listeners call cleanup functions, this should occur before
+	other session state is freed. */
+	remove_all_listeners();
+
+	remove_connect_pending();
+
+	while (!isempty(&ses.writequeue)) {
+		buf_free(dequeue(&ses.writequeue));
 	}
-	if (ses.hash) {
-		buf_burn(ses.hash);
-		buf_free(ses.hash);
-		ses.hash = NULL;
+
+	m_free(ses.remoteident);
+	m_free(ses.authstate.pw_dir);
+	m_free(ses.authstate.pw_name);
+	m_free(ses.authstate.pw_shell);
+	m_free(ses.authstate.pw_passwd);
+	m_free(ses.authstate.username);
+#endif
+
+	cleanup_buf(&ses.session_id);
+	cleanup_buf(&ses.hash);
+	cleanup_buf(&ses.payload);
+	cleanup_buf(&ses.readbuf);
+	cleanup_buf(&ses.writepayload);
+	cleanup_buf(&ses.kexhashbuf);
+	cleanup_buf(&ses.transkexinit);
+	if (ses.dh_K) {
+		mp_clear(ses.dh_K);
 	}
+	m_free(ses.dh_K);
+
 	m_burn(ses.keys, sizeof(struct key_context));
 	m_free(ses.keys);
 
@@ -398,15 +442,15 @@
 }
 
 void ignore_recv_response() {
-	// Do nothing
+	/* Do nothing */
 	TRACE(("Ignored msg_request_response"))
 }
 
 static void send_msg_keepalive() {
+	time_t old_time_idle = ses.last_packet_time_idle;
+	struct Channel *chan = get_any_ready_channel();
+
 	CHECKCLEARTOWRITE();
-	time_t old_time_idle = ses.last_packet_time_idle;
-
-	struct Channel *chan = get_any_ready_channel();
 
 	if (chan) {
 		/* Channel requests are preferable, more implementations
@@ -546,6 +590,11 @@
 
 	TRACE(("update_channel_prio"))
 
+	if (ses.sock_out < 0) {
+		TRACE(("leave update_channel_prio: no socket"))
+		return;
+	}
+
 	new_prio = DROPBEAR_PRIO_BULK;
 	for (i = 0; i < ses.chansize; i++) {
 		struct Channel *channel = ses.channels[i];
@@ -576,7 +625,7 @@
 	}
 
 	if (new_prio != ses.socket_prio) {
-		TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
+		TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
 		set_sock_priority(ses.sock_out, new_prio);
 		ses.socket_prio = new_prio;
 	}