113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * Copyright (C) Markus Moeller, <markus_moeller@compuserve.com> 1013498266Sopenharmony_ci * 1113498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1213498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1313498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1413498266Sopenharmony_ci * 1513498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1613498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1713498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1813498266Sopenharmony_ci * 1913498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 2013498266Sopenharmony_ci * KIND, either express or implied. 2113498266Sopenharmony_ci * 2213498266Sopenharmony_ci * SPDX-License-Identifier: curl 2313498266Sopenharmony_ci * 2413498266Sopenharmony_ci ***************************************************************************/ 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#include "curl_setup.h" 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci#include "urldata.h" 3113498266Sopenharmony_ci#include "sendf.h" 3213498266Sopenharmony_ci#include "cfilters.h" 3313498266Sopenharmony_ci#include "connect.h" 3413498266Sopenharmony_ci#include "strerror.h" 3513498266Sopenharmony_ci#include "timeval.h" 3613498266Sopenharmony_ci#include "socks.h" 3713498266Sopenharmony_ci#include "curl_sspi.h" 3813498266Sopenharmony_ci#include "curl_multibyte.h" 3913498266Sopenharmony_ci#include "warnless.h" 4013498266Sopenharmony_ci#include "strdup.h" 4113498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 4213498266Sopenharmony_ci#include "curl_printf.h" 4313498266Sopenharmony_ci#include "curl_memory.h" 4413498266Sopenharmony_ci#include "memdebug.h" 4513498266Sopenharmony_ci 4613498266Sopenharmony_ci/* 4713498266Sopenharmony_ci * Helper sspi error functions. 4813498266Sopenharmony_ci */ 4913498266Sopenharmony_cistatic int check_sspi_err(struct Curl_easy *data, 5013498266Sopenharmony_ci SECURITY_STATUS status, 5113498266Sopenharmony_ci const char *function) 5213498266Sopenharmony_ci{ 5313498266Sopenharmony_ci if(status != SEC_E_OK && 5413498266Sopenharmony_ci status != SEC_I_COMPLETE_AND_CONTINUE && 5513498266Sopenharmony_ci status != SEC_I_COMPLETE_NEEDED && 5613498266Sopenharmony_ci status != SEC_I_CONTINUE_NEEDED) { 5713498266Sopenharmony_ci char buffer[STRERROR_LEN]; 5813498266Sopenharmony_ci failf(data, "SSPI error: %s failed: %s", function, 5913498266Sopenharmony_ci Curl_sspi_strerror(status, buffer, sizeof(buffer))); 6013498266Sopenharmony_ci return 1; 6113498266Sopenharmony_ci } 6213498266Sopenharmony_ci return 0; 6313498266Sopenharmony_ci} 6413498266Sopenharmony_ci 6513498266Sopenharmony_ci/* This is the SSPI-using version of this function */ 6613498266Sopenharmony_ciCURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, 6713498266Sopenharmony_ci struct Curl_easy *data) 6813498266Sopenharmony_ci{ 6913498266Sopenharmony_ci struct connectdata *conn = cf->conn; 7013498266Sopenharmony_ci curl_socket_t sock = conn->sock[cf->sockindex]; 7113498266Sopenharmony_ci CURLcode code; 7213498266Sopenharmony_ci ssize_t actualread; 7313498266Sopenharmony_ci ssize_t written; 7413498266Sopenharmony_ci int result; 7513498266Sopenharmony_ci /* Needs GSS-API authentication */ 7613498266Sopenharmony_ci SECURITY_STATUS status; 7713498266Sopenharmony_ci unsigned long sspi_ret_flags = 0; 7813498266Sopenharmony_ci unsigned char gss_enc; 7913498266Sopenharmony_ci SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; 8013498266Sopenharmony_ci SecBufferDesc input_desc, output_desc, wrap_desc; 8113498266Sopenharmony_ci SecPkgContext_Sizes sspi_sizes; 8213498266Sopenharmony_ci CredHandle cred_handle; 8313498266Sopenharmony_ci CtxtHandle sspi_context; 8413498266Sopenharmony_ci PCtxtHandle context_handle = NULL; 8513498266Sopenharmony_ci SecPkgCredentials_Names names; 8613498266Sopenharmony_ci TimeStamp expiry; 8713498266Sopenharmony_ci char *service_name = NULL; 8813498266Sopenharmony_ci unsigned short us_length; 8913498266Sopenharmony_ci unsigned long qop; 9013498266Sopenharmony_ci unsigned char socksreq[4]; /* room for GSS-API exchange header only */ 9113498266Sopenharmony_ci const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? 9213498266Sopenharmony_ci data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; 9313498266Sopenharmony_ci const size_t service_length = strlen(service); 9413498266Sopenharmony_ci 9513498266Sopenharmony_ci /* GSS-API request looks like 9613498266Sopenharmony_ci * +----+------+-----+----------------+ 9713498266Sopenharmony_ci * |VER | MTYP | LEN | TOKEN | 9813498266Sopenharmony_ci * +----+------+----------------------+ 9913498266Sopenharmony_ci * | 1 | 1 | 2 | up to 2^16 - 1 | 10013498266Sopenharmony_ci * +----+------+-----+----------------+ 10113498266Sopenharmony_ci */ 10213498266Sopenharmony_ci 10313498266Sopenharmony_ci /* prepare service name */ 10413498266Sopenharmony_ci if(strchr(service, '/')) { 10513498266Sopenharmony_ci service_name = strdup(service); 10613498266Sopenharmony_ci if(!service_name) 10713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 10813498266Sopenharmony_ci } 10913498266Sopenharmony_ci else { 11013498266Sopenharmony_ci service_name = malloc(service_length + 11113498266Sopenharmony_ci strlen(conn->socks_proxy.host.name) + 2); 11213498266Sopenharmony_ci if(!service_name) 11313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 11413498266Sopenharmony_ci msnprintf(service_name, service_length + 11513498266Sopenharmony_ci strlen(conn->socks_proxy.host.name) + 2, "%s/%s", 11613498266Sopenharmony_ci service, conn->socks_proxy.host.name); 11713498266Sopenharmony_ci } 11813498266Sopenharmony_ci 11913498266Sopenharmony_ci input_desc.cBuffers = 1; 12013498266Sopenharmony_ci input_desc.pBuffers = &sspi_recv_token; 12113498266Sopenharmony_ci input_desc.ulVersion = SECBUFFER_VERSION; 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci sspi_recv_token.BufferType = SECBUFFER_TOKEN; 12413498266Sopenharmony_ci sspi_recv_token.cbBuffer = 0; 12513498266Sopenharmony_ci sspi_recv_token.pvBuffer = NULL; 12613498266Sopenharmony_ci 12713498266Sopenharmony_ci output_desc.cBuffers = 1; 12813498266Sopenharmony_ci output_desc.pBuffers = &sspi_send_token; 12913498266Sopenharmony_ci output_desc.ulVersion = SECBUFFER_VERSION; 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci sspi_send_token.BufferType = SECBUFFER_TOKEN; 13213498266Sopenharmony_ci sspi_send_token.cbBuffer = 0; 13313498266Sopenharmony_ci sspi_send_token.pvBuffer = NULL; 13413498266Sopenharmony_ci 13513498266Sopenharmony_ci wrap_desc.cBuffers = 3; 13613498266Sopenharmony_ci wrap_desc.pBuffers = sspi_w_token; 13713498266Sopenharmony_ci wrap_desc.ulVersion = SECBUFFER_VERSION; 13813498266Sopenharmony_ci 13913498266Sopenharmony_ci cred_handle.dwLower = 0; 14013498266Sopenharmony_ci cred_handle.dwUpper = 0; 14113498266Sopenharmony_ci 14213498266Sopenharmony_ci status = s_pSecFn->AcquireCredentialsHandle(NULL, 14313498266Sopenharmony_ci (TCHAR *) TEXT("Kerberos"), 14413498266Sopenharmony_ci SECPKG_CRED_OUTBOUND, 14513498266Sopenharmony_ci NULL, 14613498266Sopenharmony_ci NULL, 14713498266Sopenharmony_ci NULL, 14813498266Sopenharmony_ci NULL, 14913498266Sopenharmony_ci &cred_handle, 15013498266Sopenharmony_ci &expiry); 15113498266Sopenharmony_ci 15213498266Sopenharmony_ci if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { 15313498266Sopenharmony_ci failf(data, "Failed to acquire credentials."); 15413498266Sopenharmony_ci free(service_name); 15513498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 15613498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 15713498266Sopenharmony_ci } 15813498266Sopenharmony_ci 15913498266Sopenharmony_ci (void)curlx_nonblock(sock, FALSE); 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci /* As long as we need to keep sending some context info, and there's no */ 16213498266Sopenharmony_ci /* errors, keep sending it... */ 16313498266Sopenharmony_ci for(;;) { 16413498266Sopenharmony_ci TCHAR *sname; 16513498266Sopenharmony_ci 16613498266Sopenharmony_ci sname = curlx_convert_UTF8_to_tchar(service_name); 16713498266Sopenharmony_ci if(!sname) 16813498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 16913498266Sopenharmony_ci 17013498266Sopenharmony_ci status = s_pSecFn->InitializeSecurityContext(&cred_handle, 17113498266Sopenharmony_ci context_handle, 17213498266Sopenharmony_ci sname, 17313498266Sopenharmony_ci ISC_REQ_MUTUAL_AUTH | 17413498266Sopenharmony_ci ISC_REQ_ALLOCATE_MEMORY | 17513498266Sopenharmony_ci ISC_REQ_CONFIDENTIALITY | 17613498266Sopenharmony_ci ISC_REQ_REPLAY_DETECT, 17713498266Sopenharmony_ci 0, 17813498266Sopenharmony_ci SECURITY_NATIVE_DREP, 17913498266Sopenharmony_ci &input_desc, 18013498266Sopenharmony_ci 0, 18113498266Sopenharmony_ci &sspi_context, 18213498266Sopenharmony_ci &output_desc, 18313498266Sopenharmony_ci &sspi_ret_flags, 18413498266Sopenharmony_ci &expiry); 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci curlx_unicodefree(sname); 18713498266Sopenharmony_ci 18813498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) { 18913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 19013498266Sopenharmony_ci sspi_recv_token.pvBuffer = NULL; 19113498266Sopenharmony_ci sspi_recv_token.cbBuffer = 0; 19213498266Sopenharmony_ci } 19313498266Sopenharmony_ci 19413498266Sopenharmony_ci if(check_sspi_err(data, status, "InitializeSecurityContext")) { 19513498266Sopenharmony_ci free(service_name); 19613498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 19713498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 19813498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) 19913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 20013498266Sopenharmony_ci failf(data, "Failed to initialise security context."); 20113498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 20213498266Sopenharmony_ci } 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci if(sspi_send_token.cbBuffer) { 20513498266Sopenharmony_ci socksreq[0] = 1; /* GSS-API subnegotiation version */ 20613498266Sopenharmony_ci socksreq[1] = 1; /* authentication message type */ 20713498266Sopenharmony_ci us_length = htons((short)sspi_send_token.cbBuffer); 20813498266Sopenharmony_ci memcpy(socksreq + 2, &us_length, sizeof(short)); 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); 21113498266Sopenharmony_ci if(code || (4 != written)) { 21213498266Sopenharmony_ci failf(data, "Failed to send SSPI authentication request."); 21313498266Sopenharmony_ci free(service_name); 21413498266Sopenharmony_ci if(sspi_send_token.pvBuffer) 21513498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 21613498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) 21713498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 21813498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 21913498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 22013498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 22113498266Sopenharmony_ci } 22213498266Sopenharmony_ci 22313498266Sopenharmony_ci written = Curl_conn_cf_send(cf->next, data, 22413498266Sopenharmony_ci (char *)sspi_send_token.pvBuffer, 22513498266Sopenharmony_ci sspi_send_token.cbBuffer, &code); 22613498266Sopenharmony_ci if(code || (sspi_send_token.cbBuffer != (size_t)written)) { 22713498266Sopenharmony_ci failf(data, "Failed to send SSPI authentication token."); 22813498266Sopenharmony_ci free(service_name); 22913498266Sopenharmony_ci if(sspi_send_token.pvBuffer) 23013498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 23113498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) 23213498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 23313498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 23413498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 23513498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 23613498266Sopenharmony_ci } 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci } 23913498266Sopenharmony_ci 24013498266Sopenharmony_ci if(sspi_send_token.pvBuffer) { 24113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 24213498266Sopenharmony_ci sspi_send_token.pvBuffer = NULL; 24313498266Sopenharmony_ci } 24413498266Sopenharmony_ci sspi_send_token.cbBuffer = 0; 24513498266Sopenharmony_ci 24613498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) { 24713498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 24813498266Sopenharmony_ci sspi_recv_token.pvBuffer = NULL; 24913498266Sopenharmony_ci } 25013498266Sopenharmony_ci sspi_recv_token.cbBuffer = 0; 25113498266Sopenharmony_ci 25213498266Sopenharmony_ci if(status != SEC_I_CONTINUE_NEEDED) 25313498266Sopenharmony_ci break; 25413498266Sopenharmony_ci 25513498266Sopenharmony_ci /* analyse response */ 25613498266Sopenharmony_ci 25713498266Sopenharmony_ci /* GSS-API response looks like 25813498266Sopenharmony_ci * +----+------+-----+----------------+ 25913498266Sopenharmony_ci * |VER | MTYP | LEN | TOKEN | 26013498266Sopenharmony_ci * +----+------+----------------------+ 26113498266Sopenharmony_ci * | 1 | 1 | 2 | up to 2^16 - 1 | 26213498266Sopenharmony_ci * +----+------+-----+----------------+ 26313498266Sopenharmony_ci */ 26413498266Sopenharmony_ci 26513498266Sopenharmony_ci result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 26613498266Sopenharmony_ci if(result || (actualread != 4)) { 26713498266Sopenharmony_ci failf(data, "Failed to receive SSPI authentication response."); 26813498266Sopenharmony_ci free(service_name); 26913498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 27013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 27113498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 27213498266Sopenharmony_ci } 27313498266Sopenharmony_ci 27413498266Sopenharmony_ci /* ignore the first (VER) byte */ 27513498266Sopenharmony_ci if(socksreq[1] == 255) { /* status / message type */ 27613498266Sopenharmony_ci failf(data, "User was rejected by the SOCKS5 server (%u %u).", 27713498266Sopenharmony_ci (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 27813498266Sopenharmony_ci free(service_name); 27913498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 28013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 28113498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 28213498266Sopenharmony_ci } 28313498266Sopenharmony_ci 28413498266Sopenharmony_ci if(socksreq[1] != 1) { /* status / message type */ 28513498266Sopenharmony_ci failf(data, "Invalid SSPI authentication response type (%u %u).", 28613498266Sopenharmony_ci (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 28713498266Sopenharmony_ci free(service_name); 28813498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 28913498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 29013498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 29113498266Sopenharmony_ci } 29213498266Sopenharmony_ci 29313498266Sopenharmony_ci memcpy(&us_length, socksreq + 2, sizeof(short)); 29413498266Sopenharmony_ci us_length = ntohs(us_length); 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci sspi_recv_token.cbBuffer = us_length; 29713498266Sopenharmony_ci sspi_recv_token.pvBuffer = malloc(us_length); 29813498266Sopenharmony_ci 29913498266Sopenharmony_ci if(!sspi_recv_token.pvBuffer) { 30013498266Sopenharmony_ci free(service_name); 30113498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 30213498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 30313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, 30613498266Sopenharmony_ci sspi_recv_token.cbBuffer, &actualread); 30713498266Sopenharmony_ci 30813498266Sopenharmony_ci if(result || (actualread != us_length)) { 30913498266Sopenharmony_ci failf(data, "Failed to receive SSPI authentication token."); 31013498266Sopenharmony_ci free(service_name); 31113498266Sopenharmony_ci if(sspi_recv_token.pvBuffer) 31213498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); 31313498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 31413498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 31513498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 31613498266Sopenharmony_ci } 31713498266Sopenharmony_ci 31813498266Sopenharmony_ci context_handle = &sspi_context; 31913498266Sopenharmony_ci } 32013498266Sopenharmony_ci 32113498266Sopenharmony_ci free(service_name); 32213498266Sopenharmony_ci 32313498266Sopenharmony_ci /* Everything is good so far, user was authenticated! */ 32413498266Sopenharmony_ci status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, 32513498266Sopenharmony_ci SECPKG_CRED_ATTR_NAMES, 32613498266Sopenharmony_ci &names); 32713498266Sopenharmony_ci s_pSecFn->FreeCredentialsHandle(&cred_handle); 32813498266Sopenharmony_ci if(check_sspi_err(data, status, "QueryCredentialAttributes")) { 32913498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 33013498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(names.sUserName); 33113498266Sopenharmony_ci failf(data, "Failed to determine user name."); 33213498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 33313498266Sopenharmony_ci } 33413498266Sopenharmony_ci else { 33513498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS 33613498266Sopenharmony_ci char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName); 33713498266Sopenharmony_ci infof(data, "SOCKS5 server authenticated user %s with GSS-API.", 33813498266Sopenharmony_ci (user_utf8 ? user_utf8 : "(unknown)")); 33913498266Sopenharmony_ci curlx_unicodefree(user_utf8); 34013498266Sopenharmony_ci#endif 34113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(names.sUserName); 34213498266Sopenharmony_ci } 34313498266Sopenharmony_ci 34413498266Sopenharmony_ci /* Do encryption */ 34513498266Sopenharmony_ci socksreq[0] = 1; /* GSS-API subnegotiation version */ 34613498266Sopenharmony_ci socksreq[1] = 2; /* encryption message type */ 34713498266Sopenharmony_ci 34813498266Sopenharmony_ci gss_enc = 0; /* no data protection */ 34913498266Sopenharmony_ci /* do confidentiality protection if supported */ 35013498266Sopenharmony_ci if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) 35113498266Sopenharmony_ci gss_enc = 2; 35213498266Sopenharmony_ci /* else do integrity protection */ 35313498266Sopenharmony_ci else if(sspi_ret_flags & ISC_REQ_INTEGRITY) 35413498266Sopenharmony_ci gss_enc = 1; 35513498266Sopenharmony_ci 35613498266Sopenharmony_ci infof(data, "SOCKS5 server supports GSS-API %s data protection.", 35713498266Sopenharmony_ci (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); 35813498266Sopenharmony_ci /* force to no data protection, avoid encryption/decryption for now */ 35913498266Sopenharmony_ci gss_enc = 0; 36013498266Sopenharmony_ci /* 36113498266Sopenharmony_ci * Sending the encryption type in clear seems wrong. It should be 36213498266Sopenharmony_ci * protected with gss_seal()/gss_wrap(). See RFC1961 extract below 36313498266Sopenharmony_ci * The NEC reference implementations on which this is based is 36413498266Sopenharmony_ci * therefore at fault 36513498266Sopenharmony_ci * 36613498266Sopenharmony_ci * +------+------+------+.......................+ 36713498266Sopenharmony_ci * + ver | mtyp | len | token | 36813498266Sopenharmony_ci * +------+------+------+.......................+ 36913498266Sopenharmony_ci * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | 37013498266Sopenharmony_ci * +------+------+------+.......................+ 37113498266Sopenharmony_ci * 37213498266Sopenharmony_ci * Where: 37313498266Sopenharmony_ci * 37413498266Sopenharmony_ci * - "ver" is the protocol version number, here 1 to represent the 37513498266Sopenharmony_ci * first version of the SOCKS/GSS-API protocol 37613498266Sopenharmony_ci * 37713498266Sopenharmony_ci * - "mtyp" is the message type, here 2 to represent a protection 37813498266Sopenharmony_ci * -level negotiation message 37913498266Sopenharmony_ci * 38013498266Sopenharmony_ci * - "len" is the length of the "token" field in octets 38113498266Sopenharmony_ci * 38213498266Sopenharmony_ci * - "token" is the GSS-API encapsulated protection level 38313498266Sopenharmony_ci * 38413498266Sopenharmony_ci * The token is produced by encapsulating an octet containing the 38513498266Sopenharmony_ci * required protection level using gss_seal()/gss_wrap() with conf_req 38613498266Sopenharmony_ci * set to FALSE. The token is verified using gss_unseal()/ 38713498266Sopenharmony_ci * gss_unwrap(). 38813498266Sopenharmony_ci * 38913498266Sopenharmony_ci */ 39013498266Sopenharmony_ci 39113498266Sopenharmony_ci if(data->set.socks5_gssapi_nec) { 39213498266Sopenharmony_ci us_length = htons((short)1); 39313498266Sopenharmony_ci memcpy(socksreq + 2, &us_length, sizeof(short)); 39413498266Sopenharmony_ci } 39513498266Sopenharmony_ci else { 39613498266Sopenharmony_ci status = s_pSecFn->QueryContextAttributes(&sspi_context, 39713498266Sopenharmony_ci SECPKG_ATTR_SIZES, 39813498266Sopenharmony_ci &sspi_sizes); 39913498266Sopenharmony_ci if(check_sspi_err(data, status, "QueryContextAttributes")) { 40013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 40113498266Sopenharmony_ci failf(data, "Failed to query security context attributes."); 40213498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 40313498266Sopenharmony_ci } 40413498266Sopenharmony_ci 40513498266Sopenharmony_ci sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; 40613498266Sopenharmony_ci sspi_w_token[0].BufferType = SECBUFFER_TOKEN; 40713498266Sopenharmony_ci sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); 40813498266Sopenharmony_ci 40913498266Sopenharmony_ci if(!sspi_w_token[0].pvBuffer) { 41013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 41113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 41213498266Sopenharmony_ci } 41313498266Sopenharmony_ci 41413498266Sopenharmony_ci sspi_w_token[1].cbBuffer = 1; 41513498266Sopenharmony_ci sspi_w_token[1].pvBuffer = malloc(1); 41613498266Sopenharmony_ci if(!sspi_w_token[1].pvBuffer) { 41713498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 41813498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 41913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 42013498266Sopenharmony_ci } 42113498266Sopenharmony_ci 42213498266Sopenharmony_ci memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); 42313498266Sopenharmony_ci sspi_w_token[2].BufferType = SECBUFFER_PADDING; 42413498266Sopenharmony_ci sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; 42513498266Sopenharmony_ci sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); 42613498266Sopenharmony_ci if(!sspi_w_token[2].pvBuffer) { 42713498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 42813498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 42913498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 43013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 43113498266Sopenharmony_ci } 43213498266Sopenharmony_ci status = s_pSecFn->EncryptMessage(&sspi_context, 43313498266Sopenharmony_ci KERB_WRAP_NO_ENCRYPT, 43413498266Sopenharmony_ci &wrap_desc, 43513498266Sopenharmony_ci 0); 43613498266Sopenharmony_ci if(check_sspi_err(data, status, "EncryptMessage")) { 43713498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 43813498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 43913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 44013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 44113498266Sopenharmony_ci failf(data, "Failed to query security context attributes."); 44213498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 44313498266Sopenharmony_ci } 44413498266Sopenharmony_ci sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer 44513498266Sopenharmony_ci + sspi_w_token[1].cbBuffer 44613498266Sopenharmony_ci + sspi_w_token[2].cbBuffer; 44713498266Sopenharmony_ci sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); 44813498266Sopenharmony_ci if(!sspi_send_token.pvBuffer) { 44913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 45013498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 45113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 45213498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 45313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 45413498266Sopenharmony_ci } 45513498266Sopenharmony_ci 45613498266Sopenharmony_ci memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, 45713498266Sopenharmony_ci sspi_w_token[0].cbBuffer); 45813498266Sopenharmony_ci memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, 45913498266Sopenharmony_ci sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 46013498266Sopenharmony_ci memcpy((PUCHAR) sspi_send_token.pvBuffer 46113498266Sopenharmony_ci + sspi_w_token[0].cbBuffer 46213498266Sopenharmony_ci + sspi_w_token[1].cbBuffer, 46313498266Sopenharmony_ci sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); 46413498266Sopenharmony_ci 46513498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 46613498266Sopenharmony_ci sspi_w_token[0].pvBuffer = NULL; 46713498266Sopenharmony_ci sspi_w_token[0].cbBuffer = 0; 46813498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 46913498266Sopenharmony_ci sspi_w_token[1].pvBuffer = NULL; 47013498266Sopenharmony_ci sspi_w_token[1].cbBuffer = 0; 47113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); 47213498266Sopenharmony_ci sspi_w_token[2].pvBuffer = NULL; 47313498266Sopenharmony_ci sspi_w_token[2].cbBuffer = 0; 47413498266Sopenharmony_ci 47513498266Sopenharmony_ci us_length = htons((short)sspi_send_token.cbBuffer); 47613498266Sopenharmony_ci memcpy(socksreq + 2, &us_length, sizeof(short)); 47713498266Sopenharmony_ci } 47813498266Sopenharmony_ci 47913498266Sopenharmony_ci written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code); 48013498266Sopenharmony_ci if(code || (4 != written)) { 48113498266Sopenharmony_ci failf(data, "Failed to send SSPI encryption request."); 48213498266Sopenharmony_ci if(sspi_send_token.pvBuffer) 48313498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 48413498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 48513498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 48613498266Sopenharmony_ci } 48713498266Sopenharmony_ci 48813498266Sopenharmony_ci if(data->set.socks5_gssapi_nec) { 48913498266Sopenharmony_ci memcpy(socksreq, &gss_enc, 1); 49013498266Sopenharmony_ci written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code); 49113498266Sopenharmony_ci if(code || (1 != written)) { 49213498266Sopenharmony_ci failf(data, "Failed to send SSPI encryption type."); 49313498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 49413498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 49513498266Sopenharmony_ci } 49613498266Sopenharmony_ci } 49713498266Sopenharmony_ci else { 49813498266Sopenharmony_ci written = Curl_conn_cf_send(cf->next, data, 49913498266Sopenharmony_ci (char *)sspi_send_token.pvBuffer, 50013498266Sopenharmony_ci sspi_send_token.cbBuffer, &code); 50113498266Sopenharmony_ci if(code || (sspi_send_token.cbBuffer != (size_t)written)) { 50213498266Sopenharmony_ci failf(data, "Failed to send SSPI encryption type."); 50313498266Sopenharmony_ci if(sspi_send_token.pvBuffer) 50413498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 50513498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 50613498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 50713498266Sopenharmony_ci } 50813498266Sopenharmony_ci if(sspi_send_token.pvBuffer) 50913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); 51013498266Sopenharmony_ci } 51113498266Sopenharmony_ci 51213498266Sopenharmony_ci result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); 51313498266Sopenharmony_ci if(result || (actualread != 4)) { 51413498266Sopenharmony_ci failf(data, "Failed to receive SSPI encryption response."); 51513498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 51613498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 51713498266Sopenharmony_ci } 51813498266Sopenharmony_ci 51913498266Sopenharmony_ci /* ignore the first (VER) byte */ 52013498266Sopenharmony_ci if(socksreq[1] == 255) { /* status / message type */ 52113498266Sopenharmony_ci failf(data, "User was rejected by the SOCKS5 server (%u %u).", 52213498266Sopenharmony_ci (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 52313498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 52413498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 52513498266Sopenharmony_ci } 52613498266Sopenharmony_ci 52713498266Sopenharmony_ci if(socksreq[1] != 2) { /* status / message type */ 52813498266Sopenharmony_ci failf(data, "Invalid SSPI encryption response type (%u %u).", 52913498266Sopenharmony_ci (unsigned int)socksreq[0], (unsigned int)socksreq[1]); 53013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 53113498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 53213498266Sopenharmony_ci } 53313498266Sopenharmony_ci 53413498266Sopenharmony_ci memcpy(&us_length, socksreq + 2, sizeof(short)); 53513498266Sopenharmony_ci us_length = ntohs(us_length); 53613498266Sopenharmony_ci 53713498266Sopenharmony_ci sspi_w_token[0].cbBuffer = us_length; 53813498266Sopenharmony_ci sspi_w_token[0].pvBuffer = malloc(us_length); 53913498266Sopenharmony_ci if(!sspi_w_token[0].pvBuffer) { 54013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 54113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 54213498266Sopenharmony_ci } 54313498266Sopenharmony_ci 54413498266Sopenharmony_ci result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, 54513498266Sopenharmony_ci sspi_w_token[0].cbBuffer, &actualread); 54613498266Sopenharmony_ci 54713498266Sopenharmony_ci if(result || (actualread != us_length)) { 54813498266Sopenharmony_ci failf(data, "Failed to receive SSPI encryption type."); 54913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 55013498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 55113498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 55213498266Sopenharmony_ci } 55313498266Sopenharmony_ci 55413498266Sopenharmony_ci 55513498266Sopenharmony_ci if(!data->set.socks5_gssapi_nec) { 55613498266Sopenharmony_ci wrap_desc.cBuffers = 2; 55713498266Sopenharmony_ci sspi_w_token[0].BufferType = SECBUFFER_STREAM; 55813498266Sopenharmony_ci sspi_w_token[1].BufferType = SECBUFFER_DATA; 55913498266Sopenharmony_ci sspi_w_token[1].cbBuffer = 0; 56013498266Sopenharmony_ci sspi_w_token[1].pvBuffer = NULL; 56113498266Sopenharmony_ci 56213498266Sopenharmony_ci status = s_pSecFn->DecryptMessage(&sspi_context, 56313498266Sopenharmony_ci &wrap_desc, 56413498266Sopenharmony_ci 0, 56513498266Sopenharmony_ci &qop); 56613498266Sopenharmony_ci 56713498266Sopenharmony_ci if(check_sspi_err(data, status, "DecryptMessage")) { 56813498266Sopenharmony_ci if(sspi_w_token[0].pvBuffer) 56913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 57013498266Sopenharmony_ci if(sspi_w_token[1].pvBuffer) 57113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 57213498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 57313498266Sopenharmony_ci failf(data, "Failed to query security context attributes."); 57413498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 57513498266Sopenharmony_ci } 57613498266Sopenharmony_ci 57713498266Sopenharmony_ci if(sspi_w_token[1].cbBuffer != 1) { 57813498266Sopenharmony_ci failf(data, "Invalid SSPI encryption response length (%lu).", 57913498266Sopenharmony_ci (unsigned long)sspi_w_token[1].cbBuffer); 58013498266Sopenharmony_ci if(sspi_w_token[0].pvBuffer) 58113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 58213498266Sopenharmony_ci if(sspi_w_token[1].pvBuffer) 58313498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 58413498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 58513498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 58613498266Sopenharmony_ci } 58713498266Sopenharmony_ci 58813498266Sopenharmony_ci memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); 58913498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 59013498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); 59113498266Sopenharmony_ci } 59213498266Sopenharmony_ci else { 59313498266Sopenharmony_ci if(sspi_w_token[0].cbBuffer != 1) { 59413498266Sopenharmony_ci failf(data, "Invalid SSPI encryption response length (%lu).", 59513498266Sopenharmony_ci (unsigned long)sspi_w_token[0].cbBuffer); 59613498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 59713498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 59813498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 59913498266Sopenharmony_ci } 60013498266Sopenharmony_ci memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); 60113498266Sopenharmony_ci s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); 60213498266Sopenharmony_ci } 60313498266Sopenharmony_ci (void)curlx_nonblock(sock, TRUE); 60413498266Sopenharmony_ci 60513498266Sopenharmony_ci infof(data, "SOCKS5 access with%s protection granted.", 60613498266Sopenharmony_ci (socksreq[0] == 0)?"out GSS-API data": 60713498266Sopenharmony_ci ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); 60813498266Sopenharmony_ci 60913498266Sopenharmony_ci /* For later use if encryption is required 61013498266Sopenharmony_ci conn->socks5_gssapi_enctype = socksreq[0]; 61113498266Sopenharmony_ci if(socksreq[0] != 0) 61213498266Sopenharmony_ci conn->socks5_sspi_context = sspi_context; 61313498266Sopenharmony_ci else { 61413498266Sopenharmony_ci s_pSecFn->DeleteSecurityContext(&sspi_context); 61513498266Sopenharmony_ci conn->socks5_sspi_context = sspi_context; 61613498266Sopenharmony_ci } 61713498266Sopenharmony_ci */ 61813498266Sopenharmony_ci return CURLE_OK; 61913498266Sopenharmony_ci} 62013498266Sopenharmony_ci#endif 621