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