File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vauth / ntlm.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years, 1 month ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>