--- a/ChangeLog Sun Jan 30 12:19:12 2005 -0500
+++ b/ChangeLog Mon Jan 31 23:30:14 2005 -0500
@@ -1,5 +1,8 @@
Gaim: The Pimpin' Penguin IM Client that's good for the soul!
+ * CHAP authentication support for SOCKS5 proxies (Malcolm Smith) version 1.1.2 (1/20/2005):
* MSN 'HTTP Method' fixed (Felipe Contreras)
* Better handling of MSN's Individuals group and buddy status updates
--- a/src/proxy.c Sun Jan 30 12:19:12 2005 -0500
+++ b/src/proxy.c Mon Jan 31 23:30:14 2005 -0500
@@ -35,6 +35,7 @@
@@ -1131,7 +1132,14 @@
fcntl(source, F_SETFL, 0);
- /* XXX does socks4 not support host name lookups by the proxy? */
+ * The socks4 spec doesn't include support for doing host name + * lookups by the proxy. Some socks4 servers do this via + * extensions to the protocol. Since we don't know if a + * server supports this, it would need to be implemented + * with an option, or some detection mechanism - in the + * meantime, stick with plain old SOCKS4. if (!(hp = gethostbyname(phb->host))) {
@@ -1278,10 +1286,10 @@
buf[3] = 0x03; /* address type -- host name */
memcpy(buf + 5, phb->host, hlen);
- buf[5 + strlen(phb->host)] = phb->port >> 8;
- buf[5 + strlen(phb->host) + 1] = phb->port & 0xff;
+ buf[5 + hlen] = phb->port >> 8; + buf[5 + hlen + 1] = phb->port & 0xff; - if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {
+ if (write(source, buf, (5 + hlen + 2)) < (5 + hlen + 2)) { @@ -1317,6 +1325,141 @@
s5_sendconnect(phb, source);
+static void hmacmd5_chap(const unsigned char * challenge, int challen, const char * passwd, unsigned char * response) + unsigned char Kxoripad[65]; + unsigned char Kxoropad[65]; + pwinput=(char *)passwd; + md5_append(&ctx, (unsigned char *)passwd, strlen(passwd)); + md5_finish(&ctx, (unsigned char *)md5buf); + pwinput=(char *)md5buf; + memset(Kxoripad,0,sizeof(Kxoripad)); + memset(Kxoropad,0,sizeof(Kxoropad)); + memcpy(Kxoripad,pwinput,pwlen); + memcpy(Kxoropad,pwinput,pwlen); + md5_append(&ctx, Kxoripad, 64); + md5_append(&ctx, challenge, challen); + md5_finish(&ctx, (unsigned char *)Kxoripad); + md5_append(&ctx, Kxoropad, 64); + md5_append(&ctx, Kxoripad, 16); + md5_finish(&ctx, response); +s5_readchap(gpointer data, gint source, GaimInputCondition cond) + unsigned char buf[260]; + unsigned char cmdbuf[20]; + struct PHB *phb = data; + gaim_input_remove(phb->inpa); + gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n"); + if (read(source, cmdbuf, 2) < 2) { + if (cmdbuf[0] != 0x01) { + for (currentav = 0; currentav < navas; currentav++) { + if (read(source, cmdbuf, 2) < 2) { + if (read(source, buf, cmdbuf[1]) < cmdbuf[1]) { + return s5_sendconnect(phb, source); + gaim_debug_warning("proxy", "socks5 CHAP authentication " + "failed. Disconnecting..."); + /* Server wants our credentials */ + hmacmd5_chap(buf, cmdbuf[1], + gaim_proxy_info_get_password(phb->gpi), + if (write(source, buf, 20) < 20) { + /* Server wants to select an algorithm */ + /* Only currently support HMAC-MD5 */ + gaim_debug_warning("proxy", "Server tried to select an " + "algorithm that we did not advertise " + "as supporting. This is a violation " + "of the socks5 CHAP specification. " + /* 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. */ + phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readchap, phb); s5_canread(gpointer data, gint source, GaimInputCondition cond)
@@ -1360,6 +1503,25 @@
phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb);
+ } else if (buf[1] == 0x03) { + userlen = strlen(gaim_proxy_info_get_username(phb->gpi)); + memcpy(buf + 7, gaim_proxy_info_get_username(phb->gpi), userlen); + if (write(source, buf, 7 + userlen) < 7 + userlen) { + phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readchap, phb); s5_sendconnect(phb, source);
@@ -1393,10 +1555,11 @@
buf[0] = 0x05; /* SOCKS version 5 */
if (gaim_proxy_info_get_username(phb->gpi) != NULL) {
- buf[1] = 0x02; /* two methods */
+ buf[1] = 0x03; /* three methods */ buf[2] = 0x00; /* no authentication */
- buf[3] = 0x02; /* username/password authentication */
+ buf[3] = 0x03; /* CHAP authentication */ + buf[4] = 0x02; /* username/password authentication */