Coverage Report

Created: 2025-12-04 07:04

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
75
#define NTLM_BUFSIZE 1024
50
51
/* Flag bits definitions based on
52
   https://davenport.sourceforge.net/ntlm.html */
53
54
25
#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
29
#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
34
#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.30k
#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.25k
#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
27
{
256
27
  unsigned short target_info_len = 0;
257
27
  unsigned int target_info_offset = 0;
258
27
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
259
27
  size_t type2len = Curl_bufref_len(type2ref);
260
261
#ifdef CURL_DISABLE_VERBOSE_STRINGS
262
  (void)data;
263
#endif
264
265
27
  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
3
         (target_info_offset + target_info_len) > type2len ||
271
9
         target_info_offset < 48) {
272
9
        infof(data, "NTLM handshake failure (bad type-2 message). "
273
9
              "Target Info Offset Len is set incorrect by the peer");
274
9
        return CURLE_BAD_CONTENT_ENCODING;
275
9
      }
276
277
1
      curlx_free(ntlm->target_info); /* replace any previous data */
278
1
      ntlm->target_info = Curl_memdup(&type2[target_info_offset],
279
1
                                      target_info_len);
280
1
      if(!ntlm->target_info)
281
0
        return CURLE_OUT_OF_MEMORY;
282
1
    }
283
11
  }
284
285
18
  ntlm->target_info_len = target_info_len;
286
287
18
  return CURLE_OK;
288
27
}
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.47k
{
317
4.47k
  return TRUE;
318
4.47k
}
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
337
{
339
337
  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
337
  CURLcode result = CURLE_OK;
358
337
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
359
337
  size_t type2len = Curl_bufref_len(type2ref);
360
361
#ifdef CURL_DISABLE_VERBOSE_STRINGS
362
  (void)data;
363
#endif
364
365
337
  ntlm->flags = 0;
366
367
337
  if((type2len < 32) ||
368
124
     (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
369
303
     (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
370
    /* This was not a good enough type-2 message */
371
303
    infof(data, "NTLM handshake failure (bad type-2 message)");
372
303
    return CURLE_BAD_CONTENT_ENCODING;
373
303
  }
374
375
34
  ntlm->flags = Curl_read32_le(&type2[20]);
376
34
  memcpy(ntlm->nonce, &type2[24], 8);
377
378
34
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
379
27
    result = ntlm_decode_type2_target(data, type2ref, ntlm);
380
27
    if(result) {
381
9
      infof(data, "NTLM handshake failure (bad type-2 message)");
382
9
      return result;
383
9
    }
384
27
  }
385
386
25
  DEBUG_OUT({
387
25
    curl_mfprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
388
25
    ntlm_print_flags(stderr, ntlm->flags);
389
25
    curl_mfprintf(stderr, "\n                  nonce=");
390
25
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
391
25
    curl_mfprintf(stderr, "\n****\n");
392
25
    curl_mfprintf(stderr, "**** Header %s\n ", header);
393
25
  });
394
395
25
  return result;
396
34
}
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
72
{
402
72
  size_t i;
403
577
  for(i = 0; i < length; i++) {
404
505
    dest[2 * i] = (unsigned char)src[i];
405
505
    dest[2 * i + 1] = '\0';
406
505
  }
407
72
}
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.15k
{
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.15k
  size_t size;
450
451
5.15k
  char *ntlmbuf;
452
5.15k
  const char *host = "";              /* empty */
453
5.15k
  const char *domain = "";            /* empty */
454
5.15k
  size_t hostlen = 0;
455
5.15k
  size_t domlen = 0;
456
5.15k
  size_t hostoff = 0;
457
5.15k
  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
458
                                         domain are empty */
459
5.15k
  (void)data;
460
5.15k
  (void)userp;
461
5.15k
  (void)passwdp;
462
5.15k
  (void)service;
463
5.15k
  (void)hostname;
464
465
  /* Clean up any former leftovers and initialise to defaults */
466
5.15k
  Curl_auth_cleanup_ntlm(ntlm);
467
468
5.15k
  ntlmbuf = curl_maprintf(NTLMSSP_SIGNATURE "%c"
469
5.15k
                          "\x01%c%c%c" /* 32-bit type = 1 */
470
5.15k
                          "%c%c%c%c"   /* 32-bit NTLM flag field */
471
5.15k
                          "%c%c"       /* domain length */
472
5.15k
                          "%c%c"       /* domain allocated space */
473
5.15k
                          "%c%c"       /* domain name offset */
474
5.15k
                          "%c%c"       /* 2 zeroes */
475
5.15k
                          "%c%c"       /* host length */
476
5.15k
                          "%c%c"       /* host allocated space */
477
5.15k
                          "%c%c"       /* hostname offset */
478
5.15k
                          "%c%c"       /* 2 zeroes */
479
5.15k
                          "%s"         /* hostname */
480
5.15k
                          "%s",        /* domain string */
481
5.15k
                          0,           /* trailing zero */
482
5.15k
                          0, 0, 0,     /* part of type-1 long */
483
484
5.15k
                          LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
485
5.15k
                                      NTLMFLAG_REQUEST_TARGET |
486
5.15k
                                      NTLMFLAG_NEGOTIATE_NTLM_KEY |
487
5.15k
                                      NTLMFLAG_NEGOTIATE_NTLM2_KEY |
488
5.15k
                                      NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
489
5.15k
                          SHORTPAIR(domlen),
490
5.15k
                          SHORTPAIR(domlen),
491
5.15k
                          SHORTPAIR(domoff),
492
5.15k
                          0, 0,
493
5.15k
                          SHORTPAIR(hostlen),
494
5.15k
                          SHORTPAIR(hostlen),
495
5.15k
                          SHORTPAIR(hostoff),
496
5.15k
                          0, 0,
497
5.15k
                          host,  /* this is empty */
498
5.15k
                          domain /* this is empty */);
499
500
5.15k
  if(!ntlmbuf)
501
0
    return CURLE_OUT_OF_MEMORY;
502
503
  /* Initial packet length */
504
5.15k
  size = 32 + hostlen + domlen;
505
506
5.15k
  DEBUG_OUT({
507
5.15k
    curl_mfprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
508
5.15k
                  "0x%08.8x ",
509
5.15k
                  LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
510
5.15k
                              NTLMFLAG_REQUEST_TARGET |
511
5.15k
                              NTLMFLAG_NEGOTIATE_NTLM_KEY |
512
5.15k
                              NTLMFLAG_NEGOTIATE_NTLM2_KEY |
513
5.15k
                              NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
514
5.15k
                  NTLMFLAG_NEGOTIATE_OEM |
515
5.15k
                  NTLMFLAG_REQUEST_TARGET |
516
5.15k
                  NTLMFLAG_NEGOTIATE_NTLM_KEY |
517
5.15k
                  NTLMFLAG_NEGOTIATE_NTLM2_KEY |
518
5.15k
                  NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
519
5.15k
    ntlm_print_flags(stderr,
520
5.15k
                     NTLMFLAG_NEGOTIATE_OEM |
521
5.15k
                     NTLMFLAG_REQUEST_TARGET |
522
5.15k
                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
523
5.15k
                     NTLMFLAG_NEGOTIATE_NTLM2_KEY |
524
5.15k
                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
525
5.15k
    curl_mfprintf(stderr, "\n****\n");
526
5.15k
  });
527
528
5.15k
  Curl_bufref_set(out, ntlmbuf, size, curl_free);
529
5.15k
  return CURLE_OK;
530
5.15k
}
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
25
{
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
25
  CURLcode result = CURLE_OK;
573
25
  size_t size;
574
25
  unsigned char ntlmbuf[NTLM_BUFSIZE];
575
25
  unsigned int lmrespoff;
576
25
  unsigned char lmresp[24]; /* fixed-size */
577
25
  unsigned int ntrespoff;
578
25
  unsigned int ntresplen = 24;
579
25
  unsigned char ntresp[24]; /* fixed-size */
580
25
  unsigned char *ptr_ntresp = &ntresp[0];
581
25
  unsigned char *ntlmv2resp = NULL;
582
25
  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
25
  static const char host[] = "WORKSTATION";
586
25
  const char *user;
587
25
  const char *domain = "";
588
25
  size_t hostoff = 0;
589
25
  size_t useroff = 0;
590
25
  size_t domoff = 0;
591
25
  size_t hostlen = 0;
592
25
  size_t userlen = 0;
593
25
  size_t domlen = 0;
594
595
25
  memset(lmresp, 0, sizeof(lmresp));
596
25
  memset(ntresp, 0, sizeof(ntresp));
597
25
  user = strchr(userp, '\\');
598
25
  if(!user)
599
14
    user = strchr(userp, '/');
600
601
25
  if(user) {
602
12
    domain = userp;
603
12
    domlen = (user - domain);
604
12
    user++;
605
12
  }
606
13
  else
607
13
    user = userp;
608
609
25
  userlen = strlen(user);
610
25
  hostlen = sizeof(host) - 1;
611
612
25
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
613
21
    unsigned char ntbuffer[0x18];
614
21
    unsigned char entropy[8];
615
21
    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
21
    result = Curl_rand(data, entropy, 8);
622
21
    if(result)
623
0
      return result;
624
625
21
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
626
21
    if(result)
627
0
      return result;
628
629
21
    result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
630
21
                                           ntbuffer, ntlmv2hash);
631
21
    if(result)
632
0
      return result;
633
634
    /* LMv2 response */
635
21
    result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
636
21
                                         &ntlm->nonce[0], lmresp);
637
21
    if(result)
638
0
      return result;
639
640
    /* NTLMv2 response */
641
21
    result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
642
21
                                           ntlm, &ntlmv2resp, &ntresplen);
643
21
    if(result)
644
0
      return result;
645
646
21
    ptr_ntresp = ntlmv2resp;
647
21
  }
648
4
  else {
649
650
4
    unsigned char ntbuffer[0x18];
651
4
    unsigned char lmbuffer[0x18];
652
653
    /* NTLM version 1 */
654
655
4
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
656
4
    if(result)
657
0
      return result;
658
659
4
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
660
661
4
    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
662
4
    if(result)
663
0
      return result;
664
665
4
    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
666
4
    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
4
  }
672
673
25
  if(unicode) {
674
24
    domlen = domlen * 2;
675
24
    userlen = userlen * 2;
676
24
    hostlen = hostlen * 2;
677
24
  }
678
679
25
  lmrespoff = 64; /* size of the message header */
680
25
  ntrespoff = lmrespoff + 0x18;
681
25
  domoff = ntrespoff + ntresplen;
682
25
  useroff = domoff + domlen;
683
25
  hostoff = useroff + userlen;
684
685
  /* Create the big type-3 message binary blob */
686
25
  size = curl_msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
687
25
                         NTLMSSP_SIGNATURE "%c"
688
25
                         "\x03%c%c%c"  /* 32-bit type = 3 */
689
690
25
                         "%c%c"  /* LanManager length */
691
25
                         "%c%c"  /* LanManager allocated space */
692
25
                         "%c%c"  /* LanManager offset */
693
25
                         "%c%c"  /* 2 zeroes */
694
695
25
                         "%c%c"  /* NT-response length */
696
25
                         "%c%c"  /* NT-response allocated space */
697
25
                         "%c%c"  /* NT-response offset */
698
25
                         "%c%c"  /* 2 zeroes */
699
700
25
                         "%c%c"  /* domain length */
701
25
                         "%c%c"  /* domain allocated space */
702
25
                         "%c%c"  /* domain name offset */
703
25
                         "%c%c"  /* 2 zeroes */
704
705
25
                         "%c%c"  /* user length */
706
25
                         "%c%c"  /* user allocated space */
707
25
                         "%c%c"  /* user offset */
708
25
                         "%c%c"  /* 2 zeroes */
709
710
25
                         "%c%c"  /* host length */
711
25
                         "%c%c"  /* host allocated space */
712
25
                         "%c%c"  /* host offset */
713
25
                         "%c%c"  /* 2 zeroes */
714
715
25
                         "%c%c"  /* session key length (unknown purpose) */
716
25
                         "%c%c"  /* session key allocated space
717
                                    (unknown purpose) */
718
25
                         "%c%c"  /* session key offset (unknown purpose) */
719
25
                         "%c%c"  /* 2 zeroes */
720
721
25
                         "%c%c%c%c",  /* flags */
722
723
                         /* domain string */
724
                         /* user string */
725
                         /* host string */
726
                         /* LanManager response */
727
                         /* NT response */
728
729
25
                         0,                /* null-termination */
730
25
                         0, 0, 0,          /* type-3 long, the 24 upper bits */
731
732
25
                         SHORTPAIR(0x18),  /* LanManager response length,
733
                                              twice */
734
25
                         SHORTPAIR(0x18),
735
25
                         SHORTPAIR(lmrespoff),
736
25
                         0x0, 0x0,
737
738
25
                         SHORTPAIR(ntresplen),  /* NT-response length, twice */
739
25
                         SHORTPAIR(ntresplen),
740
25
                         SHORTPAIR(ntrespoff),
741
25
                         0x0, 0x0,
742
743
25
                         SHORTPAIR(domlen),
744
25
                         SHORTPAIR(domlen),
745
25
                         SHORTPAIR(domoff),
746
25
                         0x0, 0x0,
747
748
25
                         SHORTPAIR(userlen),
749
25
                         SHORTPAIR(userlen),
750
25
                         SHORTPAIR(useroff),
751
25
                         0x0, 0x0,
752
753
25
                         SHORTPAIR(hostlen),
754
25
                         SHORTPAIR(hostlen),
755
25
                         SHORTPAIR(hostoff),
756
25
                         0x0, 0x0,
757
758
25
                         0x0, 0x0,
759
25
                         0x0, 0x0,
760
25
                         0x0, 0x0,
761
25
                         0x0, 0x0,
762
763
25
                         LONGQUARTET(ntlm->flags));
764
765
25
  DEBUGASSERT(size == 64);
766
25
  DEBUGASSERT(size == (size_t)lmrespoff);
767
768
  /* We append the binary hashes */
769
25
  if(size < (NTLM_BUFSIZE - 0x18)) {
770
25
    memcpy(&ntlmbuf[size], lmresp, 0x18);
771
25
    size += 0x18;
772
25
  }
773
774
25
  DEBUG_OUT({
775
25
    curl_mfprintf(stderr, "**** TYPE3 header lmresp=");
776
25
    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
777
25
  });
778
779
  /* ntresplen + size should not be risking an integer overflow here */
780
25
  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
25
  DEBUGASSERT(size == (size_t)ntrespoff);
786
25
  memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
787
25
  size += ntresplen;
788
789
25
  DEBUG_OUT({
790
25
    curl_mfprintf(stderr, "\n   ntresp=");
791
25
    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
792
25
  });
793
794
25
  DEBUG_OUT({
795
25
    curl_mfprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
796
25
                  LONGQUARTET(ntlm->flags), ntlm->flags);
797
25
    ntlm_print_flags(stderr, ntlm->flags);
798
25
    curl_mfprintf(stderr, "\n****\n");
799
25
  });
800
801
  /* Make sure that the domain, user and host strings fit in the
802
     buffer before we copy them there. */
803
25
  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
25
  DEBUGASSERT(size == domoff);
810
25
  if(unicode)
811
24
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
812
1
  else
813
1
    memcpy(&ntlmbuf[size], domain, domlen);
814
815
25
  size += domlen;
816
817
25
  DEBUGASSERT(size == useroff);
818
25
  if(unicode)
819
24
    unicodecpy(&ntlmbuf[size], user, userlen / 2);
820
1
  else
821
1
    memcpy(&ntlmbuf[size], user, userlen);
822
823
25
  size += userlen;
824
825
25
  DEBUGASSERT(size == hostoff);
826
25
  if(unicode)
827
24
    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
828
1
  else
829
1
    memcpy(&ntlmbuf[size], host, hostlen);
830
831
25
  size += hostlen;
832
833
  /* Return the binary blob. */
834
25
  result = Curl_bufref_memdup(out, ntlmbuf, size);
835
836
25
error:
837
25
  curlx_free(ntlmv2resp);  /* Free the dynamic buffer allocated for NTLMv2 */
838
839
25
  Curl_auth_cleanup_ntlm(ntlm);
840
841
25
  return result;
842
25
}
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.55k
{
856
  /* Free the target info */
857
6.55k
  Curl_safefree(ntlm->target_info);
858
859
  /* Reset any variables */
860
6.55k
  ntlm->target_info_len = 0;
861
6.55k
}
862
863
#endif /* USE_NTLM && !USE_WINDOWS_SSPI */