113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci/* 3013498266Sopenharmony_ci * NTLM details: 3113498266Sopenharmony_ci * 3213498266Sopenharmony_ci * https://davenport.sourceforge.net/ntlm.html 3313498266Sopenharmony_ci * https://www.innovation.ch/java/ntlm.html 3413498266Sopenharmony_ci */ 3513498266Sopenharmony_ci 3613498266Sopenharmony_ci#define DEBUG_ME 0 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci#include "urldata.h" 3913498266Sopenharmony_ci#include "sendf.h" 4013498266Sopenharmony_ci#include "strcase.h" 4113498266Sopenharmony_ci#include "http_ntlm.h" 4213498266Sopenharmony_ci#include "curl_ntlm_core.h" 4313498266Sopenharmony_ci#include "curl_ntlm_wb.h" 4413498266Sopenharmony_ci#include "curl_base64.h" 4513498266Sopenharmony_ci#include "vauth/vauth.h" 4613498266Sopenharmony_ci#include "url.h" 4713498266Sopenharmony_ci 4813498266Sopenharmony_ci/* SSL backend-specific #if branches in this file must be kept in the order 4913498266Sopenharmony_ci documented in curl_ntlm_core. */ 5013498266Sopenharmony_ci#if defined(USE_WINDOWS_SSPI) 5113498266Sopenharmony_ci#include "curl_sspi.h" 5213498266Sopenharmony_ci#endif 5313498266Sopenharmony_ci 5413498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 5513498266Sopenharmony_ci#include "curl_printf.h" 5613498266Sopenharmony_ci#include "curl_memory.h" 5713498266Sopenharmony_ci#include "memdebug.h" 5813498266Sopenharmony_ci 5913498266Sopenharmony_ci#if DEBUG_ME 6013498266Sopenharmony_ci# define DEBUG_OUT(x) x 6113498266Sopenharmony_ci#else 6213498266Sopenharmony_ci# define DEBUG_OUT(x) Curl_nop_stmt 6313498266Sopenharmony_ci#endif 6413498266Sopenharmony_ci 6513498266Sopenharmony_ciCURLcode Curl_input_ntlm(struct Curl_easy *data, 6613498266Sopenharmony_ci bool proxy, /* if proxy or not */ 6713498266Sopenharmony_ci const char *header) /* rest of the www-authenticate: 6813498266Sopenharmony_ci header */ 6913498266Sopenharmony_ci{ 7013498266Sopenharmony_ci /* point to the correct struct with this */ 7113498266Sopenharmony_ci struct ntlmdata *ntlm; 7213498266Sopenharmony_ci curlntlm *state; 7313498266Sopenharmony_ci CURLcode result = CURLE_OK; 7413498266Sopenharmony_ci struct connectdata *conn = data->conn; 7513498266Sopenharmony_ci 7613498266Sopenharmony_ci ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; 7713498266Sopenharmony_ci state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; 7813498266Sopenharmony_ci 7913498266Sopenharmony_ci if(checkprefix("NTLM", header)) { 8013498266Sopenharmony_ci header += strlen("NTLM"); 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci while(*header && ISSPACE(*header)) 8313498266Sopenharmony_ci header++; 8413498266Sopenharmony_ci 8513498266Sopenharmony_ci if(*header) { 8613498266Sopenharmony_ci unsigned char *hdr; 8713498266Sopenharmony_ci size_t hdrlen; 8813498266Sopenharmony_ci 8913498266Sopenharmony_ci result = Curl_base64_decode(header, &hdr, &hdrlen); 9013498266Sopenharmony_ci if(!result) { 9113498266Sopenharmony_ci struct bufref hdrbuf; 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci Curl_bufref_init(&hdrbuf); 9413498266Sopenharmony_ci Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free); 9513498266Sopenharmony_ci result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm); 9613498266Sopenharmony_ci Curl_bufref_free(&hdrbuf); 9713498266Sopenharmony_ci } 9813498266Sopenharmony_ci if(result) 9913498266Sopenharmony_ci return result; 10013498266Sopenharmony_ci 10113498266Sopenharmony_ci *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ 10213498266Sopenharmony_ci } 10313498266Sopenharmony_ci else { 10413498266Sopenharmony_ci if(*state == NTLMSTATE_LAST) { 10513498266Sopenharmony_ci infof(data, "NTLM auth restarted"); 10613498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm(conn); 10713498266Sopenharmony_ci } 10813498266Sopenharmony_ci else if(*state == NTLMSTATE_TYPE3) { 10913498266Sopenharmony_ci infof(data, "NTLM handshake rejected"); 11013498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm(conn); 11113498266Sopenharmony_ci *state = NTLMSTATE_NONE; 11213498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 11313498266Sopenharmony_ci } 11413498266Sopenharmony_ci else if(*state >= NTLMSTATE_TYPE1) { 11513498266Sopenharmony_ci infof(data, "NTLM handshake failure (internal error)"); 11613498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 11713498266Sopenharmony_ci } 11813498266Sopenharmony_ci 11913498266Sopenharmony_ci *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ 12013498266Sopenharmony_ci } 12113498266Sopenharmony_ci } 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci return result; 12413498266Sopenharmony_ci} 12513498266Sopenharmony_ci 12613498266Sopenharmony_ci/* 12713498266Sopenharmony_ci * This is for creating ntlm header output 12813498266Sopenharmony_ci */ 12913498266Sopenharmony_ciCURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) 13013498266Sopenharmony_ci{ 13113498266Sopenharmony_ci char *base64 = NULL; 13213498266Sopenharmony_ci size_t len = 0; 13313498266Sopenharmony_ci CURLcode result = CURLE_OK; 13413498266Sopenharmony_ci struct bufref ntlmmsg; 13513498266Sopenharmony_ci 13613498266Sopenharmony_ci /* point to the address of the pointer that holds the string to send to the 13713498266Sopenharmony_ci server, which is for a plain host or for an HTTP proxy */ 13813498266Sopenharmony_ci char **allocuserpwd; 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci /* point to the username, password, service and host */ 14113498266Sopenharmony_ci const char *userp; 14213498266Sopenharmony_ci const char *passwdp; 14313498266Sopenharmony_ci const char *service = NULL; 14413498266Sopenharmony_ci const char *hostname = NULL; 14513498266Sopenharmony_ci 14613498266Sopenharmony_ci /* point to the correct struct with this */ 14713498266Sopenharmony_ci struct ntlmdata *ntlm; 14813498266Sopenharmony_ci curlntlm *state; 14913498266Sopenharmony_ci struct auth *authp; 15013498266Sopenharmony_ci struct connectdata *conn = data->conn; 15113498266Sopenharmony_ci 15213498266Sopenharmony_ci DEBUGASSERT(conn); 15313498266Sopenharmony_ci DEBUGASSERT(data); 15413498266Sopenharmony_ci 15513498266Sopenharmony_ci if(proxy) { 15613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 15713498266Sopenharmony_ci allocuserpwd = &data->state.aptr.proxyuserpwd; 15813498266Sopenharmony_ci userp = data->state.aptr.proxyuser; 15913498266Sopenharmony_ci passwdp = data->state.aptr.proxypasswd; 16013498266Sopenharmony_ci service = data->set.str[STRING_PROXY_SERVICE_NAME] ? 16113498266Sopenharmony_ci data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; 16213498266Sopenharmony_ci hostname = conn->http_proxy.host.name; 16313498266Sopenharmony_ci ntlm = &conn->proxyntlm; 16413498266Sopenharmony_ci state = &conn->proxy_ntlm_state; 16513498266Sopenharmony_ci authp = &data->state.authproxy; 16613498266Sopenharmony_ci#else 16713498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 16813498266Sopenharmony_ci#endif 16913498266Sopenharmony_ci } 17013498266Sopenharmony_ci else { 17113498266Sopenharmony_ci allocuserpwd = &data->state.aptr.userpwd; 17213498266Sopenharmony_ci userp = data->state.aptr.user; 17313498266Sopenharmony_ci passwdp = data->state.aptr.passwd; 17413498266Sopenharmony_ci service = data->set.str[STRING_SERVICE_NAME] ? 17513498266Sopenharmony_ci data->set.str[STRING_SERVICE_NAME] : "HTTP"; 17613498266Sopenharmony_ci hostname = conn->host.name; 17713498266Sopenharmony_ci ntlm = &conn->ntlm; 17813498266Sopenharmony_ci state = &conn->http_ntlm_state; 17913498266Sopenharmony_ci authp = &data->state.authhost; 18013498266Sopenharmony_ci } 18113498266Sopenharmony_ci authp->done = FALSE; 18213498266Sopenharmony_ci 18313498266Sopenharmony_ci /* not set means empty */ 18413498266Sopenharmony_ci if(!userp) 18513498266Sopenharmony_ci userp = ""; 18613498266Sopenharmony_ci 18713498266Sopenharmony_ci if(!passwdp) 18813498266Sopenharmony_ci passwdp = ""; 18913498266Sopenharmony_ci 19013498266Sopenharmony_ci#ifdef USE_WINDOWS_SSPI 19113498266Sopenharmony_ci if(!s_hSecDll) { 19213498266Sopenharmony_ci /* not thread safe and leaks - use curl_global_init() to avoid */ 19313498266Sopenharmony_ci CURLcode err = Curl_sspi_global_init(); 19413498266Sopenharmony_ci if(!s_hSecDll) 19513498266Sopenharmony_ci return err; 19613498266Sopenharmony_ci } 19713498266Sopenharmony_ci#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS 19813498266Sopenharmony_ci ntlm->sslContext = conn->sslContext; 19913498266Sopenharmony_ci#endif 20013498266Sopenharmony_ci#endif 20113498266Sopenharmony_ci 20213498266Sopenharmony_ci Curl_bufref_init(&ntlmmsg); 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci /* connection is already authenticated, don't send a header in future 20513498266Sopenharmony_ci * requests so go directly to NTLMSTATE_LAST */ 20613498266Sopenharmony_ci if(*state == NTLMSTATE_TYPE3) 20713498266Sopenharmony_ci *state = NTLMSTATE_LAST; 20813498266Sopenharmony_ci 20913498266Sopenharmony_ci switch(*state) { 21013498266Sopenharmony_ci case NTLMSTATE_TYPE1: 21113498266Sopenharmony_ci default: /* for the weird cases we (re)start here */ 21213498266Sopenharmony_ci /* Create a type-1 message */ 21313498266Sopenharmony_ci result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, 21413498266Sopenharmony_ci service, hostname, 21513498266Sopenharmony_ci ntlm, &ntlmmsg); 21613498266Sopenharmony_ci if(!result) { 21713498266Sopenharmony_ci DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0); 21813498266Sopenharmony_ci result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg), 21913498266Sopenharmony_ci Curl_bufref_len(&ntlmmsg), &base64, &len); 22013498266Sopenharmony_ci if(!result) { 22113498266Sopenharmony_ci free(*allocuserpwd); 22213498266Sopenharmony_ci *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 22313498266Sopenharmony_ci proxy ? "Proxy-" : "", 22413498266Sopenharmony_ci base64); 22513498266Sopenharmony_ci free(base64); 22613498266Sopenharmony_ci if(!*allocuserpwd) 22713498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 22813498266Sopenharmony_ci } 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci break; 23113498266Sopenharmony_ci 23213498266Sopenharmony_ci case NTLMSTATE_TYPE2: 23313498266Sopenharmony_ci /* We already received the type-2 message, create a type-3 message */ 23413498266Sopenharmony_ci result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp, 23513498266Sopenharmony_ci ntlm, &ntlmmsg); 23613498266Sopenharmony_ci if(!result && Curl_bufref_len(&ntlmmsg)) { 23713498266Sopenharmony_ci result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg), 23813498266Sopenharmony_ci Curl_bufref_len(&ntlmmsg), &base64, &len); 23913498266Sopenharmony_ci if(!result) { 24013498266Sopenharmony_ci free(*allocuserpwd); 24113498266Sopenharmony_ci *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 24213498266Sopenharmony_ci proxy ? "Proxy-" : "", 24313498266Sopenharmony_ci base64); 24413498266Sopenharmony_ci free(base64); 24513498266Sopenharmony_ci if(!*allocuserpwd) 24613498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 24713498266Sopenharmony_ci else { 24813498266Sopenharmony_ci *state = NTLMSTATE_TYPE3; /* we send a type-3 */ 24913498266Sopenharmony_ci authp->done = TRUE; 25013498266Sopenharmony_ci } 25113498266Sopenharmony_ci } 25213498266Sopenharmony_ci } 25313498266Sopenharmony_ci break; 25413498266Sopenharmony_ci 25513498266Sopenharmony_ci case NTLMSTATE_LAST: 25613498266Sopenharmony_ci Curl_safefree(*allocuserpwd); 25713498266Sopenharmony_ci authp->done = TRUE; 25813498266Sopenharmony_ci break; 25913498266Sopenharmony_ci } 26013498266Sopenharmony_ci Curl_bufref_free(&ntlmmsg); 26113498266Sopenharmony_ci 26213498266Sopenharmony_ci return result; 26313498266Sopenharmony_ci} 26413498266Sopenharmony_ci 26513498266Sopenharmony_civoid Curl_http_auth_cleanup_ntlm(struct connectdata *conn) 26613498266Sopenharmony_ci{ 26713498266Sopenharmony_ci Curl_auth_cleanup_ntlm(&conn->ntlm); 26813498266Sopenharmony_ci Curl_auth_cleanup_ntlm(&conn->proxyntlm); 26913498266Sopenharmony_ci 27013498266Sopenharmony_ci#if defined(NTLM_WB_ENABLED) 27113498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm_wb(conn); 27213498266Sopenharmony_ci#endif 27313498266Sopenharmony_ci} 27413498266Sopenharmony_ci 27513498266Sopenharmony_ci#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ 276