Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/socks_sspi.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 2012 - 2019, 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 /* As long as we need to keep sending some context info, and there's no */ | |
| 157 /* errors, keep sending it... */ | |
| 158 for(;;) { | |
| 159 TCHAR *sname; | |
| 160 | |
| 161 sname = Curl_convert_UTF8_to_tchar(service_name); | |
| 162 if(!sname) | |
| 163 return CURLE_OUT_OF_MEMORY; | |
| 164 | |
| 165 status = s_pSecFn->InitializeSecurityContext(&cred_handle, | |
| 166 context_handle, | |
| 167 sname, | |
| 168 ISC_REQ_MUTUAL_AUTH | | |
| 169 ISC_REQ_ALLOCATE_MEMORY | | |
| 170 ISC_REQ_CONFIDENTIALITY | | |
| 171 ISC_REQ_REPLAY_DETECT, | |
| 172 0, | |
| 173 SECURITY_NATIVE_DREP, | |
| 174 &input_desc, | |
| 175 0, | |
| 176 &sspi_context, | |
| 177 &output_desc, | |
| 178 &sspi_ret_flags, | |
| 179 &expiry); | |
| 180 | |
| 181 Curl_unicodefree(sname); | |
| 182 | |
| 183 if(sspi_recv_token.pvBuffer) { | |
| 184 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 185 sspi_recv_token.pvBuffer = NULL; | |
| 186 sspi_recv_token.cbBuffer = 0; | |
| 187 } | |
| 188 | |
| 189 if(check_sspi_err(conn, status, "InitializeSecurityContext")) { | |
| 190 free(service_name); | |
| 191 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 192 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 193 if(sspi_recv_token.pvBuffer) | |
| 194 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 195 failf(data, "Failed to initialise security context."); | |
| 196 return CURLE_COULDNT_CONNECT; | |
| 197 } | |
| 198 | |
| 199 if(sspi_send_token.cbBuffer != 0) { | |
| 200 socksreq[0] = 1; /* GSS-API subnegotiation version */ | |
| 201 socksreq[1] = 1; /* authentication message type */ | |
| 202 us_length = htons((short)sspi_send_token.cbBuffer); | |
| 203 memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| 204 | |
| 205 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); | |
| 206 if(code || (4 != written)) { | |
| 207 failf(data, "Failed to send SSPI authentication request."); | |
| 208 free(service_name); | |
| 209 if(sspi_send_token.pvBuffer) | |
| 210 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 211 if(sspi_recv_token.pvBuffer) | |
| 212 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 213 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 214 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 215 return CURLE_COULDNT_CONNECT; | |
| 216 } | |
| 217 | |
| 218 code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, | |
| 219 sspi_send_token.cbBuffer, &written); | |
| 220 if(code || (sspi_send_token.cbBuffer != (size_t)written)) { | |
| 221 failf(data, "Failed to send SSPI authentication token."); | |
| 222 free(service_name); | |
| 223 if(sspi_send_token.pvBuffer) | |
| 224 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 225 if(sspi_recv_token.pvBuffer) | |
| 226 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 227 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 228 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 229 return CURLE_COULDNT_CONNECT; | |
| 230 } | |
| 231 | |
| 232 } | |
| 233 | |
| 234 if(sspi_send_token.pvBuffer) { | |
| 235 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 236 sspi_send_token.pvBuffer = NULL; | |
| 237 } | |
| 238 sspi_send_token.cbBuffer = 0; | |
| 239 | |
| 240 if(sspi_recv_token.pvBuffer) { | |
| 241 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 242 sspi_recv_token.pvBuffer = NULL; | |
| 243 } | |
| 244 sspi_recv_token.cbBuffer = 0; | |
| 245 | |
| 246 if(status != SEC_I_CONTINUE_NEEDED) | |
| 247 break; | |
| 248 | |
| 249 /* analyse response */ | |
| 250 | |
| 251 /* GSS-API response looks like | |
| 252 * +----+------+-----+----------------+ | |
| 253 * |VER | MTYP | LEN | TOKEN | | |
| 254 * +----+------+----------------------+ | |
| 255 * | 1 | 1 | 2 | up to 2^16 - 1 | | |
| 256 * +----+------+-----+----------------+ | |
| 257 */ | |
| 258 | |
| 259 result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); | |
| 260 if(result || (actualread != 4)) { | |
| 261 failf(data, "Failed to receive SSPI authentication response."); | |
| 262 free(service_name); | |
| 263 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 264 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 265 return CURLE_COULDNT_CONNECT; | |
| 266 } | |
| 267 | |
| 268 /* ignore the first (VER) byte */ | |
| 269 if(socksreq[1] == 255) { /* status / message type */ | |
| 270 failf(data, "User was rejected by the SOCKS5 server (%u %u).", | |
| 271 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| 272 free(service_name); | |
| 273 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 274 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 275 return CURLE_COULDNT_CONNECT; | |
| 276 } | |
| 277 | |
| 278 if(socksreq[1] != 1) { /* status / messgae type */ | |
| 279 failf(data, "Invalid SSPI authentication response type (%u %u).", | |
| 280 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| 281 free(service_name); | |
| 282 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 283 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 284 return CURLE_COULDNT_CONNECT; | |
| 285 } | |
| 286 | |
| 287 memcpy(&us_length, socksreq + 2, sizeof(short)); | |
| 288 us_length = ntohs(us_length); | |
| 289 | |
| 290 sspi_recv_token.cbBuffer = us_length; | |
| 291 sspi_recv_token.pvBuffer = malloc(us_length); | |
| 292 | |
| 293 if(!sspi_recv_token.pvBuffer) { | |
| 294 free(service_name); | |
| 295 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 296 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 297 return CURLE_OUT_OF_MEMORY; | |
| 298 } | |
| 299 result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, | |
| 300 sspi_recv_token.cbBuffer, &actualread); | |
| 301 | |
| 302 if(result || (actualread != us_length)) { | |
| 303 failf(data, "Failed to receive SSPI authentication token."); | |
| 304 free(service_name); | |
| 305 if(sspi_recv_token.pvBuffer) | |
| 306 s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); | |
| 307 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 308 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 309 return CURLE_COULDNT_CONNECT; | |
| 310 } | |
| 311 | |
| 312 context_handle = &sspi_context; | |
| 313 } | |
| 314 | |
| 315 free(service_name); | |
| 316 | |
| 317 /* Everything is good so far, user was authenticated! */ | |
| 318 status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, | |
| 319 SECPKG_CRED_ATTR_NAMES, | |
| 320 &names); | |
| 321 s_pSecFn->FreeCredentialsHandle(&cred_handle); | |
| 322 if(check_sspi_err(conn, status, "QueryCredentialAttributes")) { | |
| 323 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 324 s_pSecFn->FreeContextBuffer(names.sUserName); | |
| 325 failf(data, "Failed to determine user name."); | |
| 326 return CURLE_COULDNT_CONNECT; | |
| 327 } | |
| 328 infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n", | |
| 329 names.sUserName); | |
| 330 s_pSecFn->FreeContextBuffer(names.sUserName); | |
| 331 | |
| 332 /* Do encryption */ | |
| 333 socksreq[0] = 1; /* GSS-API subnegotiation version */ | |
| 334 socksreq[1] = 2; /* encryption message type */ | |
| 335 | |
| 336 gss_enc = 0; /* no data protection */ | |
| 337 /* do confidentiality protection if supported */ | |
| 338 if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) | |
| 339 gss_enc = 2; | |
| 340 /* else do integrity protection */ | |
| 341 else if(sspi_ret_flags & ISC_REQ_INTEGRITY) | |
| 342 gss_enc = 1; | |
| 343 | |
| 344 infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", | |
| 345 (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); | |
| 346 /* force to no data protection, avoid encryption/decryption for now */ | |
| 347 gss_enc = 0; | |
| 348 /* | |
| 349 * Sending the encryption type in clear seems wrong. It should be | |
| 350 * protected with gss_seal()/gss_wrap(). See RFC1961 extract below | |
| 351 * The NEC reference implementations on which this is based is | |
| 352 * therefore at fault | |
| 353 * | |
| 354 * +------+------+------+.......................+ | |
| 355 * + ver | mtyp | len | token | | |
| 356 * +------+------+------+.......................+ | |
| 357 * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | | |
| 358 * +------+------+------+.......................+ | |
| 359 * | |
| 360 * Where: | |
| 361 * | |
| 362 * - "ver" is the protocol version number, here 1 to represent the | |
| 363 * first version of the SOCKS/GSS-API protocol | |
| 364 * | |
| 365 * - "mtyp" is the message type, here 2 to represent a protection | |
| 366 * -level negotiation message | |
| 367 * | |
| 368 * - "len" is the length of the "token" field in octets | |
| 369 * | |
| 370 * - "token" is the GSS-API encapsulated protection level | |
| 371 * | |
| 372 * The token is produced by encapsulating an octet containing the | |
| 373 * required protection level using gss_seal()/gss_wrap() with conf_req | |
| 374 * set to FALSE. The token is verified using gss_unseal()/ | |
| 375 * gss_unwrap(). | |
| 376 * | |
| 377 */ | |
| 378 | |
| 379 if(data->set.socks5_gssapi_nec) { | |
| 380 us_length = htons((short)1); | |
| 381 memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| 382 } | |
| 383 else { | |
| 384 status = s_pSecFn->QueryContextAttributes(&sspi_context, | |
| 385 SECPKG_ATTR_SIZES, | |
| 386 &sspi_sizes); | |
| 387 if(check_sspi_err(conn, status, "QueryContextAttributes")) { | |
| 388 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 389 failf(data, "Failed to query security context attributes."); | |
| 390 return CURLE_COULDNT_CONNECT; | |
| 391 } | |
| 392 | |
| 393 sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; | |
| 394 sspi_w_token[0].BufferType = SECBUFFER_TOKEN; | |
| 395 sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); | |
| 396 | |
| 397 if(!sspi_w_token[0].pvBuffer) { | |
| 398 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 399 return CURLE_OUT_OF_MEMORY; | |
| 400 } | |
| 401 | |
| 402 sspi_w_token[1].cbBuffer = 1; | |
| 403 sspi_w_token[1].pvBuffer = malloc(1); | |
| 404 if(!sspi_w_token[1].pvBuffer) { | |
| 405 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 406 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 407 return CURLE_OUT_OF_MEMORY; | |
| 408 } | |
| 409 | |
| 410 memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); | |
| 411 sspi_w_token[2].BufferType = SECBUFFER_PADDING; | |
| 412 sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; | |
| 413 sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); | |
| 414 if(!sspi_w_token[2].pvBuffer) { | |
| 415 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 416 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 417 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 418 return CURLE_OUT_OF_MEMORY; | |
| 419 } | |
| 420 status = s_pSecFn->EncryptMessage(&sspi_context, | |
| 421 KERB_WRAP_NO_ENCRYPT, | |
| 422 &wrap_desc, | |
| 423 0); | |
| 424 if(check_sspi_err(conn, status, "EncryptMessage")) { | |
| 425 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 426 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 427 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); | |
| 428 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 429 failf(data, "Failed to query security context attributes."); | |
| 430 return CURLE_COULDNT_CONNECT; | |
| 431 } | |
| 432 sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer | |
| 433 + sspi_w_token[1].cbBuffer | |
| 434 + sspi_w_token[2].cbBuffer; | |
| 435 sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); | |
| 436 if(!sspi_send_token.pvBuffer) { | |
| 437 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 438 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 439 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); | |
| 440 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 441 return CURLE_OUT_OF_MEMORY; | |
| 442 } | |
| 443 | |
| 444 memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, | |
| 445 sspi_w_token[0].cbBuffer); | |
| 446 memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, | |
| 447 sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); | |
| 448 memcpy((PUCHAR) sspi_send_token.pvBuffer | |
| 449 + sspi_w_token[0].cbBuffer | |
| 450 + sspi_w_token[1].cbBuffer, | |
| 451 sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); | |
| 452 | |
| 453 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 454 sspi_w_token[0].pvBuffer = NULL; | |
| 455 sspi_w_token[0].cbBuffer = 0; | |
| 456 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 457 sspi_w_token[1].pvBuffer = NULL; | |
| 458 sspi_w_token[1].cbBuffer = 0; | |
| 459 s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); | |
| 460 sspi_w_token[2].pvBuffer = NULL; | |
| 461 sspi_w_token[2].cbBuffer = 0; | |
| 462 | |
| 463 us_length = htons((short)sspi_send_token.cbBuffer); | |
| 464 memcpy(socksreq + 2, &us_length, sizeof(short)); | |
| 465 } | |
| 466 | |
| 467 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); | |
| 468 if(code || (4 != written)) { | |
| 469 failf(data, "Failed to send SSPI encryption request."); | |
| 470 if(sspi_send_token.pvBuffer) | |
| 471 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 472 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 473 return CURLE_COULDNT_CONNECT; | |
| 474 } | |
| 475 | |
| 476 if(data->set.socks5_gssapi_nec) { | |
| 477 memcpy(socksreq, &gss_enc, 1); | |
| 478 code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); | |
| 479 if(code || (1 != written)) { | |
| 480 failf(data, "Failed to send SSPI encryption type."); | |
| 481 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 482 return CURLE_COULDNT_CONNECT; | |
| 483 } | |
| 484 } | |
| 485 else { | |
| 486 code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, | |
| 487 sspi_send_token.cbBuffer, &written); | |
| 488 if(code || (sspi_send_token.cbBuffer != (size_t)written)) { | |
| 489 failf(data, "Failed to send SSPI encryption type."); | |
| 490 if(sspi_send_token.pvBuffer) | |
| 491 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 492 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 493 return CURLE_COULDNT_CONNECT; | |
| 494 } | |
| 495 if(sspi_send_token.pvBuffer) | |
| 496 s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); | |
| 497 } | |
| 498 | |
| 499 result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); | |
| 500 if(result || (actualread != 4)) { | |
| 501 failf(data, "Failed to receive SSPI encryption response."); | |
| 502 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 503 return CURLE_COULDNT_CONNECT; | |
| 504 } | |
| 505 | |
| 506 /* ignore the first (VER) byte */ | |
| 507 if(socksreq[1] == 255) { /* status / message type */ | |
| 508 failf(data, "User was rejected by the SOCKS5 server (%u %u).", | |
| 509 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| 510 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 511 return CURLE_COULDNT_CONNECT; | |
| 512 } | |
| 513 | |
| 514 if(socksreq[1] != 2) { /* status / message type */ | |
| 515 failf(data, "Invalid SSPI encryption response type (%u %u).", | |
| 516 (unsigned int)socksreq[0], (unsigned int)socksreq[1]); | |
| 517 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 518 return CURLE_COULDNT_CONNECT; | |
| 519 } | |
| 520 | |
| 521 memcpy(&us_length, socksreq + 2, sizeof(short)); | |
| 522 us_length = ntohs(us_length); | |
| 523 | |
| 524 sspi_w_token[0].cbBuffer = us_length; | |
| 525 sspi_w_token[0].pvBuffer = malloc(us_length); | |
| 526 if(!sspi_w_token[0].pvBuffer) { | |
| 527 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 528 return CURLE_OUT_OF_MEMORY; | |
| 529 } | |
| 530 | |
| 531 result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, | |
| 532 sspi_w_token[0].cbBuffer, &actualread); | |
| 533 | |
| 534 if(result || (actualread != us_length)) { | |
| 535 failf(data, "Failed to receive SSPI encryption type."); | |
| 536 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 537 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 538 return CURLE_COULDNT_CONNECT; | |
| 539 } | |
| 540 | |
| 541 | |
| 542 if(!data->set.socks5_gssapi_nec) { | |
| 543 wrap_desc.cBuffers = 2; | |
| 544 sspi_w_token[0].BufferType = SECBUFFER_STREAM; | |
| 545 sspi_w_token[1].BufferType = SECBUFFER_DATA; | |
| 546 sspi_w_token[1].cbBuffer = 0; | |
| 547 sspi_w_token[1].pvBuffer = NULL; | |
| 548 | |
| 549 status = s_pSecFn->DecryptMessage(&sspi_context, | |
| 550 &wrap_desc, | |
| 551 0, | |
| 552 &qop); | |
| 553 | |
| 554 if(check_sspi_err(conn, status, "DecryptMessage")) { | |
| 555 if(sspi_w_token[0].pvBuffer) | |
| 556 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 557 if(sspi_w_token[1].pvBuffer) | |
| 558 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 559 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 560 failf(data, "Failed to query security context attributes."); | |
| 561 return CURLE_COULDNT_CONNECT; | |
| 562 } | |
| 563 | |
| 564 if(sspi_w_token[1].cbBuffer != 1) { | |
| 565 failf(data, "Invalid SSPI encryption response length (%lu).", | |
| 566 (unsigned long)sspi_w_token[1].cbBuffer); | |
| 567 if(sspi_w_token[0].pvBuffer) | |
| 568 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 569 if(sspi_w_token[1].pvBuffer) | |
| 570 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 571 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 572 return CURLE_COULDNT_CONNECT; | |
| 573 } | |
| 574 | |
| 575 memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); | |
| 576 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 577 s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); | |
| 578 } | |
| 579 else { | |
| 580 if(sspi_w_token[0].cbBuffer != 1) { | |
| 581 failf(data, "Invalid SSPI encryption response length (%lu).", | |
| 582 (unsigned long)sspi_w_token[0].cbBuffer); | |
| 583 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 584 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 585 return CURLE_COULDNT_CONNECT; | |
| 586 } | |
| 587 memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); | |
| 588 s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); | |
| 589 } | |
| 590 | |
| 591 infof(data, "SOCKS5 access with%s protection granted.\n", | |
| 592 (socksreq[0] == 0)?"out GSS-API data": | |
| 593 ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); | |
| 594 | |
| 595 /* For later use if encryption is required | |
| 596 conn->socks5_gssapi_enctype = socksreq[0]; | |
| 597 if(socksreq[0] != 0) | |
| 598 conn->socks5_sspi_context = sspi_context; | |
| 599 else { | |
| 600 s_pSecFn->DeleteSecurityContext(&sspi_context); | |
| 601 conn->socks5_sspi_context = sspi_context; | |
| 602 } | |
| 603 */ | |
| 604 return CURLE_OK; | |
| 605 } | |
| 606 #endif |
