# HG changeset patch # User Matt Johnston # Date 1185556422 0 # Node ID 4cab613698792d78f0a722840745b6b210cf83d4 # Parent f2aa5aeea619691b22e12a3aff183d3e7d0a6d02 Prevent invalid packets being sent during key-exchange, instead queue them until afterwards. This could sometimes terminate connections after 8 hours if (for example) a new TCP forwarded connection was sent at the KEX timeout. diff -r f2aa5aeea619 -r 4cab61369879 common-session.c --- a/common-session.c Wed Jul 25 16:20:57 2007 +0000 +++ b/common-session.c Fri Jul 27 17:13:42 2007 +0000 @@ -80,9 +80,12 @@ initqueue(&ses.writequeue); ses.requirenext = SSH_MSG_KEXINIT; - ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */ + ses.dataallowed = 1; /* we can send data until we actually + send the SSH_MSG_KEXINIT */ ses.ignorenext = 0; ses.lastpacket = 0; + ses.reply_queue_head = NULL; + ses.reply_queue_tail = NULL; /* set all the algos to none */ ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context)); @@ -192,6 +195,10 @@ process_packet(); } } + + /* if required, flush out any queued reply packets that + were being held up during a KEX */ + maybe_flush_reply_queue(); /* process pipes etc for the channels, ses.dataallowed == 0 * during rekeying ) */ diff -r f2aa5aeea619 -r 4cab61369879 packet.c --- a/packet.c Wed Jul 25 16:20:57 2007 +0000 +++ b/packet.c Fri Jul 27 17:13:42 2007 +0000 @@ -403,7 +403,60 @@ #endif +/* returns 1 if the packet is a valid type during kex (see 7.1 of rfc4253) */ +static int packet_is_okay_kex(unsigned char type) { + if (type >= SSH_MSG_USERAUTH_REQUEST) { + return 0; + } + if (type == SSH_MSG_SERVICE_REQUEST || type == SSH_MSG_SERVICE_ACCEPT) { + return 0; + } + if (type == SSH_MSG_KEXINIT) { + /* XXX should this die horribly if !dataallowed ?? */ + return 0; + } + return 1; +} +static void enqueue_reply_packet() { + struct packetlist * new_item = NULL; + new_item = m_malloc(sizeof(struct packetlist)); + new_item->next = NULL; + + new_item->payload = buf_newcopy(ses.writepayload); + buf_setpos(ses.writepayload, 0); + buf_setlen(ses.writepayload, 0); + + if (ses.reply_queue_tail) { + ses.reply_queue_tail->next = new_item; + } else { + ses.reply_queue_head = new_item; + ses.reply_queue_tail = new_item; + } + TRACE(("leave enqueue_reply_packet")) +} + +void maybe_flush_reply_queue() { + struct packetlist *tmp_item = NULL, *curr_item = NULL; + if (!ses.dataallowed) + { + TRACE(("maybe_empty_reply_queue - no data allowed")) + return; + } + + for (curr_item = ses.reply_queue_head; curr_item; ) { + CHECKCLEARTOWRITE(); + buf_putbytes(ses.writepayload, + curr_item->payload->data, curr_item->payload->len); + + buf_free(curr_item->payload); + tmp_item = curr_item; + curr_item = curr_item->next; + m_free(tmp_item); + encrypt_packet(); + } + ses.reply_queue_head = ses.reply_queue_tail = NULL; +} /* encrypt the writepayload, putting into writebuf, ready for write_packet() * to put on the wire */ @@ -413,9 +466,20 @@ unsigned char blocksize, macsize; buffer * writebuf; /* the packet which will go on the wire */ buffer * clearwritebuf; /* unencrypted, possibly compressed */ + unsigned char type; + type = ses.writepayload->data[0]; TRACE(("enter encrypt_packet()")) - TRACE(("encrypt_packet type is %d", ses.writepayload->data[0])) + TRACE(("encrypt_packet type is %d", type)) + + if (!ses.dataallowed && !packet_is_okay_kex(type)) { + /* During key exchange only particular packets are allowed. + Since this type isn't OK we just enqueue it to send + after the KEX, see maybe_flush_reply_queue */ + enqueue_reply_packet(); + return; + } + blocksize = ses.keys->trans_algo_crypt->blocksize; macsize = ses.keys->trans_algo_mac->hashsize; diff -r f2aa5aeea619 -r 4cab61369879 packet.h --- a/packet.h Wed Jul 25 16:20:57 2007 +0000 +++ b/packet.h Fri Jul 27 17:13:42 2007 +0000 @@ -35,6 +35,7 @@ void process_packet(); +void maybe_flush_reply_queue(); typedef struct PacketType { unsigned char type; /* SSH_MSG_FOO */ void (*handler)(); diff -r f2aa5aeea619 -r 4cab61369879 session.h --- a/session.h Wed Jul 25 16:20:57 2007 +0000 +++ b/session.h Fri Jul 27 17:13:42 2007 +0000 @@ -81,6 +81,12 @@ }; +struct packetlist; +struct packetlist { + struct packetlist *next; + buffer * payload; +}; + struct sshsession { /* Is it a client or server? */ @@ -137,6 +143,10 @@ buffer* kexhashbuf; /* session hash buffer calculated from various packets*/ buffer* transkexinit; /* the kexinit packet we send should be kept so we can add it to the hash when generating keys */ + + /* a list of queued replies that should be sent after a KEX has + 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