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>