PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/neo/curl/lib/http_ntlm.c

https://bitbucket.org/festevezga/doom3.gpl
C | 587 lines | 364 code | 97 blank | 126 comment | 24 complexity | f9ca20ea5e693f5fee8b37f6bca96b80 MD5 | raw file
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id: http_ntlm.c,v 1.28 2004/03/08 16:20:51 bagder Exp $
  22. ***************************************************************************/
  23. #include "setup.h"
  24. /* NTLM details:
  25. http://davenport.sourceforge.net/ntlm.html
  26. http://www.innovation.ch/java/ntlm.html
  27. */
  28. #ifndef CURL_DISABLE_HTTP
  29. #ifdef USE_SSLEAY
  30. /* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
  31. /* -- WIN32 approved -- */
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <stdarg.h>
  35. #include <stdlib.h>
  36. #include <ctype.h>
  37. #include "urldata.h"
  38. #include "sendf.h"
  39. #include "strequal.h"
  40. #include "base64.h"
  41. #include "http_ntlm.h"
  42. #include "url.h"
  43. #include "http.h" /* for Curl_http_auth_stage() */
  44. #define _MPRINTF_REPLACE /* use our functions only */
  45. #include <curl/mprintf.h>
  46. #include <openssl/des.h>
  47. #include <openssl/md4.h>
  48. #include <openssl/ssl.h>
  49. #if OPENSSL_VERSION_NUMBER < 0x00907001L
  50. #define DES_key_schedule des_key_schedule
  51. #define DES_cblock des_cblock
  52. #define DES_set_odd_parity des_set_odd_parity
  53. #define DES_set_key des_set_key
  54. #define DES_ecb_encrypt des_ecb_encrypt
  55. /* This is how things were done in the old days */
  56. #define DESKEY(x) x
  57. #define DESKEYARG(x) x
  58. #else
  59. /* Modern version */
  60. #define DESKEYARG(x) *x
  61. #define DESKEY(x) &x
  62. #endif
  63. /* The last #include file should be: */
  64. #ifdef CURLDEBUG
  65. #include "memdebug.h"
  66. #endif
  67. /* Define this to make the type-3 message include the NT response message */
  68. #undef USE_NTRESPONSES
  69. /*
  70. (*) = A "security buffer" is a triplet consisting of two shorts and one
  71. long:
  72. 1. a 'short' containing the length of the buffer in bytes
  73. 2. a 'short' containing the allocated space for the buffer in bytes
  74. 3. a 'long' containing the offset to the start of the buffer from the
  75. beginning of the NTLM message, in bytes.
  76. */
  77. CURLntlm Curl_input_ntlm(struct connectdata *conn,
  78. bool proxy, /* if proxy or not */
  79. char *header) /* rest of the www-authenticate:
  80. header */
  81. {
  82. /* point to the correct struct with this */
  83. struct ntlmdata *ntlm;
  84. ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
  85. /* skip initial whitespaces */
  86. while(*header && isspace((int)*header))
  87. header++;
  88. if(checkprefix("NTLM", header)) {
  89. unsigned char buffer[256];
  90. header += strlen("NTLM");
  91. while(*header && isspace((int)*header))
  92. header++;
  93. if(*header) {
  94. /* We got a type-2 message here:
  95. Index Description Content
  96. 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
  97. (0x4e544c4d53535000)
  98. 8 NTLM Message Type long (0x02000000)
  99. 12 Target Name security buffer(*)
  100. 20 Flags long
  101. 24 Challenge 8 bytes
  102. (32) Context (optional) 8 bytes (two consecutive longs)
  103. (40) Target Information (optional) security buffer(*)
  104. 32 (48) start of data block
  105. */
  106. size_t size = Curl_base64_decode(header, (char *)buffer);
  107. ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
  108. if(size >= 48)
  109. /* the nonce of interest is index [24 .. 31], 8 bytes */
  110. memcpy(ntlm->nonce, &buffer[24], 8);
  111. /* at index decimal 20, there's a 32bit NTLM flag field */
  112. }
  113. else {
  114. if(ntlm->state >= NTLMSTATE_TYPE1)
  115. return CURLNTLM_BAD;
  116. ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
  117. }
  118. }
  119. return CURLNTLM_FINE;
  120. }
  121. /*
  122. * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
  123. * key schedule ks is also set.
  124. */
  125. static void setup_des_key(unsigned char *key_56,
  126. DES_key_schedule DESKEYARG(ks))
  127. {
  128. DES_cblock key;
  129. key[0] = key_56[0];
  130. key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
  131. key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
  132. key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
  133. key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
  134. key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
  135. key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
  136. key[7] = (key_56[6] << 1) & 0xFF;
  137. DES_set_odd_parity(&key);
  138. DES_set_key(&key, ks);
  139. }
  140. /*
  141. * takes a 21 byte array and treats it as 3 56-bit DES keys. The
  142. * 8 byte plaintext is encrypted with each key and the resulting 24
  143. * bytes are stored in the results array.
  144. */
  145. static void calc_resp(unsigned char *keys,
  146. unsigned char *plaintext,
  147. unsigned char *results)
  148. {
  149. DES_key_schedule ks;
  150. setup_des_key(keys, DESKEY(ks));
  151. DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
  152. DESKEY(ks), DES_ENCRYPT);
  153. setup_des_key(keys+7, DESKEY(ks));
  154. DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
  155. DESKEY(ks), DES_ENCRYPT);
  156. setup_des_key(keys+14, DESKEY(ks));
  157. DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
  158. DESKEY(ks), DES_ENCRYPT);
  159. }
  160. /*
  161. * Set up lanmanager and nt hashed passwords
  162. */
  163. static void mkhash(char *password,
  164. unsigned char *nonce, /* 8 bytes */
  165. unsigned char *lmresp /* must fit 0x18 bytes */
  166. #ifdef USE_NTRESPONSES
  167. , unsigned char *ntresp /* must fit 0x18 bytes */
  168. #endif
  169. )
  170. {
  171. unsigned char lmbuffer[21];
  172. #ifdef USE_NTRESPONSES
  173. unsigned char ntbuffer[21];
  174. #endif
  175. unsigned char *pw;
  176. static const unsigned char magic[] = {
  177. 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
  178. };
  179. unsigned int i;
  180. size_t len = strlen(password);
  181. /* make it fit at least 14 bytes */
  182. pw = malloc(len<7?14:len*2);
  183. if(!pw)
  184. return; /* this will lead to a badly generated package */
  185. if (len > 14)
  186. len = 14;
  187. for (i=0; i<len; i++)
  188. pw[i] = toupper(password[i]);
  189. for (; i<14; i++)
  190. pw[i] = 0;
  191. {
  192. /* create LanManager hashed password */
  193. DES_key_schedule ks;
  194. setup_des_key(pw, DESKEY(ks));
  195. DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
  196. DESKEY(ks), DES_ENCRYPT);
  197. setup_des_key(pw+7, DESKEY(ks));
  198. DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
  199. DESKEY(ks), DES_ENCRYPT);
  200. memset(lmbuffer+16, 0, 5);
  201. }
  202. /* create LM responses */
  203. calc_resp(lmbuffer, nonce, lmresp);
  204. #ifdef USE_NTRESPONSES
  205. {
  206. /* create NT hashed password */
  207. MD4_CTX MD4;
  208. len = strlen(password);
  209. for (i=0; i<len; i++) {
  210. pw[2*i] = password[i];
  211. pw[2*i+1] = 0;
  212. }
  213. MD4_Init(&MD4);
  214. MD4_Update(&MD4, pw, 2*len);
  215. MD4_Final(ntbuffer, &MD4);
  216. memset(ntbuffer+16, 0, 8);
  217. }
  218. calc_resp(ntbuffer, nonce, ntresp);
  219. #endif
  220. free(pw);
  221. }
  222. #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
  223. #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
  224. (((x) >>16)&0xff), ((x)>>24)
  225. /* this is for creating ntlm header output */
  226. CURLcode Curl_output_ntlm(struct connectdata *conn,
  227. bool proxy,
  228. bool *ready)
  229. {
  230. const char *domain=""; /* empty */
  231. const char *host=""; /* empty */
  232. int domlen=(int)strlen(domain);
  233. int hostlen = (int)strlen(host);
  234. int hostoff; /* host name offset */
  235. int domoff; /* domain name offset */
  236. size_t size;
  237. char *base64=NULL;
  238. unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
  239. /* point to the address of the pointer that holds the string to sent to the
  240. server, which is for a plain host or for a HTTP proxy */
  241. char **allocuserpwd;
  242. /* point to the name and password for this */
  243. char *userp;
  244. char *passwdp;
  245. /* point to the correct struct with this */
  246. struct ntlmdata *ntlm;
  247. *ready = FALSE;
  248. if(proxy) {
  249. allocuserpwd = &conn->allocptr.proxyuserpwd;
  250. userp = conn->proxyuser;
  251. passwdp = conn->proxypasswd;
  252. ntlm = &conn->proxyntlm;
  253. }
  254. else {
  255. allocuserpwd = &conn->allocptr.userpwd;
  256. userp = conn->user;
  257. passwdp = conn->passwd;
  258. ntlm = &conn->ntlm;
  259. }
  260. /* not set means empty */
  261. if(!userp)
  262. userp=(char *)"";
  263. if(!passwdp)
  264. passwdp=(char *)"";
  265. switch(ntlm->state) {
  266. case NTLMSTATE_TYPE1:
  267. default: /* for the weird cases we (re)start here */
  268. hostoff = 32;
  269. domoff = hostoff + hostlen;
  270. /* Create and send a type-1 message:
  271. Index Description Content
  272. 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
  273. (0x4e544c4d53535000)
  274. 8 NTLM Message Type long (0x01000000)
  275. 12 Flags long
  276. 16 Supplied Domain security buffer(*)
  277. 24 Supplied Workstation security buffer(*)
  278. 32 start of data block
  279. */
  280. snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
  281. "\x01%c%c%c" /* 32-bit type = 1 */
  282. "%c%c%c%c" /* 32-bit NTLM flag field */
  283. "%c%c" /* domain length */
  284. "%c%c" /* domain allocated space */
  285. "%c%c" /* domain name offset */
  286. "%c%c" /* 2 zeroes */
  287. "%c%c" /* host length */
  288. "%c%c" /* host allocated space */
  289. "%c%c" /* host name offset */
  290. "%c%c" /* 2 zeroes */
  291. "%s" /* host name */
  292. "%s", /* domain string */
  293. 0, /* trailing zero */
  294. 0,0,0, /* part of type-1 long */
  295. LONGQUARTET(
  296. NTLMFLAG_NEGOTIATE_OEM| /* 2 */
  297. NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
  298. /* equals 0x0202 */
  299. ),
  300. SHORTPAIR(domlen),
  301. SHORTPAIR(domlen),
  302. SHORTPAIR(domoff),
  303. 0,0,
  304. SHORTPAIR(hostlen),
  305. SHORTPAIR(hostlen),
  306. SHORTPAIR(hostoff),
  307. 0,0,
  308. host, domain);
  309. /* initial packet length */
  310. size = 32 + hostlen + domlen;
  311. /* now keeper of the base64 encoded package size */
  312. size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
  313. if(size >0 ) {
  314. Curl_safefree(*allocuserpwd);
  315. *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
  316. proxy?"Proxy-":"",
  317. base64);
  318. free(base64);
  319. }
  320. else
  321. return CURLE_OUT_OF_MEMORY; /* FIX TODO */
  322. break;
  323. case NTLMSTATE_TYPE2:
  324. /* We received the type-2 already, create a type-3 message:
  325. Index Description Content
  326. 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
  327. (0x4e544c4d53535000)
  328. 8 NTLM Message Type long (0x03000000)
  329. 12 LM/LMv2 Response security buffer(*)
  330. 20 NTLM/NTLMv2 Response security buffer(*)
  331. 28 Domain Name security buffer(*)
  332. 36 User Name security buffer(*)
  333. 44 Workstation Name security buffer(*)
  334. (52) Session Key (optional) security buffer(*)
  335. (60) Flags (optional) long
  336. 52 (64) start of data block
  337. */
  338. {
  339. int lmrespoff;
  340. int ntrespoff;
  341. int useroff;
  342. unsigned char lmresp[0x18]; /* fixed-size */
  343. #ifdef USE_NTRESPONSES
  344. unsigned char ntresp[0x18]; /* fixed-size */
  345. #endif
  346. const char *user;
  347. int userlen;
  348. user = strchr(userp, '\\');
  349. if(!user)
  350. user = strchr(userp, '/');
  351. if (user) {
  352. domain = userp;
  353. domlen = user - domain;
  354. user++;
  355. }
  356. else
  357. user = userp;
  358. userlen = strlen(user);
  359. mkhash(passwdp, &ntlm->nonce[0], lmresp
  360. #ifdef USE_NTRESPONSES
  361. , ntresp
  362. #endif
  363. );
  364. domoff = 64; /* always */
  365. useroff = domoff + domlen;
  366. hostoff = useroff + userlen;
  367. lmrespoff = hostoff + hostlen;
  368. ntrespoff = lmrespoff + 0x18;
  369. /* Create the big type-3 message binary blob */
  370. size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
  371. "NTLMSSP%c"
  372. "\x03%c%c%c" /* type-3, 32 bits */
  373. "%c%c%c%c" /* LanManager length + allocated space */
  374. "%c%c" /* LanManager offset */
  375. "%c%c" /* 2 zeroes */
  376. "%c%c" /* NT-response length */
  377. "%c%c" /* NT-response allocated space */
  378. "%c%c" /* NT-response offset */
  379. "%c%c" /* 2 zeroes */
  380. "%c%c" /* domain length */
  381. "%c%c" /* domain allocated space */
  382. "%c%c" /* domain name offset */
  383. "%c%c" /* 2 zeroes */
  384. "%c%c" /* user length */
  385. "%c%c" /* user allocated space */
  386. "%c%c" /* user offset */
  387. "%c%c" /* 2 zeroes */
  388. "%c%c" /* host length */
  389. "%c%c" /* host allocated space */
  390. "%c%c" /* host offset */
  391. "%c%c%c%c%c%c" /* 6 zeroes */
  392. "\xff\xff" /* message length */
  393. "%c%c" /* 2 zeroes */
  394. "\x01\x82" /* flags */
  395. "%c%c" /* 2 zeroes */
  396. /* domain string */
  397. /* user string */
  398. /* host string */
  399. /* LanManager response */
  400. /* NT response */
  401. ,
  402. 0, /* zero termination */
  403. 0,0,0, /* type-3 long, the 24 upper bits */
  404. SHORTPAIR(0x18), /* LanManager response length, twice */
  405. SHORTPAIR(0x18),
  406. SHORTPAIR(lmrespoff),
  407. 0x0, 0x0,
  408. #ifdef USE_NTRESPONSES
  409. SHORTPAIR(0x18), /* NT-response length, twice */
  410. SHORTPAIR(0x18),
  411. #else
  412. 0x0, 0x0,
  413. 0x0, 0x0,
  414. #endif
  415. SHORTPAIR(ntrespoff),
  416. 0x0, 0x0,
  417. SHORTPAIR(domlen),
  418. SHORTPAIR(domlen),
  419. SHORTPAIR(domoff),
  420. 0x0, 0x0,
  421. SHORTPAIR(userlen),
  422. SHORTPAIR(userlen),
  423. SHORTPAIR(useroff),
  424. 0x0, 0x0,
  425. SHORTPAIR(hostlen),
  426. SHORTPAIR(hostlen),
  427. SHORTPAIR(hostoff),
  428. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  429. 0x0, 0x0,
  430. 0x0, 0x0);
  431. /* size is now 64 */
  432. size=64;
  433. ntlmbuf[62]=ntlmbuf[63]=0;
  434. memcpy(&ntlmbuf[size], domain, domlen);
  435. size += domlen;
  436. memcpy(&ntlmbuf[size], user, userlen);
  437. size += userlen;
  438. /* we append the binary hashes to the end of the blob */
  439. if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
  440. memcpy(&ntlmbuf[size], lmresp, 0x18);
  441. size += 0x18;
  442. }
  443. #ifdef USE_NTRESPONSES
  444. if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
  445. memcpy(&ntlmbuf[size], ntresp, 0x18);
  446. size += 0x18;
  447. }
  448. #endif
  449. ntlmbuf[56] = size & 0xff;
  450. ntlmbuf[57] = size >> 8;
  451. /* convert the binary blob into base64 */
  452. size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
  453. if(size >0 ) {
  454. Curl_safefree(*allocuserpwd);
  455. *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
  456. proxy?"Proxy-":"",
  457. base64);
  458. free(base64);
  459. }
  460. else
  461. return CURLE_OUT_OF_MEMORY; /* FIX TODO */
  462. ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
  463. *ready = TRUE;
  464. /* Switch to web authentication after proxy authentication is done */
  465. if (proxy)
  466. Curl_http_auth_stage(conn->data, 401);
  467. }
  468. break;
  469. case NTLMSTATE_TYPE3:
  470. /* connection is already authenticated,
  471. * don't send a header in future requests */
  472. if(*allocuserpwd) {
  473. free(*allocuserpwd);
  474. *allocuserpwd=NULL;
  475. }
  476. *ready = TRUE;
  477. break;
  478. }
  479. return CURLE_OK;
  480. }
  481. #endif /* USE_SSLEAY */
  482. #endif /* !CURL_DISABLE_HTTP */