1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2009, 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.79 2009-02-27 08:53:10 bagder Exp $
22 ***************************************************************************/
23 #include "setup.h"
24
25 /* NTLM details:
26
27 http://davenport.sourceforge.net/ntlm.html
28 http://www.innovation.ch/java/ntlm.html
29
30 Another implementation:
31 http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
32
33 */
34
35 #ifndef CURL_DISABLE_HTTP
36 #ifdef USE_NTLM
37
38 #define DEBUG_ME 0
39
40 /* -- WIN32 approved -- */
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
52 #include <netdb.h>
53 #endif
54
55 #include "urldata.h"
56 #include "easyif.h" /* for Curl_convert_... prototypes */
57 #include "sendf.h"
58 #include "rawstr.h"
59 #include "curl_base64.h"
60 #include "http_ntlm.h"
61 #include "url.h"
62 #include "memory.h"
63
64 #define _MPRINTF_REPLACE /* use our functions only */
65 #include <curl/mprintf.h>
66
67 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
68 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
69
70 #ifdef USE_SSLEAY
71 #include "ssluse.h"
72 # ifdef USE_OPENSSL
73 # include <openssl/des.h>
74 # include <openssl/md4.h>
75 # include <openssl/md5.h>
76 # include <openssl/ssl.h>
77 # include <openssl/rand.h>
78 # else
79 # include <des.h>
80 # include <md4.h>
81 # include <md5.h>
82 # include <ssl.h>
83 # include <rand.h>
84 # endif
85
86 #if OPENSSL_VERSION_NUMBER < 0x00907001L
87 #define DES_key_schedule des_key_schedule
88 #define DES_cblock des_cblock
89 #define DES_set_odd_parity des_set_odd_parity
90 #define DES_set_key des_set_key
91 #define DES_ecb_encrypt des_ecb_encrypt
92
93 /* This is how things were done in the old days */
94 #define DESKEY(x) x
95 #define DESKEYARG(x) x
96 #else
97 /* Modern version */
98 #define DESKEYARG(x) *x
99 #define DESKEY(x) &x
100 #endif
101
102 #elif defined(USE_GNUTLS)
103
104 #include "gtls.h"
105 #include <gcrypt.h>
106
107 #define MD5_DIGEST_LENGTH 16
108 #define MD4_DIGEST_LENGTH 16
109
110 #elif defined(USE_WINDOWS_SSPI)
111
112 #include "curl_sspi.h"
113
114 #else
115 # error "Can't compile NTLM support without a crypto library."
116 #endif
117
118 /* The last #include file should be: */
119 #include "memdebug.h"
120
121 /* Define this to make the type-3 message include the NT response message */
122 #define USE_NTRESPONSES 1
123
124 /* Define this to make the type-3 message include the NTLM2Session response
125 message, requires USE_NTRESPONSES. */
126 #define USE_NTLM2SESSION 1
127
128 #ifndef USE_WINDOWS_SSPI
129 /* this function converts from the little endian format used in the incoming
130 package to whatever endian format we're using natively */
readint_le(unsigned char * buf)131 static unsigned int readint_le(unsigned char *buf) /* must point to a
132 4 bytes buffer*/
133 {
134 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
135 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
136 }
137 #endif
138
139 #if DEBUG_ME
140 # define DEBUG_OUT(x) x
print_flags(FILE * handle,unsigned long flags)141 static void print_flags(FILE *handle, unsigned long flags)
142 {
143 if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
144 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
145 if(flags & NTLMFLAG_NEGOTIATE_OEM)
146 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
147 if(flags & NTLMFLAG_REQUEST_TARGET)
148 fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
149 if(flags & (1<<3))
150 fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
151 if(flags & NTLMFLAG_NEGOTIATE_SIGN)
152 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
153 if(flags & NTLMFLAG_NEGOTIATE_SEAL)
154 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
155 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
156 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
157 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
158 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
159 if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
160 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
161 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
162 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
163 if(flags & (1<<10))
164 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
165 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
166 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
167 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
168 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
169 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
170 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
171 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
172 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
173 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
174 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
175 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
176 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
177 if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
178 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
179 if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
180 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
181 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
182 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
183 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
184 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
185 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
186 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
187 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
188 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
189 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
190 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
191 if(flags & (1<<24))
192 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
193 if(flags & (1<<25))
194 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
195 if(flags & (1<<26))
196 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
197 if(flags & (1<<27))
198 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
199 if(flags & (1<<28))
200 fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
201 if(flags & NTLMFLAG_NEGOTIATE_128)
202 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
203 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
204 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
205 if(flags & NTLMFLAG_NEGOTIATE_56)
206 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
207 }
208
print_hex(FILE * handle,const char * buf,size_t len)209 static void print_hex(FILE *handle, const char *buf, size_t len)
210 {
211 const char *p = buf;
212 fprintf(stderr, "0x");
213 while(len-- > 0)
214 fprintf(stderr, "%02.2x", (unsigned int)*p++);
215 }
216 #else
217 # define DEBUG_OUT(x)
218 #endif
219
220 /*
221 (*) = A "security buffer" is a triplet consisting of two shorts and one
222 long:
223
224 1. a 'short' containing the length of the buffer in bytes
225 2. a 'short' containing the allocated space for the buffer in bytes
226 3. a 'long' containing the offset to the start of the buffer from the
227 beginning of the NTLM message, in bytes.
228 */
229
230
Curl_input_ntlm(struct connectdata * conn,bool proxy,const char * header)231 CURLntlm Curl_input_ntlm(struct connectdata *conn,
232 bool proxy, /* if proxy or not */
233 const char *header) /* rest of the www-authenticate:
234 header */
235 {
236 /* point to the correct struct with this */
237 struct ntlmdata *ntlm;
238 #ifndef USE_WINDOWS_SSPI
239 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
240 #endif
241
242 ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
243
244 /* skip initial whitespaces */
245 while(*header && ISSPACE(*header))
246 header++;
247
248 if(checkprefix("NTLM", header)) {
249 header += strlen("NTLM");
250
251 while(*header && ISSPACE(*header))
252 header++;
253
254 if(*header) {
255 /* We got a type-2 message here:
256
257 Index Description Content
258 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
259 (0x4e544c4d53535000)
260 8 NTLM Message Type long (0x02000000)
261 12 Target Name security buffer(*)
262 20 Flags long
263 24 Challenge 8 bytes
264 (32) Context (optional) 8 bytes (two consecutive longs)
265 (40) Target Information (optional) security buffer(*)
266 32 (48) start of data block
267 */
268 size_t size;
269 unsigned char *buffer;
270 size = Curl_base64_decode(header, &buffer);
271 if(!buffer)
272 return CURLNTLM_BAD;
273
274 ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
275
276 #ifdef USE_WINDOWS_SSPI
277 ntlm->type_2 = malloc(size+1);
278 if(ntlm->type_2 == NULL) {
279 free(buffer);
280 return CURLE_OUT_OF_MEMORY;
281 }
282 ntlm->n_type_2 = size;
283 memcpy(ntlm->type_2, buffer, size);
284 #else
285 ntlm->flags = 0;
286
287 if((size < 32) ||
288 (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
289 (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
290 /* This was not a good enough type-2 message */
291 free(buffer);
292 return CURLNTLM_BAD;
293 }
294
295 ntlm->flags = readint_le(&buffer[20]);
296 memcpy(ntlm->nonce, &buffer[24], 8);
297
298 DEBUG_OUT({
299 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
300 print_flags(stderr, ntlm->flags);
301 fprintf(stderr, "\n nonce=");
302 print_hex(stderr, (char *)ntlm->nonce, 8);
303 fprintf(stderr, "\n****\n");
304 fprintf(stderr, "**** Header %s\n ", header);
305 });
306
307 free(buffer);
308 #endif
309 }
310 else {
311 if(ntlm->state >= NTLMSTATE_TYPE1)
312 return CURLNTLM_BAD;
313
314 ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
315 }
316 }
317 return CURLNTLM_FINE;
318 }
319
320 #ifndef USE_WINDOWS_SSPI
321
322 #ifdef USE_SSLEAY
323 /*
324 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
325 * key schedule ks is also set.
326 */
setup_des_key(const unsigned char * key_56,DES_key_schedule DESKEYARG (ks))327 static void setup_des_key(const unsigned char *key_56,
328 DES_key_schedule DESKEYARG(ks))
329 {
330 DES_cblock key;
331
332 key[0] = key_56[0];
333 key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
334 key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
335 key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
336 key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
337 key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
338 key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
339 key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
340
341 DES_set_odd_parity(&key);
342 DES_set_key(&key, ks);
343 }
344 #elif defined(USE_GNUTLS)
345
346 /*
347 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
348 */
setup_des_key(const unsigned char * key_56,gcry_cipher_hd_t * des)349 static void setup_des_key(const unsigned char *key_56,
350 gcry_cipher_hd_t *des)
351 {
352 char key[8];
353
354 key[0] = key_56[0];
355 key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
356 key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
357 key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
358 key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
359 key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
360 key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
361 key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
362
363 gcry_cipher_setkey(*des, key, 8);
364 }
365 #endif
366
367 /*
368 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
369 * 8 byte plaintext is encrypted with each key and the resulting 24
370 * bytes are stored in the results array.
371 */
lm_resp(const unsigned char * keys,const unsigned char * plaintext,unsigned char * results)372 static void lm_resp(const unsigned char *keys,
373 const unsigned char *plaintext,
374 unsigned char *results)
375 {
376 #ifdef USE_SSLEAY
377 DES_key_schedule ks;
378
379 setup_des_key(keys, DESKEY(ks));
380 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
381 DESKEY(ks), DES_ENCRYPT);
382
383 setup_des_key(keys+7, DESKEY(ks));
384 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
385 DESKEY(ks), DES_ENCRYPT);
386
387 setup_des_key(keys+14, DESKEY(ks));
388 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
389 DESKEY(ks), DES_ENCRYPT);
390 #elif USE_GNUTLS
391 gcry_cipher_hd_t des;
392
393 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
394 setup_des_key(keys, &des);
395 gcry_cipher_encrypt(des, results, 8, plaintext, 8);
396 gcry_cipher_close(des);
397
398 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
399 setup_des_key(keys+7, &des);
400 gcry_cipher_encrypt(des, results+8, 8, plaintext, 8);
401 gcry_cipher_close(des);
402
403 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
404 setup_des_key(keys+14, &des);
405 gcry_cipher_encrypt(des, results+16, 8, plaintext, 8);
406 gcry_cipher_close(des);
407 #endif
408 }
409
410
411 /*
412 * Set up lanmanager hashed password
413 */
mk_lm_hash(struct SessionHandle * data,const char * password,unsigned char * lmbuffer)414 static void mk_lm_hash(struct SessionHandle *data,
415 const char *password,
416 unsigned char *lmbuffer /* 21 bytes */)
417 {
418 unsigned char pw[14];
419 static const unsigned char magic[] = {
420 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
421 };
422 size_t len = CURLMIN(strlen(password), 14);
423
424 Curl_strntoupper((char *)pw, password, len);
425 memset(&pw[len], 0, 14-len);
426
427 #ifdef CURL_DOES_CONVERSIONS
428 /*
429 * The LanManager hashed password needs to be created using the
430 * password in the network encoding not the host encoding.
431 */
432 if(data)
433 Curl_convert_to_network(data, (char *)pw, 14);
434 #else
435 (void)data;
436 #endif
437
438 {
439 /* Create LanManager hashed password. */
440
441 #ifdef USE_SSLEAY
442 DES_key_schedule ks;
443
444 setup_des_key(pw, DESKEY(ks));
445 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
446 DESKEY(ks), DES_ENCRYPT);
447
448 setup_des_key(pw+7, DESKEY(ks));
449 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
450 DESKEY(ks), DES_ENCRYPT);
451 #elif USE_GNUTLS
452 gcry_cipher_hd_t des;
453
454 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
455 setup_des_key(pw, &des);
456 gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
457 gcry_cipher_close(des);
458
459 gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
460 setup_des_key(pw+7, &des);
461 gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8);
462 gcry_cipher_close(des);
463 #endif
464
465 memset(lmbuffer + 16, 0, 21 - 16);
466 }
467 }
468
469 #if USE_NTRESPONSES
ascii_to_unicode_le(unsigned char * dest,const char * src,size_t srclen)470 static void ascii_to_unicode_le(unsigned char *dest, const char *src,
471 size_t srclen)
472 {
473 size_t i;
474 for (i=0; i<srclen; i++) {
475 dest[2*i] = (unsigned char)src[i];
476 dest[2*i+1] = '\0';
477 }
478 }
479
480 /*
481 * Set up nt hashed passwords
482 */
mk_nt_hash(struct SessionHandle * data,const char * password,unsigned char * ntbuffer)483 static CURLcode mk_nt_hash(struct SessionHandle *data,
484 const char *password,
485 unsigned char *ntbuffer /* 21 bytes */)
486 {
487 size_t len = strlen(password);
488 unsigned char *pw = malloc(len*2);
489 if(!pw)
490 return CURLE_OUT_OF_MEMORY;
491
492 ascii_to_unicode_le(pw, password, len);
493
494 #ifdef CURL_DOES_CONVERSIONS
495 /*
496 * The NT hashed password needs to be created using the
497 * password in the network encoding not the host encoding.
498 */
499 if(data)
500 Curl_convert_to_network(data, (char *)pw, len*2);
501 #else
502 (void)data;
503 #endif
504
505 {
506 /* Create NT hashed password. */
507 #ifdef USE_SSLEAY
508 MD4_CTX MD4pw;
509 MD4_Init(&MD4pw);
510 MD4_Update(&MD4pw, pw, 2*len);
511 MD4_Final(ntbuffer, &MD4pw);
512 #elif USE_GNUTLS
513 gcry_md_hd_t MD4pw;
514 gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
515 gcry_md_write(MD4pw, pw, 2*len);
516 memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
517 gcry_md_close(MD4pw);
518 #endif
519
520 memset(ntbuffer + 16, 0, 21 - 16);
521 }
522
523 free(pw);
524 return CURLE_OK;
525 }
526 #endif
527
528
529 #endif
530
531 #ifdef USE_WINDOWS_SSPI
532
533 static void
ntlm_sspi_cleanup(struct ntlmdata * ntlm)534 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
535 {
536 if(ntlm->type_2) {
537 free(ntlm->type_2);
538 ntlm->type_2 = NULL;
539 }
540 if(ntlm->has_handles) {
541 s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
542 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
543 ntlm->has_handles = 0;
544 }
545 if(ntlm->p_identity) {
546 if(ntlm->identity.User) free(ntlm->identity.User);
547 if(ntlm->identity.Password) free(ntlm->identity.Password);
548 if(ntlm->identity.Domain) free(ntlm->identity.Domain);
549 ntlm->p_identity = NULL;
550 }
551 }
552
553 #endif
554
555 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
556 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
557 (((x) >>16)&0xff), (((x)>>24) & 0xff)
558
559 #define HOSTNAME_MAX 1024
560
561 /* this is for creating ntlm header output */
Curl_output_ntlm(struct connectdata * conn,bool proxy)562 CURLcode Curl_output_ntlm(struct connectdata *conn,
563 bool proxy)
564 {
565 const char *domain=""; /* empty */
566 char host [HOSTNAME_MAX+ 1] = ""; /* empty */
567 #ifndef USE_WINDOWS_SSPI
568 size_t domlen = strlen(domain);
569 size_t hostlen = strlen(host);
570 size_t hostoff; /* host name offset */
571 size_t domoff; /* domain name offset */
572 #endif
573 size_t size;
574 char *base64=NULL;
575 unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
576 long */
577
578 /* point to the address of the pointer that holds the string to sent to the
579 server, which is for a plain host or for a HTTP proxy */
580 char **allocuserpwd;
581
582 /* point to the name and password for this */
583 const char *userp;
584 const char *passwdp;
585 /* point to the correct struct with this */
586 struct ntlmdata *ntlm;
587 struct auth *authp;
588
589 DEBUGASSERT(conn);
590 DEBUGASSERT(conn->data);
591
592 if(proxy) {
593 allocuserpwd = &conn->allocptr.proxyuserpwd;
594 userp = conn->proxyuser;
595 passwdp = conn->proxypasswd;
596 ntlm = &conn->proxyntlm;
597 authp = &conn->data->state.authproxy;
598 }
599 else {
600 allocuserpwd = &conn->allocptr.userpwd;
601 userp = conn->user;
602 passwdp = conn->passwd;
603 ntlm = &conn->ntlm;
604 authp = &conn->data->state.authhost;
605 }
606 authp->done = FALSE;
607
608 /* not set means empty */
609 if(!userp)
610 userp="";
611
612 if(!passwdp)
613 passwdp="";
614
615 #ifdef USE_WINDOWS_SSPI
616 if (s_hSecDll == NULL) {
617 /* not thread safe and leaks - use curl_global_init() to avoid */
618 CURLcode err = Curl_sspi_global_init();
619 if (s_hSecDll == NULL)
620 return err;
621 }
622 #endif
623
624 switch(ntlm->state) {
625 case NTLMSTATE_TYPE1:
626 default: /* for the weird cases we (re)start here */
627 #ifdef USE_WINDOWS_SSPI
628 {
629 SecBuffer buf;
630 SecBufferDesc desc;
631 SECURITY_STATUS status;
632 ULONG attrs;
633 const char *user;
634 int domlen;
635 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
636
637 ntlm_sspi_cleanup(ntlm);
638
639 user = strchr(userp, '\\');
640 if(!user)
641 user = strchr(userp, '/');
642
643 if(user) {
644 domain = userp;
645 domlen = user - userp;
646 user++;
647 }
648 else {
649 user = userp;
650 domain = "";
651 domlen = 0;
652 }
653
654 if(user && *user) {
655 /* note: initialize all of this before doing the mallocs so that
656 * it can be cleaned up later without leaking memory.
657 */
658 ntlm->p_identity = &ntlm->identity;
659 memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
660 if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
661 return CURLE_OUT_OF_MEMORY;
662 ntlm->identity.UserLength = strlen(user);
663 if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
664 return CURLE_OUT_OF_MEMORY;
665 ntlm->identity.PasswordLength = strlen(passwdp);
666 if((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
667 return CURLE_OUT_OF_MEMORY;
668 strncpy((char *)ntlm->identity.Domain, domain, domlen);
669 ntlm->identity.Domain[domlen] = '\0';
670 ntlm->identity.DomainLength = domlen;
671 ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
672 }
673 else {
674 ntlm->p_identity = NULL;
675 }
676
677 if(s_pSecFn->AcquireCredentialsHandleA(
678 NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
679 NULL, NULL, &ntlm->handle, &tsDummy
680 ) != SEC_E_OK) {
681 return CURLE_OUT_OF_MEMORY;
682 }
683
684 desc.ulVersion = SECBUFFER_VERSION;
685 desc.cBuffers = 1;
686 desc.pBuffers = &buf;
687 buf.cbBuffer = sizeof(ntlmbuf);
688 buf.BufferType = SECBUFFER_TOKEN;
689 buf.pvBuffer = ntlmbuf;
690
691 status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
692 (char *) host,
693 ISC_REQ_CONFIDENTIALITY |
694 ISC_REQ_REPLAY_DETECT |
695 ISC_REQ_CONNECTION,
696 0, SECURITY_NETWORK_DREP,
697 NULL, 0,
698 &ntlm->c_handle, &desc,
699 &attrs, &tsDummy);
700
701 if(status == SEC_I_COMPLETE_AND_CONTINUE ||
702 status == SEC_I_CONTINUE_NEEDED) {
703 s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
704 }
705 else if(status != SEC_E_OK) {
706 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
707 return CURLE_RECV_ERROR;
708 }
709
710 ntlm->has_handles = 1;
711 size = buf.cbBuffer;
712 }
713 #else
714 hostoff = 0;
715 domoff = hostoff + hostlen; /* This is 0: remember that host and domain
716 are empty */
717
718 /* Create and send a type-1 message:
719
720 Index Description Content
721 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
722 (0x4e544c4d53535000)
723 8 NTLM Message Type long (0x01000000)
724 12 Flags long
725 16 Supplied Domain security buffer(*)
726 24 Supplied Workstation security buffer(*)
727 32 start of data block
728
729 */
730 #if USE_NTLM2SESSION
731 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
732 #else
733 #define NTLM2FLAG 0
734 #endif
735 snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c"
736 "\x01%c%c%c" /* 32-bit type = 1 */
737 "%c%c%c%c" /* 32-bit NTLM flag field */
738 "%c%c" /* domain length */
739 "%c%c" /* domain allocated space */
740 "%c%c" /* domain name offset */
741 "%c%c" /* 2 zeroes */
742 "%c%c" /* host length */
743 "%c%c" /* host allocated space */
744 "%c%c" /* host name offset */
745 "%c%c" /* 2 zeroes */
746 "%s" /* host name */
747 "%s", /* domain string */
748 0, /* trailing zero */
749 0,0,0, /* part of type-1 long */
750
751 LONGQUARTET(
752 NTLMFLAG_NEGOTIATE_OEM|
753 NTLMFLAG_REQUEST_TARGET|
754 NTLMFLAG_NEGOTIATE_NTLM_KEY|
755 NTLM2FLAG|
756 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
757 ),
758 SHORTPAIR(domlen),
759 SHORTPAIR(domlen),
760 SHORTPAIR(domoff),
761 0,0,
762 SHORTPAIR(hostlen),
763 SHORTPAIR(hostlen),
764 SHORTPAIR(hostoff),
765 0,0,
766 host /* this is empty */, domain /* this is empty */);
767
768 /* initial packet length */
769 size = 32 + hostlen + domlen;
770 #endif
771
772 DEBUG_OUT({
773 fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
774 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
775 NTLMFLAG_REQUEST_TARGET|
776 NTLMFLAG_NEGOTIATE_NTLM_KEY|
777 NTLM2FLAG|
778 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
779 NTLMFLAG_NEGOTIATE_OEM|
780 NTLMFLAG_REQUEST_TARGET|
781 NTLMFLAG_NEGOTIATE_NTLM_KEY|
782 NTLM2FLAG|
783 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
784 print_flags(stderr,
785 NTLMFLAG_NEGOTIATE_OEM|
786 NTLMFLAG_REQUEST_TARGET|
787 NTLMFLAG_NEGOTIATE_NTLM_KEY|
788 NTLM2FLAG|
789 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
790 fprintf(stderr, "\n****\n");
791 });
792
793 /* now size is the size of the base64 encoded package size */
794 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
795
796 if(size >0 ) {
797 Curl_safefree(*allocuserpwd);
798 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
799 proxy?"Proxy-":"",
800 base64);
801 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
802 free(base64);
803 }
804 else
805 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
806
807 break;
808
809 case NTLMSTATE_TYPE2:
810 /* We received the type-2 message already, create a type-3 message:
811
812 Index Description Content
813 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
814 (0x4e544c4d53535000)
815 8 NTLM Message Type long (0x03000000)
816 12 LM/LMv2 Response security buffer(*)
817 20 NTLM/NTLMv2 Response security buffer(*)
818 28 Domain Name security buffer(*)
819 36 User Name security buffer(*)
820 44 Workstation Name security buffer(*)
821 (52) Session Key (optional) security buffer(*)
822 (60) Flags (optional) long
823 52 (64) start of data block
824
825 */
826
827 {
828 #ifdef USE_WINDOWS_SSPI
829 SecBuffer type_2, type_3;
830 SecBufferDesc type_2_desc, type_3_desc;
831 SECURITY_STATUS status;
832 ULONG attrs;
833 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
834
835 type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
836 type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
837 type_2_desc.pBuffers = &type_2;
838 type_3_desc.pBuffers = &type_3;
839
840 type_2.BufferType = SECBUFFER_TOKEN;
841 type_2.pvBuffer = ntlm->type_2;
842 type_2.cbBuffer = ntlm->n_type_2;
843 type_3.BufferType = SECBUFFER_TOKEN;
844 type_3.pvBuffer = ntlmbuf;
845 type_3.cbBuffer = sizeof(ntlmbuf);
846
847 status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, &ntlm->c_handle,
848 (char *) host,
849 ISC_REQ_CONFIDENTIALITY |
850 ISC_REQ_REPLAY_DETECT |
851 ISC_REQ_CONNECTION,
852 0, SECURITY_NETWORK_DREP, &type_2_desc,
853 0, &ntlm->c_handle, &type_3_desc,
854 &attrs, &tsDummy);
855
856 if(status != SEC_E_OK)
857 return CURLE_RECV_ERROR;
858
859 size = type_3.cbBuffer;
860
861 ntlm_sspi_cleanup(ntlm);
862
863 #else
864 int lmrespoff;
865 unsigned char lmresp[24]; /* fixed-size */
866 #if USE_NTRESPONSES
867 int ntrespoff;
868 unsigned char ntresp[24]; /* fixed-size */
869 #endif
870 size_t useroff;
871 const char *user;
872 size_t userlen;
873
874 user = strchr(userp, '\\');
875 if(!user)
876 user = strchr(userp, '/');
877
878 if(user) {
879 domain = userp;
880 domlen = (user - domain);
881 user++;
882 }
883 else
884 user = userp;
885 userlen = strlen(user);
886
887 if(gethostname(host, HOSTNAME_MAX)) {
888 infof(conn->data, "gethostname() failed, continuing without!");
889 hostlen = 0;
890 }
891 else {
892 /* If the workstation if configured with a full DNS name (i.e.
893 * workstation.somewhere.net) gethostname() returns the fully qualified
894 * name, which NTLM doesn't like.
895 */
896 char *dot = strchr(host, '.');
897 if(dot)
898 *dot = '\0';
899 hostlen = strlen(host);
900 }
901
902 #if USE_NTLM2SESSION
903 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
904 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
905 unsigned char ntbuffer[0x18];
906 unsigned char tmp[0x18];
907 unsigned char md5sum[MD5_DIGEST_LENGTH];
908 unsigned char entropy[8];
909
910 /* Need to create 8 bytes random data */
911 #ifdef USE_SSLEAY
912 MD5_CTX MD5pw;
913 Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
914 RAND_bytes(entropy,8);
915 #elif USE_GNUTLS
916 gcry_md_hd_t MD5pw;
917 Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
918 gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
919 #endif
920
921 /* 8 bytes random data as challenge in lmresp */
922 memcpy(lmresp,entropy,8);
923 /* Pad with zeros */
924 memset(lmresp+8,0,0x10);
925
926 /* Fill tmp with challenge(nonce?) + entropy */
927 memcpy(tmp,&ntlm->nonce[0],8);
928 memcpy(tmp+8,entropy,8);
929
930 #ifdef USE_SSLEAY
931 MD5_Init(&MD5pw);
932 MD5_Update(&MD5pw, tmp, 16);
933 MD5_Final(md5sum, &MD5pw);
934 #elif USE_GNUTLS
935 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
936 gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
937 memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
938 gcry_md_close(MD5pw);
939 #endif
940
941 /* We shall only use the first 8 bytes of md5sum,
942 but the des code in lm_resp only encrypt the first 8 bytes */
943 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
944 return CURLE_OUT_OF_MEMORY;
945 lm_resp(ntbuffer, md5sum, ntresp);
946
947 /* End of NTLM2 Session code */
948 }
949 else {
950 #endif
951
952 #if USE_NTRESPONSES
953 unsigned char ntbuffer[0x18];
954 #endif
955 unsigned char lmbuffer[0x18];
956
957 #if USE_NTRESPONSES
958 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
959 return CURLE_OUT_OF_MEMORY;
960 lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
961 #endif
962
963 mk_lm_hash(conn->data, passwdp, lmbuffer);
964 lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
965 /* A safer but less compatible alternative is:
966 * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
967 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
968 #if USE_NTLM2SESSION
969 }
970 #endif
971
972 lmrespoff = 64; /* size of the message header */
973 #if USE_NTRESPONSES
974 ntrespoff = lmrespoff + 0x18;
975 domoff = ntrespoff + 0x18;
976 #else
977 domoff = lmrespoff + 0x18;
978 #endif
979 useroff = domoff + domlen;
980 hostoff = useroff + userlen;
981
982 /*
983 * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
984 * need to filter it off because libcurl doesn't UNICODE encode the
985 * strings it packs into the NTLM authenticate packet.
986 */
987 ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE;
988
989 /* Create the big type-3 message binary blob */
990 size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
991 NTLMSSP_SIGNATURE "%c"
992 "\x03%c%c%c" /* type-3, 32 bits */
993
994 "%c%c" /* LanManager length */
995 "%c%c" /* LanManager allocated space */
996 "%c%c" /* LanManager offset */
997 "%c%c" /* 2 zeroes */
998
999 "%c%c" /* NT-response length */
1000 "%c%c" /* NT-response allocated space */
1001 "%c%c" /* NT-response offset */
1002 "%c%c" /* 2 zeroes */
1003
1004 "%c%c" /* domain length */
1005 "%c%c" /* domain allocated space */
1006 "%c%c" /* domain name offset */
1007 "%c%c" /* 2 zeroes */
1008
1009 "%c%c" /* user length */
1010 "%c%c" /* user allocated space */
1011 "%c%c" /* user offset */
1012 "%c%c" /* 2 zeroes */
1013
1014 "%c%c" /* host length */
1015 "%c%c" /* host allocated space */
1016 "%c%c" /* host offset */
1017 "%c%c" /* 2 zeroes */
1018
1019 "%c%c" /* session key length (unknown purpose) */
1020 "%c%c" /* session key allocated space (unknown purpose) */
1021 "%c%c" /* session key offset (unknown purpose) */
1022 "%c%c" /* 2 zeroes */
1023
1024 "%c%c%c%c" /* flags */
1025
1026 /* domain string */
1027 /* user string */
1028 /* host string */
1029 /* LanManager response */
1030 /* NT response */
1031 ,
1032 0, /* zero termination */
1033 0,0,0, /* type-3 long, the 24 upper bits */
1034
1035 SHORTPAIR(0x18), /* LanManager response length, twice */
1036 SHORTPAIR(0x18),
1037 SHORTPAIR(lmrespoff),
1038 0x0, 0x0,
1039
1040 #if USE_NTRESPONSES
1041 SHORTPAIR(0x18), /* NT-response length, twice */
1042 SHORTPAIR(0x18),
1043 SHORTPAIR(ntrespoff),
1044 0x0, 0x0,
1045 #else
1046 0x0, 0x0,
1047 0x0, 0x0,
1048 0x0, 0x0,
1049 0x0, 0x0,
1050 #endif
1051 SHORTPAIR(domlen),
1052 SHORTPAIR(domlen),
1053 SHORTPAIR(domoff),
1054 0x0, 0x0,
1055
1056 SHORTPAIR(userlen),
1057 SHORTPAIR(userlen),
1058 SHORTPAIR(useroff),
1059 0x0, 0x0,
1060
1061 SHORTPAIR(hostlen),
1062 SHORTPAIR(hostlen),
1063 SHORTPAIR(hostoff),
1064 0x0, 0x0,
1065
1066 0x0, 0x0,
1067 0x0, 0x0,
1068 0x0, 0x0,
1069 0x0, 0x0,
1070
1071 LONGQUARTET(ntlm->flags));
1072 DEBUGASSERT(size==64);
1073
1074 DEBUGASSERT(size == (size_t)lmrespoff);
1075 /* We append the binary hashes */
1076 if(size < (sizeof(ntlmbuf) - 0x18)) {
1077 memcpy(&ntlmbuf[size], lmresp, 0x18);
1078 size += 0x18;
1079 }
1080
1081 DEBUG_OUT({
1082 fprintf(stderr, "**** TYPE3 header lmresp=");
1083 print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1084 });
1085
1086 #if USE_NTRESPONSES
1087 if(size < (sizeof(ntlmbuf) - 0x18)) {
1088 DEBUGASSERT(size == (size_t)ntrespoff);
1089 memcpy(&ntlmbuf[size], ntresp, 0x18);
1090 size += 0x18;
1091 }
1092
1093 DEBUG_OUT({
1094 fprintf(stderr, "\n ntresp=");
1095 print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1096 });
1097
1098 #endif
1099
1100 DEBUG_OUT({
1101 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1102 LONGQUARTET(ntlm->flags), ntlm->flags);
1103 print_flags(stderr, ntlm->flags);
1104 fprintf(stderr, "\n****\n");
1105 });
1106
1107
1108 /* Make sure that the domain, user and host strings fit in the target
1109 buffer before we copy them there. */
1110 if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
1111 failf(conn->data, "user + domain + host name too big");
1112 return CURLE_OUT_OF_MEMORY;
1113 }
1114
1115 DEBUGASSERT(size == domoff);
1116 memcpy(&ntlmbuf[size], domain, domlen);
1117 size += domlen;
1118
1119 DEBUGASSERT(size == useroff);
1120 memcpy(&ntlmbuf[size], user, userlen);
1121 size += userlen;
1122
1123 DEBUGASSERT(size == hostoff);
1124 memcpy(&ntlmbuf[size], host, hostlen);
1125 size += hostlen;
1126
1127 #ifdef CURL_DOES_CONVERSIONS
1128 /* convert domain, user, and host to ASCII but leave the rest as-is */
1129 if(CURLE_OK != Curl_convert_to_network(conn->data,
1130 (char *)&ntlmbuf[domoff],
1131 size-domoff)) {
1132 return CURLE_CONV_FAILED;
1133 }
1134 #endif /* CURL_DOES_CONVERSIONS */
1135
1136 #endif
1137
1138 /* convert the binary blob into base64 */
1139 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1140
1141 if(size >0 ) {
1142 Curl_safefree(*allocuserpwd);
1143 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1144 proxy?"Proxy-":"",
1145 base64);
1146 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1147 free(base64);
1148 }
1149 else
1150 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1151
1152 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1153 authp->done = TRUE;
1154 }
1155 break;
1156
1157 case NTLMSTATE_TYPE3:
1158 /* connection is already authenticated,
1159 * don't send a header in future requests */
1160 if(*allocuserpwd) {
1161 free(*allocuserpwd);
1162 *allocuserpwd=NULL;
1163 }
1164 authp->done = TRUE;
1165 break;
1166 }
1167
1168 return CURLE_OK;
1169 }
1170
1171
1172 void
Curl_ntlm_cleanup(struct connectdata * conn)1173 Curl_ntlm_cleanup(struct connectdata *conn)
1174 {
1175 #ifdef USE_WINDOWS_SSPI
1176 ntlm_sspi_cleanup(&conn->ntlm);
1177 ntlm_sspi_cleanup(&conn->proxyntlm);
1178 #else
1179 (void)conn;
1180 #endif
1181 }
1182
1183
1184 #endif /* USE_NTLM */
1185 #endif /* !CURL_DISABLE_HTTP */
1186