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