Return to ntlm.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vauth |
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 */