quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

socks_sspi.c (23581B)


      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 "curlx/timeval.h"
     36 #include "socks.h"
     37 #include "curl_sspi.h"
     38 #include "curlx/multibyte.h"
     39 #include "curlx/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  */
     49 static 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 */
     66 CURLcode 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   size_t actualread;
     73   size_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 = Curl_pSecFn->AcquireCredentialsHandle(NULL,
    143                                        (TCHAR *)CURL_UNCONST(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     Curl_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 is 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 = Curl_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       Curl_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       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    197       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    198       if(sspi_recv_token.pvBuffer)
    199         Curl_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((unsigned short)sspi_send_token.cbBuffer);
    208       memcpy(socksreq + 2, &us_length, sizeof(short));
    209 
    210       code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
    211                                &written);
    212       if(code || (4 != written)) {
    213         failf(data, "Failed to send SSPI authentication request.");
    214         free(service_name);
    215         if(sspi_send_token.pvBuffer)
    216           Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    217         if(sspi_recv_token.pvBuffer)
    218           Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
    219         Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    220         Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    221         return CURLE_COULDNT_CONNECT;
    222       }
    223 
    224       code = Curl_conn_cf_send(cf->next, data,
    225                                (char *)sspi_send_token.pvBuffer,
    226                                sspi_send_token.cbBuffer, FALSE, &written);
    227       if(code || (sspi_send_token.cbBuffer != written)) {
    228         failf(data, "Failed to send SSPI authentication token.");
    229         free(service_name);
    230         if(sspi_send_token.pvBuffer)
    231           Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    232         if(sspi_recv_token.pvBuffer)
    233           Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
    234         Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    235         Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    236         return CURLE_COULDNT_CONNECT;
    237       }
    238 
    239     }
    240 
    241     if(sspi_send_token.pvBuffer) {
    242       Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    243       sspi_send_token.pvBuffer = NULL;
    244     }
    245     sspi_send_token.cbBuffer = 0;
    246 
    247     if(sspi_recv_token.pvBuffer) {
    248       Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
    249       sspi_recv_token.pvBuffer = NULL;
    250     }
    251     sspi_recv_token.cbBuffer = 0;
    252 
    253     if(status != SEC_I_CONTINUE_NEEDED)
    254       break;
    255 
    256     /* analyse response */
    257 
    258     /*   GSS-API response looks like
    259      * +----+------+-----+----------------+
    260      * |VER | MTYP | LEN |     TOKEN      |
    261      * +----+------+----------------------+
    262      * | 1  |  1   |  2  | up to 2^16 - 1 |
    263      * +----+------+-----+----------------+
    264      */
    265 
    266     result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
    267     if(result || (actualread != 4)) {
    268       failf(data, "Failed to receive SSPI authentication response.");
    269       free(service_name);
    270       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    271       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    272       return CURLE_COULDNT_CONNECT;
    273     }
    274 
    275     /* ignore the first (VER) byte */
    276     if(socksreq[1] == 255) { /* status / message type */
    277       failf(data, "User was rejected by the SOCKS5 server (%u %u).",
    278             (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
    279       free(service_name);
    280       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    281       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    282       return CURLE_COULDNT_CONNECT;
    283     }
    284 
    285     if(socksreq[1] != 1) { /* status / message type */
    286       failf(data, "Invalid SSPI authentication response type (%u %u).",
    287             (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
    288       free(service_name);
    289       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    290       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    291       return CURLE_COULDNT_CONNECT;
    292     }
    293 
    294     memcpy(&us_length, socksreq + 2, sizeof(short));
    295     us_length = ntohs(us_length);
    296 
    297     sspi_recv_token.cbBuffer = us_length;
    298     sspi_recv_token.pvBuffer = malloc(us_length);
    299 
    300     if(!sspi_recv_token.pvBuffer) {
    301       free(service_name);
    302       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    303       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    304       return CURLE_OUT_OF_MEMORY;
    305     }
    306     result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer,
    307                                 sspi_recv_token.cbBuffer, &actualread);
    308 
    309     if(result || (actualread != us_length)) {
    310       failf(data, "Failed to receive SSPI authentication token.");
    311       free(service_name);
    312       if(sspi_recv_token.pvBuffer)
    313         Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
    314       Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    315       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    316       return CURLE_COULDNT_CONNECT;
    317     }
    318 
    319     context_handle = &sspi_context;
    320   }
    321 
    322   free(service_name);
    323 
    324   /* Everything is good so far, user was authenticated! */
    325   status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle,
    326                                                 SECPKG_CRED_ATTR_NAMES,
    327                                                 &names);
    328   Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
    329   if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
    330     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    331     Curl_pSecFn->FreeContextBuffer(names.sUserName);
    332     failf(data, "Failed to determine username.");
    333     return CURLE_COULDNT_CONNECT;
    334   }
    335   else {
    336 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    337     char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
    338     infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
    339           (user_utf8 ? user_utf8 : "(unknown)"));
    340     curlx_unicodefree(user_utf8);
    341 #endif
    342     Curl_pSecFn->FreeContextBuffer(names.sUserName);
    343   }
    344 
    345   /* Do encryption */
    346   socksreq[0] = 1;    /* GSS-API subnegotiation version */
    347   socksreq[1] = 2;    /* encryption message type */
    348 
    349   gss_enc = 0; /* no data protection */
    350   /* do confidentiality protection if supported */
    351   if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
    352     gss_enc = 2;
    353   /* else do integrity protection */
    354   else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
    355     gss_enc = 1;
    356 
    357   infof(data, "SOCKS5 server supports GSS-API %s data protection.",
    358         (gss_enc == 0) ? "no" :
    359         ((gss_enc == 1) ? "integrity":"confidentiality") );
    360   /* force to no data protection, avoid encryption/decryption for now */
    361   gss_enc = 0;
    362   /*
    363    * Sending the encryption type in clear seems wrong. It should be
    364    * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
    365    * The NEC reference implementations on which this is based is
    366    * therefore at fault
    367    *
    368    *  +------+------+------+.......................+
    369    *  + ver  | mtyp | len  |   token               |
    370    *  +------+------+------+.......................+
    371    *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
    372    *  +------+------+------+.......................+
    373    *
    374    *   Where:
    375    *
    376    *  - "ver" is the protocol version number, here 1 to represent the
    377    *    first version of the SOCKS/GSS-API protocol
    378    *
    379    *  - "mtyp" is the message type, here 2 to represent a protection
    380    *    -level negotiation message
    381    *
    382    *  - "len" is the length of the "token" field in octets
    383    *
    384    *  - "token" is the GSS-API encapsulated protection level
    385    *
    386    * The token is produced by encapsulating an octet containing the
    387    * required protection level using gss_seal()/gss_wrap() with conf_req
    388    * set to FALSE. The token is verified using gss_unseal()/
    389    * gss_unwrap().
    390    *
    391    */
    392 
    393   if(data->set.socks5_gssapi_nec) {
    394     us_length = htons((unsigned short)1);
    395     memcpy(socksreq + 2, &us_length, sizeof(short));
    396   }
    397   else {
    398     status = Curl_pSecFn->QueryContextAttributes(&sspi_context,
    399                                               SECPKG_ATTR_SIZES,
    400                                               &sspi_sizes);
    401     if(check_sspi_err(data, status, "QueryContextAttributes")) {
    402       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    403       failf(data, "Failed to query security context attributes.");
    404       return CURLE_COULDNT_CONNECT;
    405     }
    406 
    407     sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
    408     sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
    409     sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
    410 
    411     if(!sspi_w_token[0].pvBuffer) {
    412       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    413       return CURLE_OUT_OF_MEMORY;
    414     }
    415 
    416     sspi_w_token[1].cbBuffer = 1;
    417     sspi_w_token[1].pvBuffer = malloc(1);
    418     if(!sspi_w_token[1].pvBuffer) {
    419       Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    420       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    421       return CURLE_OUT_OF_MEMORY;
    422     }
    423 
    424     memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1);
    425     sspi_w_token[2].BufferType = SECBUFFER_PADDING;
    426     sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
    427     sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
    428     if(!sspi_w_token[2].pvBuffer) {
    429       Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    430       Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    431       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    432       return CURLE_OUT_OF_MEMORY;
    433     }
    434     status = Curl_pSecFn->EncryptMessage(&sspi_context,
    435                                       KERB_WRAP_NO_ENCRYPT,
    436                                       &wrap_desc,
    437                                       0);
    438     if(check_sspi_err(data, status, "EncryptMessage")) {
    439       Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    440       Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    441       Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    442       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    443       failf(data, "Failed to query security context attributes.");
    444       return CURLE_COULDNT_CONNECT;
    445     }
    446     sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
    447       + sspi_w_token[1].cbBuffer
    448       + sspi_w_token[2].cbBuffer;
    449     sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
    450     if(!sspi_send_token.pvBuffer) {
    451       Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    452       Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    453       Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    454       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    455       return CURLE_OUT_OF_MEMORY;
    456     }
    457 
    458     memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
    459            sspi_w_token[0].cbBuffer);
    460     memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
    461            sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
    462     memcpy((PUCHAR) sspi_send_token.pvBuffer
    463            + sspi_w_token[0].cbBuffer
    464            + sspi_w_token[1].cbBuffer,
    465            sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
    466 
    467     Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    468     sspi_w_token[0].pvBuffer = NULL;
    469     sspi_w_token[0].cbBuffer = 0;
    470     Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    471     sspi_w_token[1].pvBuffer = NULL;
    472     sspi_w_token[1].cbBuffer = 0;
    473     Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    474     sspi_w_token[2].pvBuffer = NULL;
    475     sspi_w_token[2].cbBuffer = 0;
    476 
    477     us_length = htons((unsigned short)sspi_send_token.cbBuffer);
    478     memcpy(socksreq + 2, &us_length, sizeof(short));
    479   }
    480 
    481   code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
    482                            &written);
    483   if(code || (4 != written)) {
    484     failf(data, "Failed to send SSPI encryption request.");
    485     if(sspi_send_token.pvBuffer)
    486       Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    487     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    488     return CURLE_COULDNT_CONNECT;
    489   }
    490 
    491   if(data->set.socks5_gssapi_nec) {
    492     memcpy(socksreq, &gss_enc, 1);
    493     code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
    494                              &written);
    495     if(code || (1 != written)) {
    496       failf(data, "Failed to send SSPI encryption type.");
    497       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    498       return CURLE_COULDNT_CONNECT;
    499     }
    500   }
    501   else {
    502     code = Curl_conn_cf_send(cf->next, data,
    503                              (char *)sspi_send_token.pvBuffer,
    504                              sspi_send_token.cbBuffer, FALSE, &written);
    505     if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
    506       failf(data, "Failed to send SSPI encryption type.");
    507       if(sspi_send_token.pvBuffer)
    508         Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    509       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    510       return CURLE_COULDNT_CONNECT;
    511     }
    512     if(sspi_send_token.pvBuffer)
    513       Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
    514   }
    515 
    516   result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
    517   if(result || (actualread != 4)) {
    518     failf(data, "Failed to receive SSPI encryption response.");
    519     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    520     return CURLE_COULDNT_CONNECT;
    521   }
    522 
    523   /* ignore the first (VER) byte */
    524   if(socksreq[1] == 255) { /* status / message type */
    525     failf(data, "User was rejected by the SOCKS5 server (%u %u).",
    526           (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
    527     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    528     return CURLE_COULDNT_CONNECT;
    529   }
    530 
    531   if(socksreq[1] != 2) { /* status / message type */
    532     failf(data, "Invalid SSPI encryption response type (%u %u).",
    533           (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
    534     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    535     return CURLE_COULDNT_CONNECT;
    536   }
    537 
    538   memcpy(&us_length, socksreq + 2, sizeof(short));
    539   us_length = ntohs(us_length);
    540 
    541   sspi_w_token[0].cbBuffer = us_length;
    542   sspi_w_token[0].pvBuffer = malloc(us_length);
    543   if(!sspi_w_token[0].pvBuffer) {
    544     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    545     return CURLE_OUT_OF_MEMORY;
    546   }
    547 
    548   result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer,
    549                               sspi_w_token[0].cbBuffer, &actualread);
    550 
    551   if(result || (actualread != us_length)) {
    552     failf(data, "Failed to receive SSPI encryption type.");
    553     Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    554     Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    555     return CURLE_COULDNT_CONNECT;
    556   }
    557 
    558 
    559   if(!data->set.socks5_gssapi_nec) {
    560     wrap_desc.cBuffers = 2;
    561     sspi_w_token[0].BufferType = SECBUFFER_STREAM;
    562     sspi_w_token[1].BufferType = SECBUFFER_DATA;
    563     sspi_w_token[1].cbBuffer = 0;
    564     sspi_w_token[1].pvBuffer = NULL;
    565 
    566     status = Curl_pSecFn->DecryptMessage(&sspi_context,
    567                                       &wrap_desc,
    568                                       0,
    569                                       &qop);
    570 
    571     if(check_sspi_err(data, status, "DecryptMessage")) {
    572       if(sspi_w_token[0].pvBuffer)
    573         Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    574       if(sspi_w_token[1].pvBuffer)
    575         Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    576       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    577       failf(data, "Failed to query security context attributes.");
    578       return CURLE_COULDNT_CONNECT;
    579     }
    580 
    581     if(sspi_w_token[1].cbBuffer != 1) {
    582       failf(data, "Invalid SSPI encryption response length (%lu).",
    583             (unsigned long)sspi_w_token[1].cbBuffer);
    584       if(sspi_w_token[0].pvBuffer)
    585         Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    586       if(sspi_w_token[1].pvBuffer)
    587         Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    588       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    589       return CURLE_COULDNT_CONNECT;
    590     }
    591 
    592     memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
    593     Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    594     Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    595   }
    596   else {
    597     if(sspi_w_token[0].cbBuffer != 1) {
    598       failf(data, "Invalid SSPI encryption response length (%lu).",
    599             (unsigned long)sspi_w_token[0].cbBuffer);
    600       Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    601       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    602       return CURLE_COULDNT_CONNECT;
    603     }
    604     memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer);
    605     Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
    606   }
    607   (void)curlx_nonblock(sock, TRUE);
    608 
    609   infof(data, "SOCKS5 access with%s protection granted.",
    610         (socksreq[0] == 0) ? "out GSS-API data":
    611         ((socksreq[0] == 1) ? " GSS-API integrity" :
    612          " GSS-API confidentiality"));
    613 
    614   /* For later use if encryption is required
    615      conn->socks5_gssapi_enctype = socksreq[0];
    616      if(socksreq[0] != 0)
    617        conn->socks5_sspi_context = sspi_context;
    618      else {
    619        Curl_pSecFn->DeleteSecurityContext(&sspi_context);
    620        conn->socks5_sspi_context = sspi_context;
    621      }
    622   */
    623   return CURLE_OK;
    624 }
    625 #endif