00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "curl_setup.h"
00027
00028 #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH)
00029
00030 #include <curl/curl.h>
00031
00032 #include "vauth/vauth.h"
00033 #include "vauth/digest.h"
00034 #include "urldata.h"
00035 #include "curl_base64.h"
00036 #include "warnless.h"
00037 #include "curl_multibyte.h"
00038 #include "sendf.h"
00039 #include "strdup.h"
00040 #include "strcase.h"
00041
00042
00043 #include "curl_memory.h"
00044 #include "memdebug.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 bool Curl_auth_is_digest_supported(void)
00056 {
00057 PSecPkgInfo SecurityPackage;
00058 SECURITY_STATUS status;
00059
00060
00061 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
00062 &SecurityPackage);
00063
00064 return (status == SEC_E_OK ? TRUE : FALSE);
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
00087 const char *chlg64,
00088 const char *userp,
00089 const char *passwdp,
00090 const char *service,
00091 char **outptr, size_t *outlen)
00092 {
00093 CURLcode result = CURLE_OK;
00094 TCHAR *spn = NULL;
00095 size_t chlglen = 0;
00096 size_t token_max = 0;
00097 unsigned char *input_token = NULL;
00098 unsigned char *output_token = NULL;
00099 CredHandle credentials;
00100 CtxtHandle context;
00101 PSecPkgInfo SecurityPackage;
00102 SEC_WINNT_AUTH_IDENTITY identity;
00103 SEC_WINNT_AUTH_IDENTITY *p_identity;
00104 SecBuffer chlg_buf;
00105 SecBuffer resp_buf;
00106 SecBufferDesc chlg_desc;
00107 SecBufferDesc resp_desc;
00108 SECURITY_STATUS status;
00109 unsigned long attrs;
00110 TimeStamp expiry;
00111
00112
00113 if(strlen(chlg64) && *chlg64 != '=') {
00114 result = Curl_base64_decode(chlg64, &input_token, &chlglen);
00115 if(result)
00116 return result;
00117 }
00118
00119
00120 if(!input_token) {
00121 infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
00122
00123 return CURLE_BAD_CONTENT_ENCODING;
00124 }
00125
00126
00127 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
00128 &SecurityPackage);
00129 if(status != SEC_E_OK) {
00130 free(input_token);
00131
00132 return CURLE_NOT_BUILT_IN;
00133 }
00134
00135 token_max = SecurityPackage->cbMaxToken;
00136
00137
00138 s_pSecFn->FreeContextBuffer(SecurityPackage);
00139
00140
00141 output_token = malloc(token_max);
00142 if(!output_token) {
00143 free(input_token);
00144
00145 return CURLE_OUT_OF_MEMORY;
00146 }
00147
00148
00149 spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL);
00150 if(!spn) {
00151 free(output_token);
00152 free(input_token);
00153
00154 return CURLE_OUT_OF_MEMORY;
00155 }
00156
00157 if(userp && *userp) {
00158
00159 result = Curl_create_sspi_identity(userp, passwdp, &identity);
00160 if(result) {
00161 free(spn);
00162 free(output_token);
00163 free(input_token);
00164
00165 return result;
00166 }
00167
00168
00169 p_identity = &identity;
00170 }
00171 else
00172
00173 p_identity = NULL;
00174
00175
00176 status = s_pSecFn->AcquireCredentialsHandle(NULL,
00177 (TCHAR *) TEXT(SP_NAME_DIGEST),
00178 SECPKG_CRED_OUTBOUND, NULL,
00179 p_identity, NULL, NULL,
00180 &credentials, &expiry);
00181
00182 if(status != SEC_E_OK) {
00183 Curl_sspi_free_identity(p_identity);
00184 free(spn);
00185 free(output_token);
00186 free(input_token);
00187
00188 return CURLE_LOGIN_DENIED;
00189 }
00190
00191
00192 chlg_desc.ulVersion = SECBUFFER_VERSION;
00193 chlg_desc.cBuffers = 1;
00194 chlg_desc.pBuffers = &chlg_buf;
00195 chlg_buf.BufferType = SECBUFFER_TOKEN;
00196 chlg_buf.pvBuffer = input_token;
00197 chlg_buf.cbBuffer = curlx_uztoul(chlglen);
00198
00199
00200 resp_desc.ulVersion = SECBUFFER_VERSION;
00201 resp_desc.cBuffers = 1;
00202 resp_desc.pBuffers = &resp_buf;
00203 resp_buf.BufferType = SECBUFFER_TOKEN;
00204 resp_buf.pvBuffer = output_token;
00205 resp_buf.cbBuffer = curlx_uztoul(token_max);
00206
00207
00208 status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
00209 0, 0, 0, &chlg_desc, 0,
00210 &context, &resp_desc, &attrs,
00211 &expiry);
00212
00213 if(status == SEC_I_COMPLETE_NEEDED ||
00214 status == SEC_I_COMPLETE_AND_CONTINUE)
00215 s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
00216 else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
00217 s_pSecFn->FreeCredentialsHandle(&credentials);
00218 Curl_sspi_free_identity(p_identity);
00219 free(spn);
00220 free(output_token);
00221 free(input_token);
00222
00223 return CURLE_RECV_ERROR;
00224 }
00225
00226
00227 result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
00228 outptr, outlen);
00229
00230
00231 s_pSecFn->DeleteSecurityContext(&context);
00232 s_pSecFn->FreeCredentialsHandle(&credentials);
00233
00234
00235 Curl_sspi_free_identity(p_identity);
00236
00237
00238 free(spn);
00239
00240
00241 free(output_token);
00242
00243
00244 free(input_token);
00245
00246 return result;
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 CURLcode Curl_override_sspi_http_realm(const char *chlg,
00264 SEC_WINNT_AUTH_IDENTITY *identity)
00265 {
00266 xcharp_u domain, dup_domain;
00267
00268
00269 if(!identity->Domain || !identity->DomainLength) {
00270 for(;;) {
00271 char value[DIGEST_MAX_VALUE_LENGTH];
00272 char content[DIGEST_MAX_CONTENT_LENGTH];
00273
00274
00275 while(*chlg && ISSPACE(*chlg))
00276 chlg++;
00277
00278
00279 if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
00280 if(strcasecompare(value, "realm")) {
00281
00282
00283 domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content);
00284 if(!domain.tchar_ptr)
00285 return CURLE_OUT_OF_MEMORY;
00286
00287 dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
00288 if(!dup_domain.tchar_ptr) {
00289 Curl_unicodefree(domain.tchar_ptr);
00290 return CURLE_OUT_OF_MEMORY;
00291 }
00292
00293 free(identity->Domain);
00294 identity->Domain = dup_domain.tbyte_ptr;
00295 identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
00296 dup_domain.tchar_ptr = NULL;
00297
00298 Curl_unicodefree(domain.tchar_ptr);
00299 }
00300 else {
00301
00302 }
00303 }
00304 else
00305 break;
00306
00307
00308 while(*chlg && ISSPACE(*chlg))
00309 chlg++;
00310
00311
00312 if(',' == *chlg)
00313 chlg++;
00314 }
00315 }
00316
00317 return CURLE_OK;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
00334 struct digestdata *digest)
00335 {
00336 size_t chlglen = strlen(chlg);
00337
00338
00339
00340 if(digest->input_token)
00341 return CURLE_BAD_CONTENT_ENCODING;
00342
00343
00344 digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen);
00345 if(!digest->input_token)
00346 return CURLE_OUT_OF_MEMORY;
00347
00348 digest->input_token_len = chlglen;
00349
00350 return CURLE_OK;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
00374 const char *userp,
00375 const char *passwdp,
00376 const unsigned char *request,
00377 const unsigned char *uripath,
00378 struct digestdata *digest,
00379 char **outptr, size_t *outlen)
00380 {
00381 size_t token_max;
00382 CredHandle credentials;
00383 CtxtHandle context;
00384 char *resp;
00385 BYTE *output_token;
00386 PSecPkgInfo SecurityPackage;
00387 SEC_WINNT_AUTH_IDENTITY identity;
00388 SEC_WINNT_AUTH_IDENTITY *p_identity;
00389 SecBuffer chlg_buf[3];
00390 SecBuffer resp_buf;
00391 SecBufferDesc chlg_desc;
00392 SecBufferDesc resp_desc;
00393 SECURITY_STATUS status;
00394 unsigned long attrs;
00395 TimeStamp expiry;
00396 TCHAR *spn;
00397
00398 (void) data;
00399
00400
00401 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
00402 &SecurityPackage);
00403 if(status != SEC_E_OK)
00404 return CURLE_NOT_BUILT_IN;
00405
00406 token_max = SecurityPackage->cbMaxToken;
00407
00408
00409 s_pSecFn->FreeContextBuffer(SecurityPackage);
00410
00411 if(userp && *userp) {
00412
00413 if(Curl_create_sspi_identity(userp, passwdp, &identity))
00414 return CURLE_OUT_OF_MEMORY;
00415
00416
00417 if(Curl_override_sspi_http_realm((const char *) digest->input_token,
00418 &identity))
00419 return CURLE_OUT_OF_MEMORY;
00420
00421
00422 p_identity = &identity;
00423 }
00424 else
00425
00426 p_identity = NULL;
00427
00428
00429 status = s_pSecFn->AcquireCredentialsHandle(NULL,
00430 (TCHAR *) TEXT(SP_NAME_DIGEST),
00431 SECPKG_CRED_OUTBOUND, NULL,
00432 p_identity, NULL, NULL,
00433 &credentials, &expiry);
00434 if(status != SEC_E_OK) {
00435 Curl_sspi_free_identity(p_identity);
00436
00437 return CURLE_LOGIN_DENIED;
00438 }
00439
00440
00441
00442 output_token = malloc(token_max);
00443 if(!output_token) {
00444 s_pSecFn->FreeCredentialsHandle(&credentials);
00445
00446 Curl_sspi_free_identity(p_identity);
00447
00448 return CURLE_OUT_OF_MEMORY;
00449 }
00450
00451
00452 chlg_desc.ulVersion = SECBUFFER_VERSION;
00453 chlg_desc.cBuffers = 3;
00454 chlg_desc.pBuffers = chlg_buf;
00455 chlg_buf[0].BufferType = SECBUFFER_TOKEN;
00456 chlg_buf[0].pvBuffer = digest->input_token;
00457 chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len);
00458 chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
00459 chlg_buf[1].pvBuffer = (void *) request;
00460 chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request));
00461 chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
00462 chlg_buf[2].pvBuffer = NULL;
00463 chlg_buf[2].cbBuffer = 0;
00464
00465
00466 resp_desc.ulVersion = SECBUFFER_VERSION;
00467 resp_desc.cBuffers = 1;
00468 resp_desc.pBuffers = &resp_buf;
00469 resp_buf.BufferType = SECBUFFER_TOKEN;
00470 resp_buf.pvBuffer = output_token;
00471 resp_buf.cbBuffer = curlx_uztoul(token_max);
00472
00473 spn = Curl_convert_UTF8_to_tchar((char *) uripath);
00474 if(!spn) {
00475 s_pSecFn->FreeCredentialsHandle(&credentials);
00476
00477 Curl_sspi_free_identity(p_identity);
00478 free(output_token);
00479
00480 return CURLE_OUT_OF_MEMORY;
00481 }
00482
00483
00484 status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
00485 spn,
00486 ISC_REQ_USE_HTTP_STYLE, 0, 0,
00487 &chlg_desc, 0, &context,
00488 &resp_desc, &attrs, &expiry);
00489 Curl_unicodefree(spn);
00490
00491 if(status == SEC_I_COMPLETE_NEEDED ||
00492 status == SEC_I_COMPLETE_AND_CONTINUE)
00493 s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
00494 else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
00495 s_pSecFn->FreeCredentialsHandle(&credentials);
00496
00497 Curl_sspi_free_identity(p_identity);
00498 free(output_token);
00499
00500 return CURLE_OUT_OF_MEMORY;
00501 }
00502
00503 resp = malloc(resp_buf.cbBuffer + 1);
00504 if(!resp) {
00505 s_pSecFn->DeleteSecurityContext(&context);
00506 s_pSecFn->FreeCredentialsHandle(&credentials);
00507
00508 Curl_sspi_free_identity(p_identity);
00509 free(output_token);
00510
00511 return CURLE_OUT_OF_MEMORY;
00512 }
00513
00514
00515 memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer);
00516 resp[resp_buf.cbBuffer] = 0x00;
00517
00518
00519 *outptr = resp;
00520 *outlen = resp_buf.cbBuffer;
00521
00522
00523 s_pSecFn->DeleteSecurityContext(&context);
00524 s_pSecFn->FreeCredentialsHandle(&credentials);
00525
00526
00527 Curl_sspi_free_identity(p_identity);
00528
00529
00530 free(output_token);
00531
00532 return CURLE_OK;
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 void Curl_auth_digest_cleanup(struct digestdata *digest)
00546 {
00547
00548 Curl_safefree(digest->input_token);
00549
00550
00551 digest->input_token_len = 0;
00552 }
00553
00554 #endif