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