The unified diff between revisions [83535bce..] and [48426bd6..] is displayed below. It can also be downloaded as a raw diff.
#
#
# patch "common-session.c"
# from [7f63e471153926d751212402da879eaf20bc30f6]
# to [a9d10f22cb28660dc98684c3a472f4d45b5fc843]
#
# patch "packet.c"
# from [ec8a36b39e6ba82575fe40bb0203f209a273d137]
# to [44903e72c3e83e405fad2b95480caa07bbd9591b]
#
# patch "packet.h"
# from [a7413a8a5b4f1d838c5cdd30701b53b7fe0bd2a0]
# to [e13b394061a590cae21bf3a1cba83df2f35c2d2e]
#
# patch "session.h"
# from [c0d237959045de3757213c394a53963bee9abeb7]
# to [cfedca9627c9f3e628b46215050ef0a136bd41c1]
#
============================================================
--- common-session.c 7f63e471153926d751212402da879eaf20bc30f6
+++ common-session.c a9d10f22cb28660dc98684c3a472f4d45b5fc843
@@ -80,9 +80,12 @@ void common_session_init(int sock, char*
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 @@ void session_loop(void(*loophandler)())
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 ) */
============================================================
--- packet.c ec8a36b39e6ba82575fe40bb0203f209a273d137
+++ packet.c 44903e72c3e83e405fad2b95480caa07bbd9591b
@@ -403,8 +403,61 @@ static buffer* buf_decompress(buffer* bu
#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 */
void encrypt_packet() {
@@ -413,9 +466,20 @@ void encrypt_packet() {
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;
============================================================
--- packet.h a7413a8a5b4f1d838c5cdd30701b53b7fe0bd2a0
+++ packet.h e13b394061a590cae21bf3a1cba83df2f35c2d2e
@@ -35,6 +35,7 @@ void process_packet();
void process_packet();
+void maybe_flush_reply_queue();
typedef struct PacketType {
unsigned char type; /* SSH_MSG_FOO */
void (*handler)();
============================================================
--- session.h c0d237959045de3757213c394a53963bee9abeb7
+++ session.h cfedca9627c9f3e628b46215050ef0a136bd41c1
@@ -81,6 +81,12 @@ struct key_context {
};
+struct packetlist;
+struct packetlist {
+ struct packetlist *next;
+ buffer * payload;
+};
+
struct sshsession {
/* Is it a client or server? */
@@ -137,6 +143,10 @@ struct sshsession {
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