Coverage Report

Created: 2025-11-23 06:22

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