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 */
49static 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 */
66CURLcode 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