socks_sspi: split Curl_SOCKS5_gssapi_negotiate into sub functions
No binary (build failed)
—
(log yok)
| @@ -56,52 +56,70 @@ static int check_sspi_err(struct Curl_easy *data, | |
| } | |
| /* This is the SSPI-using version of this function */ | |
| - | CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, |
| - | struct Curl_easy *data) |
| + | static CURLcode socks5_sspi_setup(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | CredHandle *cred_handle, |
| + | char **service_namep) |
| { | |
| struct connectdata *conn = cf->conn; | |
| - | curl_socket_t sock = conn->sock[cf->sockindex]; |
| - | CURLcode code; |
| - | size_t actualread; |
| - | size_t written; |
| - | CURLcode result; |
| - | /* Needs GSS-API authentication */ |
| - | SECURITY_STATUS status; |
| - | unsigned long sspi_ret_flags = 0; |
| - | unsigned char gss_enc; |
| - | SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; |
| - | SecBufferDesc input_desc, output_desc, wrap_desc; |
| - | SecPkgContext_Sizes sspi_sizes; |
| - | CredHandle cred_handle; |
| - | CtxtHandle sspi_context; |
| - | PCtxtHandle context_handle = NULL; |
| - | SecPkgCredentials_Names names; |
| - | char *service_name = NULL; |
| - | unsigned short us_length; |
| - | unsigned long qop; |
| - | unsigned char socksreq[4]; /* room for GSS-API exchange header only */ |
| const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? | |
| - | data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; |
| - | uint8_t *etbuf; |
| - | size_t etbuf_size; |
| - | |
| - | /* GSS-API request looks like |
| - | * +----+------+-----+----------------+ |
| - | * |VER | MTYP | LEN | TOKEN | |
| - | * +----+------+----------------------+ |
| - | * | 1 | 1 | 2 | up to 2^16 - 1 | |
| - | * +----+------+-----+----------------+ |
| - | */ |
| + | data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; |
| + | SECURITY_STATUS status; |
| /* prepare service name */ | |
| if(strchr(service, '/')) | |
| - | service_name = curlx_strdup(service); |
| + | *service_namep = curlx_strdup(service); |
| else | |
| - | service_name = curl_maprintf("%s/%s", |
| - | service, conn->socks_proxy.host.name); |
| - | if(!service_name) |
| + | *service_namep = curl_maprintf("%s/%s", |
| + | service, conn->socks_proxy.host.name); |
| + | if(!*service_namep) |
| return CURLE_OUT_OF_MEMORY; | |
| + | status = |
| + | Curl_pSecFn->AcquireCredentialsHandle(NULL, |
| + | (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), |
| + | SECPKG_CRED_OUTBOUND, |
| + | NULL, NULL, NULL, NULL, |
| + | cred_handle, NULL); |
| + | |
| + | if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { |
| + | failf(data, "Failed to acquire credentials."); |
| + | return CURLE_COULDNT_CONNECT; |
| + | } |
| + | |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | static CURLcode socks5_free_token(SecBuffer *send_token, |
| + | CURLcode result) |
| + | { |
| + | if(send_token->pvBuffer) { |
| + | Curl_pSecFn->FreeContextBuffer(send_token->pvBuffer); |
| + | send_token->pvBuffer = NULL; |
| + | } |
| + | return result; |
| + | } |
| + | |
| + | static CURLcode socks5_sspi_loop(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | CredHandle *cred_handle, |
| + | CtxtHandle *sspi_context, |
| + | char *service_name, |
| + | unsigned long *sspi_ret_flagsp) |
| + | { |
| + | struct connectdata *conn = cf->conn; |
| + | curl_socket_t sock = conn->sock[cf->sockindex]; |
| + | CURLcode result = CURLE_OK; |
| + | CURLcode code; |
| + | SECURITY_STATUS status; |
| + | SecBuffer sspi_send_token, sspi_recv_token; |
| + | SecBufferDesc input_desc, output_desc; |
| + | PCtxtHandle context_handle = NULL; |
| + | unsigned short us_length; |
| + | size_t actualread; |
| + | size_t written; |
| + | unsigned char socksreq[4]; |
| + | |
| input_desc.cBuffers = 1; | |
| input_desc.pBuffers = &sspi_recv_token; | |
| input_desc.ulVersion = SECBUFFER_VERSION; | |
| @@ -118,50 +136,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| sspi_send_token.cbBuffer = 0; | |
| sspi_send_token.pvBuffer = NULL; | |
| - | sspi_w_token[0].pvBuffer = |
| - | sspi_w_token[1].pvBuffer = |
| - | sspi_w_token[2].pvBuffer = NULL; |
| - | |
| - | wrap_desc.cBuffers = 3; |
| - | wrap_desc.pBuffers = sspi_w_token; |
| - | wrap_desc.ulVersion = SECBUFFER_VERSION; |
| - | |
| - | memset(&cred_handle, 0, sizeof(cred_handle)); |
| - | memset(&sspi_context, 0, sizeof(sspi_context)); |
| - | |
| - | names.sUserName = NULL; |
| - | |
| - | etbuf = NULL; |
| - | etbuf_size = 0; |
| - | |
| - | status = |
| - | Curl_pSecFn->AcquireCredentialsHandle(NULL, |
| - | (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), |
| - | SECPKG_CRED_OUTBOUND, |
| - | NULL, NULL, NULL, NULL, |
| - | &cred_handle, NULL); |
| - | |
| - | if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { |
| - | failf(data, "Failed to acquire credentials."); |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| - | } |
| - | |
| (void)curlx_nonblock(sock, FALSE); | |
| - | /* As long as we need to keep sending some context info, and there is no */ |
| - | /* errors, keep sending it... */ |
| for(;;) { | |
| - | TCHAR *sname; |
| - | |
| - | sname = curlx_convert_UTF8_to_tchar(service_name); |
| + | TCHAR *sname = curlx_convert_UTF8_to_tchar(service_name); |
| if(!sname) { | |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| + | curlx_free(sspi_recv_token.pvBuffer); |
| + | return socks5_free_token(&sspi_send_token, CURLE_OUT_OF_MEMORY); |
| } | |
| status = | |
| - | Curl_pSecFn->InitializeSecurityContext(&cred_handle, context_handle, |
| + | Curl_pSecFn->InitializeSecurityContext(cred_handle, context_handle, |
| sname, | |
| ISC_REQ_MUTUAL_AUTH | | |
| ISC_REQ_ALLOCATE_MEMORY | | |
| @@ -169,19 +154,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| ISC_REQ_REPLAY_DETECT, | |
| 0, SECURITY_NATIVE_DREP, | |
| &input_desc, 0, | |
| - | &sspi_context, |
| + | sspi_context, |
| &output_desc, | |
| - | &sspi_ret_flags, NULL); |
| + | sspi_ret_flagsp, NULL); |
| curlx_free(sname); | |
| - | |
| Curl_safefree(sspi_recv_token.pvBuffer); | |
| sspi_recv_token.cbBuffer = 0; | |
| if(check_sspi_err(data, status, "InitializeSecurityContext")) { | |
| failf(data, "Failed to initialise security context."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return socks5_free_token(&sspi_send_token, CURLE_COULDNT_CONNECT); |
| } | |
| if(sspi_send_token.cbBuffer) { | |
| @@ -189,8 +172,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| socksreq[1] = 1; /* authentication message type */ | |
| if(sspi_send_token.cbBuffer > 0xffff) { | |
| /* needs to fit in an unsigned 16-bit field */ | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return socks5_free_token(&sspi_send_token, CURLE_COULDNT_CONNECT); |
| } | |
| us_length = htons((unsigned short)sspi_send_token.cbBuffer); | |
| memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| @@ -198,8 +180,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| code = Curl_conn_cf_send(cf->next, data, socksreq, 4, FALSE, &written); | |
| if(code || (written != 4)) { | |
| failf(data, "Failed to send SSPI authentication request."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return socks5_free_token(&sspi_send_token, CURLE_COULDNT_CONNECT); |
| } | |
| code = Curl_conn_cf_send(cf->next, data, | |
| @@ -207,15 +188,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| sspi_send_token.cbBuffer, FALSE, &written); | |
| if(code || (sspi_send_token.cbBuffer != written)) { | |
| failf(data, "Failed to send SSPI authentication token."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return socks5_free_token(&sspi_send_token, CURLE_COULDNT_CONNECT); |
| } | |
| } | |
| - | if(sspi_send_token.pvBuffer) { |
| - | Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); |
| - | sspi_send_token.pvBuffer = NULL; |
| - | } |
| + | if(sspi_send_token.pvBuffer) |
| + | socks5_free_token(&sspi_send_token, CURLE_OK); |
| sspi_send_token.cbBuffer = 0; | |
| Curl_safefree(sspi_recv_token.pvBuffer); | |
| @@ -224,37 +202,22 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| if(status != SEC_I_CONTINUE_NEEDED) | |
| break; | |
| - | /* analyse response */ |
| - | |
| - | /* GSS-API response looks like |
| - | * +----+------+-----+----------------+ |
| - | * |VER | MTYP | LEN | TOKEN | |
| - | * +----+------+----------------------+ |
| - | * | 1 | 1 | 2 | up to 2^16 - 1 | |
| - | * +----+------+-----+----------------+ |
| - | */ |
| - | |
| result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); | |
| if(result || (actualread != 4)) { | |
| failf(data, "Failed to receive SSPI authentication response."); | |
| - | if(!result) |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return result ? result : CURLE_COULDNT_CONNECT; |
| } | |
| - | /* ignore the first (VER) byte */ |
| - | if(socksreq[1] == 255) { /* status / message type */ |
| + | if(socksreq[1] == 255) { |
| failf(data, "User was rejected by the SOCKS5 server (%u %u).", | |
| (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| - | if(socksreq[1] != 1) { /* status / message type */ |
| + | if(socksreq[1] != 1) { |
| failf(data, "Invalid SSPI authentication response type (%u %u).", | |
| (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| memcpy(&us_length, socksreq + 2, sizeof(short)); | |
| @@ -263,52 +226,56 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| sspi_recv_token.cbBuffer = us_length; | |
| sspi_recv_token.pvBuffer = curlx_malloc(us_length); | |
| - | if(!sspi_recv_token.pvBuffer) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| + | if(!sspi_recv_token.pvBuffer) |
| + | return CURLE_OUT_OF_MEMORY; |
| + | |
| result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, | |
| sspi_recv_token.cbBuffer, &actualread); | |
| if(result || (actualread != us_length)) { | |
| failf(data, "Failed to receive SSPI authentication token."); | |
| - | if(!result) |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | curlx_free(sspi_recv_token.pvBuffer); |
| + | return result ? result : CURLE_COULDNT_CONNECT; |
| } | |
| - | context_handle = &sspi_context; |
| + | context_handle = sspi_context; |
| } | |
| - | Curl_safefree(service_name); |
| + | return CURLE_OK; |
| + | } |
| - | /* Everything is good so far, user was authenticated! */ |
| - | status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, |
| - | SECPKG_CRED_ATTR_NAMES, |
| - | &names); |
| - | if(check_sspi_err(data, status, "QueryCredentialAttributes")) { |
| - | failf(data, "Failed to determine username."); |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| - | } |
| - | else { |
| - | VERBOSE(char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName)); |
| - | infof(data, "SOCKS5 server authenticated user %s with GSS-API.", |
| - | (user_utf8 ? user_utf8 : "(unknown)")); |
| - | VERBOSE(curlx_free(user_utf8)); |
| - | Curl_pSecFn->FreeContextBuffer(names.sUserName); |
| - | names.sUserName = NULL; |
| - | } |
| + | static CURLcode socks5_free(SecBuffer *sspi_w_token, |
| + | CURLcode result) |
| + | { |
| + | Curl_safefree(sspi_w_token[0].pvBuffer); |
| + | Curl_safefree(sspi_w_token[1].pvBuffer); |
| + | Curl_safefree(sspi_w_token[2].pvBuffer); |
| + | return result; |
| + | } |
| - | /* Do encryption */ |
| - | socksreq[0] = 1; /* GSS-API subnegotiation version */ |
| - | socksreq[1] = 2; /* encryption message type */ |
| + | static CURLcode socks5_sspi_encrypt(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data, |
| + | CtxtHandle *sspi_context, |
| + | unsigned long sspi_ret_flags) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | CURLcode code; |
| + | SECURITY_STATUS status; |
| + | unsigned char gss_enc; |
| + | SecBuffer sspi_w_token[3]; |
| + | SecBufferDesc wrap_desc; |
| + | SecPkgContext_Sizes sspi_sizes; |
| + | unsigned short us_length; |
| + | unsigned long qop; |
| + | unsigned char socksreq[4]; |
| + | uint8_t *etbuf = NULL; |
| + | size_t etbuf_size = 0; |
| + | size_t actualread; |
| + | size_t written; |
| - | gss_enc = 0; /* no data protection */ |
| - | /* do confidentiality protection if supported */ |
| + | gss_enc = 0; |
| if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) | |
| gss_enc = 2; | |
| - | /* else do integrity protection */ |
| else if(sspi_ret_flags & ISC_REQ_INTEGRITY) | |
| gss_enc = 1; | |
| @@ -316,96 +283,64 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| (gss_enc == 0) ? "no" : | |
| ((gss_enc == 1) ? "integrity" : "confidentiality") ); | |
| - | /* |
| - | * Sending the encryption type in clear seems wrong. It should be |
| - | * protected with gss_seal()/gss_wrap(). See RFC1961 extract below |
| - | * The NEC reference implementations on which this is based is |
| - | * therefore at fault |
| - | * |
| - | * +------+------+------+.......................+ |
| - | * + ver | mtyp | len | token | |
| - | * +------+------+------+.......................+ |
| - | * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | |
| - | * +------+------+------+.......................+ |
| - | * |
| - | * Where: |
| - | * |
| - | * - "ver" is the protocol version number, here 1 to represent the |
| - | * first version of the SOCKS/GSS-API protocol |
| - | * |
| - | * - "mtyp" is the message type, here 2 to represent a protection |
| - | * -level negotiation message |
| - | * |
| - | * - "len" is the length of the "token" field in octets |
| - | * |
| - | * - "token" is the GSS-API encapsulated protection level |
| - | * |
| - | * The token is produced by encapsulating an octet containing the |
| - | * required protection level using gss_seal()/gss_wrap() with conf_req |
| - | * set to FALSE. The token is verified using gss_unseal()/ |
| - | * gss_unwrap(). |
| - | * |
| - | */ |
| + | sspi_w_token[0].pvBuffer = |
| + | sspi_w_token[1].pvBuffer = |
| + | sspi_w_token[2].pvBuffer = NULL; |
| + | |
| + | wrap_desc.cBuffers = 3; |
| + | wrap_desc.pBuffers = sspi_w_token; |
| + | wrap_desc.ulVersion = SECBUFFER_VERSION; |
| + | |
| + | socksreq[0] = 1; |
| + | socksreq[1] = 2; |
| if(data->set.socks5_gssapi_nec) { | |
| us_length = htons((unsigned short)1); | |
| memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| } | |
| else { | |
| - | status = Curl_pSecFn->QueryContextAttributes(&sspi_context, |
| + | status = Curl_pSecFn->QueryContextAttributes(sspi_context, |
| SECPKG_ATTR_SIZES, | |
| &sspi_sizes); | |
| if(check_sspi_err(data, status, "QueryContextAttributes")) { | |
| failf(data, "Failed to query security context attributes."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; | |
| sspi_w_token[0].BufferType = SECBUFFER_TOKEN; | |
| sspi_w_token[0].pvBuffer = curlx_malloc(sspi_sizes.cbSecurityTrailer); | |
| - | if(!sspi_w_token[0].pvBuffer) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| + | if(!sspi_w_token[0].pvBuffer) |
| + | return CURLE_OUT_OF_MEMORY; |
| sspi_w_token[1].cbBuffer = 1; | |
| + | sspi_w_token[1].BufferType = SECBUFFER_DATA; |
| sspi_w_token[1].pvBuffer = curlx_malloc(1); | |
| - | if(!sspi_w_token[1].pvBuffer) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| + | if(!sspi_w_token[1].pvBuffer) |
| + | return socks5_free(sspi_w_token, CURLE_OUT_OF_MEMORY); |
| memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); | |
| sspi_w_token[2].BufferType = SECBUFFER_PADDING; | |
| sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; | |
| sspi_w_token[2].pvBuffer = curlx_malloc(sspi_sizes.cbBlockSize); | |
| - | if(!sspi_w_token[2].pvBuffer) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| - | status = Curl_pSecFn->EncryptMessage(&sspi_context, |
| + | if(!sspi_w_token[2].pvBuffer) |
| + | return socks5_free(sspi_w_token, CURLE_OUT_OF_MEMORY); |
| + | |
| + | status = Curl_pSecFn->EncryptMessage(sspi_context, |
| KERB_WRAP_NO_ENCRYPT, | |
| &wrap_desc, 0); | |
| - | if(check_sspi_err(data, status, "EncryptMessage")) { |
| - | failf(data, "Failed to query security context attributes."); |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| - | } |
| + | if(check_sspi_err(data, status, "EncryptMessage")) |
| + | return socks5_free(sspi_w_token, CURLE_COULDNT_CONNECT); |
| etbuf_size = sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer + | |
| - | sspi_w_token[2].cbBuffer; |
| - | if(etbuf_size > 0xffff) { |
| - | /* needs to fit in an unsigned 16-bit field */ |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| - | } |
| + | sspi_w_token[2].cbBuffer; |
| + | if(etbuf_size > 0xffff) |
| + | return socks5_free(sspi_w_token, CURLE_COULDNT_CONNECT); |
| + | |
| etbuf = curlx_malloc(etbuf_size); | |
| - | if(!etbuf) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| + | if(!etbuf) |
| + | return socks5_free(sspi_w_token, CURLE_OUT_OF_MEMORY); |
| memcpy(etbuf, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); | |
| memcpy(etbuf + sspi_w_token[0].cbBuffer, | |
| @@ -413,12 +348,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| memcpy(etbuf + sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer, | |
| sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); | |
| - | Curl_safefree(sspi_w_token[0].pvBuffer); |
| - | sspi_w_token[0].cbBuffer = 0; |
| - | Curl_safefree(sspi_w_token[1].pvBuffer); |
| - | sspi_w_token[1].cbBuffer = 0; |
| - | Curl_safefree(sspi_w_token[2].pvBuffer); |
| - | sspi_w_token[2].cbBuffer = 0; |
| + | (void)socks5_free(sspi_w_token, CURLE_OK); |
| us_length = htons((unsigned short)etbuf_size); | |
| memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| @@ -427,8 +357,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| code = Curl_conn_cf_send(cf->next, data, socksreq, 4, FALSE, &written); | |
| if(code || (written != 4)) { | |
| failf(data, "Failed to send SSPI encryption request."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | curlx_free(etbuf); |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| if(data->set.socks5_gssapi_nec) { | |
| @@ -436,42 +366,35 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| code = Curl_conn_cf_send(cf->next, data, socksreq, 1, FALSE, &written); | |
| if(code || (written != 1)) { | |
| failf(data, "Failed to send SSPI encryption type."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| } | |
| else { | |
| - | code = Curl_conn_cf_send(cf->next, data, etbuf, etbuf_size, |
| - | FALSE, &written); |
| + | code = Curl_conn_cf_send(cf->next, data, etbuf, etbuf_size, FALSE, |
| + | &written); |
| + | curlx_free(etbuf); |
| if(code || (etbuf_size != written)) { | |
| failf(data, "Failed to send SSPI encryption type."); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| - | Curl_safefree(etbuf); |
| } | |
| result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); | |
| if(result || (actualread != 4)) { | |
| failf(data, "Failed to receive SSPI encryption response."); | |
| - | if(!result) |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return result ? result : CURLE_COULDNT_CONNECT; |
| } | |
| - | /* ignore the first (VER) byte */ |
| - | if(socksreq[1] == 255) { /* status / message type */ |
| + | if(socksreq[1] == 255) { |
| failf(data, "User was rejected by the SOCKS5 server (%u %u).", | |
| (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| - | if(socksreq[1] != 2) { /* status / message type */ |
| + | if(socksreq[1] != 2) { |
| failf(data, "Invalid SSPI encryption response type (%u %u).", | |
| (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| memcpy(&us_length, socksreq + 2, sizeof(short)); | |
| @@ -479,19 +402,16 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| sspi_w_token[0].cbBuffer = us_length; | |
| sspi_w_token[0].pvBuffer = curlx_malloc(us_length); | |
| - | if(!sspi_w_token[0].pvBuffer) { |
| - | result = CURLE_OUT_OF_MEMORY; |
| - | goto error; |
| - | } |
| + | if(!sspi_w_token[0].pvBuffer) |
| + | return CURLE_OUT_OF_MEMORY; |
| result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, | |
| sspi_w_token[0].cbBuffer, &actualread); | |
| if(result || (actualread != us_length)) { | |
| failf(data, "Failed to receive SSPI encryption type."); | |
| - | if(!result) |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | curlx_free(sspi_w_token[0].pvBuffer); |
| + | return result ? result : CURLE_COULDNT_CONNECT; |
| } | |
| if(!data->set.socks5_gssapi_nec) { | |
| @@ -501,86 +421,108 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, | |
| sspi_w_token[1].cbBuffer = 0; | |
| sspi_w_token[1].pvBuffer = NULL; | |
| - | status = Curl_pSecFn->DecryptMessage(&sspi_context, &wrap_desc, |
| + | status = Curl_pSecFn->DecryptMessage(sspi_context, &wrap_desc, |
| 0, &qop); | |
| - | /* since sspi_w_token[1].pvBuffer is allocated by the SSPI in this case, it |
| - | must be freed in this block using FreeContextBuffer() instead of |
| - | potentially in error cleanup using curlx_free(). */ |
| - | |
| if(check_sspi_err(data, status, "DecryptMessage")) { | |
| - | failf(data, "Failed to query security context attributes."); |
| - | if(sspi_w_token[1].pvBuffer) { |
| + | if(sspi_w_token[1].pvBuffer) |
| Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| - | sspi_w_token[1].pvBuffer = NULL; |
| - | } |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | curlx_free(sspi_w_token[0].pvBuffer); |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| if(sspi_w_token[1].cbBuffer != 1) { | |
| failf(data, "Invalid SSPI encryption response length (%lu).", | |
| (unsigned long)sspi_w_token[1].cbBuffer); | |
| - | if(sspi_w_token[1].pvBuffer) { |
| + | if(sspi_w_token[1].pvBuffer) |
| Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| - | sspi_w_token[1].pvBuffer = NULL; |
| - | } |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | curlx_free(sspi_w_token[0].pvBuffer); |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); | |
| - | Curl_safefree(sspi_w_token[0].pvBuffer); |
| - | sspi_w_token[0].cbBuffer = 0; |
| Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| - | sspi_w_token[1].pvBuffer = NULL; |
| - | sspi_w_token[1].cbBuffer = 0; |
| } | |
| else { | |
| if(sspi_w_token[0].cbBuffer != 1) { | |
| failf(data, "Invalid SSPI encryption response length (%lu).", | |
| - | sspi_w_token[0].cbBuffer); |
| - | result = CURLE_COULDNT_CONNECT; |
| - | goto error; |
| + | (unsigned long)sspi_w_token[0].cbBuffer); |
| + | curlx_free(sspi_w_token[0].pvBuffer); |
| + | return CURLE_COULDNT_CONNECT; |
| } | |
| memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); | |
| - | Curl_safefree(sspi_w_token[0].pvBuffer); |
| - | sspi_w_token[0].cbBuffer = 0; |
| } | |
| - | (void)curlx_nonblock(sock, TRUE); |
| + | curlx_free(sspi_w_token[0].pvBuffer); |
| infof(data, "SOCKS5 access with%s protection granted BUT NOT USED.", | |
| (socksreq[0] == 0) ? "out GSS-API data" : | |
| ((socksreq[0] == 1) ? " GSS-API integrity" : | |
| " GSS-API confidentiality")); | |
| - | /* For later use if encryption is required |
| - | conn->socks5_gssapi_enctype = socksreq[0]; |
| - | if(socksreq[0] != 0) |
| - | conn->socks5_sspi_context = sspi_context; |
| - | else { |
| - | Curl_pSecFn->DeleteSecurityContext(&sspi_context); |
| - | conn->socks5_sspi_context = sspi_context; |
| - | } |
| - | */ |
| + | return CURLE_OK; |
| + | } |
| + | |
| + | CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, |
| + | struct Curl_easy *data) |
| + | { |
| + | struct connectdata *conn = cf->conn; |
| + | curl_socket_t sock = conn->sock[cf->sockindex]; |
| + | CURLcode result; |
| + | SECURITY_STATUS status; |
| + | CredHandle cred_handle; |
| + | CtxtHandle sspi_context; |
| + | SecPkgCredentials_Names names; |
| + | char *service_name = NULL; |
| + | unsigned long sspi_ret_flags = 0; |
| + | |
| + | memset(&cred_handle, 0, sizeof(cred_handle)); |
| + | memset(&sspi_context, 0, sizeof(sspi_context)); |
| + | names.sUserName = NULL; |
| + | |
| + | result = socks5_sspi_setup(cf, data, &cred_handle, &service_name); |
| + | if(result) |
| + | goto error; |
| + | |
| + | result = socks5_sspi_loop(cf, data, &cred_handle, &sspi_context, |
| + | service_name, &sspi_ret_flags); |
| + | if(result) |
| + | goto error; |
| + | Curl_safefree(service_name); |
| + | |
| + | status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, |
| + | SECPKG_CRED_ATTR_NAMES, |
| + | &names); |
| + | if(check_sspi_err(data, status, "QueryCredentialAttributes")) { |
| + | failf(data, "Failed to determine username."); |
| + | result = CURLE_COULDNT_CONNECT; |
| + | goto error; |
| + | } |
| + | else { |
| + | VERBOSE(char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName)); |
| + | infof(data, "SOCKS5 server authenticated user %s with GSS-API.", |
| + | (user_utf8 ? user_utf8 : "(unknown)")); |
| + | VERBOSE(curlx_free(user_utf8)); |
| + | Curl_pSecFn->FreeContextBuffer(names.sUserName); |
| + | names.sUserName = NULL; |
| + | } |
| + | |
| + | result = socks5_sspi_encrypt(cf, data, &sspi_context, sspi_ret_flags); |
| + | if(result) |
| + | goto error; |
| + | |
| + | (void)curlx_nonblock(sock, TRUE); |
| Curl_pSecFn->DeleteSecurityContext(&sspi_context); | |
| Curl_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| return CURLE_OK; | |
| + | |
| error: | |
| (void)curlx_nonblock(sock, TRUE); | |
| curlx_free(service_name); | |
| Curl_pSecFn->DeleteSecurityContext(&sspi_context); | |
| Curl_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| - | curlx_free(sspi_recv_token.pvBuffer); |
| - | if(sspi_send_token.pvBuffer) |
| - | Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); |
| if(names.sUserName) | |
| Curl_pSecFn->FreeContextBuffer(names.sUserName); | |
| - | curlx_free(sspi_w_token[0].pvBuffer); |
| - | curlx_free(sspi_w_token[1].pvBuffer); |
| - | curlx_free(sspi_w_token[2].pvBuffer); |
| - | curlx_free(etbuf); |
| return result; | |
| } | |
| #endif | |