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