quickjs-tart

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

http_ntlm.c (7951B)


      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_NTLM)
     28 
     29 /*
     30  * NTLM details:
     31  *
     32  * https://davenport.sourceforge.net/ntlm.html
     33  * https://www.innovation.ch/java/ntlm.html
     34  */
     35 
     36 #include "urldata.h"
     37 #include "sendf.h"
     38 #include "strcase.h"
     39 #include "http_ntlm.h"
     40 #include "curl_ntlm_core.h"
     41 #include "curlx/base64.h"
     42 #include "vauth/vauth.h"
     43 #include "url.h"
     44 #include "curlx/strparse.h"
     45 
     46 /* SSL backend-specific #if branches in this file must be kept in the order
     47    documented in curl_ntlm_core. */
     48 #if defined(USE_WINDOWS_SSPI)
     49 #include "curl_sspi.h"
     50 #endif
     51 
     52 /* The last 3 #include files should be in this order */
     53 #include "curl_printf.h"
     54 #include "curl_memory.h"
     55 #include "memdebug.h"
     56 
     57 CURLcode Curl_input_ntlm(struct Curl_easy *data,
     58                          bool proxy,         /* if proxy or not */
     59                          const char *header) /* rest of the www-authenticate:
     60                                                 header */
     61 {
     62   /* point to the correct struct with this */
     63   curlntlm *state;
     64   CURLcode result = CURLE_OK;
     65   struct connectdata *conn = data->conn;
     66 
     67   state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
     68 
     69   if(checkprefix("NTLM", header)) {
     70     struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, proxy);
     71     if(!ntlm)
     72       return CURLE_FAILED_INIT;
     73 
     74     header += strlen("NTLM");
     75     curlx_str_passblanks(&header);
     76     if(*header) {
     77       unsigned char *hdr;
     78       size_t hdrlen;
     79 
     80       result = curlx_base64_decode(header, &hdr, &hdrlen);
     81       if(!result) {
     82         struct bufref hdrbuf;
     83 
     84         Curl_bufref_init(&hdrbuf);
     85         Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free);
     86         result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm);
     87         Curl_bufref_free(&hdrbuf);
     88       }
     89       if(result)
     90         return result;
     91 
     92       *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
     93     }
     94     else {
     95       if(*state == NTLMSTATE_LAST) {
     96         infof(data, "NTLM auth restarted");
     97         Curl_auth_ntlm_remove(conn, proxy);
     98       }
     99       else if(*state == NTLMSTATE_TYPE3) {
    100         infof(data, "NTLM handshake rejected");
    101         Curl_auth_ntlm_remove(conn, proxy);
    102         *state = NTLMSTATE_NONE;
    103         return CURLE_REMOTE_ACCESS_DENIED;
    104       }
    105       else if(*state >= NTLMSTATE_TYPE1) {
    106         infof(data, "NTLM handshake failure (internal error)");
    107         return CURLE_REMOTE_ACCESS_DENIED;
    108       }
    109 
    110       *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
    111     }
    112   }
    113 
    114   return result;
    115 }
    116 
    117 /*
    118  * This is for creating NTLM header output
    119  */
    120 CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
    121 {
    122   char *base64 = NULL;
    123   size_t len = 0;
    124   CURLcode result = CURLE_OK;
    125   struct bufref ntlmmsg;
    126 
    127   /* point to the address of the pointer that holds the string to send to the
    128      server, which is for a plain host or for an HTTP proxy */
    129   char **allocuserpwd;
    130 
    131   /* point to the username, password, service and host */
    132   const char *userp;
    133   const char *passwdp;
    134   const char *service = NULL;
    135   const char *hostname = NULL;
    136 
    137   /* point to the correct struct with this */
    138   struct ntlmdata *ntlm;
    139   curlntlm *state;
    140   struct auth *authp;
    141   struct connectdata *conn = data->conn;
    142 
    143   DEBUGASSERT(conn);
    144   DEBUGASSERT(data);
    145 
    146   if(proxy) {
    147 #ifndef CURL_DISABLE_PROXY
    148     allocuserpwd = &data->state.aptr.proxyuserpwd;
    149     userp = data->state.aptr.proxyuser;
    150     passwdp = data->state.aptr.proxypasswd;
    151     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
    152       data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
    153     hostname = conn->http_proxy.host.name;
    154     state = &conn->proxy_ntlm_state;
    155     authp = &data->state.authproxy;
    156 #else
    157     return CURLE_NOT_BUILT_IN;
    158 #endif
    159   }
    160   else {
    161     allocuserpwd = &data->state.aptr.userpwd;
    162     userp = data->state.aptr.user;
    163     passwdp = data->state.aptr.passwd;
    164     service = data->set.str[STRING_SERVICE_NAME] ?
    165       data->set.str[STRING_SERVICE_NAME] : "HTTP";
    166     hostname = conn->host.name;
    167     state = &conn->http_ntlm_state;
    168     authp = &data->state.authhost;
    169   }
    170   ntlm = Curl_auth_ntlm_get(conn, proxy);
    171   if(!ntlm)
    172     return CURLE_OUT_OF_MEMORY;
    173   authp->done = FALSE;
    174 
    175   /* not set means empty */
    176   if(!userp)
    177     userp = "";
    178 
    179   if(!passwdp)
    180     passwdp = "";
    181 
    182 #ifdef USE_WINDOWS_SSPI
    183   if(!Curl_pSecFn) {
    184     /* not thread safe and leaks - use curl_global_init() to avoid */
    185     CURLcode err = Curl_sspi_global_init();
    186     if(!Curl_pSecFn)
    187       return err;
    188   }
    189 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
    190   ntlm->sslContext = conn->sslContext;
    191 #endif
    192 #endif
    193 
    194   Curl_bufref_init(&ntlmmsg);
    195 
    196   /* connection is already authenticated, do not send a header in future
    197    * requests so go directly to NTLMSTATE_LAST */
    198   if(*state == NTLMSTATE_TYPE3)
    199     *state = NTLMSTATE_LAST;
    200 
    201   switch(*state) {
    202   case NTLMSTATE_TYPE1:
    203   default: /* for the weird cases we (re)start here */
    204     /* Create a type-1 message */
    205     result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service,
    206                                                  hostname, ntlm, &ntlmmsg);
    207     if(!result) {
    208       DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
    209       result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
    210                                   Curl_bufref_len(&ntlmmsg), &base64, &len);
    211       if(!result) {
    212         free(*allocuserpwd);
    213         *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
    214                                 proxy ? "Proxy-" : "",
    215                                 base64);
    216         free(base64);
    217         if(!*allocuserpwd)
    218           result = CURLE_OUT_OF_MEMORY;
    219       }
    220     }
    221     break;
    222 
    223   case NTLMSTATE_TYPE2:
    224     /* We already received the type-2 message, create a type-3 message */
    225     result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
    226                                                  ntlm, &ntlmmsg);
    227     if(!result && Curl_bufref_len(&ntlmmsg)) {
    228       result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
    229                                    Curl_bufref_len(&ntlmmsg), &base64, &len);
    230       if(!result) {
    231         free(*allocuserpwd);
    232         *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
    233                                 proxy ? "Proxy-" : "",
    234                                 base64);
    235         free(base64);
    236         if(!*allocuserpwd)
    237           result = CURLE_OUT_OF_MEMORY;
    238         else {
    239           *state = NTLMSTATE_TYPE3; /* we send a type-3 */
    240           authp->done = TRUE;
    241         }
    242       }
    243     }
    244     break;
    245 
    246   case NTLMSTATE_LAST:
    247     /* since this is a little artificial in that this is used without any
    248        outgoing auth headers being set, we need to set the bit by force */
    249     if(proxy)
    250       data->info.proxyauthpicked = CURLAUTH_NTLM;
    251     else
    252       data->info.httpauthpicked = CURLAUTH_NTLM;
    253     Curl_safefree(*allocuserpwd);
    254     authp->done = TRUE;
    255     break;
    256   }
    257   Curl_bufref_free(&ntlmmsg);
    258 
    259   return result;
    260 }
    261 
    262 #endif /* !CURL_DISABLE_HTTP && USE_NTLM */