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