xref: /third_party/curl/lib/vauth/ntlm.c (revision 13498266)
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#include "strdup.h"
48
49#define BUILDING_CURL_NTLM_MSGS_C
50#include "vauth/vauth.h"
51#include "vauth/ntlm.h"
52#include "curl_endian.h"
53#include "curl_printf.h"
54
55/* The last #include files should be: */
56#include "curl_memory.h"
57#include "memdebug.h"
58
59/* "NTLMSSP" signature is always in ASCII regardless of the platform */
60#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
61
62/* The fixed host name we provide, in order to not leak our real local host
63   name. Copy the name used by Firefox. */
64#define NTLM_HOSTNAME "WORKSTATION"
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_NTLM_KEY)
87    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
88  if(flags & (1<<10))
89    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
90  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
91    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
92  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
93    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
94  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
95    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
96  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
97    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
98  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
99    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
100  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
101    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
102  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
103    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
104  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
105    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
106  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
107    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
108  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
109    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
110  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
111    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
112  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
113    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
114  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
115    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
116  if(flags & (1<<24))
117    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
118  if(flags & (1<<25))
119    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
120  if(flags & (1<<26))
121    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
122  if(flags & (1<<27))
123    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
124  if(flags & (1<<28))
125    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
126  if(flags & NTLMFLAG_NEGOTIATE_128)
127    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
128  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
129    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
130  if(flags & NTLMFLAG_NEGOTIATE_56)
131    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
132}
133
134static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
135{
136  const char *p = buf;
137
138  (void) handle;
139
140  fprintf(stderr, "0x");
141  while(len-- > 0)
142    fprintf(stderr, "%02.2x", (unsigned int)*p++);
143}
144#else
145# define DEBUG_OUT(x) Curl_nop_stmt
146#endif
147
148/*
149 * ntlm_decode_type2_target()
150 *
151 * This is used to decode the "target info" in the NTLM type-2 message
152 * received.
153 *
154 * Parameters:
155 *
156 * data      [in]     - The session handle.
157 * type2ref  [in]     - The type-2 message.
158 * ntlm      [in/out] - The NTLM data struct being used and modified.
159 *
160 * Returns CURLE_OK on success.
161 */
162static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
163                                         const struct bufref *type2ref,
164                                         struct ntlmdata *ntlm)
165{
166  unsigned short target_info_len = 0;
167  unsigned int target_info_offset = 0;
168  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
169  size_t type2len = Curl_bufref_len(type2ref);
170
171#if defined(CURL_DISABLE_VERBOSE_STRINGS)
172  (void) data;
173#endif
174
175  if(type2len >= 48) {
176    target_info_len = Curl_read16_le(&type2[40]);
177    target_info_offset = Curl_read32_le(&type2[44]);
178    if(target_info_len > 0) {
179      if((target_info_offset > type2len) ||
180         (target_info_offset + target_info_len) > type2len ||
181         target_info_offset < 48) {
182        infof(data, "NTLM handshake failure (bad type-2 message). "
183              "Target Info Offset Len is set incorrect by the peer");
184        return CURLE_BAD_CONTENT_ENCODING;
185      }
186
187      free(ntlm->target_info); /* replace any previous data */
188      ntlm->target_info = Curl_memdup(&type2[target_info_offset],
189                                      target_info_len);
190      if(!ntlm->target_info)
191        return CURLE_OUT_OF_MEMORY;
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(type2ref);
269  size_t type2len = Curl_bufref_len(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(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
279     (memcmp(type2 + 8, type2_marker, 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(&type2[20]);
286  memcpy(ntlm->nonce, &type2[24], 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(out, ntlmbuf, size, 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(lmresp, 0, sizeof(lmresp));
504  memset(ntresp, 0, sizeof(ntresp));
505  user = strchr(userp, '\\');
506  if(!user)
507    user = strchr(userp, '/');
508
509  if(user) {
510    domain = userp;
511    domlen = (user - domain);
512    user++;
513  }
514  else
515    user = userp;
516
517  userlen = strlen(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(host, sizeof(host), "%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, entropy, 8);
544    if(result)
545      return result;
546
547    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
548    if(result)
549      return result;
550
551    result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
552                                           ntbuffer, ntlmv2hash);
553    if(result)
554      return result;
555
556    /* LMv2 response */
557    result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
558                                         &ntlm->nonce[0], lmresp);
559    if(result)
560      return result;
561
562    /* NTLMv2 response */
563    result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
564                                           ntlm, &ntlmv2resp, &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(passwdp, ntbuffer);
578    if(result)
579      return result;
580
581    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
582
583    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
584    if(result)
585      return result;
586
587    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], 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((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(&ntlmbuf[size], lmresp, 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, "incoming NTLM message too big");
702    return CURLE_OUT_OF_MEMORY;
703  }
704  DEBUGASSERT(size == (size_t)ntrespoff);
705  memcpy(&ntlmbuf[size], ptr_ntresp, 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, "user + domain + host name too big");
726    return CURLE_OUT_OF_MEMORY;
727  }
728
729  DEBUGASSERT(size == domoff);
730  if(unicode)
731    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
732  else
733    memcpy(&ntlmbuf[size], domain, domlen);
734
735  size += domlen;
736
737  DEBUGASSERT(size == useroff);
738  if(unicode)
739    unicodecpy(&ntlmbuf[size], user, userlen / 2);
740  else
741    memcpy(&ntlmbuf[size], user, userlen);
742
743  size += userlen;
744
745  DEBUGASSERT(size == hostoff);
746  if(unicode)
747    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
748  else
749    memcpy(&ntlmbuf[size], host, hostlen);
750
751  size += hostlen;
752
753  /* Return the binary blob. */
754  result = Curl_bufref_memdup(out, ntlmbuf, 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