1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, 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 https://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 ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
26
27 /*
28 * NTLM details:
29 *
30 * https://davenport.sourceforge.io/ntlm.html
31 * https://www.innovation.ch/java/ntlm.html
32 */
33
34 #define DEBUG_ME 0
35
36 #include "urldata.h"
37 #include "non-ascii.h"
38 #include "sendf.h"
39 #include "curl_base64.h"
40 #include "curl_ntlm_core.h"
41 #include "curl_gethostname.h"
42 #include "curl_multibyte.h"
43 #include "warnless.h"
44 #include "rand.h"
45 #include "vtls/vtls.h"
46
47 /* SSL backend-specific #if branches in this file must be kept in the order
48 documented in curl_ntlm_core. */
49 #if defined(NTLM_NEEDS_NSS_INIT)
50 #include "vtls/nssg.h" /* for Curl_nss_force_init() */
51 #endif
52
53 #define BUILDING_CURL_NTLM_MSGS_C
54 #include "vauth/vauth.h"
55 #include "vauth/ntlm.h"
56 #include "curl_endian.h"
57 #include "curl_printf.h"
58
59 /* The last #include files should be: */
60 #include "curl_memory.h"
61 #include "memdebug.h"
62
63 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
64 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
65
66 #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
67 #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
68 ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
69
70 #if DEBUG_ME
71 # define DEBUG_OUT(x) x
ntlm_print_flags(FILE * handle,unsigned long flags)72 static void ntlm_print_flags(FILE *handle, unsigned long flags)
73 {
74 if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
75 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
76 if(flags & NTLMFLAG_NEGOTIATE_OEM)
77 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
78 if(flags & NTLMFLAG_REQUEST_TARGET)
79 fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
80 if(flags & (1<<3))
81 fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
82 if(flags & NTLMFLAG_NEGOTIATE_SIGN)
83 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
84 if(flags & NTLMFLAG_NEGOTIATE_SEAL)
85 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
86 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
87 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
88 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
89 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
90 if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
91 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
92 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
93 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
94 if(flags & (1<<10))
95 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
96 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
97 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
98 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
99 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
100 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
101 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
102 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
103 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
104 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
105 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
106 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
107 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
108 if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
109 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
110 if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
111 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
112 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
113 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
114 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
115 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
116 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
117 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
118 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
119 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
120 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
121 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
122 if(flags & (1<<24))
123 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
124 if(flags & (1<<25))
125 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
126 if(flags & (1<<26))
127 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
128 if(flags & (1<<27))
129 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
130 if(flags & (1<<28))
131 fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
132 if(flags & NTLMFLAG_NEGOTIATE_128)
133 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
134 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
135 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
136 if(flags & NTLMFLAG_NEGOTIATE_56)
137 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
138 }
139
ntlm_print_hex(FILE * handle,const char * buf,size_t len)140 static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
141 {
142 const char *p = buf;
143
144 (void) handle;
145
146 fprintf(stderr, "0x");
147 while(len-- > 0)
148 fprintf(stderr, "%02.2x", (unsigned int)*p++);
149 }
150 #else
151 # define DEBUG_OUT(x) Curl_nop_stmt
152 #endif
153
154 /*
155 * ntlm_decode_type2_target()
156 *
157 * This is used to decode the "target info" in the NTLM type-2 message
158 * received.
159 *
160 * Parameters:
161 *
162 * data [in] - The session handle.
163 * buffer [in] - The decoded type-2 message.
164 * size [in] - The input buffer size, at least 32 bytes.
165 * ntlm [in/out] - The NTLM data struct being used and modified.
166 *
167 * Returns CURLE_OK on success.
168 */
ntlm_decode_type2_target(struct Curl_easy * data,unsigned char * buffer,size_t size,struct ntlmdata * ntlm)169 static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
170 unsigned char *buffer,
171 size_t size,
172 struct ntlmdata *ntlm)
173 {
174 unsigned short target_info_len = 0;
175 unsigned int target_info_offset = 0;
176
177 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
178 (void) data;
179 #endif
180
181 if(size >= 48) {
182 target_info_len = Curl_read16_le(&buffer[40]);
183 target_info_offset = Curl_read32_le(&buffer[44]);
184 if(target_info_len > 0) {
185 if((target_info_offset >= size) ||
186 ((target_info_offset + target_info_len) > size) ||
187 (target_info_offset < 48)) {
188 infof(data, "NTLM handshake failure (bad type-2 message). "
189 "Target Info Offset Len is set incorrect by the peer\n");
190 return CURLE_BAD_CONTENT_ENCODING;
191 }
192
193 ntlm->target_info = malloc(target_info_len);
194 if(!ntlm->target_info)
195 return CURLE_OUT_OF_MEMORY;
196
197 memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len);
198 }
199 }
200
201 ntlm->target_info_len = target_info_len;
202
203 return CURLE_OK;
204 }
205
206 /*
207 NTLM message structure notes:
208
209 A 'short' is a 'network short', a little-endian 16-bit unsigned value.
210
211 A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
212
213 A 'security buffer' represents a triplet used to point to a buffer,
214 consisting of two shorts and one long:
215
216 1. A 'short' containing the length of the buffer content in bytes.
217 2. A 'short' containing the allocated space for the buffer in bytes.
218 3. A 'long' containing the offset to the start of the buffer in bytes,
219 from the beginning of the NTLM message.
220 */
221
222 /*
223 * Curl_auth_is_ntlm_supported()
224 *
225 * This is used to evaluate if NTLM is supported.
226 *
227 * Parameters: None
228 *
229 * Returns TRUE as NTLM as handled by libcurl.
230 */
Curl_auth_is_ntlm_supported(void)231 bool Curl_auth_is_ntlm_supported(void)
232 {
233 return TRUE;
234 }
235
236 /*
237 * Curl_auth_decode_ntlm_type2_message()
238 *
239 * This is used to decode an already encoded NTLM type-2 message. The message
240 * is first decoded from a base64 string into a raw NTLM message and checked
241 * for validity before the appropriate data for creating a type-3 message is
242 * written to the given NTLM data structure.
243 *
244 * Parameters:
245 *
246 * data [in] - The session handle.
247 * type2msg [in] - The base64 encoded type-2 message.
248 * ntlm [in/out] - The NTLM data struct being used and modified.
249 *
250 * Returns CURLE_OK on success.
251 */
Curl_auth_decode_ntlm_type2_message(struct Curl_easy * data,const char * type2msg,struct ntlmdata * ntlm)252 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
253 const char *type2msg,
254 struct ntlmdata *ntlm)
255 {
256 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
257
258 /* NTLM type-2 message structure:
259
260 Index Description Content
261 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
262 (0x4e544c4d53535000)
263 8 NTLM Message Type long (0x02000000)
264 12 Target Name security buffer
265 20 Flags long
266 24 Challenge 8 bytes
267 (32) Context 8 bytes (two consecutive longs) (*)
268 (40) Target Information security buffer (*)
269 (48) OS Version Structure 8 bytes (*)
270 32 (48) (56) Start of data block (*)
271 (*) -> Optional
272 */
273
274 CURLcode result = CURLE_OK;
275 unsigned char *type2 = NULL;
276 size_t type2_len = 0;
277
278 #if defined(NTLM_NEEDS_NSS_INIT)
279 /* Make sure the crypto backend is initialized */
280 result = Curl_nss_force_init(data);
281 if(result)
282 return result;
283 #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
284 (void)data;
285 #endif
286
287 /* Decode the base-64 encoded type-2 message */
288 if(strlen(type2msg) && *type2msg != '=') {
289 result = Curl_base64_decode(type2msg, &type2, &type2_len);
290 if(result)
291 return result;
292 }
293
294 /* Ensure we have a valid type-2 message */
295 if(!type2) {
296 infof(data, "NTLM handshake failure (empty type-2 message)\n");
297 return CURLE_BAD_CONTENT_ENCODING;
298 }
299
300 ntlm->flags = 0;
301
302 if((type2_len < 32) ||
303 (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
304 (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
305 /* This was not a good enough type-2 message */
306 free(type2);
307 infof(data, "NTLM handshake failure (bad type-2 message)\n");
308 return CURLE_BAD_CONTENT_ENCODING;
309 }
310
311 ntlm->flags = Curl_read32_le(&type2[20]);
312 memcpy(ntlm->nonce, &type2[24], 8);
313
314 if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
315 result = ntlm_decode_type2_target(data, type2, type2_len, ntlm);
316 if(result) {
317 free(type2);
318 infof(data, "NTLM handshake failure (bad type-2 message)\n");
319 return result;
320 }
321 }
322
323 DEBUG_OUT({
324 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
325 ntlm_print_flags(stderr, ntlm->flags);
326 fprintf(stderr, "\n nonce=");
327 ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
328 fprintf(stderr, "\n****\n");
329 fprintf(stderr, "**** Header %s\n ", header);
330 });
331
332 free(type2);
333
334 return result;
335 }
336
337 /* copy the source to the destination and fill in zeroes in every
338 other destination byte! */
unicodecpy(unsigned char * dest,const char * src,size_t length)339 static void unicodecpy(unsigned char *dest, const char *src, size_t length)
340 {
341 size_t i;
342 for(i = 0; i < length; i++) {
343 dest[2 * i] = (unsigned char)src[i];
344 dest[2 * i + 1] = '\0';
345 }
346 }
347
348 /*
349 * Curl_auth_create_ntlm_type1_message()
350 *
351 * This is used to generate an already encoded NTLM type-1 message ready for
352 * sending to the recipient using the appropriate compile time crypto API.
353 *
354 * Parameters:
355 *
356 * data [in] - The session handle.
357 * userp [in] - The user name in the format User or Domain\User.
358 * passwdp [in] - The user's password.
359 * service [in] - The service type such as http, smtp, pop or imap.
360 * host [in] - The host name.
361 * ntlm [in/out] - The NTLM data struct being used and modified.
362 * outptr [in/out] - The address where a pointer to newly allocated memory
363 * holding the result will be stored upon completion.
364 * outlen [out] - The length of the output message.
365 *
366 * Returns CURLE_OK on success.
367 */
Curl_auth_create_ntlm_type1_message(struct Curl_easy * data,const char * userp,const char * passwdp,const char * service,const char * hostname,struct ntlmdata * ntlm,char ** outptr,size_t * outlen)368 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
369 const char *userp,
370 const char *passwdp,
371 const char *service,
372 const char *hostname,
373 struct ntlmdata *ntlm,
374 char **outptr, size_t *outlen)
375 {
376 /* NTLM type-1 message structure:
377
378 Index Description Content
379 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
380 (0x4e544c4d53535000)
381 8 NTLM Message Type long (0x01000000)
382 12 Flags long
383 (16) Supplied Domain security buffer (*)
384 (24) Supplied Workstation security buffer (*)
385 (32) OS Version Structure 8 bytes (*)
386 (32) (40) Start of data block (*)
387 (*) -> Optional
388 */
389
390 size_t size;
391
392 unsigned char ntlmbuf[NTLM_BUFSIZE];
393 const char *host = ""; /* empty */
394 const char *domain = ""; /* empty */
395 size_t hostlen = 0;
396 size_t domlen = 0;
397 size_t hostoff = 0;
398 size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
399 domain are empty */
400 (void)userp;
401 (void)passwdp;
402 (void)service,
403 (void)hostname,
404
405 /* Clean up any former leftovers and initialise to defaults */
406 Curl_auth_ntlm_cleanup(ntlm);
407
408 #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
409 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
410 #else
411 #define NTLM2FLAG 0
412 #endif
413 msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
414 NTLMSSP_SIGNATURE "%c"
415 "\x01%c%c%c" /* 32-bit type = 1 */
416 "%c%c%c%c" /* 32-bit NTLM flag field */
417 "%c%c" /* domain length */
418 "%c%c" /* domain allocated space */
419 "%c%c" /* domain name offset */
420 "%c%c" /* 2 zeroes */
421 "%c%c" /* host length */
422 "%c%c" /* host allocated space */
423 "%c%c" /* host name offset */
424 "%c%c" /* 2 zeroes */
425 "%s" /* host name */
426 "%s", /* domain string */
427 0, /* trailing zero */
428 0, 0, 0, /* part of type-1 long */
429
430 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
431 NTLMFLAG_REQUEST_TARGET |
432 NTLMFLAG_NEGOTIATE_NTLM_KEY |
433 NTLM2FLAG |
434 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
435 SHORTPAIR(domlen),
436 SHORTPAIR(domlen),
437 SHORTPAIR(domoff),
438 0, 0,
439 SHORTPAIR(hostlen),
440 SHORTPAIR(hostlen),
441 SHORTPAIR(hostoff),
442 0, 0,
443 host, /* this is empty */
444 domain /* this is empty */);
445
446 /* Initial packet length */
447 size = 32 + hostlen + domlen;
448
449 DEBUG_OUT({
450 fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
451 "0x%08.8x ",
452 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
453 NTLMFLAG_REQUEST_TARGET |
454 NTLMFLAG_NEGOTIATE_NTLM_KEY |
455 NTLM2FLAG |
456 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
457 NTLMFLAG_NEGOTIATE_OEM |
458 NTLMFLAG_REQUEST_TARGET |
459 NTLMFLAG_NEGOTIATE_NTLM_KEY |
460 NTLM2FLAG |
461 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
462 ntlm_print_flags(stderr,
463 NTLMFLAG_NEGOTIATE_OEM |
464 NTLMFLAG_REQUEST_TARGET |
465 NTLMFLAG_NEGOTIATE_NTLM_KEY |
466 NTLM2FLAG |
467 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
468 fprintf(stderr, "\n****\n");
469 });
470
471 /* Return with binary blob encoded into base64 */
472 return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
473 }
474
475 /*
476 * Curl_auth_create_ntlm_type3_message()
477 *
478 * This is used to generate an already encoded NTLM type-3 message ready for
479 * sending to the recipient using the appropriate compile time crypto API.
480 *
481 * Parameters:
482 *
483 * data [in] - The session handle.
484 * userp [in] - The user name in the format User or Domain\User.
485 * passwdp [in] - The user's password.
486 * ntlm [in/out] - The NTLM data struct being used and modified.
487 * outptr [in/out] - The address where a pointer to newly allocated memory
488 * holding the result will be stored upon completion.
489 * outlen [out] - The length of the output message.
490 *
491 * Returns CURLE_OK on success.
492 */
Curl_auth_create_ntlm_type3_message(struct Curl_easy * data,const char * userp,const char * passwdp,struct ntlmdata * ntlm,char ** outptr,size_t * outlen)493 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
494 const char *userp,
495 const char *passwdp,
496 struct ntlmdata *ntlm,
497 char **outptr, size_t *outlen)
498
499 {
500 /* NTLM type-3 message structure:
501
502 Index Description Content
503 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
504 (0x4e544c4d53535000)
505 8 NTLM Message Type long (0x03000000)
506 12 LM/LMv2 Response security buffer
507 20 NTLM/NTLMv2 Response security buffer
508 28 Target Name security buffer
509 36 User Name security buffer
510 44 Workstation Name security buffer
511 (52) Session Key security buffer (*)
512 (60) Flags long (*)
513 (64) OS Version Structure 8 bytes (*)
514 52 (64) (72) Start of data block
515 (*) -> Optional
516 */
517
518 CURLcode result = CURLE_OK;
519 size_t size;
520 unsigned char ntlmbuf[NTLM_BUFSIZE];
521 int lmrespoff;
522 unsigned char lmresp[24]; /* fixed-size */
523 #ifdef USE_NTRESPONSES
524 int ntrespoff;
525 unsigned int ntresplen = 24;
526 unsigned char ntresp[24]; /* fixed-size */
527 unsigned char *ptr_ntresp = &ntresp[0];
528 unsigned char *ntlmv2resp = NULL;
529 #endif
530 bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
531 char host[HOSTNAME_MAX + 1] = "";
532 const char *user;
533 const char *domain = "";
534 size_t hostoff = 0;
535 size_t useroff = 0;
536 size_t domoff = 0;
537 size_t hostlen = 0;
538 size_t userlen = 0;
539 size_t domlen = 0;
540
541 user = strchr(userp, '\\');
542 if(!user)
543 user = strchr(userp, '/');
544
545 if(user) {
546 domain = userp;
547 domlen = (user - domain);
548 user++;
549 }
550 else
551 user = userp;
552
553 userlen = strlen(user);
554
555 /* Get the machine's un-qualified host name as NTLM doesn't like the fully
556 qualified domain name */
557 if(Curl_gethostname(host, sizeof(host))) {
558 infof(data, "gethostname() failed, continuing without!\n");
559 hostlen = 0;
560 }
561 else {
562 hostlen = strlen(host);
563 }
564
565 #if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
566 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
567 unsigned char ntbuffer[0x18];
568 unsigned char entropy[8];
569 unsigned char ntlmv2hash[0x18];
570
571 result = Curl_rand(data, entropy, 8);
572 if(result)
573 return result;
574
575 result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
576 if(result)
577 return result;
578
579 result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
580 ntbuffer, ntlmv2hash);
581 if(result)
582 return result;
583
584 /* LMv2 response */
585 result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
586 &ntlm->nonce[0], lmresp);
587 if(result)
588 return result;
589
590 /* NTLMv2 response */
591 result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
592 ntlm, &ntlmv2resp, &ntresplen);
593 if(result)
594 return result;
595
596 ptr_ntresp = ntlmv2resp;
597 }
598 else
599 #endif
600
601 #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
602 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
603 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
604 unsigned char ntbuffer[0x18];
605 unsigned char tmp[0x18];
606 unsigned char md5sum[MD5_DIGEST_LENGTH];
607 unsigned char entropy[8];
608
609 /* Need to create 8 bytes random data */
610 result = Curl_rand(data, entropy, 8);
611 if(result)
612 return result;
613
614 /* 8 bytes random data as challenge in lmresp */
615 memcpy(lmresp, entropy, 8);
616
617 /* Pad with zeros */
618 memset(lmresp + 8, 0, 0x10);
619
620 /* Fill tmp with challenge(nonce?) + entropy */
621 memcpy(tmp, &ntlm->nonce[0], 8);
622 memcpy(tmp + 8, entropy, 8);
623
624 result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
625 if(!result)
626 /* We shall only use the first 8 bytes of md5sum, but the des code in
627 Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
628 result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
629 if(result)
630 return result;
631
632 Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
633
634 /* End of NTLM2 Session code */
635 /* NTLM v2 session security is a misnomer because it is not NTLM v2.
636 It is NTLM v1 using the extended session security that is also
637 in NTLM v2 */
638 }
639 else
640 #endif
641 {
642
643 #ifdef USE_NTRESPONSES
644 unsigned char ntbuffer[0x18];
645 #endif
646 unsigned char lmbuffer[0x18];
647
648 #ifdef USE_NTRESPONSES
649 result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
650 if(result)
651 return result;
652
653 Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
654 #endif
655
656 result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
657 if(result)
658 return result;
659
660 Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
661
662 /* A safer but less compatible alternative is:
663 * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
664 * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */
665 }
666
667 if(unicode) {
668 domlen = domlen * 2;
669 userlen = userlen * 2;
670 hostlen = hostlen * 2;
671 }
672
673 lmrespoff = 64; /* size of the message header */
674 #ifdef USE_NTRESPONSES
675 ntrespoff = lmrespoff + 0x18;
676 domoff = ntrespoff + ntresplen;
677 #else
678 domoff = lmrespoff + 0x18;
679 #endif
680 useroff = domoff + domlen;
681 hostoff = useroff + userlen;
682
683 /* Create the big type-3 message binary blob */
684 size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
685 NTLMSSP_SIGNATURE "%c"
686 "\x03%c%c%c" /* 32-bit type = 3 */
687
688 "%c%c" /* LanManager length */
689 "%c%c" /* LanManager allocated space */
690 "%c%c" /* LanManager offset */
691 "%c%c" /* 2 zeroes */
692
693 "%c%c" /* NT-response length */
694 "%c%c" /* NT-response allocated space */
695 "%c%c" /* NT-response offset */
696 "%c%c" /* 2 zeroes */
697
698 "%c%c" /* domain length */
699 "%c%c" /* domain allocated space */
700 "%c%c" /* domain name offset */
701 "%c%c" /* 2 zeroes */
702
703 "%c%c" /* user length */
704 "%c%c" /* user allocated space */
705 "%c%c" /* user offset */
706 "%c%c" /* 2 zeroes */
707
708 "%c%c" /* host length */
709 "%c%c" /* host allocated space */
710 "%c%c" /* host offset */
711 "%c%c" /* 2 zeroes */
712
713 "%c%c" /* session key length (unknown purpose) */
714 "%c%c" /* session key allocated space (unknown purpose) */
715 "%c%c" /* session key offset (unknown purpose) */
716 "%c%c" /* 2 zeroes */
717
718 "%c%c%c%c", /* flags */
719
720 /* domain string */
721 /* user string */
722 /* host string */
723 /* LanManager response */
724 /* NT response */
725
726 0, /* zero termination */
727 0, 0, 0, /* type-3 long, the 24 upper bits */
728
729 SHORTPAIR(0x18), /* LanManager response length, twice */
730 SHORTPAIR(0x18),
731 SHORTPAIR(lmrespoff),
732 0x0, 0x0,
733
734 #ifdef USE_NTRESPONSES
735 SHORTPAIR(ntresplen), /* NT-response length, twice */
736 SHORTPAIR(ntresplen),
737 SHORTPAIR(ntrespoff),
738 0x0, 0x0,
739 #else
740 0x0, 0x0,
741 0x0, 0x0,
742 0x0, 0x0,
743 0x0, 0x0,
744 #endif
745 SHORTPAIR(domlen),
746 SHORTPAIR(domlen),
747 SHORTPAIR(domoff),
748 0x0, 0x0,
749
750 SHORTPAIR(userlen),
751 SHORTPAIR(userlen),
752 SHORTPAIR(useroff),
753 0x0, 0x0,
754
755 SHORTPAIR(hostlen),
756 SHORTPAIR(hostlen),
757 SHORTPAIR(hostoff),
758 0x0, 0x0,
759
760 0x0, 0x0,
761 0x0, 0x0,
762 0x0, 0x0,
763 0x0, 0x0,
764
765 LONGQUARTET(ntlm->flags));
766
767 DEBUGASSERT(size == 64);
768 DEBUGASSERT(size == (size_t)lmrespoff);
769
770 /* We append the binary hashes */
771 if(size < (NTLM_BUFSIZE - 0x18)) {
772 memcpy(&ntlmbuf[size], lmresp, 0x18);
773 size += 0x18;
774 }
775
776 DEBUG_OUT({
777 fprintf(stderr, "**** TYPE3 header lmresp=");
778 ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
779 });
780
781 #ifdef USE_NTRESPONSES
782 /* ntresplen + size should not be risking an integer overflow here */
783 if(ntresplen + size > sizeof(ntlmbuf)) {
784 failf(data, "incoming NTLM message too big");
785 return CURLE_OUT_OF_MEMORY;
786 }
787 DEBUGASSERT(size == (size_t)ntrespoff);
788 memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
789 size += ntresplen;
790
791 DEBUG_OUT({
792 fprintf(stderr, "\n ntresp=");
793 ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
794 });
795
796 free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
797
798 #endif
799
800 DEBUG_OUT({
801 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
802 LONGQUARTET(ntlm->flags), ntlm->flags);
803 ntlm_print_flags(stderr, ntlm->flags);
804 fprintf(stderr, "\n****\n");
805 });
806
807 /* Make sure that the domain, user and host strings fit in the
808 buffer before we copy them there. */
809 if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
810 failf(data, "user + domain + host name too big");
811 return CURLE_OUT_OF_MEMORY;
812 }
813
814 DEBUGASSERT(size == domoff);
815 if(unicode)
816 unicodecpy(&ntlmbuf[size], domain, domlen / 2);
817 else
818 memcpy(&ntlmbuf[size], domain, domlen);
819
820 size += domlen;
821
822 DEBUGASSERT(size == useroff);
823 if(unicode)
824 unicodecpy(&ntlmbuf[size], user, userlen / 2);
825 else
826 memcpy(&ntlmbuf[size], user, userlen);
827
828 size += userlen;
829
830 DEBUGASSERT(size == hostoff);
831 if(unicode)
832 unicodecpy(&ntlmbuf[size], host, hostlen / 2);
833 else
834 memcpy(&ntlmbuf[size], host, hostlen);
835
836 size += hostlen;
837
838 /* Convert domain, user, and host to ASCII but leave the rest as-is */
839 result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
840 size - domoff);
841 if(result)
842 return CURLE_CONV_FAILED;
843
844 /* Return with binary blob encoded into base64 */
845 result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
846
847 Curl_auth_ntlm_cleanup(ntlm);
848
849 return result;
850 }
851
852 /*
853 * Curl_auth_ntlm_cleanup()
854 *
855 * This is used to clean up the NTLM specific data.
856 *
857 * Parameters:
858 *
859 * ntlm [in/out] - The NTLM data struct being cleaned up.
860 *
861 */
Curl_auth_ntlm_cleanup(struct ntlmdata * ntlm)862 void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
863 {
864 /* Free the target info */
865 Curl_safefree(ntlm->target_info);
866
867 /* Reset any variables */
868 ntlm->target_info_len = 0;
869 }
870
871 #endif /* USE_NTLM && !USE_WINDOWS_SSPI */
872