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