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 |
607 | |