quickjs-tart

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

http_negotiate.c (7443B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
     28 
     29 #include "urldata.h"
     30 #include "cfilters.h"
     31 #include "sendf.h"
     32 #include "http_negotiate.h"
     33 #include "vauth/vauth.h"
     34 #include "vtls/vtls.h"
     35 #include "curlx/strparse.h"
     36 
     37 /* The last 3 #include files should be in this order */
     38 #include "curl_printf.h"
     39 #include "curl_memory.h"
     40 #include "memdebug.h"
     41 
     42 
     43 static void http_auth_nego_reset(struct connectdata *conn,
     44                                  struct negotiatedata *neg_ctx,
     45                                  bool proxy)
     46 {
     47   if(proxy)
     48     conn->proxy_negotiate_state = GSS_AUTHNONE;
     49   else
     50     conn->http_negotiate_state = GSS_AUTHNONE;
     51   if(neg_ctx)
     52     Curl_auth_cleanup_spnego(neg_ctx);
     53 }
     54 
     55 
     56 CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
     57                               bool proxy, const char *header)
     58 {
     59   CURLcode result;
     60   size_t len;
     61 
     62   /* Point to the username, password, service and host */
     63   const char *userp;
     64   const char *passwdp;
     65   const char *service;
     66   const char *host;
     67 
     68   /* Point to the correct struct with this */
     69   struct negotiatedata *neg_ctx;
     70   curlnegotiate state;
     71 
     72   if(proxy) {
     73 #ifndef CURL_DISABLE_PROXY
     74     userp = conn->http_proxy.user;
     75     passwdp = conn->http_proxy.passwd;
     76     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
     77               data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     78     host = conn->http_proxy.host.name;
     79     state = conn->proxy_negotiate_state;
     80 #else
     81     return CURLE_NOT_BUILT_IN;
     82 #endif
     83   }
     84   else {
     85     userp = conn->user;
     86     passwdp = conn->passwd;
     87     service = data->set.str[STRING_SERVICE_NAME] ?
     88               data->set.str[STRING_SERVICE_NAME] : "HTTP";
     89     host = conn->host.name;
     90     state = conn->http_negotiate_state;
     91   }
     92 
     93   neg_ctx = Curl_auth_nego_get(conn, proxy);
     94   if(!neg_ctx)
     95     return CURLE_OUT_OF_MEMORY;
     96 
     97   /* Not set means empty */
     98   if(!userp)
     99     userp = "";
    100 
    101   if(!passwdp)
    102     passwdp = "";
    103 
    104   /* Obtain the input token, if any */
    105   header += strlen("Negotiate");
    106   curlx_str_passblanks(&header);
    107 
    108   len = strlen(header);
    109   neg_ctx->havenegdata = len != 0;
    110   if(!len) {
    111     if(state == GSS_AUTHSUCC) {
    112       infof(data, "Negotiate auth restarted");
    113       http_auth_nego_reset(conn, neg_ctx, proxy);
    114     }
    115     else if(state != GSS_AUTHNONE) {
    116       /* The server rejected our authentication and has not supplied any more
    117       negotiation mechanisms */
    118       http_auth_nego_reset(conn, neg_ctx, proxy);
    119       return CURLE_LOGIN_DENIED;
    120     }
    121   }
    122 
    123   /* Supports SSL channel binding for Windows ISS extended protection */
    124 #if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
    125   neg_ctx->sslContext = conn->sslContext;
    126 #endif
    127   /* Check if the connection is using SSL and get the channel binding data */
    128 #ifdef HAVE_GSSAPI
    129 #ifdef USE_SSL
    130   curlx_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1);
    131   if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
    132     result = Curl_ssl_get_channel_binding(
    133       data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
    134     if(result) {
    135       http_auth_nego_reset(conn, neg_ctx, proxy);
    136       return result;
    137     }
    138   }
    139 #else
    140   curlx_dyn_init(&neg_ctx->channel_binding_data, 1);
    141 #endif /* USE_SSL */
    142 #endif /* HAVE_GSSAPI */
    143 
    144   /* Initialize the security context and decode our challenge */
    145   result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
    146                                            host, header, neg_ctx);
    147 
    148 #ifdef HAVE_GSSAPI
    149   curlx_dyn_free(&neg_ctx->channel_binding_data);
    150 #endif
    151 
    152   if(result)
    153     http_auth_nego_reset(conn, neg_ctx, proxy);
    154 
    155   return result;
    156 }
    157 
    158 CURLcode Curl_output_negotiate(struct Curl_easy *data,
    159                                struct connectdata *conn, bool proxy)
    160 {
    161   struct negotiatedata *neg_ctx;
    162   struct auth *authp;
    163   curlnegotiate *state;
    164   char *base64 = NULL;
    165   size_t len = 0;
    166   char *userp;
    167   CURLcode result;
    168 
    169   if(proxy) {
    170 #ifndef CURL_DISABLE_PROXY
    171     authp = &data->state.authproxy;
    172     state = &conn->proxy_negotiate_state;
    173 #else
    174     return CURLE_NOT_BUILT_IN;
    175 #endif
    176   }
    177   else {
    178     authp = &data->state.authhost;
    179     state = &conn->http_negotiate_state;
    180   }
    181   neg_ctx = Curl_auth_nego_get(conn, proxy);
    182   if(!neg_ctx)
    183     return CURLE_OUT_OF_MEMORY;
    184 
    185   authp->done = FALSE;
    186 
    187   if(*state == GSS_AUTHRECV) {
    188     if(neg_ctx->havenegdata) {
    189       neg_ctx->havemultiplerequests = TRUE;
    190     }
    191   }
    192   else if(*state == GSS_AUTHSUCC) {
    193     if(!neg_ctx->havenoauthpersist) {
    194       neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests;
    195     }
    196   }
    197 
    198   if(neg_ctx->noauthpersist ||
    199      (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
    200 
    201     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
    202       infof(data, "Curl_output_negotiate, "
    203             "no persistent authentication: cleanup existing context");
    204       http_auth_nego_reset(conn, neg_ctx, proxy);
    205     }
    206     if(!neg_ctx->context) {
    207       result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
    208       if(result == CURLE_AUTH_ERROR) {
    209         /* negotiate auth failed, let's continue unauthenticated to stay
    210          * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
    211         authp->done = TRUE;
    212         return CURLE_OK;
    213       }
    214       else if(result)
    215         return result;
    216     }
    217 
    218     result = Curl_auth_create_spnego_message(neg_ctx, &base64, &len);
    219     if(result)
    220       return result;
    221 
    222     userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
    223                     base64);
    224 
    225     if(proxy) {
    226 #ifndef CURL_DISABLE_PROXY
    227       free(data->state.aptr.proxyuserpwd);
    228       data->state.aptr.proxyuserpwd = userp;
    229 #endif
    230     }
    231     else {
    232       free(data->state.aptr.userpwd);
    233       data->state.aptr.userpwd = userp;
    234     }
    235 
    236     free(base64);
    237 
    238     if(!userp) {
    239       return CURLE_OUT_OF_MEMORY;
    240     }
    241 
    242     *state = GSS_AUTHSENT;
    243   #ifdef HAVE_GSSAPI
    244     if(neg_ctx->status == GSS_S_COMPLETE ||
    245        neg_ctx->status == GSS_S_CONTINUE_NEEDED) {
    246       *state = GSS_AUTHDONE;
    247     }
    248   #else
    249   #ifdef USE_WINDOWS_SSPI
    250     if(neg_ctx->status == SEC_E_OK ||
    251        neg_ctx->status == SEC_I_CONTINUE_NEEDED) {
    252       *state = GSS_AUTHDONE;
    253     }
    254   #endif
    255   #endif
    256   }
    257 
    258   if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
    259     /* connection is already authenticated,
    260      * do not send a header in future requests */
    261     authp->done = TRUE;
    262   }
    263 
    264   neg_ctx->havenegdata = FALSE;
    265 
    266   return CURLE_OK;
    267 }
    268 
    269 #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */