Coverage Report

Created: 2025-10-30 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/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
0
#define NTLM_BUFSIZE 1024
58
59
/* Flag bits definitions based on
60
   https://davenport.sourceforge.net/ntlm.html */
61
62
0
#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
0
#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
0
#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
0
#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
0
# 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
0
{
264
0
  unsigned short target_info_len = 0;
265
0
  unsigned int target_info_offset = 0;
266
0
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
267
0
  size_t type2len = Curl_bufref_len(type2ref);
268
269
#ifdef CURL_DISABLE_VERBOSE_STRINGS
270
  (void)data;
271
#endif
272
273
0
  if(type2len >= 48) {
274
0
    target_info_len = Curl_read16_le(&type2[40]);
275
0
    target_info_offset = Curl_read32_le(&type2[44]);
276
0
    if(target_info_len > 0) {
277
0
      if((target_info_offset > type2len) ||
278
0
         (target_info_offset + target_info_len) > type2len ||
279
0
         target_info_offset < 48) {
280
0
        infof(data, "NTLM handshake failure (bad type-2 message). "
281
0
              "Target Info Offset Len is set incorrect by the peer");
282
0
        return CURLE_BAD_CONTENT_ENCODING;
283
0
      }
284
285
0
      free(ntlm->target_info); /* replace any previous data */
286
0
      ntlm->target_info = Curl_memdup(&type2[target_info_offset],
287
0
                                      target_info_len);
288
0
      if(!ntlm->target_info)
289
0
        return CURLE_OUT_OF_MEMORY;
290
0
    }
291
0
  }
292
293
0
  ntlm->target_info_len = target_info_len;
294
295
0
  return CURLE_OK;
296
0
}
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
0
{
325
0
  return TRUE;
326
0
}
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
0
{
347
0
  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
0
  CURLcode result = CURLE_OK;
366
0
  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
367
0
  size_t type2len = Curl_bufref_len(type2ref);
368
369
#ifdef CURL_DISABLE_VERBOSE_STRINGS
370
  (void)data;
371
#endif
372
373
0
  ntlm->flags = 0;
374
375
0
  if((type2len < 32) ||
376
0
     (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
377
0
     (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
378
    /* This was not a good enough type-2 message */
379
0
    infof(data, "NTLM handshake failure (bad type-2 message)");
380
0
    return CURLE_BAD_CONTENT_ENCODING;
381
0
  }
382
383
0
  ntlm->flags = Curl_read32_le(&type2[20]);
384
0
  memcpy(ntlm->nonce, &type2[24], 8);
385
386
0
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
387
0
    result = ntlm_decode_type2_target(data, type2ref, ntlm);
388
0
    if(result) {
389
0
      infof(data, "NTLM handshake failure (bad type-2 message)");
390
0
      return result;
391
0
    }
392
0
  }
393
394
0
  DEBUG_OUT({
395
0
    curl_mfprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
396
0
    ntlm_print_flags(stderr, ntlm->flags);
397
0
    curl_mfprintf(stderr, "\n                  nonce=");
398
0
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
399
0
    curl_mfprintf(stderr, "\n****\n");
400
0
    curl_mfprintf(stderr, "**** Header %s\n ", header);
401
0
  });
402
403
0
  return result;
404
0
}
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
0
{
410
0
  size_t i;
411
0
  for(i = 0; i < length; i++) {
412
0
    dest[2 * i] = (unsigned char)src[i];
413
0
    dest[2 * i + 1] = '\0';
414
0
  }
415
0
}
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
0
{
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
0
  size_t size;
458
459
0
  char *ntlmbuf;
460
0
  const char *host = "";              /* empty */
461
0
  const char *domain = "";            /* empty */
462
0
  size_t hostlen = 0;
463
0
  size_t domlen = 0;
464
0
  size_t hostoff = 0;
465
0
  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
466
                                         domain are empty */
467
0
  (void)data;
468
0
  (void)userp;
469
0
  (void)passwdp;
470
0
  (void)service;
471
0
  (void)hostname;
472
473
  /* Clean up any former leftovers and initialise to defaults */
474
0
  Curl_auth_cleanup_ntlm(ntlm);
475
476
0
  ntlmbuf = curl_maprintf(NTLMSSP_SIGNATURE "%c"
477
0
                          "\x01%c%c%c" /* 32-bit type = 1 */
478
0
                          "%c%c%c%c"   /* 32-bit NTLM flag field */
479
0
                          "%c%c"       /* domain length */
480
0
                          "%c%c"       /* domain allocated space */
481
0
                          "%c%c"       /* domain name offset */
482
0
                          "%c%c"       /* 2 zeroes */
483
0
                          "%c%c"       /* host length */
484
0
                          "%c%c"       /* host allocated space */
485
0
                          "%c%c"       /* hostname offset */
486
0
                          "%c%c"       /* 2 zeroes */
487
0
                          "%s"         /* hostname */
488
0
                          "%s",        /* domain string */
489
0
                          0,           /* trailing zero */
490
0
                          0, 0, 0,     /* part of type-1 long */
491
492
0
                          LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
493
0
                                      NTLMFLAG_REQUEST_TARGET |
494
0
                                      NTLMFLAG_NEGOTIATE_NTLM_KEY |
495
0
                                      NTLMFLAG_NEGOTIATE_NTLM2_KEY |
496
0
                                      NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
497
0
                          SHORTPAIR(domlen),
498
0
                          SHORTPAIR(domlen),
499
0
                          SHORTPAIR(domoff),
500
0
                          0, 0,
501
0
                          SHORTPAIR(hostlen),
502
0
                          SHORTPAIR(hostlen),
503
0
                          SHORTPAIR(hostoff),
504
0
                          0, 0,
505
0
                          host,  /* this is empty */
506
0
                          domain /* this is empty */);
507
508
0
  if(!ntlmbuf)
509
0
    return CURLE_OUT_OF_MEMORY;
510
511
  /* Initial packet length */
512
0
  size = 32 + hostlen + domlen;
513
514
0
  DEBUG_OUT({
515
0
    curl_mfprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
516
0
                  "0x%08.8x ",
517
0
                  LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
518
0
                              NTLMFLAG_REQUEST_TARGET |
519
0
                              NTLMFLAG_NEGOTIATE_NTLM_KEY |
520
0
                              NTLMFLAG_NEGOTIATE_NTLM2_KEY |
521
0
                              NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
522
0
                  NTLMFLAG_NEGOTIATE_OEM |
523
0
                  NTLMFLAG_REQUEST_TARGET |
524
0
                  NTLMFLAG_NEGOTIATE_NTLM_KEY |
525
0
                  NTLMFLAG_NEGOTIATE_NTLM2_KEY |
526
0
                  NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
527
0
    ntlm_print_flags(stderr,
528
0
                     NTLMFLAG_NEGOTIATE_OEM |
529
0
                     NTLMFLAG_REQUEST_TARGET |
530
0
                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
531
0
                     NTLMFLAG_NEGOTIATE_NTLM2_KEY |
532
0
                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
533
0
    curl_mfprintf(stderr, "\n****\n");
534
0
  });
535
536
0
  Curl_bufref_set(out, ntlmbuf, size, curl_free);
537
0
  return CURLE_OK;
538
0
}
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
0
{
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
0
  CURLcode result = CURLE_OK;
581
0
  size_t size;
582
0
  unsigned char ntlmbuf[NTLM_BUFSIZE];
583
0
  unsigned int lmrespoff;
584
0
  unsigned char lmresp[24]; /* fixed-size */
585
0
  unsigned int ntrespoff;
586
0
  unsigned int ntresplen = 24;
587
0
  unsigned char ntresp[24]; /* fixed-size */
588
0
  unsigned char *ptr_ntresp = &ntresp[0];
589
0
  unsigned char *ntlmv2resp = NULL;
590
0
  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
0
  static const char host[] = "WORKSTATION";
594
0
  const char *user;
595
0
  const char *domain = "";
596
0
  size_t hostoff = 0;
597
0
  size_t useroff = 0;
598
0
  size_t domoff = 0;
599
0
  size_t hostlen = 0;
600
0
  size_t userlen = 0;
601
0
  size_t domlen = 0;
602
603
0
  memset(lmresp, 0, sizeof(lmresp));
604
0
  memset(ntresp, 0, sizeof(ntresp));
605
0
  user = strchr(userp, '\\');
606
0
  if(!user)
607
0
    user = strchr(userp, '/');
608
609
0
  if(user) {
610
0
    domain = userp;
611
0
    domlen = (user - domain);
612
0
    user++;
613
0
  }
614
0
  else
615
0
    user = userp;
616
617
0
  userlen = strlen(user);
618
0
  hostlen = sizeof(host) - 1;
619
620
0
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
621
0
    unsigned char ntbuffer[0x18];
622
0
    unsigned char entropy[8];
623
0
    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
0
    result = Curl_rand(data, entropy, 8);
630
0
    if(result)
631
0
      return result;
632
633
0
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
634
0
    if(result)
635
0
      return result;
636
637
0
    result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
638
0
                                           ntbuffer, ntlmv2hash);
639
0
    if(result)
640
0
      return result;
641
642
    /* LMv2 response */
643
0
    result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
644
0
                                         &ntlm->nonce[0], lmresp);
645
0
    if(result)
646
0
      return result;
647
648
    /* NTLMv2 response */
649
0
    result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
650
0
                                           ntlm, &ntlmv2resp, &ntresplen);
651
0
    if(result)
652
0
      return result;
653
654
0
    ptr_ntresp = ntlmv2resp;
655
0
  }
656
0
  else {
657
658
0
    unsigned char ntbuffer[0x18];
659
0
    unsigned char lmbuffer[0x18];
660
661
    /* NTLM version 1 */
662
663
0
    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
664
0
    if(result)
665
0
      return result;
666
667
0
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
668
669
0
    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
670
0
    if(result)
671
0
      return result;
672
673
0
    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
674
0
    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
0
  }
680
681
0
  if(unicode) {
682
0
    domlen = domlen * 2;
683
0
    userlen = userlen * 2;
684
0
    hostlen = hostlen * 2;
685
0
  }
686
687
0
  lmrespoff = 64; /* size of the message header */
688
0
  ntrespoff = lmrespoff + 0x18;
689
0
  domoff = ntrespoff + ntresplen;
690
0
  useroff = domoff + domlen;
691
0
  hostoff = useroff + userlen;
692
693
  /* Create the big type-3 message binary blob */
694
0
  size = curl_msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
695
0
                         NTLMSSP_SIGNATURE "%c"
696
0
                         "\x03%c%c%c"  /* 32-bit type = 3 */
697
698
0
                         "%c%c"  /* LanManager length */
699
0
                         "%c%c"  /* LanManager allocated space */
700
0
                         "%c%c"  /* LanManager offset */
701
0
                         "%c%c"  /* 2 zeroes */
702
703
0
                         "%c%c"  /* NT-response length */
704
0
                         "%c%c"  /* NT-response allocated space */
705
0
                         "%c%c"  /* NT-response offset */
706
0
                         "%c%c"  /* 2 zeroes */
707
708
0
                         "%c%c"  /* domain length */
709
0
                         "%c%c"  /* domain allocated space */
710
0
                         "%c%c"  /* domain name offset */
711
0
                         "%c%c"  /* 2 zeroes */
712
713
0
                         "%c%c"  /* user length */
714
0
                         "%c%c"  /* user allocated space */
715
0
                         "%c%c"  /* user offset */
716
0
                         "%c%c"  /* 2 zeroes */
717
718
0
                         "%c%c"  /* host length */
719
0
                         "%c%c"  /* host allocated space */
720
0
                         "%c%c"  /* host offset */
721
0
                         "%c%c"  /* 2 zeroes */
722
723
0
                         "%c%c"  /* session key length (unknown purpose) */
724
0
                         "%c%c"  /* session key allocated space
725
                                    (unknown purpose) */
726
0
                         "%c%c"  /* session key offset (unknown purpose) */
727
0
                         "%c%c"  /* 2 zeroes */
728
729
0
                         "%c%c%c%c",  /* flags */
730
731
                         /* domain string */
732
                         /* user string */
733
                         /* host string */
734
                         /* LanManager response */
735
                         /* NT response */
736
737
0
                         0,                /* null-termination */
738
0
                         0, 0, 0,          /* type-3 long, the 24 upper bits */
739
740
0
                         SHORTPAIR(0x18),  /* LanManager response length,
741
                                              twice */
742
0
                         SHORTPAIR(0x18),
743
0
                         SHORTPAIR(lmrespoff),
744
0
                         0x0, 0x0,
745
746
0
                         SHORTPAIR(ntresplen),  /* NT-response length, twice */
747
0
                         SHORTPAIR(ntresplen),
748
0
                         SHORTPAIR(ntrespoff),
749
0
                         0x0, 0x0,
750
751
0
                         SHORTPAIR(domlen),
752
0
                         SHORTPAIR(domlen),
753
0
                         SHORTPAIR(domoff),
754
0
                         0x0, 0x0,
755
756
0
                         SHORTPAIR(userlen),
757
0
                         SHORTPAIR(userlen),
758
0
                         SHORTPAIR(useroff),
759
0
                         0x0, 0x0,
760
761
0
                         SHORTPAIR(hostlen),
762
0
                         SHORTPAIR(hostlen),
763
0
                         SHORTPAIR(hostoff),
764
0
                         0x0, 0x0,
765
766
0
                         0x0, 0x0,
767
0
                         0x0, 0x0,
768
0
                         0x0, 0x0,
769
0
                         0x0, 0x0,
770
771
0
                         LONGQUARTET(ntlm->flags));
772
773
0
  DEBUGASSERT(size == 64);
774
0
  DEBUGASSERT(size == (size_t)lmrespoff);
775
776
  /* We append the binary hashes */
777
0
  if(size < (NTLM_BUFSIZE - 0x18)) {
778
0
    memcpy(&ntlmbuf[size], lmresp, 0x18);
779
0
    size += 0x18;
780
0
  }
781
782
0
  DEBUG_OUT({
783
0
    curl_mfprintf(stderr, "**** TYPE3 header lmresp=");
784
0
    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
785
0
  });
786
787
  /* ntresplen + size should not be risking an integer overflow here */
788
0
  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
0
  DEBUGASSERT(size == (size_t)ntrespoff);
794
0
  memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
795
0
  size += ntresplen;
796
797
0
  DEBUG_OUT({
798
0
    curl_mfprintf(stderr, "\n   ntresp=");
799
0
    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
800
0
  });
801
802
0
  DEBUG_OUT({
803
0
    curl_mfprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
804
0
                  LONGQUARTET(ntlm->flags), ntlm->flags);
805
0
    ntlm_print_flags(stderr, ntlm->flags);
806
0
    curl_mfprintf(stderr, "\n****\n");
807
0
  });
808
809
  /* Make sure that the domain, user and host strings fit in the
810
     buffer before we copy them there. */
811
0
  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
0
  DEBUGASSERT(size == domoff);
818
0
  if(unicode)
819
0
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
820
0
  else
821
0
    memcpy(&ntlmbuf[size], domain, domlen);
822
823
0
  size += domlen;
824
825
0
  DEBUGASSERT(size == useroff);
826
0
  if(unicode)
827
0
    unicodecpy(&ntlmbuf[size], user, userlen / 2);
828
0
  else
829
0
    memcpy(&ntlmbuf[size], user, userlen);
830
831
0
  size += userlen;
832
833
0
  DEBUGASSERT(size == hostoff);
834
0
  if(unicode)
835
0
    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
836
0
  else
837
0
    memcpy(&ntlmbuf[size], host, hostlen);
838
839
0
  size += hostlen;
840
841
  /* Return the binary blob. */
842
0
  result = Curl_bufref_memdup(out, ntlmbuf, size);
843
844
0
error:
845
0
  free(ntlmv2resp);  /* Free the dynamic buffer allocated for NTLMv2 */
846
847
0
  Curl_auth_cleanup_ntlm(ntlm);
848
849
0
  return result;
850
0
}
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
0
{
864
  /* Free the target info */
865
0
  Curl_safefree(ntlm->target_info);
866
867
  /* Reset any variables */
868
0
  ntlm->target_info_len = 0;
869
0
}
870
871
#endif /* USE_NTLM && !USE_WINDOWS_SSPI */