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