Return to ntlm_sspi.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 - 2019, 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_WINDOWS_SSPI) && defined(USE_NTLM) ! 26: ! 27: #include <curl/curl.h> ! 28: ! 29: #include "vauth/vauth.h" ! 30: #include "urldata.h" ! 31: #include "curl_base64.h" ! 32: #include "curl_ntlm_core.h" ! 33: #include "warnless.h" ! 34: #include "curl_multibyte.h" ! 35: #include "sendf.h" ! 36: ! 37: /* The last #include files should be: */ ! 38: #include "curl_memory.h" ! 39: #include "memdebug.h" ! 40: ! 41: /* ! 42: * Curl_auth_is_ntlm_supported() ! 43: * ! 44: * This is used to evaluate if NTLM is supported. ! 45: * ! 46: * Parameters: None ! 47: * ! 48: * Returns TRUE if NTLM is supported by Windows SSPI. ! 49: */ ! 50: bool Curl_auth_is_ntlm_supported(void) ! 51: { ! 52: PSecPkgInfo SecurityPackage; ! 53: SECURITY_STATUS status; ! 54: ! 55: /* Query the security package for NTLM */ ! 56: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), ! 57: &SecurityPackage); ! 58: ! 59: /* Release the package buffer as it is not required anymore */ ! 60: if(status == SEC_E_OK) { ! 61: s_pSecFn->FreeContextBuffer(SecurityPackage); ! 62: } ! 63: ! 64: return (status == SEC_E_OK ? TRUE : FALSE); ! 65: } ! 66: ! 67: /* ! 68: * Curl_auth_create_ntlm_type1_message() ! 69: * ! 70: * This is used to generate an already encoded NTLM type-1 message ready for ! 71: * sending to the recipient. ! 72: * ! 73: * Parameters: ! 74: * ! 75: * data [in] - The session handle. ! 76: * userp [in] - The user name in the format User or Domain\User. ! 77: * passwdp [in] - The user's password. ! 78: * service [in] - The service type such as http, smtp, pop or imap. ! 79: * host [in] - The host name. ! 80: * ntlm [in/out] - The NTLM data struct being used and modified. ! 81: * outptr [in/out] - The address where a pointer to newly allocated memory ! 82: * holding the result will be stored upon completion. ! 83: * outlen [out] - The length of the output message. ! 84: * ! 85: * Returns CURLE_OK on success. ! 86: */ ! 87: CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, ! 88: const char *userp, ! 89: const char *passwdp, ! 90: const char *service, ! 91: const char *host, ! 92: struct ntlmdata *ntlm, ! 93: char **outptr, size_t *outlen) ! 94: { ! 95: PSecPkgInfo SecurityPackage; ! 96: SecBuffer type_1_buf; ! 97: SecBufferDesc type_1_desc; ! 98: SECURITY_STATUS status; ! 99: unsigned long attrs; ! 100: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ ! 101: ! 102: /* Clean up any former leftovers and initialise to defaults */ ! 103: Curl_auth_cleanup_ntlm(ntlm); ! 104: ! 105: /* Query the security package for NTLM */ ! 106: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), ! 107: &SecurityPackage); ! 108: if(status != SEC_E_OK) ! 109: return CURLE_NOT_BUILT_IN; ! 110: ! 111: ntlm->token_max = SecurityPackage->cbMaxToken; ! 112: ! 113: /* Release the package buffer as it is not required anymore */ ! 114: s_pSecFn->FreeContextBuffer(SecurityPackage); ! 115: ! 116: /* Allocate our output buffer */ ! 117: ntlm->output_token = malloc(ntlm->token_max); ! 118: if(!ntlm->output_token) ! 119: return CURLE_OUT_OF_MEMORY; ! 120: ! 121: if(userp && *userp) { ! 122: CURLcode result; ! 123: ! 124: /* Populate our identity structure */ ! 125: result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); ! 126: if(result) ! 127: return result; ! 128: ! 129: /* Allow proper cleanup of the identity structure */ ! 130: ntlm->p_identity = &ntlm->identity; ! 131: } ! 132: else ! 133: /* Use the current Windows user */ ! 134: ntlm->p_identity = NULL; ! 135: ! 136: /* Allocate our credentials handle */ ! 137: ntlm->credentials = calloc(1, sizeof(CredHandle)); ! 138: if(!ntlm->credentials) ! 139: return CURLE_OUT_OF_MEMORY; ! 140: ! 141: /* Acquire our credentials handle */ ! 142: status = s_pSecFn->AcquireCredentialsHandle(NULL, ! 143: (TCHAR *) TEXT(SP_NAME_NTLM), ! 144: SECPKG_CRED_OUTBOUND, NULL, ! 145: ntlm->p_identity, NULL, NULL, ! 146: ntlm->credentials, &expiry); ! 147: if(status != SEC_E_OK) ! 148: return CURLE_LOGIN_DENIED; ! 149: ! 150: /* Allocate our new context handle */ ! 151: ntlm->context = calloc(1, sizeof(CtxtHandle)); ! 152: if(!ntlm->context) ! 153: return CURLE_OUT_OF_MEMORY; ! 154: ! 155: ntlm->spn = Curl_auth_build_spn(service, host, NULL); ! 156: if(!ntlm->spn) ! 157: return CURLE_OUT_OF_MEMORY; ! 158: ! 159: /* Setup the type-1 "output" security buffer */ ! 160: type_1_desc.ulVersion = SECBUFFER_VERSION; ! 161: type_1_desc.cBuffers = 1; ! 162: type_1_desc.pBuffers = &type_1_buf; ! 163: type_1_buf.BufferType = SECBUFFER_TOKEN; ! 164: type_1_buf.pvBuffer = ntlm->output_token; ! 165: type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); ! 166: ! 167: /* Generate our type-1 message */ ! 168: status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, ! 169: ntlm->spn, ! 170: 0, 0, SECURITY_NETWORK_DREP, ! 171: NULL, 0, ! 172: ntlm->context, &type_1_desc, ! 173: &attrs, &expiry); ! 174: if(status == SEC_I_COMPLETE_NEEDED || ! 175: status == SEC_I_COMPLETE_AND_CONTINUE) ! 176: s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); ! 177: else if(status == SEC_E_INSUFFICIENT_MEMORY) ! 178: return CURLE_OUT_OF_MEMORY; ! 179: else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) ! 180: return CURLE_AUTH_ERROR; ! 181: ! 182: /* Base64 encode the response */ ! 183: return Curl_base64_encode(data, (char *) ntlm->output_token, ! 184: type_1_buf.cbBuffer, outptr, outlen); ! 185: } ! 186: ! 187: /* ! 188: * Curl_auth_decode_ntlm_type2_message() ! 189: * ! 190: * This is used to decode an already encoded NTLM type-2 message. ! 191: * ! 192: * Parameters: ! 193: * ! 194: * data [in] - The session handle. ! 195: * type2msg [in] - The base64 encoded type-2 message. ! 196: * ntlm [in/out] - The NTLM data struct being used and modified. ! 197: * ! 198: * Returns CURLE_OK on success. ! 199: */ ! 200: CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, ! 201: const char *type2msg, ! 202: struct ntlmdata *ntlm) ! 203: { ! 204: CURLcode result = CURLE_OK; ! 205: unsigned char *type2 = NULL; ! 206: size_t type2_len = 0; ! 207: ! 208: #if defined(CURL_DISABLE_VERBOSE_STRINGS) ! 209: (void) data; ! 210: #endif ! 211: ! 212: /* Decode the base-64 encoded type-2 message */ ! 213: if(strlen(type2msg) && *type2msg != '=') { ! 214: result = Curl_base64_decode(type2msg, &type2, &type2_len); ! 215: if(result) ! 216: return result; ! 217: } ! 218: ! 219: /* Ensure we have a valid type-2 message */ ! 220: if(!type2) { ! 221: infof(data, "NTLM handshake failure (empty type-2 message)\n"); ! 222: ! 223: return CURLE_BAD_CONTENT_ENCODING; ! 224: } ! 225: ! 226: /* Simply store the challenge for use later */ ! 227: ntlm->input_token = type2; ! 228: ntlm->input_token_len = type2_len; ! 229: ! 230: return result; ! 231: } ! 232: ! 233: /* ! 234: * Curl_auth_create_ntlm_type3_message() ! 235: * Curl_auth_create_ntlm_type3_message() ! 236: * ! 237: * This is used to generate an already encoded NTLM type-3 message ready for ! 238: * sending to the recipient. ! 239: * ! 240: * Parameters: ! 241: * ! 242: * data [in] - The session handle. ! 243: * userp [in] - The user name in the format User or Domain\User. ! 244: * passwdp [in] - The user's password. ! 245: * ntlm [in/out] - The NTLM data struct being used and modified. ! 246: * outptr [in/out] - The address where a pointer to newly allocated memory ! 247: * holding the result will be stored upon completion. ! 248: * outlen [out] - The length of the output message. ! 249: * ! 250: * Returns CURLE_OK on success. ! 251: */ ! 252: CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, ! 253: const char *userp, ! 254: const char *passwdp, ! 255: struct ntlmdata *ntlm, ! 256: char **outptr, size_t *outlen) ! 257: { ! 258: CURLcode result = CURLE_OK; ! 259: SecBuffer type_2_bufs[2]; ! 260: SecBuffer type_3_buf; ! 261: SecBufferDesc type_2_desc; ! 262: SecBufferDesc type_3_desc; ! 263: SECURITY_STATUS status; ! 264: unsigned long attrs; ! 265: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ ! 266: ! 267: (void) passwdp; ! 268: (void) userp; ! 269: ! 270: /* Setup the type-2 "input" security buffer */ ! 271: type_2_desc.ulVersion = SECBUFFER_VERSION; ! 272: type_2_desc.cBuffers = 1; ! 273: type_2_desc.pBuffers = &type_2_bufs[0]; ! 274: type_2_bufs[0].BufferType = SECBUFFER_TOKEN; ! 275: type_2_bufs[0].pvBuffer = ntlm->input_token; ! 276: type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len); ! 277: ! 278: #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS ! 279: /* ssl context comes from schannel. ! 280: * When extended protection is used in IIS server, ! 281: * we have to pass a second SecBuffer to the SecBufferDesc ! 282: * otherwise IIS will not pass the authentication (401 response). ! 283: * Minimum supported version is Windows 7. ! 284: * https://docs.microsoft.com/en-us/security-updates ! 285: * /SecurityAdvisories/2009/973811 ! 286: */ ! 287: if(ntlm->sslContext) { ! 288: SEC_CHANNEL_BINDINGS channelBindings; ! 289: SecPkgContext_Bindings pkgBindings; ! 290: pkgBindings.Bindings = &channelBindings; ! 291: status = s_pSecFn->QueryContextAttributes( ! 292: ntlm->sslContext, ! 293: SECPKG_ATTR_ENDPOINT_BINDINGS, ! 294: &pkgBindings ! 295: ); ! 296: if(status == SEC_E_OK) { ! 297: type_2_desc.cBuffers++; ! 298: type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; ! 299: type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength; ! 300: type_2_bufs[1].pvBuffer = pkgBindings.Bindings; ! 301: } ! 302: } ! 303: #endif ! 304: ! 305: /* Setup the type-3 "output" security buffer */ ! 306: type_3_desc.ulVersion = SECBUFFER_VERSION; ! 307: type_3_desc.cBuffers = 1; ! 308: type_3_desc.pBuffers = &type_3_buf; ! 309: type_3_buf.BufferType = SECBUFFER_TOKEN; ! 310: type_3_buf.pvBuffer = ntlm->output_token; ! 311: type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); ! 312: ! 313: /* Generate our type-3 message */ ! 314: status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, ! 315: ntlm->context, ! 316: ntlm->spn, ! 317: 0, 0, SECURITY_NETWORK_DREP, ! 318: &type_2_desc, ! 319: 0, ntlm->context, ! 320: &type_3_desc, ! 321: &attrs, &expiry); ! 322: if(status != SEC_E_OK) { ! 323: infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", ! 324: status); ! 325: ! 326: if(status == SEC_E_INSUFFICIENT_MEMORY) ! 327: return CURLE_OUT_OF_MEMORY; ! 328: ! 329: return CURLE_AUTH_ERROR; ! 330: } ! 331: ! 332: /* Base64 encode the response */ ! 333: result = Curl_base64_encode(data, (char *) ntlm->output_token, ! 334: type_3_buf.cbBuffer, outptr, outlen); ! 335: ! 336: Curl_auth_cleanup_ntlm(ntlm); ! 337: ! 338: return result; ! 339: } ! 340: ! 341: /* ! 342: * Curl_auth_cleanup_ntlm() ! 343: * ! 344: * This is used to clean up the NTLM specific data. ! 345: * ! 346: * Parameters: ! 347: * ! 348: * ntlm [in/out] - The NTLM data struct being cleaned up. ! 349: * ! 350: */ ! 351: void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) ! 352: { ! 353: /* Free our security context */ ! 354: if(ntlm->context) { ! 355: s_pSecFn->DeleteSecurityContext(ntlm->context); ! 356: free(ntlm->context); ! 357: ntlm->context = NULL; ! 358: } ! 359: ! 360: /* Free our credentials handle */ ! 361: if(ntlm->credentials) { ! 362: s_pSecFn->FreeCredentialsHandle(ntlm->credentials); ! 363: free(ntlm->credentials); ! 364: ntlm->credentials = NULL; ! 365: } ! 366: ! 367: /* Free our identity */ ! 368: Curl_sspi_free_identity(ntlm->p_identity); ! 369: ntlm->p_identity = NULL; ! 370: ! 371: /* Free the input and output tokens */ ! 372: Curl_safefree(ntlm->input_token); ! 373: Curl_safefree(ntlm->output_token); ! 374: ! 375: /* Reset any variables */ ! 376: ntlm->token_max = 0; ! 377: ! 378: Curl_safefree(ntlm->spn); ! 379: } ! 380: ! 381: #endif /* USE_WINDOWS_SSPI && USE_NTLM */