pidgin: 81dff419: Fix the SOCKS5 CHAP authentication to pa...

datallah at pidgin.im datallah at pidgin.im
Thu Sep 11 18:35:40 EDT 2008


-----------------------------------------------------------------
Revision: 81dff419c8d1b9ad4ab4c0445844b21410505890
Ancestor: 26e23ab91560b6065ecfbd282960e82668431a93
Author: datallah at pidgin.im
Date: 2008-09-11T22:00:23
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/81dff419c8d1b9ad4ab4c0445844b21410505890

Modified files:
        libpurple/proxy.c

ChangeLog: 

Fix the SOCKS5 CHAP authentication to parse several messages if they are read at
in the intial read.  This allows us to accept the CHALLENGE attrib in a
different message than the ALGORITHMS attrib since the IETF draft is somewhat
ambiguous about this.
Also include some additional debugging output for the CHAP processing.
Thanks to Jonathan Rudolph ("simple" on IRC) for debugging.

-------------- next part --------------
============================================================
--- libpurple/proxy.c	1b56d841e40a3206119b45132a241c3c10d18351
+++ libpurple/proxy.c	0168a30adf1d8a95d1aa807783b605ae48a101a2
@@ -1505,62 +1505,31 @@ static void
 }
 
 static void
-s5_readchap(gpointer data, gint source, PurpleInputCondition cond)
+s5_readchap(gpointer data, gint source, PurpleInputCondition cond);
+
+/*
+ * Return how many bytes we processed
+ * -1 means we've shouldn't keep reading from the buffer
+ */
+static gssize
+s5_parse_chap_msg(PurpleProxyConnectData *connect_data)
 {
-	guchar *cmdbuf, *buf;
-	PurpleProxyConnectData *connect_data = data;
+	guchar *buf, *cmdbuf = connect_data->read_buffer;
 	int len, navas, currentav;
 
-	purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n");
+	purple_debug_misc("socks5 proxy", "Reading CHAP message: %x\n", *cmdbuf);
 
-	if (connect_data->read_buffer == NULL) {
-		/* A big enough butfer to read the message header (2 bytes) and at least one complete attribute and value (1 + 1 + 255). */
-		connect_data->read_buf_len = 259;
-		connect_data->read_buffer = g_malloc(connect_data->read_buf_len);
-		connect_data->read_len = 0;
-	}
-
-	if (connect_data->read_buf_len - connect_data->read_len == 0) {
-		/*If the stuff below is right, this shouldn't be possible. */
-		purple_debug_error("socks5 proxy", "This is about to suck because the read buffer is full (shouldn't happen).\n");
-	}
-
-	len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len,
-		connect_data->read_buf_len - connect_data->read_len);
-
-	if (len == 0)
-	{
-		purple_proxy_connect_data_disconnect(connect_data,
-				_("Server closed the connection."));
-		return;
-	}
-
-	if (len < 0)
-	{
-		if (errno == EAGAIN)
-			/* No worries */
-			return;
-
-		/* Error! */
-		purple_proxy_connect_data_disconnect_formatted(connect_data,
-				_("Lost connection with server:\n%s"), g_strerror(errno));
-		return;
-	}
-
-	connect_data->read_len += len;
-	if (connect_data->read_len < 2)
-		return;
-
-	cmdbuf = connect_data->read_buffer;
-
 	if (*cmdbuf != 0x01) {
 		purple_proxy_connect_data_disconnect(connect_data,
 				_("Received invalid data on connection with server."));
-		return;
+		return -1;
 	}
 	cmdbuf++;
 
 	navas = *cmdbuf;
+
+	purple_debug_misc("socks5 proxy", "Expecting %d attribute(s).\n", navas);
+
 	cmdbuf++;
 
 	for (currentav = 0; currentav < navas; currentav++) {
@@ -1575,7 +1544,10 @@ s5_readchap(gpointer data, gint source, 
 			memmove((connect_data->read_buffer + 2), cmdbuf, len);
 			/* Decrease the read count accordingly */
 			connect_data->read_len = len + 2;
-			return;
+
+			purple_debug_info("socks5 proxy", "Need more data to retrieve attribute %d.\n", currentav);
+
+			return -1;
 		}
 
 		buf = cmdbuf + 2;
@@ -1605,7 +1577,7 @@ s5_readchap(gpointer data, gint source, 
 					purple_proxy_connect_data_disconnect(connect_data,
 							_("Authentication failed"));
 				}
-				return;
+				return -1;
 			case 0x03:
 				purple_debug_info("socks5 proxy", "Received CHALLENGE\n");
 				/* Server wants our credentials */
@@ -1632,7 +1604,7 @@ s5_readchap(gpointer data, gint source, 
 					PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
 
 				proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
-				return;
+				return -1;
 			case 0x11:
 				purple_debug_info("socks5 proxy", "Received ALGORIGTHMS of %x\n", buf[0]);
 				/* Server wants to select an algorithm */
@@ -1646,7 +1618,7 @@ s5_readchap(gpointer data, gint source, 
 						"Disconnecting...");
 					purple_proxy_connect_data_disconnect(connect_data,
 							_("Received invalid data on connection with server."));
-					return;
+					return -1;
 				}
 				break;
 			default:
@@ -1655,10 +1627,85 @@ s5_readchap(gpointer data, gint source, 
 		cmdbuf = buf + cmdbuf[1];
 	}
 
+	return (cmdbuf - connect_data->read_buffer);
+}
+
+static void
+s5_readchap(gpointer data, gint source, PurpleInputCondition cond)
+{
+	gssize msg_ret;
+	PurpleProxyConnectData *connect_data = data;
+	int len;
+
+	purple_debug(PURPLE_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n");
+
+	if (connect_data->read_buffer == NULL) {
+		/* A big enough butfer to read the message header (2 bytes) and at least one complete attribute and value (1 + 1 + 255). */
+		connect_data->read_buf_len = 259;
+		connect_data->read_buffer = g_malloc(connect_data->read_buf_len);
+		connect_data->read_len = 0;
+	}
+
+	if (connect_data->read_buf_len - connect_data->read_len == 0) {
+		/*If the stuff below is right, this shouldn't be possible. */
+		purple_debug_error("socks5 proxy", "This is about to suck because the read buffer is full (shouldn't happen).\n");
+	}
+
+	len = read(connect_data->fd, connect_data->read_buffer + connect_data->read_len,
+		connect_data->read_buf_len - connect_data->read_len);
+
+	if (len == 0) {
+		purple_proxy_connect_data_disconnect(connect_data,
+				_("Server closed the connection."));
+		return;
+	}
+
+	if (len < 0) {
+		if (errno == EAGAIN)
+			/* No worries */
+			return;
+
+		/* Error! */
+		purple_proxy_connect_data_disconnect_formatted(connect_data,
+				_("Lost connection with server:\n%s"), g_strerror(errno));
+		return;
+	}
+
+	connect_data->read_len += len;
+
+	/* We may have read more than one message into the buffer, we need to make sure to process them all */
+	while (1) {
+
+		/* We need more to be able to read this message */
+		if (connect_data->read_len < 2)
+			return;
+
+		msg_ret = s5_parse_chap_msg(connect_data);
+	
+		if (msg_ret < 0)
+			return;
+
+		/* See if we have another message already in the buffer */
+		if ((len = connect_data->read_len - msg_ret) > 0) {
+
+			/* Move on to the next message */
+			memmove(connect_data->read_buffer, connect_data->read_buffer + msg_ret, len);
+			/* Decrease the read count accordingly */
+			connect_data->read_len = len;
+
+			/* Try to read the message that connect_data->read_buffer now points to */
+			continue;
+		}
+
+		break;
+	}
+
 	/* Fell through.  We ran out of CHAP events to process, but haven't
 	 * succeeded or failed authentication - there may be more to come.
 	 * If this is the case, come straight back here. */
 
+	purple_debug_info("socks5 proxy", "Waiting for another message from which to read CHAP info.\n");
+
 	/* We've processed all the available attributes, so get ready for a whole new message */
  	g_free(connect_data->read_buffer);
 	connect_data->read_buffer = NULL;


More information about the Commits mailing list