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