Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/vauth/digest_sspi.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 */ |
