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 defined(NTLM_WB_ENABLED) 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci/* 3113498266Sopenharmony_ci * NTLM details: 3213498266Sopenharmony_ci * 3313498266Sopenharmony_ci * https://davenport.sourceforge.net/ntlm.html 3413498266Sopenharmony_ci * https://www.innovation.ch/java/ntlm.html 3513498266Sopenharmony_ci */ 3613498266Sopenharmony_ci 3713498266Sopenharmony_ci#define DEBUG_ME 0 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci#ifdef HAVE_SYS_WAIT_H 4013498266Sopenharmony_ci#include <sys/wait.h> 4113498266Sopenharmony_ci#endif 4213498266Sopenharmony_ci#include <signal.h> 4313498266Sopenharmony_ci#ifdef HAVE_PWD_H 4413498266Sopenharmony_ci#include <pwd.h> 4513498266Sopenharmony_ci#endif 4613498266Sopenharmony_ci 4713498266Sopenharmony_ci#include "urldata.h" 4813498266Sopenharmony_ci#include "sendf.h" 4913498266Sopenharmony_ci#include "select.h" 5013498266Sopenharmony_ci#include "vauth/ntlm.h" 5113498266Sopenharmony_ci#include "curl_ntlm_core.h" 5213498266Sopenharmony_ci#include "curl_ntlm_wb.h" 5313498266Sopenharmony_ci#include "url.h" 5413498266Sopenharmony_ci#include "strerror.h" 5513498266Sopenharmony_ci#include "strdup.h" 5613498266Sopenharmony_ci#include "strcase.h" 5713498266Sopenharmony_ci 5813498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 5913498266Sopenharmony_ci#include "curl_printf.h" 6013498266Sopenharmony_ci#include "curl_memory.h" 6113498266Sopenharmony_ci#include "memdebug.h" 6213498266Sopenharmony_ci 6313498266Sopenharmony_ci#if DEBUG_ME 6413498266Sopenharmony_ci# define DEBUG_OUT(x) x 6513498266Sopenharmony_ci#else 6613498266Sopenharmony_ci# define DEBUG_OUT(x) Curl_nop_stmt 6713498266Sopenharmony_ci#endif 6813498266Sopenharmony_ci 6913498266Sopenharmony_ci/* Portable 'sclose_nolog' used only in child process instead of 'sclose' 7013498266Sopenharmony_ci to avoid fooling the socket leak detector */ 7113498266Sopenharmony_ci#ifdef HAVE_PIPE 7213498266Sopenharmony_ci# define sclose_nolog(x) close((x)) 7313498266Sopenharmony_ci#elif defined(HAVE_CLOSESOCKET) 7413498266Sopenharmony_ci# define sclose_nolog(x) closesocket((x)) 7513498266Sopenharmony_ci#elif defined(HAVE_CLOSESOCKET_CAMEL) 7613498266Sopenharmony_ci# define sclose_nolog(x) CloseSocket((x)) 7713498266Sopenharmony_ci#else 7813498266Sopenharmony_ci# define sclose_nolog(x) close((x)) 7913498266Sopenharmony_ci#endif 8013498266Sopenharmony_ci 8113498266Sopenharmony_cistatic void ntlm_wb_cleanup(struct ntlmdata *ntlm) 8213498266Sopenharmony_ci{ 8313498266Sopenharmony_ci if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { 8413498266Sopenharmony_ci sclose(ntlm->ntlm_auth_hlpr_socket); 8513498266Sopenharmony_ci ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; 8613498266Sopenharmony_ci } 8713498266Sopenharmony_ci 8813498266Sopenharmony_ci if(ntlm->ntlm_auth_hlpr_pid) { 8913498266Sopenharmony_ci int i; 9013498266Sopenharmony_ci for(i = 0; i < 4; i++) { 9113498266Sopenharmony_ci pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG); 9213498266Sopenharmony_ci if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD) 9313498266Sopenharmony_ci break; 9413498266Sopenharmony_ci switch(i) { 9513498266Sopenharmony_ci case 0: 9613498266Sopenharmony_ci kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM); 9713498266Sopenharmony_ci break; 9813498266Sopenharmony_ci case 1: 9913498266Sopenharmony_ci /* Give the process another moment to shut down cleanly before 10013498266Sopenharmony_ci bringing down the axe */ 10113498266Sopenharmony_ci Curl_wait_ms(1); 10213498266Sopenharmony_ci break; 10313498266Sopenharmony_ci case 2: 10413498266Sopenharmony_ci kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL); 10513498266Sopenharmony_ci break; 10613498266Sopenharmony_ci case 3: 10713498266Sopenharmony_ci break; 10813498266Sopenharmony_ci } 10913498266Sopenharmony_ci } 11013498266Sopenharmony_ci ntlm->ntlm_auth_hlpr_pid = 0; 11113498266Sopenharmony_ci } 11213498266Sopenharmony_ci 11313498266Sopenharmony_ci Curl_safefree(ntlm->challenge); 11413498266Sopenharmony_ci Curl_safefree(ntlm->response); 11513498266Sopenharmony_ci} 11613498266Sopenharmony_ci 11713498266Sopenharmony_cistatic CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm, 11813498266Sopenharmony_ci const char *userp) 11913498266Sopenharmony_ci{ 12013498266Sopenharmony_ci curl_socket_t sockfds[2]; 12113498266Sopenharmony_ci pid_t child_pid; 12213498266Sopenharmony_ci const char *username; 12313498266Sopenharmony_ci char *slash, *domain = NULL; 12413498266Sopenharmony_ci const char *ntlm_auth = NULL; 12513498266Sopenharmony_ci char *ntlm_auth_alloc = NULL; 12613498266Sopenharmony_ci#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) 12713498266Sopenharmony_ci struct passwd pw, *pw_res; 12813498266Sopenharmony_ci char pwbuf[1024]; 12913498266Sopenharmony_ci#endif 13013498266Sopenharmony_ci char buffer[STRERROR_LEN]; 13113498266Sopenharmony_ci 13213498266Sopenharmony_ci#if defined(CURL_DISABLE_VERBOSE_STRINGS) 13313498266Sopenharmony_ci (void) data; 13413498266Sopenharmony_ci#endif 13513498266Sopenharmony_ci 13613498266Sopenharmony_ci /* Return if communication with ntlm_auth already set up */ 13713498266Sopenharmony_ci if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || 13813498266Sopenharmony_ci ntlm->ntlm_auth_hlpr_pid) 13913498266Sopenharmony_ci return CURLE_OK; 14013498266Sopenharmony_ci 14113498266Sopenharmony_ci username = userp; 14213498266Sopenharmony_ci /* The real ntlm_auth really doesn't like being invoked with an 14313498266Sopenharmony_ci empty username. It won't make inferences for itself, and expects 14413498266Sopenharmony_ci the client to do so (mostly because it's really designed for 14513498266Sopenharmony_ci servers like squid to use for auth, and client support is an 14613498266Sopenharmony_ci afterthought for it). So try hard to provide a suitable username 14713498266Sopenharmony_ci if we don't already have one. But if we can't, provide the 14813498266Sopenharmony_ci empty one anyway. Perhaps they have an implementation of the 14913498266Sopenharmony_ci ntlm_auth helper which *doesn't* need it so we might as well try */ 15013498266Sopenharmony_ci if(!username || !username[0]) { 15113498266Sopenharmony_ci username = getenv("NTLMUSER"); 15213498266Sopenharmony_ci if(!username || !username[0]) 15313498266Sopenharmony_ci username = getenv("LOGNAME"); 15413498266Sopenharmony_ci if(!username || !username[0]) 15513498266Sopenharmony_ci username = getenv("USER"); 15613498266Sopenharmony_ci#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) 15713498266Sopenharmony_ci if((!username || !username[0]) && 15813498266Sopenharmony_ci !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && 15913498266Sopenharmony_ci pw_res) { 16013498266Sopenharmony_ci username = pw.pw_name; 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci#endif 16313498266Sopenharmony_ci if(!username || !username[0]) 16413498266Sopenharmony_ci username = userp; 16513498266Sopenharmony_ci } 16613498266Sopenharmony_ci slash = strpbrk(username, "\\/"); 16713498266Sopenharmony_ci if(slash) { 16813498266Sopenharmony_ci domain = strdup(username); 16913498266Sopenharmony_ci if(!domain) 17013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 17113498266Sopenharmony_ci slash = domain + (slash - username); 17213498266Sopenharmony_ci *slash = '\0'; 17313498266Sopenharmony_ci username = username + (slash - domain) + 1; 17413498266Sopenharmony_ci } 17513498266Sopenharmony_ci 17613498266Sopenharmony_ci /* For testing purposes, when DEBUGBUILD is defined and environment 17713498266Sopenharmony_ci variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform 17813498266Sopenharmony_ci NTLM challenge/response which only accepts commands and output 17913498266Sopenharmony_ci strings pre-written in test case definitions */ 18013498266Sopenharmony_ci#ifdef DEBUGBUILD 18113498266Sopenharmony_ci ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); 18213498266Sopenharmony_ci if(ntlm_auth_alloc) 18313498266Sopenharmony_ci ntlm_auth = ntlm_auth_alloc; 18413498266Sopenharmony_ci else 18513498266Sopenharmony_ci#endif 18613498266Sopenharmony_ci ntlm_auth = NTLM_WB_FILE; 18713498266Sopenharmony_ci 18813498266Sopenharmony_ci if(access(ntlm_auth, X_OK) != 0) { 18913498266Sopenharmony_ci failf(data, "Could not access ntlm_auth: %s errno %d: %s", 19013498266Sopenharmony_ci ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer))); 19113498266Sopenharmony_ci goto done; 19213498266Sopenharmony_ci } 19313498266Sopenharmony_ci 19413498266Sopenharmony_ci if(wakeup_create(sockfds)) { 19513498266Sopenharmony_ci failf(data, "Could not open socket pair. errno %d: %s", 19613498266Sopenharmony_ci errno, Curl_strerror(errno, buffer, sizeof(buffer))); 19713498266Sopenharmony_ci goto done; 19813498266Sopenharmony_ci } 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci child_pid = fork(); 20113498266Sopenharmony_ci if(child_pid == -1) { 20213498266Sopenharmony_ci wakeup_close(sockfds[0]); 20313498266Sopenharmony_ci wakeup_close(sockfds[1]); 20413498266Sopenharmony_ci failf(data, "Could not fork. errno %d: %s", 20513498266Sopenharmony_ci errno, Curl_strerror(errno, buffer, sizeof(buffer))); 20613498266Sopenharmony_ci goto done; 20713498266Sopenharmony_ci } 20813498266Sopenharmony_ci else if(!child_pid) { 20913498266Sopenharmony_ci /* 21013498266Sopenharmony_ci * child process 21113498266Sopenharmony_ci */ 21213498266Sopenharmony_ci 21313498266Sopenharmony_ci /* Don't use sclose in the child since it fools the socket leak detector */ 21413498266Sopenharmony_ci sclose_nolog(sockfds[0]); 21513498266Sopenharmony_ci if(dup2(sockfds[1], STDIN_FILENO) == -1) { 21613498266Sopenharmony_ci failf(data, "Could not redirect child stdin. errno %d: %s", 21713498266Sopenharmony_ci errno, Curl_strerror(errno, buffer, sizeof(buffer))); 21813498266Sopenharmony_ci exit(1); 21913498266Sopenharmony_ci } 22013498266Sopenharmony_ci 22113498266Sopenharmony_ci if(dup2(sockfds[1], STDOUT_FILENO) == -1) { 22213498266Sopenharmony_ci failf(data, "Could not redirect child stdout. errno %d: %s", 22313498266Sopenharmony_ci errno, Curl_strerror(errno, buffer, sizeof(buffer))); 22413498266Sopenharmony_ci exit(1); 22513498266Sopenharmony_ci } 22613498266Sopenharmony_ci 22713498266Sopenharmony_ci if(domain) 22813498266Sopenharmony_ci execl(ntlm_auth, ntlm_auth, 22913498266Sopenharmony_ci "--helper-protocol", "ntlmssp-client-1", 23013498266Sopenharmony_ci "--use-cached-creds", 23113498266Sopenharmony_ci "--username", username, 23213498266Sopenharmony_ci "--domain", domain, 23313498266Sopenharmony_ci NULL); 23413498266Sopenharmony_ci else 23513498266Sopenharmony_ci execl(ntlm_auth, ntlm_auth, 23613498266Sopenharmony_ci "--helper-protocol", "ntlmssp-client-1", 23713498266Sopenharmony_ci "--use-cached-creds", 23813498266Sopenharmony_ci "--username", username, 23913498266Sopenharmony_ci NULL); 24013498266Sopenharmony_ci 24113498266Sopenharmony_ci sclose_nolog(sockfds[1]); 24213498266Sopenharmony_ci failf(data, "Could not execl(). errno %d: %s", 24313498266Sopenharmony_ci errno, Curl_strerror(errno, buffer, sizeof(buffer))); 24413498266Sopenharmony_ci exit(1); 24513498266Sopenharmony_ci } 24613498266Sopenharmony_ci 24713498266Sopenharmony_ci sclose(sockfds[1]); 24813498266Sopenharmony_ci ntlm->ntlm_auth_hlpr_socket = sockfds[0]; 24913498266Sopenharmony_ci ntlm->ntlm_auth_hlpr_pid = child_pid; 25013498266Sopenharmony_ci free(domain); 25113498266Sopenharmony_ci free(ntlm_auth_alloc); 25213498266Sopenharmony_ci return CURLE_OK; 25313498266Sopenharmony_ci 25413498266Sopenharmony_cidone: 25513498266Sopenharmony_ci free(domain); 25613498266Sopenharmony_ci free(ntlm_auth_alloc); 25713498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 25813498266Sopenharmony_ci} 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci/* if larger than this, something is seriously wrong */ 26113498266Sopenharmony_ci#define MAX_NTLM_WB_RESPONSE 100000 26213498266Sopenharmony_ci 26313498266Sopenharmony_cistatic CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, 26413498266Sopenharmony_ci const char *input, curlntlm state) 26513498266Sopenharmony_ci{ 26613498266Sopenharmony_ci size_t len_in = strlen(input), len_out = 0; 26713498266Sopenharmony_ci struct dynbuf b; 26813498266Sopenharmony_ci char *ptr = NULL; 26913498266Sopenharmony_ci unsigned char buf[1024]; 27013498266Sopenharmony_ci Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE); 27113498266Sopenharmony_ci 27213498266Sopenharmony_ci while(len_in > 0) { 27313498266Sopenharmony_ci ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in); 27413498266Sopenharmony_ci if(written == -1) { 27513498266Sopenharmony_ci /* Interrupted by a signal, retry it */ 27613498266Sopenharmony_ci if(errno == EINTR) 27713498266Sopenharmony_ci continue; 27813498266Sopenharmony_ci /* write failed if other errors happen */ 27913498266Sopenharmony_ci goto done; 28013498266Sopenharmony_ci } 28113498266Sopenharmony_ci input += written; 28213498266Sopenharmony_ci len_in -= written; 28313498266Sopenharmony_ci } 28413498266Sopenharmony_ci /* Read one line */ 28513498266Sopenharmony_ci while(1) { 28613498266Sopenharmony_ci ssize_t size = 28713498266Sopenharmony_ci wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf)); 28813498266Sopenharmony_ci if(size == -1) { 28913498266Sopenharmony_ci if(errno == EINTR) 29013498266Sopenharmony_ci continue; 29113498266Sopenharmony_ci goto done; 29213498266Sopenharmony_ci } 29313498266Sopenharmony_ci else if(size == 0) 29413498266Sopenharmony_ci goto done; 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci if(Curl_dyn_addn(&b, buf, size)) 29713498266Sopenharmony_ci goto done; 29813498266Sopenharmony_ci 29913498266Sopenharmony_ci len_out = Curl_dyn_len(&b); 30013498266Sopenharmony_ci ptr = Curl_dyn_ptr(&b); 30113498266Sopenharmony_ci if(len_out && ptr[len_out - 1] == '\n') { 30213498266Sopenharmony_ci ptr[len_out - 1] = '\0'; 30313498266Sopenharmony_ci break; /* done! */ 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci /* loop */ 30613498266Sopenharmony_ci } 30713498266Sopenharmony_ci 30813498266Sopenharmony_ci /* Samba/winbind installed but not configured */ 30913498266Sopenharmony_ci if(state == NTLMSTATE_TYPE1 && 31013498266Sopenharmony_ci len_out == 3 && 31113498266Sopenharmony_ci ptr[0] == 'P' && ptr[1] == 'W') 31213498266Sopenharmony_ci goto done; 31313498266Sopenharmony_ci /* invalid response */ 31413498266Sopenharmony_ci if(len_out < 4) 31513498266Sopenharmony_ci goto done; 31613498266Sopenharmony_ci if(state == NTLMSTATE_TYPE1 && 31713498266Sopenharmony_ci (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' ')) 31813498266Sopenharmony_ci goto done; 31913498266Sopenharmony_ci if(state == NTLMSTATE_TYPE2 && 32013498266Sopenharmony_ci (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') && 32113498266Sopenharmony_ci (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' ')) 32213498266Sopenharmony_ci goto done; 32313498266Sopenharmony_ci 32413498266Sopenharmony_ci ntlm->response = strdup(ptr + 3); 32513498266Sopenharmony_ci Curl_dyn_free(&b); 32613498266Sopenharmony_ci if(!ntlm->response) 32713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 32813498266Sopenharmony_ci return CURLE_OK; 32913498266Sopenharmony_cidone: 33013498266Sopenharmony_ci Curl_dyn_free(&b); 33113498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 33213498266Sopenharmony_ci} 33313498266Sopenharmony_ci 33413498266Sopenharmony_ciCURLcode Curl_input_ntlm_wb(struct Curl_easy *data, 33513498266Sopenharmony_ci struct connectdata *conn, 33613498266Sopenharmony_ci bool proxy, 33713498266Sopenharmony_ci const char *header) 33813498266Sopenharmony_ci{ 33913498266Sopenharmony_ci struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; 34013498266Sopenharmony_ci curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; 34113498266Sopenharmony_ci 34213498266Sopenharmony_ci (void) data; /* In case it gets unused by nop log macros. */ 34313498266Sopenharmony_ci 34413498266Sopenharmony_ci if(!checkprefix("NTLM", header)) 34513498266Sopenharmony_ci return CURLE_BAD_CONTENT_ENCODING; 34613498266Sopenharmony_ci 34713498266Sopenharmony_ci header += strlen("NTLM"); 34813498266Sopenharmony_ci while(*header && ISSPACE(*header)) 34913498266Sopenharmony_ci header++; 35013498266Sopenharmony_ci 35113498266Sopenharmony_ci if(*header) { 35213498266Sopenharmony_ci ntlm->challenge = strdup(header); 35313498266Sopenharmony_ci if(!ntlm->challenge) 35413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 35513498266Sopenharmony_ci 35613498266Sopenharmony_ci *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ 35713498266Sopenharmony_ci } 35813498266Sopenharmony_ci else { 35913498266Sopenharmony_ci if(*state == NTLMSTATE_LAST) { 36013498266Sopenharmony_ci infof(data, "NTLM auth restarted"); 36113498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm_wb(conn); 36213498266Sopenharmony_ci } 36313498266Sopenharmony_ci else if(*state == NTLMSTATE_TYPE3) { 36413498266Sopenharmony_ci infof(data, "NTLM handshake rejected"); 36513498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm_wb(conn); 36613498266Sopenharmony_ci *state = NTLMSTATE_NONE; 36713498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 36813498266Sopenharmony_ci } 36913498266Sopenharmony_ci else if(*state >= NTLMSTATE_TYPE1) { 37013498266Sopenharmony_ci infof(data, "NTLM handshake failure (internal error)"); 37113498266Sopenharmony_ci return CURLE_REMOTE_ACCESS_DENIED; 37213498266Sopenharmony_ci } 37313498266Sopenharmony_ci 37413498266Sopenharmony_ci *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ 37513498266Sopenharmony_ci } 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci return CURLE_OK; 37813498266Sopenharmony_ci} 37913498266Sopenharmony_ci 38013498266Sopenharmony_ci/* 38113498266Sopenharmony_ci * This is for creating ntlm header output by delegating challenge/response 38213498266Sopenharmony_ci * to Samba's winbind daemon helper ntlm_auth. 38313498266Sopenharmony_ci */ 38413498266Sopenharmony_ciCURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn, 38513498266Sopenharmony_ci bool proxy) 38613498266Sopenharmony_ci{ 38713498266Sopenharmony_ci /* point to the address of the pointer that holds the string to send to the 38813498266Sopenharmony_ci server, which is for a plain host or for an HTTP proxy */ 38913498266Sopenharmony_ci char **allocuserpwd; 39013498266Sopenharmony_ci /* point to the name and password for this */ 39113498266Sopenharmony_ci const char *userp; 39213498266Sopenharmony_ci struct ntlmdata *ntlm; 39313498266Sopenharmony_ci curlntlm *state; 39413498266Sopenharmony_ci struct auth *authp; 39513498266Sopenharmony_ci 39613498266Sopenharmony_ci CURLcode res = CURLE_OK; 39713498266Sopenharmony_ci 39813498266Sopenharmony_ci DEBUGASSERT(conn); 39913498266Sopenharmony_ci DEBUGASSERT(data); 40013498266Sopenharmony_ci 40113498266Sopenharmony_ci if(proxy) { 40213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 40313498266Sopenharmony_ci allocuserpwd = &data->state.aptr.proxyuserpwd; 40413498266Sopenharmony_ci userp = conn->http_proxy.user; 40513498266Sopenharmony_ci ntlm = &conn->proxyntlm; 40613498266Sopenharmony_ci state = &conn->proxy_ntlm_state; 40713498266Sopenharmony_ci authp = &data->state.authproxy; 40813498266Sopenharmony_ci#else 40913498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 41013498266Sopenharmony_ci#endif 41113498266Sopenharmony_ci } 41213498266Sopenharmony_ci else { 41313498266Sopenharmony_ci allocuserpwd = &data->state.aptr.userpwd; 41413498266Sopenharmony_ci userp = conn->user; 41513498266Sopenharmony_ci ntlm = &conn->ntlm; 41613498266Sopenharmony_ci state = &conn->http_ntlm_state; 41713498266Sopenharmony_ci authp = &data->state.authhost; 41813498266Sopenharmony_ci } 41913498266Sopenharmony_ci authp->done = FALSE; 42013498266Sopenharmony_ci 42113498266Sopenharmony_ci /* not set means empty */ 42213498266Sopenharmony_ci if(!userp) 42313498266Sopenharmony_ci userp = ""; 42413498266Sopenharmony_ci 42513498266Sopenharmony_ci switch(*state) { 42613498266Sopenharmony_ci case NTLMSTATE_TYPE1: 42713498266Sopenharmony_ci default: 42813498266Sopenharmony_ci /* Use Samba's 'winbind' daemon to support NTLM authentication, 42913498266Sopenharmony_ci * by delegating the NTLM challenge/response protocol to a helper 43013498266Sopenharmony_ci * in ntlm_auth. 43113498266Sopenharmony_ci * https://web.archive.org/web/20190925164737 43213498266Sopenharmony_ci * /devel.squid-cache.org/ntlm/squid_helper_protocol.html 43313498266Sopenharmony_ci * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html 43413498266Sopenharmony_ci * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html 43513498266Sopenharmony_ci * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this 43613498266Sopenharmony_ci * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute 43713498266Sopenharmony_ci * filename of ntlm_auth helper. 43813498266Sopenharmony_ci * If NTLM authentication using winbind fails, go back to original 43913498266Sopenharmony_ci * request handling process. 44013498266Sopenharmony_ci */ 44113498266Sopenharmony_ci /* Create communication with ntlm_auth */ 44213498266Sopenharmony_ci res = ntlm_wb_init(data, ntlm, userp); 44313498266Sopenharmony_ci if(res) 44413498266Sopenharmony_ci return res; 44513498266Sopenharmony_ci res = ntlm_wb_response(data, ntlm, "YR\n", *state); 44613498266Sopenharmony_ci if(res) 44713498266Sopenharmony_ci return res; 44813498266Sopenharmony_ci 44913498266Sopenharmony_ci free(*allocuserpwd); 45013498266Sopenharmony_ci *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 45113498266Sopenharmony_ci proxy ? "Proxy-" : "", 45213498266Sopenharmony_ci ntlm->response); 45313498266Sopenharmony_ci DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); 45413498266Sopenharmony_ci Curl_safefree(ntlm->response); 45513498266Sopenharmony_ci if(!*allocuserpwd) 45613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 45713498266Sopenharmony_ci break; 45813498266Sopenharmony_ci 45913498266Sopenharmony_ci case NTLMSTATE_TYPE2: { 46013498266Sopenharmony_ci char *input = aprintf("TT %s\n", ntlm->challenge); 46113498266Sopenharmony_ci if(!input) 46213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 46313498266Sopenharmony_ci res = ntlm_wb_response(data, ntlm, input, *state); 46413498266Sopenharmony_ci free(input); 46513498266Sopenharmony_ci if(res) 46613498266Sopenharmony_ci return res; 46713498266Sopenharmony_ci 46813498266Sopenharmony_ci free(*allocuserpwd); 46913498266Sopenharmony_ci *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", 47013498266Sopenharmony_ci proxy ? "Proxy-" : "", 47113498266Sopenharmony_ci ntlm->response); 47213498266Sopenharmony_ci DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); 47313498266Sopenharmony_ci *state = NTLMSTATE_TYPE3; /* we sent a type-3 */ 47413498266Sopenharmony_ci authp->done = TRUE; 47513498266Sopenharmony_ci Curl_http_auth_cleanup_ntlm_wb(conn); 47613498266Sopenharmony_ci if(!*allocuserpwd) 47713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 47813498266Sopenharmony_ci break; 47913498266Sopenharmony_ci } 48013498266Sopenharmony_ci case NTLMSTATE_TYPE3: 48113498266Sopenharmony_ci /* connection is already authenticated, 48213498266Sopenharmony_ci * don't send a header in future requests */ 48313498266Sopenharmony_ci *state = NTLMSTATE_LAST; 48413498266Sopenharmony_ci FALLTHROUGH(); 48513498266Sopenharmony_ci case NTLMSTATE_LAST: 48613498266Sopenharmony_ci Curl_safefree(*allocuserpwd); 48713498266Sopenharmony_ci authp->done = TRUE; 48813498266Sopenharmony_ci break; 48913498266Sopenharmony_ci } 49013498266Sopenharmony_ci 49113498266Sopenharmony_ci return CURLE_OK; 49213498266Sopenharmony_ci} 49313498266Sopenharmony_ci 49413498266Sopenharmony_civoid Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) 49513498266Sopenharmony_ci{ 49613498266Sopenharmony_ci ntlm_wb_cleanup(&conn->ntlm); 49713498266Sopenharmony_ci ntlm_wb_cleanup(&conn->proxyntlm); 49813498266Sopenharmony_ci} 49913498266Sopenharmony_ci 50013498266Sopenharmony_ci#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ 501