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