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