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