1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com> 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23 24#include "setup.h" 25 26#ifdef USE_WINDOWS_SSPI 27 28#include <string.h> 29 30#ifdef HAVE_STDLIB_H 31#include <stdlib.h> 32#endif 33 34#include "urldata.h" 35#include "sendf.h" 36#include "connect.h" 37#include "timeval.h" 38#include "socks.h" 39#include "curl_sspi.h" 40#include "warnless.h" 41 42#define _MPRINTF_REPLACE /* use the internal *printf() functions */ 43#include <curl/mprintf.h> 44 45#include "curl_memory.h" 46/* The last #include file should be: */ 47#include "memdebug.h" 48 49/* 50 * Definitions required from ntsecapi.h are directly provided below this point 51 * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h 52 */ 53#define KERB_WRAP_NO_ENCRYPT 0x80000001 54 55/* 56 * Helper sspi error functions. 57 */ 58static int check_sspi_err(struct SessionHandle *data, 59 SECURITY_STATUS major_status, 60 SECURITY_STATUS minor_status, 61 const char* function) 62{ 63 const char *txt; 64 (void)minor_status; 65 66 if(major_status != SEC_E_OK && 67 major_status != SEC_I_COMPLETE_AND_CONTINUE && 68 major_status != SEC_I_COMPLETE_NEEDED && 69 major_status != SEC_I_CONTINUE_NEEDED) { 70 failf(data, "SSPI error: %s failed: %d\n", function, major_status); 71 switch (major_status) { 72 case SEC_I_COMPLETE_AND_CONTINUE: 73 txt="SEC_I_COMPLETE_AND_CONTINUE"; 74 break; 75 case SEC_I_COMPLETE_NEEDED: 76 txt="SEC_I_COMPLETE_NEEDED"; 77 break; 78 case SEC_I_CONTINUE_NEEDED: 79 txt="SEC_I_CONTINUE_NEEDED"; 80 break; 81 case SEC_I_CONTEXT_EXPIRED: 82 txt="SEC_I_CONTEXT_EXPIRED"; 83 break; 84 case SEC_I_INCOMPLETE_CREDENTIALS: 85 txt="SEC_I_INCOMPLETE_CREDENTIALS"; 86 break; 87 case SEC_I_RENEGOTIATE: 88 txt="SEC_I_RENEGOTIATE"; 89 break; 90 case SEC_E_BUFFER_TOO_SMALL: 91 txt="SEC_E_BUFFER_TOO_SMALL"; 92 break; 93 case SEC_E_CONTEXT_EXPIRED: 94 txt="SEC_E_CONTEXT_EXPIRED"; 95 break; 96 case SEC_E_CRYPTO_SYSTEM_INVALID: 97 txt="SEC_E_CRYPTO_SYSTEM_INVALID"; 98 break; 99 case SEC_E_INCOMPLETE_MESSAGE: 100 txt="SEC_E_INCOMPLETE_MESSAGE"; 101 break; 102 case SEC_E_INSUFFICIENT_MEMORY: 103 txt="SEC_E_INSUFFICIENT_MEMORY"; 104 break; 105 case SEC_E_INTERNAL_ERROR: 106 txt="SEC_E_INTERNAL_ERROR"; 107 break; 108 case SEC_E_INVALID_HANDLE: 109 txt="SEC_E_INVALID_HANDLE"; 110 break; 111 case SEC_E_INVALID_TOKEN: 112 txt="SEC_E_INVALID_TOKEN"; 113 break; 114 case SEC_E_LOGON_DENIED: 115 txt="SEC_E_LOGON_DENIED"; 116 break; 117 case SEC_E_MESSAGE_ALTERED: 118 txt="SEC_E_MESSAGE_ALTERED"; 119 break; 120 case SEC_E_NO_AUTHENTICATING_AUTHORITY: 121 txt="SEC_E_NO_AUTHENTICATING_AUTHORITY"; 122 break; 123 case SEC_E_NO_CREDENTIALS: 124 txt="SEC_E_NO_CREDENTIALS"; 125 break; 126 case SEC_E_NOT_OWNER: 127 txt="SEC_E_NOT_OWNER"; 128 break; 129 case SEC_E_OUT_OF_SEQUENCE: 130 txt="SEC_E_OUT_OF_SEQUENCE"; 131 break; 132 case SEC_E_QOP_NOT_SUPPORTED: 133 txt="SEC_E_QOP_NOT_SUPPORTED"; 134 break; 135 case SEC_E_SECPKG_NOT_FOUND: 136 txt="SEC_E_SECPKG_NOT_FOUND"; 137 break; 138 case SEC_E_TARGET_UNKNOWN: 139 txt="SEC_E_TARGET_UNKNOWN"; 140 break; 141 case SEC_E_UNKNOWN_CREDENTIALS: 142 txt="SEC_E_UNKNOWN_CREDENTIALS"; 143 break; 144 case SEC_E_UNSUPPORTED_FUNCTION: 145 txt="SEC_E_UNSUPPORTED_FUNCTION"; 146 break; 147 case SEC_E_WRONG_PRINCIPAL: 148 txt="SEC_E_WRONG_PRINCIPAL"; 149 break; 150 default: 151 txt="Unknown error"; 152 153 } 154 failf(data, "SSPI error: %s failed: %s\n", function, txt); 155 return 1; 156 } 157 return 0; 158} 159 160/* This is the SSPI-using version of this function */ 161CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, 162 struct connectdata *conn) 163{ 164 struct SessionHandle *data = conn->data; 165 curl_socket_t sock = conn->sock[sockindex]; 166 CURLcode code; 167 ssize_t actualread; 168 ssize_t written; 169 int result; 170 long timeout; 171 /* Needs GSSAPI authentication */ 172 SECURITY_STATUS sspi_major_status, sspi_minor_status=0; 173 unsigned long sspi_ret_flags=0; 174 int gss_enc; 175 SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; 176 SecBufferDesc input_desc, output_desc, wrap_desc; 177 SecPkgContext_Sizes sspi_sizes; 178 CredHandle cred_handle; 179 CtxtHandle sspi_context; 180 PCtxtHandle context_handle = NULL; 181 SecPkgCredentials_Names names; 182 TimeStamp expiry; 183 char *service_name=NULL; 184 unsigned short us_length; 185 ULONG qop; 186 unsigned char socksreq[4]; /* room for gssapi exchange header only */ 187 char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; 188 189 /* get timeout */ 190 timeout = Curl_timeleft(data, NULL, TRUE); 191 192 /* GSSAPI request looks like 193 * +----+------+-----+----------------+ 194 * |VER | MTYP | LEN | TOKEN | 195 * +----+------+----------------------+ 196 * | 1 | 1 | 2 | up to 2^16 - 1 | 197 * +----+------+-----+----------------+ 198 */ 199 200 /* prepare service name */ 201 if(strchr(service, '/')) { 202 service_name = malloc(strlen(service)); 203 if(!service_name) 204 return CURLE_OUT_OF_MEMORY; 205 memcpy(service_name, service, strlen(service)); 206 } 207 else { 208 service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); 209 if(!service_name) 210 return CURLE_OUT_OF_MEMORY; 211 snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s", 212 service,conn->proxy.name); 213 } 214 215 input_desc.cBuffers = 1; 216 input_desc.pBuffers = &sspi_recv_token; 217 input_desc.ulVersion = SECBUFFER_VERSION; 218 219 sspi_recv_token.BufferType = SECBUFFER_TOKEN; 220 sspi_recv_token.cbBuffer = 0; 221 sspi_recv_token.pvBuffer = NULL; 222 223 output_desc.cBuffers = 1; 224 output_desc.pBuffers = &sspi_send_token; 225 output_desc.ulVersion = SECBUFFER_VERSION; 226 227 sspi_send_token.BufferType = SECBUFFER_TOKEN; 228 sspi_send_token.cbBuffer = 0; 229 sspi_send_token.pvBuffer = NULL; 230 231 wrap_desc.cBuffers = 3; 232 wrap_desc.pBuffers = sspi_w_token; 233 wrap_desc.ulVersion = SECBUFFER_VERSION; 234 235 cred_handle.dwLower = 0; 236 cred_handle.dwUpper = 0; 237 238 sspi_major_status = 239 s_pSecFn->AcquireCredentialsHandleA( NULL, 240 (char *)"Kerberos", 241 SECPKG_CRED_OUTBOUND, 242 NULL, 243 NULL, 244 NULL, 245 NULL, 246 &cred_handle, 247 &expiry); 248 249 if(check_sspi_err(data, sspi_major_status,sspi_minor_status, 250 "AcquireCredentialsHandleA") ) { 251 failf(data, "Failed to acquire credentials."); 252 free(service_name); 253 service_name=NULL; 254 s_pSecFn->FreeCredentialsHandle(&cred_handle); 255 return CURLE_COULDNT_CONNECT; 256 } 257 258 /* As long as we need to keep sending some context info, and there's no */ 259 /* errors, keep sending it... */ 260 for(;;) { 261 262 sspi_major_status = s_pSecFn->InitializeSecurityContextA( 263 &cred_handle, 264 context_handle, 265 service_name, 266 ISC_REQ_MUTUAL_AUTH | 267 ISC_REQ_ALLOCATE_MEMORY | 268 ISC_REQ_CONFIDENTIALITY | 269 ISC_REQ_REPLAY_DETECT, 270 0, 271 SECURITY_NATIVE_DREP, 272 &input_desc, 273 0, 274 &sspi_context, 275 &output_desc, 276 &sspi_ret_flags, 277 &expiry); 278 279 if(sspi_recv_token.pvBuffer) { 280 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 281 sspi_recv_token.pvBuffer = NULL; 282 sspi_recv_token.cbBuffer = 0; 283 } 284 285 if(check_sspi_err(data,sspi_major_status,sspi_minor_status, 286 "InitializeSecurityContextA") ){ 287 free(service_name); 288 service_name=NULL; 289 s_pSecFn->FreeCredentialsHandle(&cred_handle); 290 s_pSecFn->DeleteSecurityContext(&sspi_context); 291 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 292 failf(data, "Failed to initialise security context."); 293 return CURLE_COULDNT_CONNECT; 294 } 295 296 if(sspi_send_token.cbBuffer != 0) { 297 socksreq[0] = 1; /* gssapi subnegotiation version */ 298 socksreq[1] = 1; /* authentication message type */ 299 us_length = htons((short)sspi_send_token.cbBuffer); 300 memcpy(socksreq+2, &us_length, sizeof(short)); 301 302 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); 303 if((code != CURLE_OK) || (4 != written)) { 304 failf(data, "Failed to send SSPI authentication request."); 305 free(service_name); 306 service_name=NULL; 307 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 308 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 309 s_pSecFn->FreeCredentialsHandle(&cred_handle); 310 s_pSecFn->DeleteSecurityContext(&sspi_context); 311 return CURLE_COULDNT_CONNECT; 312 } 313 314 code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, 315 sspi_send_token.cbBuffer, &written); 316 if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { 317 failf(data, "Failed to send SSPI authentication token."); 318 free(service_name); 319 service_name=NULL; 320 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 321 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 322 s_pSecFn->FreeCredentialsHandle(&cred_handle); 323 s_pSecFn->DeleteSecurityContext(&sspi_context); 324 return CURLE_COULDNT_CONNECT; 325 } 326 327 } 328 329 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 330 sspi_send_token.pvBuffer = NULL; 331 sspi_send_token.cbBuffer = 0; 332 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 333 sspi_recv_token.pvBuffer = NULL; 334 sspi_recv_token.cbBuffer = 0; 335 if(sspi_major_status != SEC_I_CONTINUE_NEEDED) break; 336 337 /* analyse response */ 338 339 /* GSSAPI response looks like 340 * +----+------+-----+----------------+ 341 * |VER | MTYP | LEN | TOKEN | 342 * +----+------+----------------------+ 343 * | 1 | 1 | 2 | up to 2^16 - 1 | 344 * +----+------+-----+----------------+ 345 */ 346 347 result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, 348 &actualread, timeout); 349 if(result != CURLE_OK || actualread != 4) { 350 failf(data, "Failed to receive SSPI authentication response."); 351 free(service_name); 352 service_name=NULL; 353 s_pSecFn->FreeCredentialsHandle(&cred_handle); 354 s_pSecFn->DeleteSecurityContext(&sspi_context); 355 return CURLE_COULDNT_CONNECT; 356 } 357 358 /* ignore the first (VER) byte */ 359 if(socksreq[1] == 255) { /* status / message type */ 360 failf(data, "User was rejected by the SOCKS5 server (%d %d).", 361 socksreq[0], socksreq[1]); 362 free(service_name); 363 service_name=NULL; 364 s_pSecFn->FreeCredentialsHandle(&cred_handle); 365 s_pSecFn->DeleteSecurityContext(&sspi_context); 366 return CURLE_COULDNT_CONNECT; 367 } 368 369 if(socksreq[1] != 1) { /* status / messgae type */ 370 failf(data, "Invalid SSPI authentication response type (%d %d).", 371 socksreq[0], socksreq[1]); 372 free(service_name); 373 service_name=NULL; 374 s_pSecFn->FreeCredentialsHandle(&cred_handle); 375 s_pSecFn->DeleteSecurityContext(&sspi_context); 376 return CURLE_COULDNT_CONNECT; 377 } 378 379 memcpy(&us_length, socksreq+2, sizeof(short)); 380 us_length = ntohs(us_length); 381 382 sspi_recv_token.cbBuffer = us_length; 383 sspi_recv_token.pvBuffer = malloc(us_length); 384 385 if(!sspi_recv_token.pvBuffer) { 386 free(service_name); 387 service_name=NULL; 388 s_pSecFn->FreeCredentialsHandle(&cred_handle); 389 s_pSecFn->DeleteSecurityContext(&sspi_context); 390 return CURLE_OUT_OF_MEMORY; 391 } 392 result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, 393 sspi_recv_token.cbBuffer, 394 &actualread, timeout); 395 396 if(result != CURLE_OK || actualread != us_length) { 397 failf(data, "Failed to receive SSPI authentication token."); 398 free(service_name); 399 service_name=NULL; 400 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 401 s_pSecFn->FreeCredentialsHandle(&cred_handle); 402 s_pSecFn->DeleteSecurityContext(&sspi_context); 403 return CURLE_COULDNT_CONNECT; 404 } 405 406 context_handle = &sspi_context; 407 } 408 409 free(service_name); 410 service_name=NULL; 411 412 /* Everything is good so far, user was authenticated! */ 413 sspi_major_status = 414 s_pSecFn->QueryCredentialsAttributes( &cred_handle, 415 SECPKG_CRED_ATTR_NAMES, 416 &names); 417 s_pSecFn->FreeCredentialsHandle(&cred_handle); 418 if(check_sspi_err(data,sspi_major_status,sspi_minor_status, 419 "QueryCredentialAttributes") ){ 420 s_pSecFn->DeleteSecurityContext(&sspi_context); 421 s_pSecFn->FreeContextBuffer(names.sUserName); 422 failf(data, "Failed to determine user name."); 423 return CURLE_COULDNT_CONNECT; 424 } 425 infof(data, "SOCKS5 server authencticated user %s with gssapi.\n", 426 names.sUserName); 427 s_pSecFn->FreeContextBuffer(names.sUserName); 428 429 /* Do encryption */ 430 socksreq[0] = 1; /* gssapi subnegotiation version */ 431 socksreq[1] = 2; /* encryption message type */ 432 433 gss_enc = 0; /* no data protection */ 434 /* do confidentiality protection if supported */ 435 if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) 436 gss_enc = 2; 437 /* else do integrity protection */ 438 else if(sspi_ret_flags & ISC_REQ_INTEGRITY) 439 gss_enc = 1; 440 441 infof(data, "SOCKS5 server supports gssapi %s data protection.\n", 442 (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") ); 443 /* force to no data protection, avoid encryption/decryption for now */ 444 gss_enc = 0; 445 /* 446 * Sending the encryption type in clear seems wrong. It should be 447 * protected with gss_seal()/gss_wrap(). See RFC1961 extract below 448 * The NEC reference implementations on which this is based is 449 * therefore at fault 450 * 451 * +------+------+------+.......................+ 452 * + ver | mtyp | len | token | 453 * +------+------+------+.......................+ 454 * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | 455 * +------+------+------+.......................+ 456 * 457 * Where: 458 * 459 * - "ver" is the protocol version number, here 1 to represent the 460 * first version of the SOCKS/GSS-API protocol 461 * 462 * - "mtyp" is the message type, here 2 to represent a protection 463 * -level negotiation message 464 * 465 * - "len" is the length of the "token" field in octets 466 * 467 * - "token" is the GSS-API encapsulated protection level 468 * 469 * The token is produced by encapsulating an octet containing the 470 * required protection level using gss_seal()/gss_wrap() with conf_req 471 * set to FALSE. The token is verified using gss_unseal()/ 472 * gss_unwrap(). 473 * 474 */ 475 476 if(data->set.socks5_gssapi_nec) { 477 us_length = htons((short)1); 478 memcpy(socksreq+2, &us_length, sizeof(short)); 479 } 480 else { 481 sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context, 482 SECPKG_ATTR_SIZES, 483 &sspi_sizes); 484 if(check_sspi_err(data,sspi_major_status,sspi_minor_status, 485 "QueryContextAttributesA")) { 486 s_pSecFn->DeleteSecurityContext(&sspi_context); 487 failf(data, "Failed to query security context attributes."); 488 return CURLE_COULDNT_CONNECT; 489 } 490 491 sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; 492 sspi_w_token[0].BufferType = SECBUFFER_TOKEN; 493 sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); 494 495 if(!sspi_w_token[0].pvBuffer) { 496 s_pSecFn->DeleteSecurityContext(&sspi_context); 497 return CURLE_OUT_OF_MEMORY; 498 } 499 500 sspi_w_token[1].cbBuffer = 1; 501 sspi_w_token[1].pvBuffer = malloc(1); 502 if(!sspi_w_token[1].pvBuffer){ 503 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 504 s_pSecFn->DeleteSecurityContext(&sspi_context); 505 return CURLE_OUT_OF_MEMORY; 506 } 507 508 memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1); 509 sspi_w_token[2].BufferType = SECBUFFER_PADDING; 510 sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; 511 sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); 512 if(!sspi_w_token[2].pvBuffer) { 513 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 514 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 515 s_pSecFn->DeleteSecurityContext(&sspi_context); 516 return CURLE_OUT_OF_MEMORY; 517 } 518 sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context, 519 KERB_WRAP_NO_ENCRYPT, 520 &wrap_desc, 521 0); 522 if(check_sspi_err(data,sspi_major_status,sspi_minor_status, 523 "EncryptMessage") ) { 524 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 525 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 526 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 527 s_pSecFn->DeleteSecurityContext(&sspi_context); 528 failf(data, "Failed to query security context attributes."); 529 return CURLE_COULDNT_CONNECT; 530 } 531 sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer 532 + sspi_w_token[1].cbBuffer 533 + sspi_w_token[2].cbBuffer; 534 sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); 535 if(!sspi_send_token.pvBuffer) { 536 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 537 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 538 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 539 s_pSecFn->DeleteSecurityContext(&sspi_context); 540 return CURLE_OUT_OF_MEMORY; 541 } 542 543 memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, 544 sspi_w_token[0].cbBuffer); 545 memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, 546 sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 547 memcpy((PUCHAR) sspi_send_token.pvBuffer 548 +sspi_w_token[0].cbBuffer 549 +sspi_w_token[1].cbBuffer, 550 sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); 551 552 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 553 sspi_w_token[0].pvBuffer = NULL; 554 sspi_w_token[0].cbBuffer = 0; 555 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 556 sspi_w_token[1].pvBuffer = NULL; 557 sspi_w_token[1].cbBuffer = 0; 558 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 559 sspi_w_token[2].pvBuffer = NULL; 560 sspi_w_token[2].cbBuffer = 0; 561 562 us_length = htons((short)sspi_send_token.cbBuffer); 563 memcpy(socksreq+2,&us_length,sizeof(short)); 564 } 565 566 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); 567 if((code != CURLE_OK) || (4 != written)) { 568 failf(data, "Failed to send SSPI encryption request."); 569 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 570 s_pSecFn->DeleteSecurityContext(&sspi_context); 571 return CURLE_COULDNT_CONNECT; 572 } 573 574 if(data->set.socks5_gssapi_nec) { 575 memcpy(socksreq,&gss_enc,1); 576 code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); 577 if((code != CURLE_OK) || (1 != written)) { 578 failf(data, "Failed to send SSPI encryption type."); 579 s_pSecFn->DeleteSecurityContext(&sspi_context); 580 return CURLE_COULDNT_CONNECT; 581 } 582 } 583 else { 584 code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, 585 sspi_send_token.cbBuffer, &written); 586 if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { 587 failf(data, "Failed to send SSPI encryption type."); 588 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 589 s_pSecFn->DeleteSecurityContext(&sspi_context); 590 return CURLE_COULDNT_CONNECT; 591 } 592 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 593 } 594 595 result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, 596 &actualread, timeout); 597 if(result != CURLE_OK || actualread != 4) { 598 failf(data, "Failed to receive SSPI encryption response."); 599 s_pSecFn->DeleteSecurityContext(&sspi_context); 600 return CURLE_COULDNT_CONNECT; 601 } 602 603 /* ignore the first (VER) byte */ 604 if(socksreq[1] == 255) { /* status / message type */ 605 failf(data, "User was rejected by the SOCKS5 server (%d %d).", 606 socksreq[0], socksreq[1]); 607 s_pSecFn->DeleteSecurityContext(&sspi_context); 608 return CURLE_COULDNT_CONNECT; 609 } 610 611 if(socksreq[1] != 2) { /* status / message type */ 612 failf(data, "Invalid SSPI encryption response type (%d %d).", 613 socksreq[0], socksreq[1]); 614 s_pSecFn->DeleteSecurityContext(&sspi_context); 615 return CURLE_COULDNT_CONNECT; 616 } 617 618 memcpy(&us_length, socksreq+2, sizeof(short)); 619 us_length = ntohs(us_length); 620 621 sspi_w_token[0].cbBuffer = us_length; 622 sspi_w_token[0].pvBuffer = malloc(us_length); 623 if(!sspi_w_token[0].pvBuffer) { 624 s_pSecFn->DeleteSecurityContext(&sspi_context); 625 return CURLE_OUT_OF_MEMORY; 626 } 627 628 result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, 629 sspi_w_token[0].cbBuffer, 630 &actualread, timeout); 631 632 if(result != CURLE_OK || actualread != us_length) { 633 failf(data, "Failed to receive SSPI encryption type."); 634 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 635 s_pSecFn->DeleteSecurityContext(&sspi_context); 636 return CURLE_COULDNT_CONNECT; 637 } 638 639 640 if(!data->set.socks5_gssapi_nec) { 641 wrap_desc.cBuffers = 2; 642 sspi_w_token[0].BufferType = SECBUFFER_STREAM; 643 sspi_w_token[1].BufferType = SECBUFFER_DATA; 644 sspi_w_token[1].cbBuffer = 0; 645 sspi_w_token[1].pvBuffer = NULL; 646 647 sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context, 648 &wrap_desc, 649 0, 650 &qop); 651 652 if(check_sspi_err(data,sspi_major_status,sspi_minor_status, 653 "DecryptMessage")) { 654 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 655 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 656 s_pSecFn->DeleteSecurityContext(&sspi_context); 657 failf(data, "Failed to query security context attributes."); 658 return CURLE_COULDNT_CONNECT; 659 } 660 661 if(sspi_w_token[1].cbBuffer != 1) { 662 failf(data, "Invalid SSPI encryption response length (%d).", 663 sspi_w_token[1].cbBuffer); 664 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 665 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 666 s_pSecFn->DeleteSecurityContext(&sspi_context); 667 return CURLE_COULDNT_CONNECT; 668 } 669 670 memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer); 671 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 672 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 673 } 674 else { 675 if(sspi_w_token[0].cbBuffer != 1) { 676 failf(data, "Invalid SSPI encryption response length (%d).", 677 sspi_w_token[0].cbBuffer); 678 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 679 s_pSecFn->DeleteSecurityContext(&sspi_context); 680 return CURLE_COULDNT_CONNECT; 681 } 682 memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer); 683 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 684 } 685 686 infof(data, "SOCKS5 access with%s protection granted.\n", 687 (socksreq[0]==0)?"out gssapi data": 688 ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality")); 689 690 /* For later use if encryption is required 691 conn->socks5_gssapi_enctype = socksreq[0]; 692 if(socksreq[0] != 0) 693 conn->socks5_sspi_context = sspi_context; 694 else { 695 s_pSecFn->DeleteSecurityContext(&sspi_context); 696 conn->socks5_sspi_context = sspi_context; 697 } 698 */ 699 return CURLE_OK; 700} 701#endif 702