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