1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) 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 http://curl.haxx.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 ***************************************************************************/ 22 23 #include "curl_setup.h" 24 25 #ifdef HAVE_PWD_H 26 #include <pwd.h> 27 #endif 28 29 #include <curl/curl.h> 30 #include "netrc.h" 31 32 #include "strequal.h" 33 #include "strtok.h" 34 #include "rawstr.h" 35 #include "curl_printf.h" 36 37 /* The last #include files should be: */ 38 #include "curl_memory.h" 39 #include "memdebug.h" 40 41 /* Get user and password from .netrc when given a machine name */ 42 43 enum host_lookup_state { 44 NOTHING, 45 HOSTFOUND, /* the 'machine' keyword was found */ 46 HOSTVALID /* this is "our" machine! */ 47 }; 48 49 /* 50 * @unittest: 1304 51 * 52 * *loginp and *passwordp MUST be allocated if they aren't NULL when passed 53 * in. 54 */ 55 int Curl_parsenetrc(const char *host, 56 char **loginp, 57 char **passwordp, 58 char *netrcfile) 59 { 60 FILE *file; 61 int retcode=1; 62 int specific_login = (*loginp && **loginp != 0); 63 bool netrc_alloc = FALSE; 64 enum host_lookup_state state=NOTHING; 65 66 char state_login=0; /* Found a login keyword */ 67 char state_password=0; /* Found a password keyword */ 68 int state_our_login=FALSE; /* With specific_login, found *our* login name */ 69 70 #define NETRC DOT_CHAR "netrc" 71 72 if(!netrcfile) { 73 bool home_alloc = FALSE; 74 char *home = curl_getenv("HOME"); /* portable environment reader */ 75 if(home) { 76 home_alloc = TRUE; 77 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) 78 } 79 else { 80 struct passwd pw, *pw_res; 81 char pwbuf[1024]; 82 if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) 83 && pw_res) { 84 home = strdup(pw.pw_dir); 85 if(!home) 86 return CURLE_OUT_OF_MEMORY; 87 home_alloc = TRUE; 88 } 89 #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) 90 } 91 else { 92 struct passwd *pw; 93 pw= getpwuid(geteuid()); 94 if(pw) { 95 home = pw->pw_dir; 96 } 97 #endif 98 } 99 100 if(!home) 101 return retcode; /* no home directory found (or possibly out of memory) */ 102 103 netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); 104 if(home_alloc) 105 free(home); 106 if(!netrcfile) { 107 return -1; 108 } 109 netrc_alloc = TRUE; 110 } 111 112 file = fopen(netrcfile, FOPEN_READTEXT); 113 if(netrc_alloc) 114 free(netrcfile); 115 if(file) { 116 char *tok; 117 char *tok_buf; 118 bool done=FALSE; 119 char netrcbuffer[256]; 120 int netrcbuffsize = (int)sizeof(netrcbuffer); 121 122 while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { 123 tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); 124 while(!done && tok) { 125 126 if((*loginp && **loginp) && (*passwordp && **passwordp)) { 127 done=TRUE; 128 break; 129 } 130 131 switch(state) { 132 case NOTHING: 133 if(Curl_raw_equal("machine", tok)) { 134 /* the next tok is the machine name, this is in itself the 135 delimiter that starts the stuff entered for this machine, 136 after this we need to search for 'login' and 137 'password'. */ 138 state=HOSTFOUND; 139 } 140 else if(Curl_raw_equal("default", tok)) { 141 state=HOSTVALID; 142 retcode=0; /* we did find our host */ 143 } 144 break; 145 case HOSTFOUND: 146 if(Curl_raw_equal(host, tok)) { 147 /* and yes, this is our host! */ 148 state=HOSTVALID; 149 retcode=0; /* we did find our host */ 150 } 151 else 152 /* not our host */ 153 state=NOTHING; 154 break; 155 case HOSTVALID: 156 /* we are now parsing sub-keywords concerning "our" host */ 157 if(state_login) { 158 if(specific_login) { 159 state_our_login = Curl_raw_equal(*loginp, tok); 160 } 161 else { 162 free(*loginp); 163 *loginp = strdup(tok); 164 if(!*loginp) { 165 retcode = -1; /* allocation failed */ 166 goto out; 167 } 168 } 169 state_login=0; 170 } 171 else if(state_password) { 172 if(state_our_login || !specific_login) { 173 free(*passwordp); 174 *passwordp = strdup(tok); 175 if(!*passwordp) { 176 retcode = -1; /* allocation failed */ 177 goto out; 178 } 179 } 180 state_password=0; 181 } 182 else if(Curl_raw_equal("login", tok)) 183 state_login=1; 184 else if(Curl_raw_equal("password", tok)) 185 state_password=1; 186 else if(Curl_raw_equal("machine", tok)) { 187 /* ok, there's machine here go => */ 188 state = HOSTFOUND; 189 state_our_login = FALSE; 190 } 191 break; 192 } /* switch (state) */ 193 194 tok = strtok_r(NULL, " \t\n", &tok_buf); 195 } /* while(tok) */ 196 } /* while fgets() */ 197 198 out: 199 fclose(file); 200 } 201 202 return retcode; 203 } 204