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 */ |
681 | |