Return to digest_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) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>. ! 9: * Copyright (C) 2015 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. ! 10: * ! 11: * This software is licensed as described in the file COPYING, which ! 12: * you should have received as part of this distribution. The terms ! 13: * are also available at https://curl.haxx.se/docs/copyright.html. ! 14: * ! 15: * You may opt to use, copy, modify, merge, publish, distribute and/or sell ! 16: * copies of the Software, and permit persons to whom the Software is ! 17: * furnished to do so, under the terms of the COPYING file. ! 18: * ! 19: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ! 20: * KIND, either express or implied. ! 21: * ! 22: * RFC2831 DIGEST-MD5 authentication ! 23: * ! 24: ***************************************************************************/ ! 25: ! 26: #include "curl_setup.h" ! 27: ! 28: #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH) ! 29: ! 30: #include <curl/curl.h> ! 31: ! 32: #include "vauth/vauth.h" ! 33: #include "vauth/digest.h" ! 34: #include "urldata.h" ! 35: #include "curl_base64.h" ! 36: #include "warnless.h" ! 37: #include "curl_multibyte.h" ! 38: #include "sendf.h" ! 39: #include "strdup.h" ! 40: #include "strcase.h" ! 41: ! 42: /* The last #include files should be: */ ! 43: #include "curl_memory.h" ! 44: #include "memdebug.h" ! 45: ! 46: /* ! 47: * Curl_auth_is_digest_supported() ! 48: * ! 49: * This is used to evaluate if DIGEST is supported. ! 50: * ! 51: * Parameters: None ! 52: * ! 53: * Returns TRUE if DIGEST is supported by Windows SSPI. ! 54: */ ! 55: bool Curl_auth_is_digest_supported(void) ! 56: { ! 57: PSecPkgInfo SecurityPackage; ! 58: SECURITY_STATUS status; ! 59: ! 60: /* Query the security package for Digest */ ! 61: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), ! 62: &SecurityPackage); ! 63: ! 64: /* Release the package buffer as it is not required anymore */ ! 65: if(status == SEC_E_OK) { ! 66: s_pSecFn->FreeContextBuffer(SecurityPackage); ! 67: } ! 68: ! 69: return (status == SEC_E_OK ? TRUE : FALSE); ! 70: } ! 71: ! 72: /* ! 73: * Curl_auth_create_digest_md5_message() ! 74: * ! 75: * This is used to generate an already encoded DIGEST-MD5 response message ! 76: * ready for sending to the recipient. ! 77: * ! 78: * Parameters: ! 79: * ! 80: * data [in] - The session handle. ! 81: * chlg64 [in] - The base64 encoded challenge message. ! 82: * userp [in] - The user name in the format User or Domain\User. ! 83: * passwdp [in] - The user's password. ! 84: * service [in] - The service type such as http, smtp, pop or imap. ! 85: * outptr [in/out] - The address where a pointer to newly allocated memory ! 86: * holding the result will be stored upon completion. ! 87: * outlen [out] - The length of the output message. ! 88: * ! 89: * Returns CURLE_OK on success. ! 90: */ ! 91: CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, ! 92: const char *chlg64, ! 93: const char *userp, ! 94: const char *passwdp, ! 95: const char *service, ! 96: char **outptr, size_t *outlen) ! 97: { ! 98: CURLcode result = CURLE_OK; ! 99: TCHAR *spn = NULL; ! 100: size_t chlglen = 0; ! 101: size_t token_max = 0; ! 102: unsigned char *input_token = NULL; ! 103: unsigned char *output_token = NULL; ! 104: CredHandle credentials; ! 105: CtxtHandle context; ! 106: PSecPkgInfo SecurityPackage; ! 107: SEC_WINNT_AUTH_IDENTITY identity; ! 108: SEC_WINNT_AUTH_IDENTITY *p_identity; ! 109: SecBuffer chlg_buf; ! 110: SecBuffer resp_buf; ! 111: SecBufferDesc chlg_desc; ! 112: SecBufferDesc resp_desc; ! 113: SECURITY_STATUS status; ! 114: unsigned long attrs; ! 115: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ ! 116: ! 117: /* Decode the base-64 encoded challenge message */ ! 118: if(strlen(chlg64) && *chlg64 != '=') { ! 119: result = Curl_base64_decode(chlg64, &input_token, &chlglen); ! 120: if(result) ! 121: return result; ! 122: } ! 123: ! 124: /* Ensure we have a valid challenge message */ ! 125: if(!input_token) { ! 126: infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); ! 127: ! 128: return CURLE_BAD_CONTENT_ENCODING; ! 129: } ! 130: ! 131: /* Query the security package for DigestSSP */ ! 132: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), ! 133: &SecurityPackage); ! 134: if(status != SEC_E_OK) { ! 135: free(input_token); ! 136: ! 137: return CURLE_NOT_BUILT_IN; ! 138: } ! 139: ! 140: token_max = SecurityPackage->cbMaxToken; ! 141: ! 142: /* Release the package buffer as it is not required anymore */ ! 143: s_pSecFn->FreeContextBuffer(SecurityPackage); ! 144: ! 145: /* Allocate our response buffer */ ! 146: output_token = malloc(token_max); ! 147: if(!output_token) { ! 148: free(input_token); ! 149: ! 150: return CURLE_OUT_OF_MEMORY; ! 151: } ! 152: ! 153: /* Generate our SPN */ ! 154: spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); ! 155: if(!spn) { ! 156: free(output_token); ! 157: free(input_token); ! 158: ! 159: return CURLE_OUT_OF_MEMORY; ! 160: } ! 161: ! 162: if(userp && *userp) { ! 163: /* Populate our identity structure */ ! 164: result = Curl_create_sspi_identity(userp, passwdp, &identity); ! 165: if(result) { ! 166: free(spn); ! 167: free(output_token); ! 168: free(input_token); ! 169: ! 170: return result; ! 171: } ! 172: ! 173: /* Allow proper cleanup of the identity structure */ ! 174: p_identity = &identity; ! 175: } ! 176: else ! 177: /* Use the current Windows user */ ! 178: p_identity = NULL; ! 179: ! 180: /* Acquire our credentials handle */ ! 181: status = s_pSecFn->AcquireCredentialsHandle(NULL, ! 182: (TCHAR *) TEXT(SP_NAME_DIGEST), ! 183: SECPKG_CRED_OUTBOUND, NULL, ! 184: p_identity, NULL, NULL, ! 185: &credentials, &expiry); ! 186: ! 187: if(status != SEC_E_OK) { ! 188: Curl_sspi_free_identity(p_identity); ! 189: free(spn); ! 190: free(output_token); ! 191: free(input_token); ! 192: ! 193: return CURLE_LOGIN_DENIED; ! 194: } ! 195: ! 196: /* Setup the challenge "input" security buffer */ ! 197: chlg_desc.ulVersion = SECBUFFER_VERSION; ! 198: chlg_desc.cBuffers = 1; ! 199: chlg_desc.pBuffers = &chlg_buf; ! 200: chlg_buf.BufferType = SECBUFFER_TOKEN; ! 201: chlg_buf.pvBuffer = input_token; ! 202: chlg_buf.cbBuffer = curlx_uztoul(chlglen); ! 203: ! 204: /* Setup the response "output" security buffer */ ! 205: resp_desc.ulVersion = SECBUFFER_VERSION; ! 206: resp_desc.cBuffers = 1; ! 207: resp_desc.pBuffers = &resp_buf; ! 208: resp_buf.BufferType = SECBUFFER_TOKEN; ! 209: resp_buf.pvBuffer = output_token; ! 210: resp_buf.cbBuffer = curlx_uztoul(token_max); ! 211: ! 212: /* Generate our response message */ ! 213: status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, ! 214: 0, 0, 0, &chlg_desc, 0, ! 215: &context, &resp_desc, &attrs, ! 216: &expiry); ! 217: ! 218: if(status == SEC_I_COMPLETE_NEEDED || ! 219: status == SEC_I_COMPLETE_AND_CONTINUE) ! 220: s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); ! 221: else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { ! 222: s_pSecFn->FreeCredentialsHandle(&credentials); ! 223: Curl_sspi_free_identity(p_identity); ! 224: free(spn); ! 225: free(output_token); ! 226: free(input_token); ! 227: ! 228: if(status == SEC_E_INSUFFICIENT_MEMORY) ! 229: return CURLE_OUT_OF_MEMORY; ! 230: ! 231: return CURLE_AUTH_ERROR; ! 232: } ! 233: ! 234: /* Base64 encode the response */ ! 235: result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, ! 236: outptr, outlen); ! 237: ! 238: /* Free our handles */ ! 239: s_pSecFn->DeleteSecurityContext(&context); ! 240: s_pSecFn->FreeCredentialsHandle(&credentials); ! 241: ! 242: /* Free the identity structure */ ! 243: Curl_sspi_free_identity(p_identity); ! 244: ! 245: /* Free the SPN */ ! 246: free(spn); ! 247: ! 248: /* Free the response buffer */ ! 249: free(output_token); ! 250: ! 251: /* Free the decoded challenge message */ ! 252: free(input_token); ! 253: ! 254: return result; ! 255: } ! 256: ! 257: /* ! 258: * Curl_override_sspi_http_realm() ! 259: * ! 260: * This is used to populate the domain in a SSPI identity structure ! 261: * The realm is extracted from the challenge message and used as the ! 262: * domain if it is not already explicitly set. ! 263: * ! 264: * Parameters: ! 265: * ! 266: * chlg [in] - The challenge message. ! 267: * identity [in/out] - The identity structure. ! 268: * ! 269: * Returns CURLE_OK on success. ! 270: */ ! 271: CURLcode Curl_override_sspi_http_realm(const char *chlg, ! 272: SEC_WINNT_AUTH_IDENTITY *identity) ! 273: { ! 274: xcharp_u domain, dup_domain; ! 275: ! 276: /* If domain is blank or unset, check challenge message for realm */ ! 277: if(!identity->Domain || !identity->DomainLength) { ! 278: for(;;) { ! 279: char value[DIGEST_MAX_VALUE_LENGTH]; ! 280: char content[DIGEST_MAX_CONTENT_LENGTH]; ! 281: ! 282: /* Pass all additional spaces here */ ! 283: while(*chlg && ISSPACE(*chlg)) ! 284: chlg++; ! 285: ! 286: /* Extract a value=content pair */ ! 287: if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { ! 288: if(strcasecompare(value, "realm")) { ! 289: ! 290: /* Setup identity's domain and length */ ! 291: domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); ! 292: if(!domain.tchar_ptr) ! 293: return CURLE_OUT_OF_MEMORY; ! 294: ! 295: dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); ! 296: if(!dup_domain.tchar_ptr) { ! 297: Curl_unicodefree(domain.tchar_ptr); ! 298: return CURLE_OUT_OF_MEMORY; ! 299: } ! 300: ! 301: free(identity->Domain); ! 302: identity->Domain = dup_domain.tbyte_ptr; ! 303: identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); ! 304: dup_domain.tchar_ptr = NULL; ! 305: ! 306: Curl_unicodefree(domain.tchar_ptr); ! 307: } ! 308: else { ! 309: /* Unknown specifier, ignore it! */ ! 310: } ! 311: } ! 312: else ! 313: break; /* We're done here */ ! 314: ! 315: /* Pass all additional spaces here */ ! 316: while(*chlg && ISSPACE(*chlg)) ! 317: chlg++; ! 318: ! 319: /* Allow the list to be comma-separated */ ! 320: if(',' == *chlg) ! 321: chlg++; ! 322: } ! 323: } ! 324: ! 325: return CURLE_OK; ! 326: } ! 327: ! 328: /* ! 329: * Curl_auth_decode_digest_http_message() ! 330: * ! 331: * This is used to decode a HTTP DIGEST challenge message into the separate ! 332: * attributes. ! 333: * ! 334: * Parameters: ! 335: * ! 336: * chlg [in] - The challenge message. ! 337: * digest [in/out] - The digest data struct being used and modified. ! 338: * ! 339: * Returns CURLE_OK on success. ! 340: */ ! 341: CURLcode Curl_auth_decode_digest_http_message(const char *chlg, ! 342: struct digestdata *digest) ! 343: { ! 344: size_t chlglen = strlen(chlg); ! 345: ! 346: /* We had an input token before so if there's another one now that means we ! 347: provided bad credentials in the previous request or it's stale. */ ! 348: if(digest->input_token) { ! 349: bool stale = false; ! 350: const char *p = chlg; ! 351: ! 352: /* Check for the 'stale' directive */ ! 353: for(;;) { ! 354: char value[DIGEST_MAX_VALUE_LENGTH]; ! 355: char content[DIGEST_MAX_CONTENT_LENGTH]; ! 356: ! 357: while(*p && ISSPACE(*p)) ! 358: p++; ! 359: ! 360: if(!Curl_auth_digest_get_pair(p, value, content, &p)) ! 361: break; ! 362: ! 363: if(strcasecompare(value, "stale") && ! 364: strcasecompare(content, "true")) { ! 365: stale = true; ! 366: break; ! 367: } ! 368: ! 369: while(*p && ISSPACE(*p)) ! 370: p++; ! 371: ! 372: if(',' == *p) ! 373: p++; ! 374: } ! 375: ! 376: if(stale) ! 377: Curl_auth_digest_cleanup(digest); ! 378: else ! 379: return CURLE_LOGIN_DENIED; ! 380: } ! 381: ! 382: /* Store the challenge for use later */ ! 383: digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); ! 384: if(!digest->input_token) ! 385: return CURLE_OUT_OF_MEMORY; ! 386: ! 387: digest->input_token_len = chlglen; ! 388: ! 389: return CURLE_OK; ! 390: } ! 391: ! 392: /* ! 393: * Curl_auth_create_digest_http_message() ! 394: * ! 395: * This is used to generate a HTTP DIGEST response message ready for sending ! 396: * to the recipient. ! 397: * ! 398: * Parameters: ! 399: * ! 400: * data [in] - The session handle. ! 401: * userp [in] - The user name in the format User or Domain\User. ! 402: * passwdp [in] - The user's password. ! 403: * request [in] - The HTTP request. ! 404: * uripath [in] - The path of the HTTP uri. ! 405: * digest [in/out] - The digest data struct being used and modified. ! 406: * outptr [in/out] - The address where a pointer to newly allocated memory ! 407: * holding the result will be stored upon completion. ! 408: * outlen [out] - The length of the output message. ! 409: * ! 410: * Returns CURLE_OK on success. ! 411: */ ! 412: CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, ! 413: const char *userp, ! 414: const char *passwdp, ! 415: const unsigned char *request, ! 416: const unsigned char *uripath, ! 417: struct digestdata *digest, ! 418: char **outptr, size_t *outlen) ! 419: { ! 420: size_t token_max; ! 421: char *resp; ! 422: BYTE *output_token; ! 423: size_t output_token_len = 0; ! 424: PSecPkgInfo SecurityPackage; ! 425: SecBuffer chlg_buf[5]; ! 426: SecBufferDesc chlg_desc; ! 427: SECURITY_STATUS status; ! 428: ! 429: (void) data; ! 430: ! 431: /* Query the security package for DigestSSP */ ! 432: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), ! 433: &SecurityPackage); ! 434: if(status != SEC_E_OK) ! 435: return CURLE_NOT_BUILT_IN; ! 436: ! 437: token_max = SecurityPackage->cbMaxToken; ! 438: ! 439: /* Release the package buffer as it is not required anymore */ ! 440: s_pSecFn->FreeContextBuffer(SecurityPackage); ! 441: ! 442: /* Allocate the output buffer according to the max token size as indicated ! 443: by the security package */ ! 444: output_token = malloc(token_max); ! 445: if(!output_token) { ! 446: return CURLE_OUT_OF_MEMORY; ! 447: } ! 448: ! 449: /* If the user/passwd that was used to make the identity for http_context ! 450: has changed then delete that context. */ ! 451: if((userp && !digest->user) || (!userp && digest->user) || ! 452: (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || ! 453: (userp && digest->user && strcmp(userp, digest->user)) || ! 454: (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { ! 455: if(digest->http_context) { ! 456: s_pSecFn->DeleteSecurityContext(digest->http_context); ! 457: Curl_safefree(digest->http_context); ! 458: } ! 459: Curl_safefree(digest->user); ! 460: Curl_safefree(digest->passwd); ! 461: } ! 462: ! 463: if(digest->http_context) { ! 464: chlg_desc.ulVersion = SECBUFFER_VERSION; ! 465: chlg_desc.cBuffers = 5; ! 466: chlg_desc.pBuffers = chlg_buf; ! 467: chlg_buf[0].BufferType = SECBUFFER_TOKEN; ! 468: chlg_buf[0].pvBuffer = NULL; ! 469: chlg_buf[0].cbBuffer = 0; ! 470: chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; ! 471: chlg_buf[1].pvBuffer = (void *) request; ! 472: chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); ! 473: chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; ! 474: chlg_buf[2].pvBuffer = (void *) uripath; ! 475: chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); ! 476: chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; ! 477: chlg_buf[3].pvBuffer = NULL; ! 478: chlg_buf[3].cbBuffer = 0; ! 479: chlg_buf[4].BufferType = SECBUFFER_PADDING; ! 480: chlg_buf[4].pvBuffer = output_token; ! 481: chlg_buf[4].cbBuffer = curlx_uztoul(token_max); ! 482: ! 483: status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); ! 484: if(status == SEC_E_OK) ! 485: output_token_len = chlg_buf[4].cbBuffer; ! 486: else { /* delete the context so a new one can be made */ ! 487: infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n", ! 488: (long)status); ! 489: s_pSecFn->DeleteSecurityContext(digest->http_context); ! 490: Curl_safefree(digest->http_context); ! 491: } ! 492: } ! 493: ! 494: if(!digest->http_context) { ! 495: CredHandle credentials; ! 496: SEC_WINNT_AUTH_IDENTITY identity; ! 497: SEC_WINNT_AUTH_IDENTITY *p_identity; ! 498: SecBuffer resp_buf; ! 499: SecBufferDesc resp_desc; ! 500: unsigned long attrs; ! 501: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ ! 502: TCHAR *spn; ! 503: ! 504: /* free the copy of user/passwd used to make the previous identity */ ! 505: Curl_safefree(digest->user); ! 506: Curl_safefree(digest->passwd); ! 507: ! 508: if(userp && *userp) { ! 509: /* Populate our identity structure */ ! 510: if(Curl_create_sspi_identity(userp, passwdp, &identity)) { ! 511: free(output_token); ! 512: return CURLE_OUT_OF_MEMORY; ! 513: } ! 514: ! 515: /* Populate our identity domain */ ! 516: if(Curl_override_sspi_http_realm((const char *) digest->input_token, ! 517: &identity)) { ! 518: free(output_token); ! 519: return CURLE_OUT_OF_MEMORY; ! 520: } ! 521: ! 522: /* Allow proper cleanup of the identity structure */ ! 523: p_identity = &identity; ! 524: } ! 525: else ! 526: /* Use the current Windows user */ ! 527: p_identity = NULL; ! 528: ! 529: if(userp) { ! 530: digest->user = strdup(userp); ! 531: ! 532: if(!digest->user) { ! 533: free(output_token); ! 534: return CURLE_OUT_OF_MEMORY; ! 535: } ! 536: } ! 537: ! 538: if(passwdp) { ! 539: digest->passwd = strdup(passwdp); ! 540: ! 541: if(!digest->passwd) { ! 542: free(output_token); ! 543: Curl_safefree(digest->user); ! 544: return CURLE_OUT_OF_MEMORY; ! 545: } ! 546: } ! 547: ! 548: /* Acquire our credentials handle */ ! 549: status = s_pSecFn->AcquireCredentialsHandle(NULL, ! 550: (TCHAR *) TEXT(SP_NAME_DIGEST), ! 551: SECPKG_CRED_OUTBOUND, NULL, ! 552: p_identity, NULL, NULL, ! 553: &credentials, &expiry); ! 554: if(status != SEC_E_OK) { ! 555: Curl_sspi_free_identity(p_identity); ! 556: free(output_token); ! 557: ! 558: return CURLE_LOGIN_DENIED; ! 559: } ! 560: ! 561: /* Setup the challenge "input" security buffer if present */ ! 562: chlg_desc.ulVersion = SECBUFFER_VERSION; ! 563: chlg_desc.cBuffers = 3; ! 564: chlg_desc.pBuffers = chlg_buf; ! 565: chlg_buf[0].BufferType = SECBUFFER_TOKEN; ! 566: chlg_buf[0].pvBuffer = digest->input_token; ! 567: chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); ! 568: chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; ! 569: chlg_buf[1].pvBuffer = (void *) request; ! 570: chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); ! 571: chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; ! 572: chlg_buf[2].pvBuffer = NULL; ! 573: chlg_buf[2].cbBuffer = 0; ! 574: ! 575: /* Setup the response "output" security buffer */ ! 576: resp_desc.ulVersion = SECBUFFER_VERSION; ! 577: resp_desc.cBuffers = 1; ! 578: resp_desc.pBuffers = &resp_buf; ! 579: resp_buf.BufferType = SECBUFFER_TOKEN; ! 580: resp_buf.pvBuffer = output_token; ! 581: resp_buf.cbBuffer = curlx_uztoul(token_max); ! 582: ! 583: spn = Curl_convert_UTF8_to_tchar((char *) uripath); ! 584: if(!spn) { ! 585: s_pSecFn->FreeCredentialsHandle(&credentials); ! 586: ! 587: Curl_sspi_free_identity(p_identity); ! 588: free(output_token); ! 589: ! 590: return CURLE_OUT_OF_MEMORY; ! 591: } ! 592: ! 593: /* Allocate our new context handle */ ! 594: digest->http_context = calloc(1, sizeof(CtxtHandle)); ! 595: if(!digest->http_context) ! 596: return CURLE_OUT_OF_MEMORY; ! 597: ! 598: /* Generate our response message */ ! 599: status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, ! 600: spn, ! 601: ISC_REQ_USE_HTTP_STYLE, 0, 0, ! 602: &chlg_desc, 0, ! 603: digest->http_context, ! 604: &resp_desc, &attrs, &expiry); ! 605: Curl_unicodefree(spn); ! 606: ! 607: if(status == SEC_I_COMPLETE_NEEDED || ! 608: status == SEC_I_COMPLETE_AND_CONTINUE) ! 609: s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); ! 610: else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { ! 611: s_pSecFn->FreeCredentialsHandle(&credentials); ! 612: ! 613: Curl_sspi_free_identity(p_identity); ! 614: free(output_token); ! 615: ! 616: Curl_safefree(digest->http_context); ! 617: ! 618: if(status == SEC_E_INSUFFICIENT_MEMORY) ! 619: return CURLE_OUT_OF_MEMORY; ! 620: ! 621: return CURLE_AUTH_ERROR; ! 622: } ! 623: ! 624: output_token_len = resp_buf.cbBuffer; ! 625: ! 626: s_pSecFn->FreeCredentialsHandle(&credentials); ! 627: Curl_sspi_free_identity(p_identity); ! 628: } ! 629: ! 630: resp = malloc(output_token_len + 1); ! 631: if(!resp) { ! 632: free(output_token); ! 633: ! 634: return CURLE_OUT_OF_MEMORY; ! 635: } ! 636: ! 637: /* Copy the generated response */ ! 638: memcpy(resp, output_token, output_token_len); ! 639: resp[output_token_len] = 0; ! 640: ! 641: /* Return the response */ ! 642: *outptr = resp; ! 643: *outlen = output_token_len; ! 644: ! 645: /* Free the response buffer */ ! 646: free(output_token); ! 647: ! 648: return CURLE_OK; ! 649: } ! 650: ! 651: /* ! 652: * Curl_auth_digest_cleanup() ! 653: * ! 654: * This is used to clean up the digest specific data. ! 655: * ! 656: * Parameters: ! 657: * ! 658: * digest [in/out] - The digest data struct being cleaned up. ! 659: * ! 660: */ ! 661: void Curl_auth_digest_cleanup(struct digestdata *digest) ! 662: { ! 663: /* Free the input token */ ! 664: Curl_safefree(digest->input_token); ! 665: ! 666: /* Reset any variables */ ! 667: digest->input_token_len = 0; ! 668: ! 669: /* Delete security context */ ! 670: if(digest->http_context) { ! 671: s_pSecFn->DeleteSecurityContext(digest->http_context); ! 672: Curl_safefree(digest->http_context); ! 673: } ! 674: ! 675: /* Free the copy of user/passwd used to make the identity for http_context */ ! 676: Curl_safefree(digest->user); ! 677: Curl_safefree(digest->passwd); ! 678: } ! 679: ! 680: #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */