Annotation of embedaddon/curl/lib/vauth/ntlm_sspi.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>