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