Mercurial > pidgin
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; |
