2
0

digest_sspi.c 21 KB

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