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