Coverage Report

Created: 2025-10-10 06:31

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