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