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#ifndef CURL_DISABLE_NETRC 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#ifdef HAVE_PWD_H 2913498266Sopenharmony_ci#include <pwd.h> 3013498266Sopenharmony_ci#endif 3113498266Sopenharmony_ci 3213498266Sopenharmony_ci#include <curl/curl.h> 3313498266Sopenharmony_ci#include "netrc.h" 3413498266Sopenharmony_ci#include "strtok.h" 3513498266Sopenharmony_ci#include "strcase.h" 3613498266Sopenharmony_ci#include "curl_get_line.h" 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 3913498266Sopenharmony_ci#include "curl_printf.h" 4013498266Sopenharmony_ci#include "curl_memory.h" 4113498266Sopenharmony_ci#include "memdebug.h" 4213498266Sopenharmony_ci 4313498266Sopenharmony_ci/* Get user and password from .netrc when given a machine name */ 4413498266Sopenharmony_ci 4513498266Sopenharmony_cienum host_lookup_state { 4613498266Sopenharmony_ci NOTHING, 4713498266Sopenharmony_ci HOSTFOUND, /* the 'machine' keyword was found */ 4813498266Sopenharmony_ci HOSTVALID, /* this is "our" machine! */ 4913498266Sopenharmony_ci MACDEF 5013498266Sopenharmony_ci}; 5113498266Sopenharmony_ci 5213498266Sopenharmony_ci#define NETRC_FILE_MISSING 1 5313498266Sopenharmony_ci#define NETRC_FAILED -1 5413498266Sopenharmony_ci#define NETRC_SUCCESS 0 5513498266Sopenharmony_ci 5613498266Sopenharmony_ci/* 5713498266Sopenharmony_ci * Returns zero on success. 5813498266Sopenharmony_ci */ 5913498266Sopenharmony_cistatic int parsenetrc(const char *host, 6013498266Sopenharmony_ci char **loginp, 6113498266Sopenharmony_ci char **passwordp, 6213498266Sopenharmony_ci char *netrcfile) 6313498266Sopenharmony_ci{ 6413498266Sopenharmony_ci FILE *file; 6513498266Sopenharmony_ci int retcode = NETRC_FILE_MISSING; 6613498266Sopenharmony_ci char *login = *loginp; 6713498266Sopenharmony_ci char *password = *passwordp; 6813498266Sopenharmony_ci bool specific_login = (login && *login != 0); 6913498266Sopenharmony_ci bool login_alloc = FALSE; 7013498266Sopenharmony_ci bool password_alloc = FALSE; 7113498266Sopenharmony_ci enum host_lookup_state state = NOTHING; 7213498266Sopenharmony_ci 7313498266Sopenharmony_ci char state_login = 0; /* Found a login keyword */ 7413498266Sopenharmony_ci char state_password = 0; /* Found a password keyword */ 7513498266Sopenharmony_ci int state_our_login = TRUE; /* With specific_login, found *our* login 7613498266Sopenharmony_ci name (or login-less line) */ 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci DEBUGASSERT(netrcfile); 7913498266Sopenharmony_ci 8013498266Sopenharmony_ci file = fopen(netrcfile, FOPEN_READTEXT); 8113498266Sopenharmony_ci if(file) { 8213498266Sopenharmony_ci bool done = FALSE; 8313498266Sopenharmony_ci char netrcbuffer[4096]; 8413498266Sopenharmony_ci int netrcbuffsize = (int)sizeof(netrcbuffer); 8513498266Sopenharmony_ci 8613498266Sopenharmony_ci while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) { 8713498266Sopenharmony_ci char *tok; 8813498266Sopenharmony_ci char *tok_end; 8913498266Sopenharmony_ci bool quoted; 9013498266Sopenharmony_ci if(state == MACDEF) { 9113498266Sopenharmony_ci if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r')) 9213498266Sopenharmony_ci state = NOTHING; 9313498266Sopenharmony_ci else 9413498266Sopenharmony_ci continue; 9513498266Sopenharmony_ci } 9613498266Sopenharmony_ci tok = netrcbuffer; 9713498266Sopenharmony_ci while(tok) { 9813498266Sopenharmony_ci while(ISBLANK(*tok)) 9913498266Sopenharmony_ci tok++; 10013498266Sopenharmony_ci /* tok is first non-space letter */ 10113498266Sopenharmony_ci if(!*tok || (*tok == '#')) 10213498266Sopenharmony_ci /* end of line or the rest is a comment */ 10313498266Sopenharmony_ci break; 10413498266Sopenharmony_ci 10513498266Sopenharmony_ci /* leading double-quote means quoted string */ 10613498266Sopenharmony_ci quoted = (*tok == '\"'); 10713498266Sopenharmony_ci 10813498266Sopenharmony_ci tok_end = tok; 10913498266Sopenharmony_ci if(!quoted) { 11013498266Sopenharmony_ci while(!ISSPACE(*tok_end)) 11113498266Sopenharmony_ci tok_end++; 11213498266Sopenharmony_ci *tok_end = 0; 11313498266Sopenharmony_ci } 11413498266Sopenharmony_ci else { 11513498266Sopenharmony_ci bool escape = FALSE; 11613498266Sopenharmony_ci bool endquote = FALSE; 11713498266Sopenharmony_ci char *store = tok; 11813498266Sopenharmony_ci tok_end++; /* pass the leading quote */ 11913498266Sopenharmony_ci while(*tok_end) { 12013498266Sopenharmony_ci char s = *tok_end; 12113498266Sopenharmony_ci if(escape) { 12213498266Sopenharmony_ci escape = FALSE; 12313498266Sopenharmony_ci switch(s) { 12413498266Sopenharmony_ci case 'n': 12513498266Sopenharmony_ci s = '\n'; 12613498266Sopenharmony_ci break; 12713498266Sopenharmony_ci case 'r': 12813498266Sopenharmony_ci s = '\r'; 12913498266Sopenharmony_ci break; 13013498266Sopenharmony_ci case 't': 13113498266Sopenharmony_ci s = '\t'; 13213498266Sopenharmony_ci break; 13313498266Sopenharmony_ci } 13413498266Sopenharmony_ci } 13513498266Sopenharmony_ci else if(s == '\\') { 13613498266Sopenharmony_ci escape = TRUE; 13713498266Sopenharmony_ci tok_end++; 13813498266Sopenharmony_ci continue; 13913498266Sopenharmony_ci } 14013498266Sopenharmony_ci else if(s == '\"') { 14113498266Sopenharmony_ci tok_end++; /* pass the ending quote */ 14213498266Sopenharmony_ci endquote = TRUE; 14313498266Sopenharmony_ci break; 14413498266Sopenharmony_ci } 14513498266Sopenharmony_ci *store++ = s; 14613498266Sopenharmony_ci tok_end++; 14713498266Sopenharmony_ci } 14813498266Sopenharmony_ci *store = 0; 14913498266Sopenharmony_ci if(escape || !endquote) { 15013498266Sopenharmony_ci /* bad syntax, get out */ 15113498266Sopenharmony_ci retcode = NETRC_FAILED; 15213498266Sopenharmony_ci goto out; 15313498266Sopenharmony_ci } 15413498266Sopenharmony_ci } 15513498266Sopenharmony_ci 15613498266Sopenharmony_ci if((login && *login) && (password && *password)) { 15713498266Sopenharmony_ci done = TRUE; 15813498266Sopenharmony_ci break; 15913498266Sopenharmony_ci } 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci switch(state) { 16213498266Sopenharmony_ci case NOTHING: 16313498266Sopenharmony_ci if(strcasecompare("macdef", tok)) { 16413498266Sopenharmony_ci /* Define a macro. A macro is defined with the specified name; its 16513498266Sopenharmony_ci contents begin with the next .netrc line and continue until a 16613498266Sopenharmony_ci null line (consecutive new-line characters) is encountered. */ 16713498266Sopenharmony_ci state = MACDEF; 16813498266Sopenharmony_ci } 16913498266Sopenharmony_ci else if(strcasecompare("machine", tok)) { 17013498266Sopenharmony_ci /* the next tok is the machine name, this is in itself the 17113498266Sopenharmony_ci delimiter that starts the stuff entered for this machine, 17213498266Sopenharmony_ci after this we need to search for 'login' and 17313498266Sopenharmony_ci 'password'. */ 17413498266Sopenharmony_ci state = HOSTFOUND; 17513498266Sopenharmony_ci } 17613498266Sopenharmony_ci else if(strcasecompare("default", tok)) { 17713498266Sopenharmony_ci state = HOSTVALID; 17813498266Sopenharmony_ci retcode = NETRC_SUCCESS; /* we did find our host */ 17913498266Sopenharmony_ci } 18013498266Sopenharmony_ci break; 18113498266Sopenharmony_ci case MACDEF: 18213498266Sopenharmony_ci if(!strlen(tok)) { 18313498266Sopenharmony_ci state = NOTHING; 18413498266Sopenharmony_ci } 18513498266Sopenharmony_ci break; 18613498266Sopenharmony_ci case HOSTFOUND: 18713498266Sopenharmony_ci if(strcasecompare(host, tok)) { 18813498266Sopenharmony_ci /* and yes, this is our host! */ 18913498266Sopenharmony_ci state = HOSTVALID; 19013498266Sopenharmony_ci retcode = NETRC_SUCCESS; /* we did find our host */ 19113498266Sopenharmony_ci } 19213498266Sopenharmony_ci else 19313498266Sopenharmony_ci /* not our host */ 19413498266Sopenharmony_ci state = NOTHING; 19513498266Sopenharmony_ci break; 19613498266Sopenharmony_ci case HOSTVALID: 19713498266Sopenharmony_ci /* we are now parsing sub-keywords concerning "our" host */ 19813498266Sopenharmony_ci if(state_login) { 19913498266Sopenharmony_ci if(specific_login) { 20013498266Sopenharmony_ci state_our_login = !Curl_timestrcmp(login, tok); 20113498266Sopenharmony_ci } 20213498266Sopenharmony_ci else if(!login || Curl_timestrcmp(login, tok)) { 20313498266Sopenharmony_ci if(login_alloc) { 20413498266Sopenharmony_ci free(login); 20513498266Sopenharmony_ci login_alloc = FALSE; 20613498266Sopenharmony_ci } 20713498266Sopenharmony_ci login = strdup(tok); 20813498266Sopenharmony_ci if(!login) { 20913498266Sopenharmony_ci retcode = NETRC_FAILED; /* allocation failed */ 21013498266Sopenharmony_ci goto out; 21113498266Sopenharmony_ci } 21213498266Sopenharmony_ci login_alloc = TRUE; 21313498266Sopenharmony_ci } 21413498266Sopenharmony_ci state_login = 0; 21513498266Sopenharmony_ci } 21613498266Sopenharmony_ci else if(state_password) { 21713498266Sopenharmony_ci if((state_our_login || !specific_login) 21813498266Sopenharmony_ci && (!password || Curl_timestrcmp(password, tok))) { 21913498266Sopenharmony_ci if(password_alloc) { 22013498266Sopenharmony_ci free(password); 22113498266Sopenharmony_ci password_alloc = FALSE; 22213498266Sopenharmony_ci } 22313498266Sopenharmony_ci password = strdup(tok); 22413498266Sopenharmony_ci if(!password) { 22513498266Sopenharmony_ci retcode = NETRC_FAILED; /* allocation failed */ 22613498266Sopenharmony_ci goto out; 22713498266Sopenharmony_ci } 22813498266Sopenharmony_ci password_alloc = TRUE; 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci state_password = 0; 23113498266Sopenharmony_ci } 23213498266Sopenharmony_ci else if(strcasecompare("login", tok)) 23313498266Sopenharmony_ci state_login = 1; 23413498266Sopenharmony_ci else if(strcasecompare("password", tok)) 23513498266Sopenharmony_ci state_password = 1; 23613498266Sopenharmony_ci else if(strcasecompare("machine", tok)) { 23713498266Sopenharmony_ci /* ok, there's machine here go => */ 23813498266Sopenharmony_ci state = HOSTFOUND; 23913498266Sopenharmony_ci state_our_login = FALSE; 24013498266Sopenharmony_ci } 24113498266Sopenharmony_ci break; 24213498266Sopenharmony_ci } /* switch (state) */ 24313498266Sopenharmony_ci tok = ++tok_end; 24413498266Sopenharmony_ci } 24513498266Sopenharmony_ci } /* while Curl_get_line() */ 24613498266Sopenharmony_ci 24713498266Sopenharmony_ciout: 24813498266Sopenharmony_ci if(!retcode) { 24913498266Sopenharmony_ci /* success */ 25013498266Sopenharmony_ci if(login_alloc) { 25113498266Sopenharmony_ci if(*loginp) 25213498266Sopenharmony_ci free(*loginp); 25313498266Sopenharmony_ci *loginp = login; 25413498266Sopenharmony_ci } 25513498266Sopenharmony_ci if(password_alloc) { 25613498266Sopenharmony_ci if(*passwordp) 25713498266Sopenharmony_ci free(*passwordp); 25813498266Sopenharmony_ci *passwordp = password; 25913498266Sopenharmony_ci } 26013498266Sopenharmony_ci } 26113498266Sopenharmony_ci else { 26213498266Sopenharmony_ci if(login_alloc) 26313498266Sopenharmony_ci free(login); 26413498266Sopenharmony_ci if(password_alloc) 26513498266Sopenharmony_ci free(password); 26613498266Sopenharmony_ci } 26713498266Sopenharmony_ci fclose(file); 26813498266Sopenharmony_ci } 26913498266Sopenharmony_ci 27013498266Sopenharmony_ci return retcode; 27113498266Sopenharmony_ci} 27213498266Sopenharmony_ci 27313498266Sopenharmony_ci/* 27413498266Sopenharmony_ci * @unittest: 1304 27513498266Sopenharmony_ci * 27613498266Sopenharmony_ci * *loginp and *passwordp MUST be allocated if they aren't NULL when passed 27713498266Sopenharmony_ci * in. 27813498266Sopenharmony_ci */ 27913498266Sopenharmony_ciint Curl_parsenetrc(const char *host, char **loginp, char **passwordp, 28013498266Sopenharmony_ci char *netrcfile) 28113498266Sopenharmony_ci{ 28213498266Sopenharmony_ci int retcode = 1; 28313498266Sopenharmony_ci char *filealloc = NULL; 28413498266Sopenharmony_ci 28513498266Sopenharmony_ci if(!netrcfile) { 28613498266Sopenharmony_ci#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) 28713498266Sopenharmony_ci char pwbuf[1024]; 28813498266Sopenharmony_ci#endif 28913498266Sopenharmony_ci char *home = NULL; 29013498266Sopenharmony_ci char *homea = curl_getenv("HOME"); /* portable environment reader */ 29113498266Sopenharmony_ci if(homea) { 29213498266Sopenharmony_ci home = homea; 29313498266Sopenharmony_ci#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) 29413498266Sopenharmony_ci } 29513498266Sopenharmony_ci else { 29613498266Sopenharmony_ci struct passwd pw, *pw_res; 29713498266Sopenharmony_ci if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) 29813498266Sopenharmony_ci && pw_res) { 29913498266Sopenharmony_ci home = pw.pw_dir; 30013498266Sopenharmony_ci } 30113498266Sopenharmony_ci#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) 30213498266Sopenharmony_ci } 30313498266Sopenharmony_ci else { 30413498266Sopenharmony_ci struct passwd *pw; 30513498266Sopenharmony_ci pw = getpwuid(geteuid()); 30613498266Sopenharmony_ci if(pw) { 30713498266Sopenharmony_ci home = pw->pw_dir; 30813498266Sopenharmony_ci } 30913498266Sopenharmony_ci#elif defined(_WIN32) 31013498266Sopenharmony_ci } 31113498266Sopenharmony_ci else { 31213498266Sopenharmony_ci homea = curl_getenv("USERPROFILE"); 31313498266Sopenharmony_ci if(homea) { 31413498266Sopenharmony_ci home = homea; 31513498266Sopenharmony_ci } 31613498266Sopenharmony_ci#endif 31713498266Sopenharmony_ci } 31813498266Sopenharmony_ci 31913498266Sopenharmony_ci if(!home) 32013498266Sopenharmony_ci return retcode; /* no home directory found (or possibly out of 32113498266Sopenharmony_ci memory) */ 32213498266Sopenharmony_ci 32313498266Sopenharmony_ci filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR); 32413498266Sopenharmony_ci if(!filealloc) { 32513498266Sopenharmony_ci free(homea); 32613498266Sopenharmony_ci return -1; 32713498266Sopenharmony_ci } 32813498266Sopenharmony_ci retcode = parsenetrc(host, loginp, passwordp, filealloc); 32913498266Sopenharmony_ci free(filealloc); 33013498266Sopenharmony_ci#ifdef _WIN32 33113498266Sopenharmony_ci if(retcode == NETRC_FILE_MISSING) { 33213498266Sopenharmony_ci /* fallback to the old-style "_netrc" file */ 33313498266Sopenharmony_ci filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR); 33413498266Sopenharmony_ci if(!filealloc) { 33513498266Sopenharmony_ci free(homea); 33613498266Sopenharmony_ci return -1; 33713498266Sopenharmony_ci } 33813498266Sopenharmony_ci retcode = parsenetrc(host, loginp, passwordp, filealloc); 33913498266Sopenharmony_ci free(filealloc); 34013498266Sopenharmony_ci } 34113498266Sopenharmony_ci#endif 34213498266Sopenharmony_ci free(homea); 34313498266Sopenharmony_ci } 34413498266Sopenharmony_ci else 34513498266Sopenharmony_ci retcode = parsenetrc(host, loginp, passwordp, netrcfile); 34613498266Sopenharmony_ci return retcode; 34713498266Sopenharmony_ci} 34813498266Sopenharmony_ci 34913498266Sopenharmony_ci#endif 350