Coverage Report

Created: 2025-07-11 06:33

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