Annotation of embedaddon/curl/lib/vauth/ntlm.c, revision 1.1

1.1     ! misho       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>