comparison src/proxy.c @ 10561:1db4f49de0c6

[gaim-migrate @ 11939] sf patch #1009209, from Malcolm Smith CHAP support for SOCKS5 Please test this. Normally I try to avoid commiting things that aren't bug fixes to oldstatus, but someone said (I think it was Felipe), "oldstatus is also good for testing things." Uh, or something like that. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Tue, 01 Feb 2005 04:29:44 +0000
parents 975c2e66cd53
children e06da39b467c
comparison
equal deleted inserted replaced
10560:33746d45bd0d 10561:1db4f49de0c6
33 #include "debug.h" 33 #include "debug.h"
34 #include "notify.h" 34 #include "notify.h"
35 #include "prefs.h" 35 #include "prefs.h"
36 #include "proxy.h" 36 #include "proxy.h"
37 #include "util.h" 37 #include "util.h"
38 #include "md5.h"
38 39
39 static GaimProxyInfo *global_proxy_info = NULL; 40 static GaimProxyInfo *global_proxy_info = NULL;
40 41
41 struct PHB { 42 struct PHB {
42 GaimInputFunction func; 43 GaimInputFunction func;
1130 try_connect(phb); 1131 try_connect(phb);
1131 return; 1132 return;
1132 } 1133 }
1133 fcntl(source, F_SETFL, 0); 1134 fcntl(source, F_SETFL, 0);
1134 1135
1135 /* XXX does socks4 not support host name lookups by the proxy? */ 1136 /*
1137 * The socks4 spec doesn't include support for doing host name
1138 * lookups by the proxy. Some socks4 servers do this via
1139 * extensions to the protocol. Since we don't know if a
1140 * server supports this, it would need to be implemented
1141 * with an option, or some detection mechanism - in the
1142 * meantime, stick with plain old SOCKS4.
1143 */
1136 if (!(hp = gethostbyname(phb->host))) { 1144 if (!(hp = gethostbyname(phb->host))) {
1137 close(source); 1145 close(source);
1138 1146
1139 try_connect(phb); 1147 try_connect(phb);
1140 return; 1148 return;
1277 buf[1] = 0x01; /* CONNECT */ 1285 buf[1] = 0x01; /* CONNECT */
1278 buf[2] = 0x00; /* reserved */ 1286 buf[2] = 0x00; /* reserved */
1279 buf[3] = 0x03; /* address type -- host name */ 1287 buf[3] = 0x03; /* address type -- host name */
1280 buf[4] = hlen; 1288 buf[4] = hlen;
1281 memcpy(buf + 5, phb->host, hlen); 1289 memcpy(buf + 5, phb->host, hlen);
1282 buf[5 + strlen(phb->host)] = phb->port >> 8; 1290 buf[5 + hlen] = phb->port >> 8;
1283 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; 1291 buf[5 + hlen + 1] = phb->port & 0xff;
1284 1292
1285 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { 1293 if (write(source, buf, (5 + hlen + 2)) < (5 + hlen + 2)) {
1286 close(source); 1294 close(source);
1287 1295
1288 try_connect(phb); 1296 try_connect(phb);
1289 return; 1297 return;
1290 } 1298 }
1314 try_connect(phb); 1322 try_connect(phb);
1315 return; 1323 return;
1316 } 1324 }
1317 1325
1318 s5_sendconnect(phb, source); 1326 s5_sendconnect(phb, source);
1327 }
1328
1329 static void hmacmd5_chap(const unsigned char * challenge, int challen, const char * passwd, unsigned char * response)
1330 {
1331 int i;
1332 unsigned char Kxoripad[65];
1333 unsigned char Kxoropad[65];
1334 md5_state_t ctx;
1335 int pwlen;
1336 char * pwinput;
1337 char md5buf[16];
1338
1339 pwinput=(char *)passwd;
1340 pwlen=strlen(passwd);
1341 if (pwlen>64) {
1342 md5_init(&ctx);
1343 md5_append(&ctx, (unsigned char *)passwd, strlen(passwd));
1344 md5_finish(&ctx, (unsigned char *)md5buf);
1345 pwinput=(char *)md5buf;
1346 pwlen=16;
1347 }
1348
1349 memset(Kxoripad,0,sizeof(Kxoripad));
1350 memset(Kxoropad,0,sizeof(Kxoropad));
1351 memcpy(Kxoripad,pwinput,pwlen);
1352 memcpy(Kxoropad,pwinput,pwlen);
1353 for (i=0;i<64;i++) {
1354 Kxoripad[i]^=0x36;
1355 Kxoropad[i]^=0x5c;
1356 }
1357 md5_init(&ctx);
1358 md5_append(&ctx, Kxoripad, 64);
1359 md5_append(&ctx, challenge, challen);
1360 md5_finish(&ctx, (unsigned char *)Kxoripad);
1361
1362 md5_init(&ctx);
1363 md5_append(&ctx, Kxoropad, 64);
1364 md5_append(&ctx, Kxoripad, 16);
1365 md5_finish(&ctx, response);
1366 }
1367
1368 static void
1369 s5_readchap(gpointer data, gint source, GaimInputCondition cond)
1370 {
1371 unsigned char buf[260];
1372 unsigned char cmdbuf[20];
1373 struct PHB *phb = data;
1374
1375 int navas, currentav;
1376
1377 gaim_input_remove(phb->inpa);
1378 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got CHAP response.\n");
1379
1380 if (read(source, cmdbuf, 2) < 2) {
1381 close(source);
1382
1383 try_connect(phb);
1384 return;
1385 }
1386
1387 if (cmdbuf[0] != 0x01) {
1388 close(source);
1389
1390 try_connect(phb);
1391 return;
1392 }
1393
1394 navas = cmdbuf[1];
1395
1396 for (currentav = 0; currentav < navas; currentav++) {
1397 if (read(source, cmdbuf, 2) < 2) {
1398 close(source);
1399
1400 try_connect(phb);
1401 return;
1402 }
1403 if (read(source, buf, cmdbuf[1]) < cmdbuf[1]) {
1404 close(source);
1405
1406 try_connect(phb);
1407 return;
1408 }
1409 switch (cmdbuf[0]) {
1410 case 0x00:
1411 /* Did auth work? */
1412 if (buf[0] == 0x00) {
1413 /* Success */
1414 return s5_sendconnect(phb, source);
1415 } else {
1416 /* Failure */
1417 gaim_debug_warning("proxy", "socks5 CHAP authentication "
1418 "failed. Disconnecting...");
1419 close(source);
1420
1421 try_connect(phb);
1422 return;
1423 }
1424 break;
1425 case 0x03:
1426 /* Server wants our credentials */
1427 hmacmd5_chap(buf, cmdbuf[1],
1428 gaim_proxy_info_get_password(phb->gpi),
1429 buf + 4);
1430 buf[0] = 0x01;
1431 buf[1] = 0x01;
1432 buf[2] = 0x04;
1433 buf[3] = 0x10;
1434 if (write(source, buf, 20) < 20) {
1435 close(source);
1436
1437 try_connect(phb);
1438 return;
1439 }
1440 break;
1441 case 0x11:
1442 /* Server wants to select an algorithm */
1443 if (buf[0] != 0x85) {
1444 /* Only currently support HMAC-MD5 */
1445 gaim_debug_warning("proxy", "Server tried to select an "
1446 "algorithm that we did not advertise "
1447 "as supporting. This is a violation "
1448 "of the socks5 CHAP specification. "
1449 "Disconnecting...");
1450 close(source);
1451
1452 try_connect(phb);
1453 return;
1454 }
1455 break;
1456 }
1457 }
1458 /* Fell through. We ran out of CHAP events to process, but haven't
1459 * succeeded or failed authentication - there may be more to come.
1460 * If this is the case, come straight back here. */
1461 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readchap, phb);
1319 } 1462 }
1320 1463
1321 static void 1464 static void
1322 s5_canread(gpointer data, gint source, GaimInputCondition cond) 1465 s5_canread(gpointer data, gint source, GaimInputCondition cond)
1323 { 1466 {
1359 try_connect(phb); 1502 try_connect(phb);
1360 return; 1503 return;
1361 } 1504 }
1362 1505
1363 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); 1506 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb);
1507 } else if (buf[1] == 0x03) {
1508 unsigned int userlen;
1509 userlen = strlen(gaim_proxy_info_get_username(phb->gpi));
1510 buf[0] = 0x01;
1511 buf[1] = 0x02;
1512 buf[2] = 0x11;
1513 buf[3] = 0x01;
1514 buf[4] = 0x85;
1515 buf[5] = 0x02;
1516 buf[6] = userlen;
1517 memcpy(buf + 7, gaim_proxy_info_get_username(phb->gpi), userlen);
1518 if (write(source, buf, 7 + userlen) < 7 + userlen) {
1519 close(source);
1520
1521 try_connect(phb);
1522 return;
1523 }
1524
1525 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readchap, phb);
1364 } 1526 }
1365 else { 1527 else {
1366 s5_sendconnect(phb, source); 1528 s5_sendconnect(phb, source);
1367 } 1529 }
1368 } 1530 }
1392 1554
1393 i = 0; 1555 i = 0;
1394 buf[0] = 0x05; /* SOCKS version 5 */ 1556 buf[0] = 0x05; /* SOCKS version 5 */
1395 1557
1396 if (gaim_proxy_info_get_username(phb->gpi) != NULL) { 1558 if (gaim_proxy_info_get_username(phb->gpi) != NULL) {
1397 buf[1] = 0x02; /* two methods */ 1559 buf[1] = 0x03; /* three methods */
1398 buf[2] = 0x00; /* no authentication */ 1560 buf[2] = 0x00; /* no authentication */
1399 buf[3] = 0x02; /* username/password authentication */ 1561 buf[3] = 0x03; /* CHAP authentication */
1400 i = 4; 1562 buf[4] = 0x02; /* username/password authentication */
1563 i = 5;
1401 } 1564 }
1402 else { 1565 else {
1403 buf[1] = 0x01; 1566 buf[1] = 0x01;
1404 buf[2] = 0x00; 1567 buf[2] = 0x00;
1405 i = 3; 1568 i = 3;