Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/curl/lib/vauth/ntlm.c
Line
Count
Source (jump to first uncovered line)
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
0
#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
0
#define NTLM_HOSTNAME "WORKSTATION"
65
66
#if DEBUG_ME
67
# define DEBUG_OUT(x) x
68
static 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
134
static 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
0
# 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
 */
162
static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
163
                                         const struct bufref *type2ref,
164
                                         struct ntlmdata *ntlm)
165
0
{
166
0
  unsigned short target_info_len = 0;
167
0
  unsigned int target_info_offset = 0;
168
0
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
169
0
  size_t type2len = Curl_bufref_len(type2ref);
170
171
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
172
  (void) data;
173
#endif
174
175
0
  if(type2len >= 48) {
176
0
    target_info_len = Curl_read16_le(&type2[40]);
177
0
    target_info_offset = Curl_read32_le(&type2[44]);
178
0
    if(target_info_len > 0) {
179
0
      if((target_info_offset > type2len) ||
180
0
         (target_info_offset + target_info_len) > type2len ||
181
0
         target_info_offset < 48) {
182
0
        infof(data, "NTLM handshake failure (bad type-2 message). "
183
0
              "Target Info Offset Len is set incorrect by the peer");
184
0
        return CURLE_BAD_CONTENT_ENCODING;
185
0
      }
186
187
0
      free(ntlm->target_info); /* replace any previous data */
188
0
      ntlm->target_info = Curl_memdup(&type2[target_info_offset],
189
0
                                      target_info_len);
190
0
      if(!ntlm->target_info)
191
0
        return CURLE_OUT_OF_MEMORY;
192
0
    }
193
0
  }
194
195
0
  ntlm->target_info_len = target_info_len;
196
197
0
  return CURLE_OK;
198
0
}
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
 */
225
bool Curl_auth_is_ntlm_supported(void)
226
0
{
227
0
  return TRUE;
228
0
}
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
 */
245
CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
246
                                             const struct bufref *type2ref,
247
                                             struct ntlmdata *ntlm)
248
0
{
249
0
  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
0
  CURLcode result = CURLE_OK;
268
0
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
269
0
  size_t type2len = Curl_bufref_len(type2ref);
270
271
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
272
  (void)data;
273
#endif
274
275
0
  ntlm->flags = 0;
276
277
0
  if((type2len < 32) ||
278
0
     (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
279
0
     (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
280
    /* This was not a good enough type-2 message */
281
0
    infof(data, "NTLM handshake failure (bad type-2 message)");
282
0
    return CURLE_BAD_CONTENT_ENCODING;
283
0
  }
284
285
0
  ntlm->flags = Curl_read32_le(&type2[20]);
286
0
  memcpy(ntlm->nonce, &type2[24], 8);
287
288
0
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
289
0
    result = ntlm_decode_type2_target(data, type2ref, ntlm);
290
0
    if(result) {
291
0
      infof(data, "NTLM handshake failure (bad type-2 message)");
292
0
      return result;
293
0
    }
294
0
  }
295
296
0
  DEBUG_OUT({
297
0
    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
298
0
    ntlm_print_flags(stderr, ntlm->flags);
299
0
    fprintf(stderr, "\n                  nonce=");
300
0
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
301
0
    fprintf(stderr, "\n****\n");
302
0
    fprintf(stderr, "**** Header %s\n ", header);
303
0
  });
304
305
0
  return result;
306
0
}
307
308
/* copy the source to the destination and fill in zeroes in every
309
   other destination byte! */
310
static void unicodecpy(unsigned char *dest, const char *src, size_t length)
311
0
{
312
0
  size_t i;
313
0
  for(i = 0; i < length; i++) {
314
0
    dest[2 * i] = (unsigned char)src[i];
315
0
    dest[2 * i + 1] = '\0';
316
0
  }
317
0
}
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
 */
337
CURLcode 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
0
{
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
0
  size_t size;
360
361
0
  char *ntlmbuf;
362
0
  const char *host = "";              /* empty */
363
0
  const char *domain = "";            /* empty */
364
0
  size_t hostlen = 0;
365
0
  size_t domlen = 0;
366
0
  size_t hostoff = 0;
367
0
  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
368
                                         domain are empty */
369
0
  (void)data;
370
0
  (void)userp;
371
0
  (void)passwdp;
372
0
  (void)service;
373
0
  (void)hostname;
374
375
  /* Clean up any former leftovers and initialise to defaults */
376
0
  Curl_auth_cleanup_ntlm(ntlm);
377
378
0
  ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c"
379
0
                    "\x01%c%c%c" /* 32-bit type = 1 */
380
0
                    "%c%c%c%c"   /* 32-bit NTLM flag field */
381
0
                    "%c%c"       /* domain length */
382
0
                    "%c%c"       /* domain allocated space */
383
0
                    "%c%c"       /* domain name offset */
384
0
                    "%c%c"       /* 2 zeroes */
385
0
                    "%c%c"       /* host length */
386
0
                    "%c%c"       /* host allocated space */
387
0
                    "%c%c"       /* host name offset */
388
0
                    "%c%c"       /* 2 zeroes */
389
0
                    "%s"         /* host name */
390
0
                    "%s",        /* domain string */
391
0
                    0,           /* trailing zero */
392
0
                    0, 0, 0,     /* part of type-1 long */
393
394
0
                    LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
395
0
                                NTLMFLAG_REQUEST_TARGET |
396
0
                                NTLMFLAG_NEGOTIATE_NTLM_KEY |
397
0
                                NTLMFLAG_NEGOTIATE_NTLM2_KEY |
398
0
                                NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
399
0
                    SHORTPAIR(domlen),
400
0
                    SHORTPAIR(domlen),
401
0
                    SHORTPAIR(domoff),
402
0
                    0, 0,
403
0
                    SHORTPAIR(hostlen),
404
0
                    SHORTPAIR(hostlen),
405
0
                    SHORTPAIR(hostoff),
406
0
                    0, 0,
407
0
                    host,  /* this is empty */
408
0
                    domain /* this is empty */);
409
410
0
  if(!ntlmbuf)
411
0
    return CURLE_OUT_OF_MEMORY;
412
413
  /* Initial packet length */
414
0
  size = 32 + hostlen + domlen;
415
416
0
  DEBUG_OUT({
417
0
    fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
418
0
            "0x%08.8x ",
419
0
            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
420
0
                        NTLMFLAG_REQUEST_TARGET |
421
0
                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
422
0
                        NTLMFLAG_NEGOTIATE_NTLM2_KEY |
423
0
                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
424
0
            NTLMFLAG_NEGOTIATE_OEM |
425
0
            NTLMFLAG_REQUEST_TARGET |
426
0
            NTLMFLAG_NEGOTIATE_NTLM_KEY |
427
0
            NTLMFLAG_NEGOTIATE_NTLM2_KEY |
428
0
            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
429
0
    ntlm_print_flags(stderr,
430
0
                     NTLMFLAG_NEGOTIATE_OEM |
431
0
                     NTLMFLAG_REQUEST_TARGET |
432
0
                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
433
0
                     NTLMFLAG_NEGOTIATE_NTLM2_KEY |
434
0
                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
435
0
    fprintf(stderr, "\n****\n");
436
0
  });
437
438
0
  Curl_bufref_set(out, ntlmbuf, size, curl_free);
439
0
  return CURLE_OK;
440
0
}
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
 */
458
CURLcode 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
0
{
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
0
  CURLcode result = CURLE_OK;
483
0
  size_t size;
484
0
  unsigned char ntlmbuf[NTLM_BUFSIZE];
485
0
  int lmrespoff;
486
0
  unsigned char lmresp[24]; /* fixed-size */
487
0
  int ntrespoff;
488
0
  unsigned int ntresplen = 24;
489
0
  unsigned char ntresp[24]; /* fixed-size */
490
0
  unsigned char *ptr_ntresp = &ntresp[0];
491
0
  unsigned char *ntlmv2resp = NULL;
492
0
  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
493
0
  char host[HOSTNAME_MAX + 1] = "";
494
0
  const char *user;
495
0
  const char *domain = "";
496
0
  size_t hostoff = 0;
497
0
  size_t useroff = 0;
498
0
  size_t domoff = 0;
499
0
  size_t hostlen = 0;
500
0
  size_t userlen = 0;
501
0
  size_t domlen = 0;
502
503
0
  memset(lmresp, 0, sizeof(lmresp));
504
0
  memset(ntresp, 0, sizeof(ntresp));
505
0
  user = strchr(userp, '\\');
506
0
  if(!user)
507
0
    user = strchr(userp, '/');
508
509
0
  if(user) {
510
0
    domain = userp;
511
0
    domlen = (user - domain);
512
0
    user++;
513
0
  }
514
0
  else
515
0
    user = userp;
516
517
0
  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
0
  (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME);
531
0
  hostlen = sizeof(NTLM_HOSTNAME)-1;
532
0
#endif
533
534
0
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
535
0
    unsigned char ntbuffer[0x18];
536
0
    unsigned char entropy[8];
537
0
    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
0
    result = Curl_rand(data, entropy, 8);
544
0
    if(result)
545
0
      return result;
546
547
0
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
548
0
    if(result)
549
0
      return result;
550
551
0
    result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
552
0
                                           ntbuffer, ntlmv2hash);
553
0
    if(result)
554
0
      return result;
555
556
    /* LMv2 response */
557
0
    result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
558
0
                                         &ntlm->nonce[0], lmresp);
559
0
    if(result)
560
0
      return result;
561
562
    /* NTLMv2 response */
563
0
    result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
564
0
                                           ntlm, &ntlmv2resp, &ntresplen);
565
0
    if(result)
566
0
      return result;
567
568
0
    ptr_ntresp = ntlmv2resp;
569
0
  }
570
0
  else {
571
572
0
    unsigned char ntbuffer[0x18];
573
0
    unsigned char lmbuffer[0x18];
574
575
    /* NTLM version 1 */
576
577
0
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
578
0
    if(result)
579
0
      return result;
580
581
0
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
582
583
0
    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
584
0
    if(result)
585
0
      return result;
586
587
0
    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
588
0
    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
0
  }
594
595
0
  if(unicode) {
596
0
    domlen = domlen * 2;
597
0
    userlen = userlen * 2;
598
0
    hostlen = hostlen * 2;
599
0
  }
600
601
0
  lmrespoff = 64; /* size of the message header */
602
0
  ntrespoff = lmrespoff + 0x18;
603
0
  domoff = ntrespoff + ntresplen;
604
0
  useroff = domoff + domlen;
605
0
  hostoff = useroff + userlen;
606
607
  /* Create the big type-3 message binary blob */
608
0
  size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
609
0
                   NTLMSSP_SIGNATURE "%c"
610
0
                   "\x03%c%c%c"  /* 32-bit type = 3 */
611
612
0
                   "%c%c"  /* LanManager length */
613
0
                   "%c%c"  /* LanManager allocated space */
614
0
                   "%c%c"  /* LanManager offset */
615
0
                   "%c%c"  /* 2 zeroes */
616
617
0
                   "%c%c"  /* NT-response length */
618
0
                   "%c%c"  /* NT-response allocated space */
619
0
                   "%c%c"  /* NT-response offset */
620
0
                   "%c%c"  /* 2 zeroes */
621
622
0
                   "%c%c"  /* domain length */
623
0
                   "%c%c"  /* domain allocated space */
624
0
                   "%c%c"  /* domain name offset */
625
0
                   "%c%c"  /* 2 zeroes */
626
627
0
                   "%c%c"  /* user length */
628
0
                   "%c%c"  /* user allocated space */
629
0
                   "%c%c"  /* user offset */
630
0
                   "%c%c"  /* 2 zeroes */
631
632
0
                   "%c%c"  /* host length */
633
0
                   "%c%c"  /* host allocated space */
634
0
                   "%c%c"  /* host offset */
635
0
                   "%c%c"  /* 2 zeroes */
636
637
0
                   "%c%c"  /* session key length (unknown purpose) */
638
0
                   "%c%c"  /* session key allocated space (unknown purpose) */
639
0
                   "%c%c"  /* session key offset (unknown purpose) */
640
0
                   "%c%c"  /* 2 zeroes */
641
642
0
                   "%c%c%c%c",  /* flags */
643
644
                   /* domain string */
645
                   /* user string */
646
                   /* host string */
647
                   /* LanManager response */
648
                   /* NT response */
649
650
0
                   0,                /* null-termination */
651
0
                   0, 0, 0,          /* type-3 long, the 24 upper bits */
652
653
0
                   SHORTPAIR(0x18),  /* LanManager response length, twice */
654
0
                   SHORTPAIR(0x18),
655
0
                   SHORTPAIR(lmrespoff),
656
0
                   0x0, 0x0,
657
658
0
                   SHORTPAIR(ntresplen),  /* NT-response length, twice */
659
0
                   SHORTPAIR(ntresplen),
660
0
                   SHORTPAIR(ntrespoff),
661
0
                   0x0, 0x0,
662
663
0
                   SHORTPAIR(domlen),
664
0
                   SHORTPAIR(domlen),
665
0
                   SHORTPAIR(domoff),
666
0
                   0x0, 0x0,
667
668
0
                   SHORTPAIR(userlen),
669
0
                   SHORTPAIR(userlen),
670
0
                   SHORTPAIR(useroff),
671
0
                   0x0, 0x0,
672
673
0
                   SHORTPAIR(hostlen),
674
0
                   SHORTPAIR(hostlen),
675
0
                   SHORTPAIR(hostoff),
676
0
                   0x0, 0x0,
677
678
0
                   0x0, 0x0,
679
0
                   0x0, 0x0,
680
0
                   0x0, 0x0,
681
0
                   0x0, 0x0,
682
683
0
                   LONGQUARTET(ntlm->flags));
684
685
0
  DEBUGASSERT(size == 64);
686
0
  DEBUGASSERT(size == (size_t)lmrespoff);
687
688
  /* We append the binary hashes */
689
0
  if(size < (NTLM_BUFSIZE - 0x18)) {
690
0
    memcpy(&ntlmbuf[size], lmresp, 0x18);
691
0
    size += 0x18;
692
0
  }
693
694
0
  DEBUG_OUT({
695
0
    fprintf(stderr, "**** TYPE3 header lmresp=");
696
0
    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
697
0
  });
698
699
  /* ntresplen + size should not be risking an integer overflow here */
700
0
  if(ntresplen + size > sizeof(ntlmbuf)) {
701
0
    failf(data, "incoming NTLM message too big");
702
0
    return CURLE_OUT_OF_MEMORY;
703
0
  }
704
0
  DEBUGASSERT(size == (size_t)ntrespoff);
705
0
  memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
706
0
  size += ntresplen;
707
708
0
  DEBUG_OUT({
709
0
    fprintf(stderr, "\n   ntresp=");
710
0
    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
711
0
  });
712
713
0
  free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
714
715
0
  DEBUG_OUT({
716
0
    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
717
0
            LONGQUARTET(ntlm->flags), ntlm->flags);
718
0
    ntlm_print_flags(stderr, ntlm->flags);
719
0
    fprintf(stderr, "\n****\n");
720
0
  });
721
722
  /* Make sure that the domain, user and host strings fit in the
723
     buffer before we copy them there. */
724
0
  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
725
0
    failf(data, "user + domain + host name too big");
726
0
    return CURLE_OUT_OF_MEMORY;
727
0
  }
728
729
0
  DEBUGASSERT(size == domoff);
730
0
  if(unicode)
731
0
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
732
0
  else
733
0
    memcpy(&ntlmbuf[size], domain, domlen);
734
735
0
  size += domlen;
736
737
0
  DEBUGASSERT(size == useroff);
738
0
  if(unicode)
739
0
    unicodecpy(&ntlmbuf[size], user, userlen / 2);
740
0
  else
741
0
    memcpy(&ntlmbuf[size], user, userlen);
742
743
0
  size += userlen;
744
745
0
  DEBUGASSERT(size == hostoff);
746
0
  if(unicode)
747
0
    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
748
0
  else
749
0
    memcpy(&ntlmbuf[size], host, hostlen);
750
751
0
  size += hostlen;
752
753
  /* Return the binary blob. */
754
0
  result = Curl_bufref_memdup(out, ntlmbuf, size);
755
756
0
  Curl_auth_cleanup_ntlm(ntlm);
757
758
0
  return result;
759
0
}
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
 */
771
void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
772
0
{
773
  /* Free the target info */
774
0
  Curl_safefree(ntlm->target_info);
775
776
  /* Reset any variables */
777
0
  ntlm->target_info_len = 0;
778
0
}
779
780
#endif /* USE_NTLM && !USE_WINDOWS_SSPI */