On Thu, Jun 26, 2008 at 5:29 PM, Dan Fandrich <[EMAIL PROTECTED]>
wrote:
> On Thu, Jun 26, 2008 at 05:22:15PM -0400, Sean Peterson wrote:
> > While testing a a SFTP client of mine using libcurl + libssh2.18, I
> discovered
> > a bug when maintaining a persistent connection with the VanDyke VShell
> Server
> > (Windows based SFTP server).
>
> Would you mind re-sending the patches to the list using the diff -u option?
> Any changes to the code since 0.18 would make those patches unable to
> apply.
> Thanks.
>
> >>> Dan
>
Dan,
I've remade the patches in the 'diff -u' format.
I've based my work on the latest CVS checkout (or at the very least, latest
as of two weeks ago). I've also generated the patches against what is in CVS
with the "cvs diff -u" command, so hopefully that will make things easier.
Regards,
Sean
Index: kex.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/kex.c,v
retrieving revision 1.36
diff -u -r1.36 kex.c
--- kex.c 18 Nov 2007 20:57:13 -0000 1.36
+++ kex.c 26 Jun 2008 21:32:50 -0000
@@ -1680,6 +1680,8 @@
int rc = 0;
int retcode;
+ session->state |= LIBSSH2_STATE_KEX_ACTIVE;
+
if (key_state->state == libssh2_NB_state_idle) {
/* Prevent loop in packet_add() */
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
@@ -1711,11 +1713,14 @@
if (key_state->state == libssh2_NB_state_sent) {
retcode = libssh2_kexinit(session);
if (retcode == PACKET_EAGAIN) {
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
session->local.kexinit = key_state->oldlocal;
session->local.kexinit_len = key_state->oldlocal_len;
key_state->state = libssh2_NB_state_idle;
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
+ session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return -1;
}
@@ -1729,6 +1734,7 @@
&key_state->data_len, 0, NULL, 0,
&key_state->req_state);
if (retcode == PACKET_EAGAIN) {
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
if (session->local.kexinit) {
@@ -1737,6 +1743,8 @@
session->local.kexinit = key_state->oldlocal;
session->local.kexinit_len = key_state->oldlocal_len;
key_state->state = libssh2_NB_state_idle;
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
+ session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return -1;
}
@@ -1763,6 +1771,7 @@
session->kex->exchange_keys(session,
&key_state->key_state_low);
if (retcode == PACKET_EAGAIN) {
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
@@ -1782,6 +1791,7 @@
session->remote.kexinit = NULL;
}
+ session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
key_state->state = libssh2_NB_state_idle;
Index: libssh2_priv.h
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/libssh2_priv.h,v
retrieving revision 1.35
diff -u -r1.35 libssh2_priv.h
--- libssh2_priv.h 6 Aug 2007 20:48:06 -0000 1.35
+++ libssh2_priv.h 26 Jun 2008 21:32:05 -0000
@@ -833,6 +833,7 @@
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
#define LIBSSH2_STATE_NEWKEYS 0x00000002
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
+#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008
/* session.flag helpers */
#ifdef MSG_NOSIGNAL
Index: packet.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/packet.c,v
retrieving revision 1.55
diff -u -r1.55 packet.c
--- packet.c 6 Aug 2007 20:48:07 -0000 1.55
+++ packet.c 26 Jun 2008 21:33:09 -0000
@@ -914,11 +914,31 @@
session->packAdd_state = libssh2_NB_state_sent2;
}
+
+ /*
+ * The KEXINIT message has been added to the queue.
+ * The packAdd and readPack states need to be reset
+ * because libssh2_kex_exchange (eventually) calls upon
+ * libssh2_packet_read to read the rest of the key exchange
+ * conversation.
+ */
+ session->readPack_state = libssh2_NB_state_idle;
+ session->packet.total_num = 0;
+ session->packAdd_state = libssh2_NB_state_idle;
+ session->fullpacket_state = libssh2_NB_state_idle;
+
+ /*
+ * Also, don't use packAdd_key_state for key re-exchange,
+ * as it will be wiped out in the middle of the exchange.
+ * How about re-using the startup_key_state?
+ */
+ memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
+
/*
* If there was a key reexchange failure, let's just hope we didn't
* send NEWKEYS yet, otherwise remote will drop us like a rock
*/
- rc = libssh2_kex_exchange(session, 1, &session->packAdd_key_state);
+ rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
Index: transport.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/transport.c,v
retrieving revision 1.13
diff -u -r1.13 transport.c
--- transport.c 8 Nov 2007 13:51:23 -0000 1.13
+++ transport.c 26 Jun 2008 21:34:04 -0000
@@ -269,6 +269,40 @@
int blocksize;
int encrypted = 1;
+ int status;
+
+ /*
+ * All channels, systems, subsystems, etc eventually make it down here
+ * when looking for more incoming data. If a key exchange is going on
+ * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end
+ * will ONLY send key exchange related traffic. In non-blocking mode,
+ * there is a chance to break out of the kex_exchange function with an
+ * EAGAIN status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS
+ * is active, then we must redirect to the key exchange. However,
+ * if kex_exchange is active (as in it is the one that calls this execution
+ * of packet_read, then don't redirect, as that would be an infinite loop!
+ */
+
+ if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
+ !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
+
+ /* Whoever wants a packet won't get anything until the key re-exchange
+ * is done!
+ */
+ _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Redirecting into the"
+ " key re-exchange");
+ status = libssh2_kex_exchange(session, 1, &session->startup_key_state);
+ if (status == PACKET_EAGAIN) {
+ libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+ "Would block exchanging encryption keys", 0);
+ return PACKET_EAGAIN;
+ } else if (status) {
+ libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
+ "Unable to exchange encryption keys",0);
+ return LIBSSH2_ERROR_KEX_FAILURE;
+ }
+ }
+
/*
* =============================== NOTE ===============================
* I know this is very ugly and not a really good use of "goto", but
@@ -527,8 +561,21 @@
libssh2_packet_read_point1:
rc = fullpacket(session, encrypted);
if (rc == PACKET_EAGAIN) {
- session->readPack_encrypted = encrypted;
- session->readPack_state = libssh2_NB_state_jump1;
+
+ if (session->packAdd_state != libssh2_NB_state_idle)
+ {
+ /* fullpacket only returns PACKET_EAGAIN if
+ * libssh2_packet_add returns PACKET_EAGAIN. If that
+ * returns PACKET_EAGAIN but the packAdd_state is idle,
+ * then the packet has been added to the brigade, but some
+ * immediate action that was taken based on the packet
+ * type (such as key re-exchange) is not yet complete.
+ * Clear the way for a new packet to be read in.
+ */
+ session->readPack_encrypted = encrypted;
+ session->readPack_state = libssh2_NB_state_jump1;
+ }
+
return PACKET_EAGAIN;
}
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
libssh2-devel mailing list
libssh2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel