quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ntlm.c (29222B)


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