Git init
[external/curl.git] / lib / socks_sspi.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23
24 #include "setup.h"
25
26 #ifdef USE_WINDOWS_SSPI
27
28 #include <string.h>
29
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33
34 #include "urldata.h"
35 #include "sendf.h"
36 #include "connect.h"
37 #include "timeval.h"
38 #include "socks.h"
39 #include "curl_sspi.h"
40
41 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
42 #include <curl/mprintf.h>
43
44 #include "curl_memory.h"
45 /* The last #include file should be: */
46 #include "memdebug.h"
47
48 /*
49  * Definitions required from ntsecapi.h are directly provided below this point
50  * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
51  */
52 #define KERB_WRAP_NO_ENCRYPT 0x80000001
53
54 /*
55  * Helper sspi error functions.
56  */
57 static int check_sspi_err(struct SessionHandle *data,
58                           SECURITY_STATUS major_status,
59                           SECURITY_STATUS minor_status,
60                           const char* function)
61 {
62   const char *txt;
63   (void)minor_status;
64
65   if(major_status != SEC_E_OK &&
66      major_status != SEC_I_COMPLETE_AND_CONTINUE &&
67      major_status != SEC_I_COMPLETE_NEEDED &&
68      major_status != SEC_I_CONTINUE_NEEDED) {
69     failf(data, "SSPI error: %s failed: %d\n", function, major_status);
70     switch (major_status) {
71     case SEC_I_COMPLETE_AND_CONTINUE:
72       txt="SEC_I_COMPLETE_AND_CONTINUE";
73       break;
74     case SEC_I_COMPLETE_NEEDED:
75       txt="SEC_I_COMPLETE_NEEDED";
76       break;
77     case SEC_I_CONTINUE_NEEDED:
78       txt="SEC_I_CONTINUE_NEEDED";
79       break;
80     case SEC_I_CONTEXT_EXPIRED:
81       txt="SEC_I_CONTEXT_EXPIRED";
82       break;
83     case SEC_I_INCOMPLETE_CREDENTIALS:
84       txt="SEC_I_INCOMPLETE_CREDENTIALS";
85       break;
86     case SEC_I_RENEGOTIATE:
87       txt="SEC_I_RENEGOTIATE";
88       break;
89     case SEC_E_BUFFER_TOO_SMALL:
90       txt="SEC_E_BUFFER_TOO_SMALL";
91       break;
92     case SEC_E_CONTEXT_EXPIRED:
93       txt="SEC_E_CONTEXT_EXPIRED";
94       break;
95     case SEC_E_CRYPTO_SYSTEM_INVALID:
96       txt="SEC_E_CRYPTO_SYSTEM_INVALID";
97       break;
98     case SEC_E_INCOMPLETE_MESSAGE:
99       txt="SEC_E_INCOMPLETE_MESSAGE";
100       break;
101     case SEC_E_INSUFFICIENT_MEMORY:
102       txt="SEC_E_INSUFFICIENT_MEMORY";
103       break;
104     case SEC_E_INTERNAL_ERROR:
105       txt="SEC_E_INTERNAL_ERROR";
106       break;
107     case SEC_E_INVALID_HANDLE:
108       txt="SEC_E_INVALID_HANDLE";
109       break;
110     case SEC_E_INVALID_TOKEN:
111       txt="SEC_E_INVALID_TOKEN";
112       break;
113     case SEC_E_LOGON_DENIED:
114       txt="SEC_E_LOGON_DENIED";
115       break;
116     case SEC_E_MESSAGE_ALTERED:
117       txt="SEC_E_MESSAGE_ALTERED";
118       break;
119     case SEC_E_NO_AUTHENTICATING_AUTHORITY:
120       txt="SEC_E_NO_AUTHENTICATING_AUTHORITY";
121       break;
122     case SEC_E_NO_CREDENTIALS:
123       txt="SEC_E_NO_CREDENTIALS";
124       break;
125     case SEC_E_NOT_OWNER:
126       txt="SEC_E_NOT_OWNER";
127       break;
128     case SEC_E_OUT_OF_SEQUENCE:
129       txt="SEC_E_OUT_OF_SEQUENCE";
130       break;
131     case SEC_E_QOP_NOT_SUPPORTED:
132       txt="SEC_E_QOP_NOT_SUPPORTED";
133       break;
134     case SEC_E_SECPKG_NOT_FOUND:
135       txt="SEC_E_SECPKG_NOT_FOUND";
136       break;
137     case SEC_E_TARGET_UNKNOWN:
138       txt="SEC_E_TARGET_UNKNOWN";
139       break;
140     case SEC_E_UNKNOWN_CREDENTIALS:
141       txt="SEC_E_UNKNOWN_CREDENTIALS";
142       break;
143     case SEC_E_UNSUPPORTED_FUNCTION:
144       txt="SEC_E_UNSUPPORTED_FUNCTION";
145       break;
146     case SEC_E_WRONG_PRINCIPAL:
147       txt="SEC_E_WRONG_PRINCIPAL";
148       break;
149     default:
150       txt="Unknown error";
151
152     }
153     failf(data, "SSPI error: %s failed: %s\n", function, txt);
154     return 1;
155   }
156   return 0;
157 }
158
159 /* This is the SSPI-using version of this function */
160 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
161                                       struct connectdata *conn)
162 {
163   struct SessionHandle *data = conn->data;
164   curl_socket_t sock = conn->sock[sockindex];
165   CURLcode code;
166   ssize_t actualread;
167   ssize_t written;
168   int result;
169   long timeout;
170   /* Needs GSSAPI authentication */
171   SECURITY_STATUS sspi_major_status, sspi_minor_status=0;
172   unsigned long sspi_ret_flags=0;
173   int gss_enc;
174   SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
175   SecBufferDesc input_desc, output_desc, wrap_desc;
176   SecPkgContext_Sizes sspi_sizes;
177   CredHandle cred_handle;
178   CtxtHandle sspi_context;
179   PCtxtHandle context_handle = NULL;
180   SecPkgCredentials_Names names;
181   TimeStamp expiry;
182   char *service_name=NULL;
183   u_short us_length;
184   ULONG qop;
185   unsigned char socksreq[4]; /* room for gssapi exchange header only */
186   char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
187
188   /* get timeout */
189   timeout = Curl_timeleft(conn, NULL, TRUE);
190
191   /*   GSSAPI request looks like
192    * +----+------+-----+----------------+
193    * |VER | MTYP | LEN |     TOKEN      |
194    * +----+------+----------------------+
195    * | 1  |  1   |  2  | up to 2^16 - 1 |
196    * +----+------+-----+----------------+
197    */
198
199   /* prepare service name */
200   if (strchr(service, '/')) {
201     service_name = malloc(strlen(service));
202     if(!service_name)
203       return CURLE_OUT_OF_MEMORY;
204     memcpy(service_name, service, strlen(service));
205   }
206   else {
207     service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
208     if(!service_name)
209       return CURLE_OUT_OF_MEMORY;
210     snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s",
211              service,conn->proxy.name);
212   }
213
214   input_desc.cBuffers = 1;
215   input_desc.pBuffers = &sspi_recv_token;
216   input_desc.ulVersion = SECBUFFER_VERSION;
217
218   sspi_recv_token.BufferType = SECBUFFER_TOKEN;
219   sspi_recv_token.cbBuffer = 0;
220   sspi_recv_token.pvBuffer = NULL;
221
222   output_desc.cBuffers = 1;
223   output_desc.pBuffers = &sspi_send_token;
224   output_desc.ulVersion = SECBUFFER_VERSION;
225
226   sspi_send_token.BufferType = SECBUFFER_TOKEN;
227   sspi_send_token.cbBuffer = 0;
228   sspi_send_token.pvBuffer = NULL;
229
230   wrap_desc.cBuffers = 3;
231   wrap_desc.pBuffers = sspi_w_token;
232   wrap_desc.ulVersion = SECBUFFER_VERSION;
233
234   cred_handle.dwLower = 0;
235   cred_handle.dwUpper = 0;
236
237   sspi_major_status = s_pSecFn->AcquireCredentialsHandleA( NULL,
238                                                            (char *)"Kerberos",
239                                                            SECPKG_CRED_OUTBOUND,
240                                                            NULL,
241                                                            NULL,
242                                                            NULL,
243                                                            NULL,
244                                                            &cred_handle,
245                                                            &expiry);
246
247   if(check_sspi_err(data, sspi_major_status,sspi_minor_status,
248                     "AcquireCredentialsHandleA") ) {
249     failf(data, "Failed to acquire credentials.");
250     free(service_name);
251     service_name=NULL;
252     s_pSecFn->FreeCredentialsHandle(&cred_handle);
253     return CURLE_COULDNT_CONNECT;
254   }
255
256   /* As long as we need to keep sending some context info, and there's no  */
257   /* errors, keep sending it...                                            */
258   for(;;) {
259
260     sspi_major_status = s_pSecFn->InitializeSecurityContextA(
261                                     &cred_handle,
262                                     context_handle,
263                                     service_name,
264                                     ISC_REQ_MUTUAL_AUTH |
265                                     ISC_REQ_ALLOCATE_MEMORY |
266                                     ISC_REQ_CONFIDENTIALITY |
267                                     ISC_REQ_REPLAY_DETECT,
268                                     0,
269                                     SECURITY_NATIVE_DREP,
270                                     &input_desc,
271                                     0,
272                                     &sspi_context,
273                                     &output_desc,
274                                     &sspi_ret_flags,
275                                     &expiry);
276
277     if(sspi_recv_token.pvBuffer) {
278       s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
279       sspi_recv_token.pvBuffer = NULL;
280       sspi_recv_token.cbBuffer = 0;
281     }
282
283     if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
284                       "InitializeSecurityContextA") ){
285       free(service_name);
286       service_name=NULL;
287       s_pSecFn->FreeCredentialsHandle(&cred_handle);
288       s_pSecFn->DeleteSecurityContext(&sspi_context);
289       s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
290       failf(data, "Failed to initialise security context.");
291       return CURLE_COULDNT_CONNECT;
292     }
293
294     if(sspi_send_token.cbBuffer != 0) {
295       socksreq[0] = 1;    /* gssapi subnegotiation version */
296       socksreq[1] = 1;    /* authentication message type */
297       us_length = htons((short)sspi_send_token.cbBuffer);
298       memcpy(socksreq+2, &us_length, sizeof(short));
299
300       code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
301       if((code != CURLE_OK) || (4 != written)) {
302         failf(data, "Failed to send SSPI authentication request.");
303         free(service_name);
304         service_name=NULL;
305         s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
306         s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
307         s_pSecFn->FreeCredentialsHandle(&cred_handle);
308         s_pSecFn->DeleteSecurityContext(&sspi_context);
309         return CURLE_COULDNT_CONNECT;
310       }
311
312       code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
313                               sspi_send_token.cbBuffer, &written);
314       if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
315         failf(data, "Failed to send SSPI authentication token.");
316         free(service_name);
317         service_name=NULL;
318         s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
319         s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
320         s_pSecFn->FreeCredentialsHandle(&cred_handle);
321         s_pSecFn->DeleteSecurityContext(&sspi_context);
322         return CURLE_COULDNT_CONNECT;
323       }
324
325     }
326
327     s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
328     sspi_send_token.pvBuffer = NULL;
329     sspi_send_token.cbBuffer = 0;
330     s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
331     sspi_recv_token.pvBuffer = NULL;
332     sspi_recv_token.cbBuffer = 0;
333     if(sspi_major_status != SEC_I_CONTINUE_NEEDED)  break;
334
335     /* analyse response */
336
337     /*   GSSAPI response looks like
338      * +----+------+-----+----------------+
339      * |VER | MTYP | LEN |     TOKEN      |
340      * +----+------+----------------------+
341      * | 1  |  1   |  2  | up to 2^16 - 1 |
342      * +----+------+-----+----------------+
343      */
344
345     result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
346                               &actualread, timeout);
347     if(result != CURLE_OK || actualread != 4) {
348       failf(data, "Failed to receive SSPI authentication response.");
349       free(service_name);
350       service_name=NULL;
351       s_pSecFn->FreeCredentialsHandle(&cred_handle);
352       s_pSecFn->DeleteSecurityContext(&sspi_context);
353       return CURLE_COULDNT_CONNECT;
354     }
355
356     /* ignore the first (VER) byte */
357     if(socksreq[1] == 255) { /* status / message type */
358       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
359             socksreq[0], socksreq[1]);
360       free(service_name);
361       service_name=NULL;
362       s_pSecFn->FreeCredentialsHandle(&cred_handle);
363       s_pSecFn->DeleteSecurityContext(&sspi_context);
364       return CURLE_COULDNT_CONNECT;
365     }
366
367     if(socksreq[1] != 1) { /* status / messgae type */
368       failf(data, "Invalid SSPI authentication response type (%d %d).",
369             socksreq[0], socksreq[1]);
370       free(service_name);
371       service_name=NULL;
372       s_pSecFn->FreeCredentialsHandle(&cred_handle);
373       s_pSecFn->DeleteSecurityContext(&sspi_context);
374       return CURLE_COULDNT_CONNECT;
375     }
376
377     memcpy(&us_length, socksreq+2, sizeof(short));
378     us_length = ntohs(us_length);
379
380     sspi_recv_token.cbBuffer = us_length;
381     sspi_recv_token.pvBuffer = malloc(us_length);
382
383     if(!sspi_recv_token.pvBuffer) {
384       free(service_name);
385       service_name=NULL;
386       s_pSecFn->FreeCredentialsHandle(&cred_handle);
387       s_pSecFn->DeleteSecurityContext(&sspi_context);
388       return CURLE_OUT_OF_MEMORY;
389     }
390     result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
391                                 sspi_recv_token.cbBuffer,
392                                 &actualread, timeout);
393
394     if(result != CURLE_OK || actualread != us_length) {
395       failf(data, "Failed to receive SSPI authentication token.");
396       free(service_name);
397       service_name=NULL;
398       s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
399       s_pSecFn->FreeCredentialsHandle(&cred_handle);
400       s_pSecFn->DeleteSecurityContext(&sspi_context);
401       return CURLE_COULDNT_CONNECT;
402     }
403
404     context_handle = &sspi_context;
405   }
406
407   free(service_name);
408   service_name=NULL;
409
410   /* Everything is good so far, user was authenticated! */
411   sspi_major_status = s_pSecFn->QueryCredentialsAttributes( &cred_handle,
412                                                             SECPKG_CRED_ATTR_NAMES,
413                                                             &names);
414   s_pSecFn->FreeCredentialsHandle(&cred_handle);
415   if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
416                     "QueryCredentialAttributes") ){
417     s_pSecFn->DeleteSecurityContext(&sspi_context);
418     s_pSecFn->FreeContextBuffer(names.sUserName);
419     failf(data, "Failed to determine user name.");
420     return CURLE_COULDNT_CONNECT;
421   }
422   infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",
423         names.sUserName);
424   s_pSecFn->FreeContextBuffer(names.sUserName);
425
426   /* Do encryption */
427   socksreq[0] = 1;    /* gssapi subnegotiation version */
428   socksreq[1] = 2;    /* encryption message type */
429
430   gss_enc = 0; /* no data protection */
431   /* do confidentiality protection if supported */
432   if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
433     gss_enc = 2;
434   /* else do integrity protection */
435   else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
436     gss_enc = 1;
437
438   infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
439         (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
440   /* force to no data protection, avoid encryption/decryption for now */
441   gss_enc = 0;
442   /*
443    * Sending the encryption type in clear seems wrong. It should be
444    * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
445    * The NEC reference implementations on which this is based is
446    * therefore at fault
447    *
448    *  +------+------+------+.......................+
449    *  + ver  | mtyp | len  |   token               |
450    *  +------+------+------+.......................+
451    *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
452    *  +------+------+------+.......................+
453    *
454    *   Where:
455    *
456    *  - "ver" is the protocol version number, here 1 to represent the
457    *    first version of the SOCKS/GSS-API protocol
458    *
459    *  - "mtyp" is the message type, here 2 to represent a protection
460    *    -level negotiation message
461    *
462    *  - "len" is the length of the "token" field in octets
463    *
464    *  - "token" is the GSS-API encapsulated protection level
465    *
466    * The token is produced by encapsulating an octet containing the
467    * required protection level using gss_seal()/gss_wrap() with conf_req
468    * set to FALSE.  The token is verified using gss_unseal()/
469    * gss_unwrap().
470    *
471    */
472
473   if(data->set.socks5_gssapi_nec) {
474     us_length = htons((short)1);
475     memcpy(socksreq+2, &us_length, sizeof(short));
476   }
477   else {
478     sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context,
479                                                            SECPKG_ATTR_SIZES,
480                                                            &sspi_sizes);
481     if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
482                       "QueryContextAttributesA")) {
483       s_pSecFn->DeleteSecurityContext(&sspi_context);
484       failf(data, "Failed to query security context attributes.");
485       return CURLE_COULDNT_CONNECT;
486     }
487
488     sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
489     sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
490     sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
491
492     if(!sspi_w_token[0].pvBuffer) {
493       s_pSecFn->DeleteSecurityContext(&sspi_context);
494       return CURLE_OUT_OF_MEMORY;
495     }
496
497     sspi_w_token[1].cbBuffer = 1;
498     sspi_w_token[1].pvBuffer = malloc(1);
499     if(!sspi_w_token[1].pvBuffer){
500       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
501       s_pSecFn->DeleteSecurityContext(&sspi_context);
502       return CURLE_OUT_OF_MEMORY;
503     }
504
505     memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1);
506     sspi_w_token[2].BufferType = SECBUFFER_PADDING;
507     sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
508     sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
509     if(!sspi_w_token[2].pvBuffer) {
510       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
511       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
512       s_pSecFn->DeleteSecurityContext(&sspi_context);
513       return CURLE_OUT_OF_MEMORY;
514     }
515     sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context,
516                                                   KERB_WRAP_NO_ENCRYPT,
517                                                   &wrap_desc,
518                                                   0);
519     if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
520                       "EncryptMessage") ) {
521       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
522       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
523       s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
524       s_pSecFn->DeleteSecurityContext(&sspi_context);
525       failf(data, "Failed to query security context attributes.");
526       return CURLE_COULDNT_CONNECT;
527     }
528     sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
529       + sspi_w_token[1].cbBuffer
530       + sspi_w_token[2].cbBuffer;
531     sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
532     if(!sspi_send_token.pvBuffer) {
533       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
534       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
535       s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
536       s_pSecFn->DeleteSecurityContext(&sspi_context);
537       return CURLE_OUT_OF_MEMORY;
538     }
539
540     memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
541            sspi_w_token[0].cbBuffer);
542     memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
543            sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
544     memcpy((PUCHAR) sspi_send_token.pvBuffer
545            +sspi_w_token[0].cbBuffer
546            +sspi_w_token[1].cbBuffer,
547            sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
548
549     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
550     sspi_w_token[0].pvBuffer = NULL;
551     sspi_w_token[0].cbBuffer = 0;
552     s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
553     sspi_w_token[1].pvBuffer = NULL;
554     sspi_w_token[1].cbBuffer = 0;
555     s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
556     sspi_w_token[2].pvBuffer = NULL;
557     sspi_w_token[2].cbBuffer = 0;
558
559     us_length = htons((short)sspi_send_token.cbBuffer);
560     memcpy(socksreq+2,&us_length,sizeof(short));
561   }
562
563   code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
564   if((code != CURLE_OK) || (4 != written)) {
565     failf(data, "Failed to send SSPI encryption request.");
566     s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
567     s_pSecFn->DeleteSecurityContext(&sspi_context);
568     return CURLE_COULDNT_CONNECT;
569   }
570
571   if(data->set.socks5_gssapi_nec) {
572     memcpy(socksreq,&gss_enc,1);
573     code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
574     if((code != CURLE_OK) || (1 != written)) {
575       failf(data, "Failed to send SSPI encryption type.");
576       s_pSecFn->DeleteSecurityContext(&sspi_context);
577       return CURLE_COULDNT_CONNECT;
578     }
579   } else {
580     code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
581                             sspi_send_token.cbBuffer, &written);
582     if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
583       failf(data, "Failed to send SSPI encryption type.");
584       s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
585       s_pSecFn->DeleteSecurityContext(&sspi_context);
586       return CURLE_COULDNT_CONNECT;
587     }
588     s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
589   }
590
591   result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
592                             &actualread, timeout);
593   if(result != CURLE_OK || actualread != 4) {
594     failf(data, "Failed to receive SSPI encryption response.");
595     s_pSecFn->DeleteSecurityContext(&sspi_context);
596     return CURLE_COULDNT_CONNECT;
597   }
598
599   /* ignore the first (VER) byte */
600   if(socksreq[1] == 255) { /* status / message type */
601     failf(data, "User was rejected by the SOCKS5 server (%d %d).",
602           socksreq[0], socksreq[1]);
603     s_pSecFn->DeleteSecurityContext(&sspi_context);
604     return CURLE_COULDNT_CONNECT;
605   }
606
607   if(socksreq[1] != 2) { /* status / message type */
608     failf(data, "Invalid SSPI encryption response type (%d %d).",
609           socksreq[0], socksreq[1]);
610     s_pSecFn->DeleteSecurityContext(&sspi_context);
611     return CURLE_COULDNT_CONNECT;
612   }
613
614   memcpy(&us_length, socksreq+2, sizeof(short));
615   us_length = ntohs(us_length);
616
617   sspi_w_token[0].cbBuffer = us_length;
618   sspi_w_token[0].pvBuffer = malloc(us_length);
619   if(!sspi_w_token[0].pvBuffer) {
620     s_pSecFn->DeleteSecurityContext(&sspi_context);
621     return CURLE_OUT_OF_MEMORY;
622   }
623
624   result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
625                             sspi_w_token[0].cbBuffer,
626                             &actualread, timeout);
627
628   if(result != CURLE_OK || actualread != us_length) {
629     failf(data, "Failed to receive SSPI encryption type.");
630     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
631     s_pSecFn->DeleteSecurityContext(&sspi_context);
632     return CURLE_COULDNT_CONNECT;
633   }
634
635
636   if(!data->set.socks5_gssapi_nec) {
637     wrap_desc.cBuffers = 2;
638     sspi_w_token[0].BufferType = SECBUFFER_STREAM;
639     sspi_w_token[1].BufferType = SECBUFFER_DATA;
640     sspi_w_token[1].cbBuffer = 0;
641     sspi_w_token[1].pvBuffer = NULL;
642
643     sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context,
644                                                   &wrap_desc,
645                                                   0,
646                                                   &qop);
647
648     if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
649                       "DecryptMessage")) {
650       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
651       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
652       s_pSecFn->DeleteSecurityContext(&sspi_context);
653       failf(data, "Failed to query security context attributes.");
654       return CURLE_COULDNT_CONNECT;
655     }
656
657     if(sspi_w_token[1].cbBuffer != 1) {
658       failf(data, "Invalid SSPI encryption response length (%d).",
659             sspi_w_token[1].cbBuffer);
660       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
661       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
662       s_pSecFn->DeleteSecurityContext(&sspi_context);
663       return CURLE_COULDNT_CONNECT;
664     }
665
666     memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer);
667     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
668     s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
669   } else {
670     if(sspi_w_token[0].cbBuffer != 1) {
671       failf(data, "Invalid SSPI encryption response length (%d).",
672             sspi_w_token[0].cbBuffer);
673       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
674       s_pSecFn->DeleteSecurityContext(&sspi_context);
675       return CURLE_COULDNT_CONNECT;
676     }
677     memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer);
678     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
679   }
680
681   infof(data, "SOCKS5 access with%s protection granted.\n",
682         (socksreq[0]==0)?"out gssapi data":
683         ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
684
685   /* For later use if encryption is required
686      conn->socks5_gssapi_enctype = socksreq[0];
687      if (socksreq[0] != 0)
688      conn->socks5_sspi_context = sspi_context;
689      else {
690      s_pSecFn->DeleteSecurityContext(&sspi_context);
691      conn->socks5_sspi_context = sspi_context;
692      }
693   */
694   return CURLE_OK;
695 }
696 #endif