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