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 #include "curl_setup.h"
00026
00027 #if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
00028
00029 #include <curl/curl.h>
00030
00031 #include "vauth/vauth.h"
00032 #include "urldata.h"
00033 #include "curl_base64.h"
00034 #include "warnless.h"
00035 #include "curl_multibyte.h"
00036 #include "sendf.h"
00037
00038
00039 #include "curl_memory.h"
00040 #include "memdebug.h"
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 bool Curl_auth_is_gssapi_supported(void)
00052 {
00053 PSecPkgInfo SecurityPackage;
00054 SECURITY_STATUS status;
00055
00056
00057 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
00058 TEXT(SP_NAME_KERBEROS),
00059 &SecurityPackage);
00060
00061 return (status == SEC_E_OK ? TRUE : FALSE);
00062 }
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
00088 const char *userp,
00089 const char *passwdp,
00090 const char *service,
00091 const char *host,
00092 const bool mutual_auth,
00093 const char *chlg64,
00094 struct kerberos5data *krb5,
00095 char **outptr, size_t *outlen)
00096 {
00097 CURLcode result = CURLE_OK;
00098 size_t chlglen = 0;
00099 unsigned char *chlg = NULL;
00100 CtxtHandle context;
00101 PSecPkgInfo SecurityPackage;
00102 SecBuffer chlg_buf;
00103 SecBuffer resp_buf;
00104 SecBufferDesc chlg_desc;
00105 SecBufferDesc resp_desc;
00106 SECURITY_STATUS status;
00107 unsigned long attrs;
00108 TimeStamp expiry;
00109
00110 if(!krb5->spn) {
00111
00112 krb5->spn = Curl_auth_build_spn(service, host, NULL);
00113 if(!krb5->spn)
00114 return CURLE_OUT_OF_MEMORY;
00115 }
00116
00117 if(!krb5->output_token) {
00118
00119 status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
00120 TEXT(SP_NAME_KERBEROS),
00121 &SecurityPackage);
00122 if(status != SEC_E_OK) {
00123 return CURLE_NOT_BUILT_IN;
00124 }
00125
00126 krb5->token_max = SecurityPackage->cbMaxToken;
00127
00128
00129 s_pSecFn->FreeContextBuffer(SecurityPackage);
00130
00131
00132 krb5->output_token = malloc(krb5->token_max);
00133 if(!krb5->output_token)
00134 return CURLE_OUT_OF_MEMORY;
00135 }
00136
00137 if(!krb5->credentials) {
00138
00139 if(userp && *userp) {
00140
00141 result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
00142 if(result)
00143 return result;
00144
00145
00146 krb5->p_identity = &krb5->identity;
00147 }
00148 else
00149
00150 krb5->p_identity = NULL;
00151
00152
00153 krb5->credentials = malloc(sizeof(CredHandle));
00154 if(!krb5->credentials)
00155 return CURLE_OUT_OF_MEMORY;
00156
00157 memset(krb5->credentials, 0, sizeof(CredHandle));
00158
00159
00160 status = s_pSecFn->AcquireCredentialsHandle(NULL,
00161 (TCHAR *)
00162 TEXT(SP_NAME_KERBEROS),
00163 SECPKG_CRED_OUTBOUND, NULL,
00164 krb5->p_identity, NULL, NULL,
00165 krb5->credentials, &expiry);
00166 if(status != SEC_E_OK)
00167 return CURLE_LOGIN_DENIED;
00168
00169
00170 krb5->context = malloc(sizeof(CtxtHandle));
00171 if(!krb5->context)
00172 return CURLE_OUT_OF_MEMORY;
00173
00174 memset(krb5->context, 0, sizeof(CtxtHandle));
00175 }
00176
00177 if(chlg64 && *chlg64) {
00178
00179 if(*chlg64 != '=') {
00180 result = Curl_base64_decode(chlg64, &chlg, &chlglen);
00181 if(result)
00182 return result;
00183 }
00184
00185
00186 if(!chlg) {
00187 infof(data, "GSSAPI handshake failure (empty challenge message)\n");
00188
00189 return CURLE_BAD_CONTENT_ENCODING;
00190 }
00191
00192
00193 chlg_desc.ulVersion = SECBUFFER_VERSION;
00194 chlg_desc.cBuffers = 1;
00195 chlg_desc.pBuffers = &chlg_buf;
00196 chlg_buf.BufferType = SECBUFFER_TOKEN;
00197 chlg_buf.pvBuffer = chlg;
00198 chlg_buf.cbBuffer = curlx_uztoul(chlglen);
00199 }
00200
00201
00202 resp_desc.ulVersion = SECBUFFER_VERSION;
00203 resp_desc.cBuffers = 1;
00204 resp_desc.pBuffers = &resp_buf;
00205 resp_buf.BufferType = SECBUFFER_TOKEN;
00206 resp_buf.pvBuffer = krb5->output_token;
00207 resp_buf.cbBuffer = curlx_uztoul(krb5->token_max);
00208
00209
00210 status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
00211 chlg ? krb5->context : NULL,
00212 krb5->spn,
00213 (mutual_auth ?
00214 ISC_REQ_MUTUAL_AUTH : 0),
00215 0, SECURITY_NATIVE_DREP,
00216 chlg ? &chlg_desc : NULL, 0,
00217 &context,
00218 &resp_desc, &attrs,
00219 &expiry);
00220
00221
00222 free(chlg);
00223
00224 if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
00225 return CURLE_RECV_ERROR;
00226 }
00227
00228 if(memcmp(&context, krb5->context, sizeof(context))) {
00229 s_pSecFn->DeleteSecurityContext(krb5->context);
00230
00231 memcpy(krb5->context, &context, sizeof(context));
00232 }
00233
00234 if(resp_buf.cbBuffer) {
00235
00236 result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer,
00237 resp_buf.cbBuffer, outptr, outlen);
00238 }
00239 else if(mutual_auth) {
00240 *outptr = strdup("");
00241 if(!*outptr)
00242 result = CURLE_OUT_OF_MEMORY;
00243 }
00244
00245 return result;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
00266 const char *chlg64,
00267 struct kerberos5data *krb5,
00268 char **outptr,
00269 size_t *outlen)
00270 {
00271 CURLcode result = CURLE_OK;
00272 size_t offset = 0;
00273 size_t chlglen = 0;
00274 size_t messagelen = 0;
00275 size_t appdatalen = 0;
00276 unsigned char *chlg = NULL;
00277 unsigned char *trailer = NULL;
00278 unsigned char *message = NULL;
00279 unsigned char *padding = NULL;
00280 unsigned char *appdata = NULL;
00281 SecBuffer input_buf[2];
00282 SecBuffer wrap_buf[3];
00283 SecBufferDesc input_desc;
00284 SecBufferDesc wrap_desc;
00285 unsigned long indata = 0;
00286 unsigned long outdata = 0;
00287 unsigned long qop = 0;
00288 unsigned long sec_layer = 0;
00289 unsigned long max_size = 0;
00290 SecPkgContext_Sizes sizes;
00291 SecPkgCredentials_Names names;
00292 SECURITY_STATUS status;
00293 char *user_name;
00294
00295
00296 if(strlen(chlg64) && *chlg64 != '=') {
00297 result = Curl_base64_decode(chlg64, &chlg, &chlglen);
00298 if(result)
00299 return result;
00300 }
00301
00302
00303 if(!chlg) {
00304 infof(data, "GSSAPI handshake failure (empty security message)\n");
00305
00306 return CURLE_BAD_CONTENT_ENCODING;
00307 }
00308
00309
00310 status = s_pSecFn->QueryContextAttributes(krb5->context,
00311 SECPKG_ATTR_SIZES,
00312 &sizes);
00313 if(status != SEC_E_OK) {
00314 free(chlg);
00315
00316 return CURLE_OUT_OF_MEMORY;
00317 }
00318
00319
00320 status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
00321 SECPKG_CRED_ATTR_NAMES,
00322 &names);
00323 if(status != SEC_E_OK) {
00324 free(chlg);
00325
00326 return CURLE_RECV_ERROR;
00327 }
00328
00329
00330 input_desc.ulVersion = SECBUFFER_VERSION;
00331 input_desc.cBuffers = 2;
00332 input_desc.pBuffers = input_buf;
00333 input_buf[0].BufferType = SECBUFFER_STREAM;
00334 input_buf[0].pvBuffer = chlg;
00335 input_buf[0].cbBuffer = curlx_uztoul(chlglen);
00336 input_buf[1].BufferType = SECBUFFER_DATA;
00337 input_buf[1].pvBuffer = NULL;
00338 input_buf[1].cbBuffer = 0;
00339
00340
00341 status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
00342 if(status != SEC_E_OK) {
00343 infof(data, "GSSAPI handshake failure (empty security message)\n");
00344
00345 free(chlg);
00346
00347 return CURLE_BAD_CONTENT_ENCODING;
00348 }
00349
00350
00351 if(input_buf[1].cbBuffer != 4) {
00352 infof(data, "GSSAPI handshake failure (invalid security data)\n");
00353
00354 free(chlg);
00355
00356 return CURLE_BAD_CONTENT_ENCODING;
00357 }
00358
00359
00360 memcpy(&indata, input_buf[1].pvBuffer, 4);
00361 s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
00362 free(chlg);
00363
00364
00365 sec_layer = indata & 0x000000FF;
00366 if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
00367 infof(data, "GSSAPI handshake failure (invalid security layer)\n");
00368
00369 return CURLE_BAD_CONTENT_ENCODING;
00370 }
00371
00372
00373 max_size = ntohl(indata & 0xFFFFFF00);
00374 if(max_size > 0) {
00375
00376
00377
00378 max_size = 0;
00379 }
00380
00381
00382 trailer = malloc(sizes.cbSecurityTrailer);
00383 if(!trailer)
00384 return CURLE_OUT_OF_MEMORY;
00385
00386
00387 user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
00388 if(!user_name) {
00389 free(trailer);
00390
00391 return CURLE_OUT_OF_MEMORY;
00392 }
00393
00394
00395 messagelen = sizeof(outdata) + strlen(user_name) + 1;
00396 message = malloc(messagelen);
00397 if(!message) {
00398 free(trailer);
00399 Curl_unicodefree(user_name);
00400
00401 return CURLE_OUT_OF_MEMORY;
00402 }
00403
00404
00405
00406
00407
00408
00409 outdata = htonl(max_size) | sec_layer;
00410 memcpy(message, &outdata, sizeof(outdata));
00411 strcpy((char *) message + sizeof(outdata), user_name);
00412 Curl_unicodefree(user_name);
00413
00414
00415 padding = malloc(sizes.cbBlockSize);
00416 if(!padding) {
00417 free(message);
00418 free(trailer);
00419
00420 return CURLE_OUT_OF_MEMORY;
00421 }
00422
00423
00424 wrap_desc.ulVersion = SECBUFFER_VERSION;
00425 wrap_desc.cBuffers = 3;
00426 wrap_desc.pBuffers = wrap_buf;
00427 wrap_buf[0].BufferType = SECBUFFER_TOKEN;
00428 wrap_buf[0].pvBuffer = trailer;
00429 wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer;
00430 wrap_buf[1].BufferType = SECBUFFER_DATA;
00431 wrap_buf[1].pvBuffer = message;
00432 wrap_buf[1].cbBuffer = curlx_uztoul(messagelen);
00433 wrap_buf[2].BufferType = SECBUFFER_PADDING;
00434 wrap_buf[2].pvBuffer = padding;
00435 wrap_buf[2].cbBuffer = sizes.cbBlockSize;
00436
00437
00438 status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
00439 &wrap_desc, 0);
00440 if(status != SEC_E_OK) {
00441 free(padding);
00442 free(message);
00443 free(trailer);
00444
00445 return CURLE_OUT_OF_MEMORY;
00446 }
00447
00448
00449 appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
00450 wrap_buf[2].cbBuffer;
00451 appdata = malloc(appdatalen);
00452 if(!appdata) {
00453 free(padding);
00454 free(message);
00455 free(trailer);
00456
00457 return CURLE_OUT_OF_MEMORY;
00458 }
00459
00460
00461 memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
00462 offset += wrap_buf[0].cbBuffer;
00463 memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
00464 offset += wrap_buf[1].cbBuffer;
00465 memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
00466
00467
00468 result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr,
00469 outlen);
00470
00471
00472 free(appdata);
00473 free(padding);
00474 free(message);
00475 free(trailer);
00476
00477 return result;
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
00491 {
00492
00493 if(krb5->context) {
00494 s_pSecFn->DeleteSecurityContext(krb5->context);
00495 free(krb5->context);
00496 krb5->context = NULL;
00497 }
00498
00499
00500 if(krb5->credentials) {
00501 s_pSecFn->FreeCredentialsHandle(krb5->credentials);
00502 free(krb5->credentials);
00503 krb5->credentials = NULL;
00504 }
00505
00506
00507 Curl_sspi_free_identity(krb5->p_identity);
00508 krb5->p_identity = NULL;
00509
00510
00511 Curl_safefree(krb5->spn);
00512 Curl_safefree(krb5->output_token);
00513
00514
00515 krb5->token_max = 0;
00516 }
00517
00518 #endif