1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * Copyright (C) Markus Moeller, <markus_moeller@compuserve.com> 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 * SPDX-License-Identifier: curl 23 * 24 ***************************************************************************/ 25 26#include "curl_setup.h" 27 28#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) 29 30#include "urldata.h" 31#include "sendf.h" 32#include "cfilters.h" 33#include "connect.h" 34#include "strerror.h" 35#include "timeval.h" 36#include "socks.h" 37#include "curl_sspi.h" 38#include "curl_multibyte.h" 39#include "warnless.h" 40#include "strdup.h" 41/* The last 3 #include files should be in this order */ 42#include "curl_printf.h" 43#include "curl_memory.h" 44#include "memdebug.h" 45 46/* 47 * Helper sspi error functions. 48 */ 49static int check_sspi_err(struct Curl_easy *data, 50 SECURITY_STATUS status, 51 const char *function) 52{ 53 if(status != SEC_E_OK && 54 status != SEC_I_COMPLETE_AND_CONTINUE && 55 status != SEC_I_COMPLETE_NEEDED && 56 status != SEC_I_CONTINUE_NEEDED) { 57 char buffer[STRERROR_LEN]; 58 failf(data, "SSPI error: %s failed: %s", function, 59 Curl_sspi_strerror(status, buffer, sizeof(buffer))); 60 return 1; 61 } 62 return 0; 63} 64 65/* This is the SSPI-using version of this function */ 66CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, 67 struct Curl_easy *data) 68{ 69 struct connectdata *conn = cf->conn; 70 curl_socket_t sock = conn->sock[cf->sockindex]; 71 CURLcode code; 72 ssize_t actualread; 73 ssize_t written; 74 int result; 75 /* Needs GSS-API authentication */ 76 SECURITY_STATUS status; 77 unsigned long sspi_ret_flags = 0; 78 unsigned char gss_enc; 79 SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; 80 SecBufferDesc input_desc, output_desc, wrap_desc; 81 SecPkgContext_Sizes sspi_sizes; 82 CredHandle cred_handle; 83 CtxtHandle sspi_context; 84 PCtxtHandle context_handle = NULL; 85 SecPkgCredentials_Names names; 86 TimeStamp expiry; 87 char *service_name = NULL; 88 unsigned short us_length; 89 unsigned long qop; 90 unsigned char socksreq[4]; /* room for GSS-API exchange header only */ 91 const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? 92 data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; 93 const size_t service_length = strlen(service); 94 95 /* GSS-API request looks like 96 * +----+------+-----+----------------+ 97 * |VER | MTYP | LEN | TOKEN | 98 * +----+------+----------------------+ 99 * | 1 | 1 | 2 | up to 2^16 - 1 | 100 * +----+------+-----+----------------+ 101 */ 102 103 /* prepare service name */ 104 if(strchr(service, '/')) { 105 service_name = strdup(service); 106 if(!service_name) 107 return CURLE_OUT_OF_MEMORY; 108 } 109 else { 110 service_name = malloc(service_length + 111 strlen(conn->socks_proxy.host.name) + 2); 112 if(!service_name) 113 return CURLE_OUT_OF_MEMORY; 114 msnprintf(service_name, service_length + 115 strlen(conn->socks_proxy.host.name) + 2, "%s/%s", 116 service, conn->socks_proxy.host.name); 117 } 118 119 input_desc.cBuffers = 1; 120 input_desc.pBuffers = &sspi_recv_token; 121 input_desc.ulVersion = SECBUFFER_VERSION; 122 123 sspi_recv_token.BufferType = SECBUFFER_TOKEN; 124 sspi_recv_token.cbBuffer = 0; 125 sspi_recv_token.pvBuffer = NULL; 126 127 output_desc.cBuffers = 1; 128 output_desc.pBuffers = &sspi_send_token; 129 output_desc.ulVersion = SECBUFFER_VERSION; 130 131 sspi_send_token.BufferType = SECBUFFER_TOKEN; 132 sspi_send_token.cbBuffer = 0; 133 sspi_send_token.pvBuffer = NULL; 134 135 wrap_desc.cBuffers = 3; 136 wrap_desc.pBuffers = sspi_w_token; 137 wrap_desc.ulVersion = SECBUFFER_VERSION; 138 139 cred_handle.dwLower = 0; 140 cred_handle.dwUpper = 0; 141 142 status = s_pSecFn->AcquireCredentialsHandle(NULL, 143 (TCHAR *) TEXT("Kerberos"), 144 SECPKG_CRED_OUTBOUND, 145 NULL, 146 NULL, 147 NULL, 148 NULL, 149 &cred_handle, 150 &expiry); 151 152 if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { 153 failf(data, "Failed to acquire credentials."); 154 free(service_name); 155 s_pSecFn->FreeCredentialsHandle(&cred_handle); 156 return CURLE_COULDNT_CONNECT; 157 } 158 159 (void)curlx_nonblock(sock, FALSE); 160 161 /* As long as we need to keep sending some context info, and there's no */ 162 /* errors, keep sending it... */ 163 for(;;) { 164 TCHAR *sname; 165 166 sname = curlx_convert_UTF8_to_tchar(service_name); 167 if(!sname) 168 return CURLE_OUT_OF_MEMORY; 169 170 status = s_pSecFn->InitializeSecurityContext(&cred_handle, 171 context_handle, 172 sname, 173 ISC_REQ_MUTUAL_AUTH | 174 ISC_REQ_ALLOCATE_MEMORY | 175 ISC_REQ_CONFIDENTIALITY | 176 ISC_REQ_REPLAY_DETECT, 177 0, 178 SECURITY_NATIVE_DREP, 179 &input_desc, 180 0, 181 &sspi_context, 182 &output_desc, 183 &sspi_ret_flags, 184 &expiry); 185 186 curlx_unicodefree(sname); 187 188 if(sspi_recv_token.pvBuffer) { 189 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 190 sspi_recv_token.pvBuffer = NULL; 191 sspi_recv_token.cbBuffer = 0; 192 } 193 194 if(check_sspi_err(data, status, "InitializeSecurityContext")) { 195 free(service_name); 196 s_pSecFn->FreeCredentialsHandle(&cred_handle); 197 s_pSecFn->DeleteSecurityContext(&sspi_context); 198 if(sspi_recv_token.pvBuffer) 199 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 200 failf(data, "Failed to initialise security context."); 201 return CURLE_COULDNT_CONNECT; 202 } 203 204 if(sspi_send_token.cbBuffer) { 205 socksreq[0] = 1; /* GSS-API subnegotiation version */ 206 socksreq[1] = 1; /* authentication message type */ 207 us_length = htons((short)sspi_send_token.cbBuffer); 208 memcpy(socksreq + 2, &us_length, sizeof(short)); 209 210 written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); 211 if(code || (4 != written)) { 212 failf(data, "Failed to send SSPI authentication request."); 213 free(service_name); 214 if(sspi_send_token.pvBuffer) 215 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 216 if(sspi_recv_token.pvBuffer) 217 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 218 s_pSecFn->FreeCredentialsHandle(&cred_handle); 219 s_pSecFn->DeleteSecurityContext(&sspi_context); 220 return CURLE_COULDNT_CONNECT; 221 } 222 223 written = Curl_conn_cf_send(cf->next, data, 224 (char *)sspi_send_token.pvBuffer, 225 sspi_send_token.cbBuffer, &code); 226 if(code || (sspi_send_token.cbBuffer != (size_t)written)) { 227 failf(data, "Failed to send SSPI authentication token."); 228 free(service_name); 229 if(sspi_send_token.pvBuffer) 230 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 231 if(sspi_recv_token.pvBuffer) 232 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 233 s_pSecFn->FreeCredentialsHandle(&cred_handle); 234 s_pSecFn->DeleteSecurityContext(&sspi_context); 235 return CURLE_COULDNT_CONNECT; 236 } 237 238 } 239 240 if(sspi_send_token.pvBuffer) { 241 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 242 sspi_send_token.pvBuffer = NULL; 243 } 244 sspi_send_token.cbBuffer = 0; 245 246 if(sspi_recv_token.pvBuffer) { 247 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 248 sspi_recv_token.pvBuffer = NULL; 249 } 250 sspi_recv_token.cbBuffer = 0; 251 252 if(status != SEC_I_CONTINUE_NEEDED) 253 break; 254 255 /* analyse response */ 256 257 /* GSS-API response looks like 258 * +----+------+-----+----------------+ 259 * |VER | MTYP | LEN | TOKEN | 260 * +----+------+----------------------+ 261 * | 1 | 1 | 2 | up to 2^16 - 1 | 262 * +----+------+-----+----------------+ 263 */ 264 265 result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 266 if(result || (actualread != 4)) { 267 failf(data, "Failed to receive SSPI authentication response."); 268 free(service_name); 269 s_pSecFn->FreeCredentialsHandle(&cred_handle); 270 s_pSecFn->DeleteSecurityContext(&sspi_context); 271 return CURLE_COULDNT_CONNECT; 272 } 273 274 /* ignore the first (VER) byte */ 275 if(socksreq[1] == 255) { /* status / message type */ 276 failf(data, "User was rejected by the SOCKS5 server (%u %u).", 277 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 278 free(service_name); 279 s_pSecFn->FreeCredentialsHandle(&cred_handle); 280 s_pSecFn->DeleteSecurityContext(&sspi_context); 281 return CURLE_COULDNT_CONNECT; 282 } 283 284 if(socksreq[1] != 1) { /* status / message type */ 285 failf(data, "Invalid SSPI authentication response type (%u %u).", 286 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 287 free(service_name); 288 s_pSecFn->FreeCredentialsHandle(&cred_handle); 289 s_pSecFn->DeleteSecurityContext(&sspi_context); 290 return CURLE_COULDNT_CONNECT; 291 } 292 293 memcpy(&us_length, socksreq + 2, sizeof(short)); 294 us_length = ntohs(us_length); 295 296 sspi_recv_token.cbBuffer = us_length; 297 sspi_recv_token.pvBuffer = malloc(us_length); 298 299 if(!sspi_recv_token.pvBuffer) { 300 free(service_name); 301 s_pSecFn->FreeCredentialsHandle(&cred_handle); 302 s_pSecFn->DeleteSecurityContext(&sspi_context); 303 return CURLE_OUT_OF_MEMORY; 304 } 305 result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, 306 sspi_recv_token.cbBuffer, &actualread); 307 308 if(result || (actualread != us_length)) { 309 failf(data, "Failed to receive SSPI authentication token."); 310 free(service_name); 311 if(sspi_recv_token.pvBuffer) 312 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 313 s_pSecFn->FreeCredentialsHandle(&cred_handle); 314 s_pSecFn->DeleteSecurityContext(&sspi_context); 315 return CURLE_COULDNT_CONNECT; 316 } 317 318 context_handle = &sspi_context; 319 } 320 321 free(service_name); 322 323 /* Everything is good so far, user was authenticated! */ 324 status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, 325 SECPKG_CRED_ATTR_NAMES, 326 &names); 327 s_pSecFn->FreeCredentialsHandle(&cred_handle); 328 if(check_sspi_err(data, status, "QueryCredentialAttributes")) { 329 s_pSecFn->DeleteSecurityContext(&sspi_context); 330 s_pSecFn->FreeContextBuffer(names.sUserName); 331 failf(data, "Failed to determine user name."); 332 return CURLE_COULDNT_CONNECT; 333 } 334 else { 335#ifndef CURL_DISABLE_VERBOSE_STRINGS 336 char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName); 337 infof(data, "SOCKS5 server authenticated user %s with GSS-API.", 338 (user_utf8 ? user_utf8 : "(unknown)")); 339 curlx_unicodefree(user_utf8); 340#endif 341 s_pSecFn->FreeContextBuffer(names.sUserName); 342 } 343 344 /* Do encryption */ 345 socksreq[0] = 1; /* GSS-API subnegotiation version */ 346 socksreq[1] = 2; /* encryption message type */ 347 348 gss_enc = 0; /* no data protection */ 349 /* do confidentiality protection if supported */ 350 if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) 351 gss_enc = 2; 352 /* else do integrity protection */ 353 else if(sspi_ret_flags & ISC_REQ_INTEGRITY) 354 gss_enc = 1; 355 356 infof(data, "SOCKS5 server supports GSS-API %s data protection.", 357 (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); 358 /* force to no data protection, avoid encryption/decryption for now */ 359 gss_enc = 0; 360 /* 361 * Sending the encryption type in clear seems wrong. It should be 362 * protected with gss_seal()/gss_wrap(). See RFC1961 extract below 363 * The NEC reference implementations on which this is based is 364 * therefore at fault 365 * 366 * +------+------+------+.......................+ 367 * + ver | mtyp | len | token | 368 * +------+------+------+.......................+ 369 * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | 370 * +------+------+------+.......................+ 371 * 372 * Where: 373 * 374 * - "ver" is the protocol version number, here 1 to represent the 375 * first version of the SOCKS/GSS-API protocol 376 * 377 * - "mtyp" is the message type, here 2 to represent a protection 378 * -level negotiation message 379 * 380 * - "len" is the length of the "token" field in octets 381 * 382 * - "token" is the GSS-API encapsulated protection level 383 * 384 * The token is produced by encapsulating an octet containing the 385 * required protection level using gss_seal()/gss_wrap() with conf_req 386 * set to FALSE. The token is verified using gss_unseal()/ 387 * gss_unwrap(). 388 * 389 */ 390 391 if(data->set.socks5_gssapi_nec) { 392 us_length = htons((short)1); 393 memcpy(socksreq + 2, &us_length, sizeof(short)); 394 } 395 else { 396 status = s_pSecFn->QueryContextAttributes(&sspi_context, 397 SECPKG_ATTR_SIZES, 398 &sspi_sizes); 399 if(check_sspi_err(data, status, "QueryContextAttributes")) { 400 s_pSecFn->DeleteSecurityContext(&sspi_context); 401 failf(data, "Failed to query security context attributes."); 402 return CURLE_COULDNT_CONNECT; 403 } 404 405 sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; 406 sspi_w_token[0].BufferType = SECBUFFER_TOKEN; 407 sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); 408 409 if(!sspi_w_token[0].pvBuffer) { 410 s_pSecFn->DeleteSecurityContext(&sspi_context); 411 return CURLE_OUT_OF_MEMORY; 412 } 413 414 sspi_w_token[1].cbBuffer = 1; 415 sspi_w_token[1].pvBuffer = malloc(1); 416 if(!sspi_w_token[1].pvBuffer) { 417 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 418 s_pSecFn->DeleteSecurityContext(&sspi_context); 419 return CURLE_OUT_OF_MEMORY; 420 } 421 422 memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); 423 sspi_w_token[2].BufferType = SECBUFFER_PADDING; 424 sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; 425 sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); 426 if(!sspi_w_token[2].pvBuffer) { 427 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 428 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 429 s_pSecFn->DeleteSecurityContext(&sspi_context); 430 return CURLE_OUT_OF_MEMORY; 431 } 432 status = s_pSecFn->EncryptMessage(&sspi_context, 433 KERB_WRAP_NO_ENCRYPT, 434 &wrap_desc, 435 0); 436 if(check_sspi_err(data, status, "EncryptMessage")) { 437 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 438 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 439 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 440 s_pSecFn->DeleteSecurityContext(&sspi_context); 441 failf(data, "Failed to query security context attributes."); 442 return CURLE_COULDNT_CONNECT; 443 } 444 sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer 445 + sspi_w_token[1].cbBuffer 446 + sspi_w_token[2].cbBuffer; 447 sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); 448 if(!sspi_send_token.pvBuffer) { 449 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 450 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 451 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 452 s_pSecFn->DeleteSecurityContext(&sspi_context); 453 return CURLE_OUT_OF_MEMORY; 454 } 455 456 memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, 457 sspi_w_token[0].cbBuffer); 458 memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, 459 sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 460 memcpy((PUCHAR) sspi_send_token.pvBuffer 461 + sspi_w_token[0].cbBuffer 462 + sspi_w_token[1].cbBuffer, 463 sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); 464 465 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 466 sspi_w_token[0].pvBuffer = NULL; 467 sspi_w_token[0].cbBuffer = 0; 468 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 469 sspi_w_token[1].pvBuffer = NULL; 470 sspi_w_token[1].cbBuffer = 0; 471 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 472 sspi_w_token[2].pvBuffer = NULL; 473 sspi_w_token[2].cbBuffer = 0; 474 475 us_length = htons((short)sspi_send_token.cbBuffer); 476 memcpy(socksreq + 2, &us_length, sizeof(short)); 477 } 478 479 written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); 480 if(code || (4 != written)) { 481 failf(data, "Failed to send SSPI encryption request."); 482 if(sspi_send_token.pvBuffer) 483 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 484 s_pSecFn->DeleteSecurityContext(&sspi_context); 485 return CURLE_COULDNT_CONNECT; 486 } 487 488 if(data->set.socks5_gssapi_nec) { 489 memcpy(socksreq, &gss_enc, 1); 490 written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code); 491 if(code || (1 != written)) { 492 failf(data, "Failed to send SSPI encryption type."); 493 s_pSecFn->DeleteSecurityContext(&sspi_context); 494 return CURLE_COULDNT_CONNECT; 495 } 496 } 497 else { 498 written = Curl_conn_cf_send(cf->next, data, 499 (char *)sspi_send_token.pvBuffer, 500 sspi_send_token.cbBuffer, &code); 501 if(code || (sspi_send_token.cbBuffer != (size_t)written)) { 502 failf(data, "Failed to send SSPI encryption type."); 503 if(sspi_send_token.pvBuffer) 504 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 505 s_pSecFn->DeleteSecurityContext(&sspi_context); 506 return CURLE_COULDNT_CONNECT; 507 } 508 if(sspi_send_token.pvBuffer) 509 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 510 } 511 512 result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 513 if(result || (actualread != 4)) { 514 failf(data, "Failed to receive SSPI encryption response."); 515 s_pSecFn->DeleteSecurityContext(&sspi_context); 516 return CURLE_COULDNT_CONNECT; 517 } 518 519 /* ignore the first (VER) byte */ 520 if(socksreq[1] == 255) { /* status / message type */ 521 failf(data, "User was rejected by the SOCKS5 server (%u %u).", 522 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 523 s_pSecFn->DeleteSecurityContext(&sspi_context); 524 return CURLE_COULDNT_CONNECT; 525 } 526 527 if(socksreq[1] != 2) { /* status / message type */ 528 failf(data, "Invalid SSPI encryption response type (%u %u).", 529 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 530 s_pSecFn->DeleteSecurityContext(&sspi_context); 531 return CURLE_COULDNT_CONNECT; 532 } 533 534 memcpy(&us_length, socksreq + 2, sizeof(short)); 535 us_length = ntohs(us_length); 536 537 sspi_w_token[0].cbBuffer = us_length; 538 sspi_w_token[0].pvBuffer = malloc(us_length); 539 if(!sspi_w_token[0].pvBuffer) { 540 s_pSecFn->DeleteSecurityContext(&sspi_context); 541 return CURLE_OUT_OF_MEMORY; 542 } 543 544 result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, 545 sspi_w_token[0].cbBuffer, &actualread); 546 547 if(result || (actualread != us_length)) { 548 failf(data, "Failed to receive SSPI encryption type."); 549 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 550 s_pSecFn->DeleteSecurityContext(&sspi_context); 551 return CURLE_COULDNT_CONNECT; 552 } 553 554 555 if(!data->set.socks5_gssapi_nec) { 556 wrap_desc.cBuffers = 2; 557 sspi_w_token[0].BufferType = SECBUFFER_STREAM; 558 sspi_w_token[1].BufferType = SECBUFFER_DATA; 559 sspi_w_token[1].cbBuffer = 0; 560 sspi_w_token[1].pvBuffer = NULL; 561 562 status = s_pSecFn->DecryptMessage(&sspi_context, 563 &wrap_desc, 564 0, 565 &qop); 566 567 if(check_sspi_err(data, status, "DecryptMessage")) { 568 if(sspi_w_token[0].pvBuffer) 569 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 570 if(sspi_w_token[1].pvBuffer) 571 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 572 s_pSecFn->DeleteSecurityContext(&sspi_context); 573 failf(data, "Failed to query security context attributes."); 574 return CURLE_COULDNT_CONNECT; 575 } 576 577 if(sspi_w_token[1].cbBuffer != 1) { 578 failf(data, "Invalid SSPI encryption response length (%lu).", 579 (unsigned long)sspi_w_token[1].cbBuffer); 580 if(sspi_w_token[0].pvBuffer) 581 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 582 if(sspi_w_token[1].pvBuffer) 583 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 584 s_pSecFn->DeleteSecurityContext(&sspi_context); 585 return CURLE_COULDNT_CONNECT; 586 } 587 588 memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 589 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 590 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 591 } 592 else { 593 if(sspi_w_token[0].cbBuffer != 1) { 594 failf(data, "Invalid SSPI encryption response length (%lu).", 595 (unsigned long)sspi_w_token[0].cbBuffer); 596 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 597 s_pSecFn->DeleteSecurityContext(&sspi_context); 598 return CURLE_COULDNT_CONNECT; 599 } 600 memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); 601 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 602 } 603 (void)curlx_nonblock(sock, TRUE); 604 605 infof(data, "SOCKS5 access with%s protection granted.", 606 (socksreq[0] == 0)?"out GSS-API data": 607 ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); 608 609 /* For later use if encryption is required 610 conn->socks5_gssapi_enctype = socksreq[0]; 611 if(socksreq[0] != 0) 612 conn->socks5_sspi_context = sspi_context; 613 else { 614 s_pSecFn->DeleteSecurityContext(&sspi_context); 615 conn->socks5_sspi_context = sspi_context; 616 } 617 */ 618 return CURLE_OK; 619} 620#endif 621