Coverage Report

Created: 2025-12-14 06:39

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