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