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