socks_sspi.c (23581B)
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 "curlx/timeval.h" 36 #include "socks.h" 37 #include "curl_sspi.h" 38 #include "curlx/multibyte.h" 39 #include "curlx/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 */ 49 static 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 */ 66 CURLcode 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 size_t actualread; 73 size_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 = Curl_pSecFn->AcquireCredentialsHandle(NULL, 143 (TCHAR *)CURL_UNCONST(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 Curl_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 is 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 = Curl_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 Curl_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 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 197 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 198 if(sspi_recv_token.pvBuffer) 199 Curl_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((unsigned short)sspi_send_token.cbBuffer); 208 memcpy(socksreq + 2, &us_length, sizeof(short)); 209 210 code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, 211 &written); 212 if(code || (4 != written)) { 213 failf(data, "Failed to send SSPI authentication request."); 214 free(service_name); 215 if(sspi_send_token.pvBuffer) 216 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 217 if(sspi_recv_token.pvBuffer) 218 Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 219 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 220 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 221 return CURLE_COULDNT_CONNECT; 222 } 223 224 code = Curl_conn_cf_send(cf->next, data, 225 (char *)sspi_send_token.pvBuffer, 226 sspi_send_token.cbBuffer, FALSE, &written); 227 if(code || (sspi_send_token.cbBuffer != written)) { 228 failf(data, "Failed to send SSPI authentication token."); 229 free(service_name); 230 if(sspi_send_token.pvBuffer) 231 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 232 if(sspi_recv_token.pvBuffer) 233 Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 234 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 235 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 236 return CURLE_COULDNT_CONNECT; 237 } 238 239 } 240 241 if(sspi_send_token.pvBuffer) { 242 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 243 sspi_send_token.pvBuffer = NULL; 244 } 245 sspi_send_token.cbBuffer = 0; 246 247 if(sspi_recv_token.pvBuffer) { 248 Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 249 sspi_recv_token.pvBuffer = NULL; 250 } 251 sspi_recv_token.cbBuffer = 0; 252 253 if(status != SEC_I_CONTINUE_NEEDED) 254 break; 255 256 /* analyse response */ 257 258 /* GSS-API response looks like 259 * +----+------+-----+----------------+ 260 * |VER | MTYP | LEN | TOKEN | 261 * +----+------+----------------------+ 262 * | 1 | 1 | 2 | up to 2^16 - 1 | 263 * +----+------+-----+----------------+ 264 */ 265 266 result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 267 if(result || (actualread != 4)) { 268 failf(data, "Failed to receive SSPI authentication response."); 269 free(service_name); 270 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 271 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 272 return CURLE_COULDNT_CONNECT; 273 } 274 275 /* ignore the first (VER) byte */ 276 if(socksreq[1] == 255) { /* status / message type */ 277 failf(data, "User was rejected by the SOCKS5 server (%u %u).", 278 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 279 free(service_name); 280 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 281 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 282 return CURLE_COULDNT_CONNECT; 283 } 284 285 if(socksreq[1] != 1) { /* status / message type */ 286 failf(data, "Invalid SSPI authentication response type (%u %u).", 287 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 288 free(service_name); 289 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 290 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 291 return CURLE_COULDNT_CONNECT; 292 } 293 294 memcpy(&us_length, socksreq + 2, sizeof(short)); 295 us_length = ntohs(us_length); 296 297 sspi_recv_token.cbBuffer = us_length; 298 sspi_recv_token.pvBuffer = malloc(us_length); 299 300 if(!sspi_recv_token.pvBuffer) { 301 free(service_name); 302 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 303 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 304 return CURLE_OUT_OF_MEMORY; 305 } 306 result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, 307 sspi_recv_token.cbBuffer, &actualread); 308 309 if(result || (actualread != us_length)) { 310 failf(data, "Failed to receive SSPI authentication token."); 311 free(service_name); 312 if(sspi_recv_token.pvBuffer) 313 Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 314 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 315 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 316 return CURLE_COULDNT_CONNECT; 317 } 318 319 context_handle = &sspi_context; 320 } 321 322 free(service_name); 323 324 /* Everything is good so far, user was authenticated! */ 325 status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, 326 SECPKG_CRED_ATTR_NAMES, 327 &names); 328 Curl_pSecFn->FreeCredentialsHandle(&cred_handle); 329 if(check_sspi_err(data, status, "QueryCredentialAttributes")) { 330 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 331 Curl_pSecFn->FreeContextBuffer(names.sUserName); 332 failf(data, "Failed to determine username."); 333 return CURLE_COULDNT_CONNECT; 334 } 335 else { 336 #ifndef CURL_DISABLE_VERBOSE_STRINGS 337 char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName); 338 infof(data, "SOCKS5 server authenticated user %s with GSS-API.", 339 (user_utf8 ? user_utf8 : "(unknown)")); 340 curlx_unicodefree(user_utf8); 341 #endif 342 Curl_pSecFn->FreeContextBuffer(names.sUserName); 343 } 344 345 /* Do encryption */ 346 socksreq[0] = 1; /* GSS-API subnegotiation version */ 347 socksreq[1] = 2; /* encryption message type */ 348 349 gss_enc = 0; /* no data protection */ 350 /* do confidentiality protection if supported */ 351 if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) 352 gss_enc = 2; 353 /* else do integrity protection */ 354 else if(sspi_ret_flags & ISC_REQ_INTEGRITY) 355 gss_enc = 1; 356 357 infof(data, "SOCKS5 server supports GSS-API %s data protection.", 358 (gss_enc == 0) ? "no" : 359 ((gss_enc == 1) ? "integrity":"confidentiality") ); 360 /* force to no data protection, avoid encryption/decryption for now */ 361 gss_enc = 0; 362 /* 363 * Sending the encryption type in clear seems wrong. It should be 364 * protected with gss_seal()/gss_wrap(). See RFC1961 extract below 365 * The NEC reference implementations on which this is based is 366 * therefore at fault 367 * 368 * +------+------+------+.......................+ 369 * + ver | mtyp | len | token | 370 * +------+------+------+.......................+ 371 * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | 372 * +------+------+------+.......................+ 373 * 374 * Where: 375 * 376 * - "ver" is the protocol version number, here 1 to represent the 377 * first version of the SOCKS/GSS-API protocol 378 * 379 * - "mtyp" is the message type, here 2 to represent a protection 380 * -level negotiation message 381 * 382 * - "len" is the length of the "token" field in octets 383 * 384 * - "token" is the GSS-API encapsulated protection level 385 * 386 * The token is produced by encapsulating an octet containing the 387 * required protection level using gss_seal()/gss_wrap() with conf_req 388 * set to FALSE. The token is verified using gss_unseal()/ 389 * gss_unwrap(). 390 * 391 */ 392 393 if(data->set.socks5_gssapi_nec) { 394 us_length = htons((unsigned short)1); 395 memcpy(socksreq + 2, &us_length, sizeof(short)); 396 } 397 else { 398 status = Curl_pSecFn->QueryContextAttributes(&sspi_context, 399 SECPKG_ATTR_SIZES, 400 &sspi_sizes); 401 if(check_sspi_err(data, status, "QueryContextAttributes")) { 402 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 403 failf(data, "Failed to query security context attributes."); 404 return CURLE_COULDNT_CONNECT; 405 } 406 407 sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; 408 sspi_w_token[0].BufferType = SECBUFFER_TOKEN; 409 sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); 410 411 if(!sspi_w_token[0].pvBuffer) { 412 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 413 return CURLE_OUT_OF_MEMORY; 414 } 415 416 sspi_w_token[1].cbBuffer = 1; 417 sspi_w_token[1].pvBuffer = malloc(1); 418 if(!sspi_w_token[1].pvBuffer) { 419 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 420 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 421 return CURLE_OUT_OF_MEMORY; 422 } 423 424 memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); 425 sspi_w_token[2].BufferType = SECBUFFER_PADDING; 426 sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; 427 sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); 428 if(!sspi_w_token[2].pvBuffer) { 429 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 430 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 431 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 432 return CURLE_OUT_OF_MEMORY; 433 } 434 status = Curl_pSecFn->EncryptMessage(&sspi_context, 435 KERB_WRAP_NO_ENCRYPT, 436 &wrap_desc, 437 0); 438 if(check_sspi_err(data, status, "EncryptMessage")) { 439 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 440 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 441 Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 442 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 443 failf(data, "Failed to query security context attributes."); 444 return CURLE_COULDNT_CONNECT; 445 } 446 sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer 447 + sspi_w_token[1].cbBuffer 448 + sspi_w_token[2].cbBuffer; 449 sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); 450 if(!sspi_send_token.pvBuffer) { 451 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 452 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 453 Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 454 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 455 return CURLE_OUT_OF_MEMORY; 456 } 457 458 memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, 459 sspi_w_token[0].cbBuffer); 460 memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, 461 sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 462 memcpy((PUCHAR) sspi_send_token.pvBuffer 463 + sspi_w_token[0].cbBuffer 464 + sspi_w_token[1].cbBuffer, 465 sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); 466 467 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 468 sspi_w_token[0].pvBuffer = NULL; 469 sspi_w_token[0].cbBuffer = 0; 470 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 471 sspi_w_token[1].pvBuffer = NULL; 472 sspi_w_token[1].cbBuffer = 0; 473 Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 474 sspi_w_token[2].pvBuffer = NULL; 475 sspi_w_token[2].cbBuffer = 0; 476 477 us_length = htons((unsigned short)sspi_send_token.cbBuffer); 478 memcpy(socksreq + 2, &us_length, sizeof(short)); 479 } 480 481 code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, 482 &written); 483 if(code || (4 != written)) { 484 failf(data, "Failed to send SSPI encryption request."); 485 if(sspi_send_token.pvBuffer) 486 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 487 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 488 return CURLE_COULDNT_CONNECT; 489 } 490 491 if(data->set.socks5_gssapi_nec) { 492 memcpy(socksreq, &gss_enc, 1); 493 code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, 494 &written); 495 if(code || (1 != written)) { 496 failf(data, "Failed to send SSPI encryption type."); 497 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 498 return CURLE_COULDNT_CONNECT; 499 } 500 } 501 else { 502 code = Curl_conn_cf_send(cf->next, data, 503 (char *)sspi_send_token.pvBuffer, 504 sspi_send_token.cbBuffer, FALSE, &written); 505 if(code || (sspi_send_token.cbBuffer != (size_t)written)) { 506 failf(data, "Failed to send SSPI encryption type."); 507 if(sspi_send_token.pvBuffer) 508 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 509 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 510 return CURLE_COULDNT_CONNECT; 511 } 512 if(sspi_send_token.pvBuffer) 513 Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 514 } 515 516 result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 517 if(result || (actualread != 4)) { 518 failf(data, "Failed to receive SSPI encryption response."); 519 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 520 return CURLE_COULDNT_CONNECT; 521 } 522 523 /* ignore the first (VER) byte */ 524 if(socksreq[1] == 255) { /* status / message type */ 525 failf(data, "User was rejected by the SOCKS5 server (%u %u).", 526 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 527 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 528 return CURLE_COULDNT_CONNECT; 529 } 530 531 if(socksreq[1] != 2) { /* status / message type */ 532 failf(data, "Invalid SSPI encryption response type (%u %u).", 533 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 534 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 535 return CURLE_COULDNT_CONNECT; 536 } 537 538 memcpy(&us_length, socksreq + 2, sizeof(short)); 539 us_length = ntohs(us_length); 540 541 sspi_w_token[0].cbBuffer = us_length; 542 sspi_w_token[0].pvBuffer = malloc(us_length); 543 if(!sspi_w_token[0].pvBuffer) { 544 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 545 return CURLE_OUT_OF_MEMORY; 546 } 547 548 result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, 549 sspi_w_token[0].cbBuffer, &actualread); 550 551 if(result || (actualread != us_length)) { 552 failf(data, "Failed to receive SSPI encryption type."); 553 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 554 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 555 return CURLE_COULDNT_CONNECT; 556 } 557 558 559 if(!data->set.socks5_gssapi_nec) { 560 wrap_desc.cBuffers = 2; 561 sspi_w_token[0].BufferType = SECBUFFER_STREAM; 562 sspi_w_token[1].BufferType = SECBUFFER_DATA; 563 sspi_w_token[1].cbBuffer = 0; 564 sspi_w_token[1].pvBuffer = NULL; 565 566 status = Curl_pSecFn->DecryptMessage(&sspi_context, 567 &wrap_desc, 568 0, 569 &qop); 570 571 if(check_sspi_err(data, status, "DecryptMessage")) { 572 if(sspi_w_token[0].pvBuffer) 573 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 574 if(sspi_w_token[1].pvBuffer) 575 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 576 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 577 failf(data, "Failed to query security context attributes."); 578 return CURLE_COULDNT_CONNECT; 579 } 580 581 if(sspi_w_token[1].cbBuffer != 1) { 582 failf(data, "Invalid SSPI encryption response length (%lu).", 583 (unsigned long)sspi_w_token[1].cbBuffer); 584 if(sspi_w_token[0].pvBuffer) 585 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 586 if(sspi_w_token[1].pvBuffer) 587 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 588 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 589 return CURLE_COULDNT_CONNECT; 590 } 591 592 memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 593 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 594 Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 595 } 596 else { 597 if(sspi_w_token[0].cbBuffer != 1) { 598 failf(data, "Invalid SSPI encryption response length (%lu).", 599 (unsigned long)sspi_w_token[0].cbBuffer); 600 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 601 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 602 return CURLE_COULDNT_CONNECT; 603 } 604 memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); 605 Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 606 } 607 (void)curlx_nonblock(sock, TRUE); 608 609 infof(data, "SOCKS5 access with%s protection granted.", 610 (socksreq[0] == 0) ? "out GSS-API data": 611 ((socksreq[0] == 1) ? " GSS-API integrity" : 612 " GSS-API confidentiality")); 613 614 /* For later use if encryption is required 615 conn->socks5_gssapi_enctype = socksreq[0]; 616 if(socksreq[0] != 0) 617 conn->socks5_sspi_context = sspi_context; 618 else { 619 Curl_pSecFn->DeleteSecurityContext(&sspi_context); 620 conn->socks5_sspi_context = sspi_context; 621 } 622 */ 623 return CURLE_OK; 624 } 625 #endif