1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, 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 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 */
Curl_parsenetrc(const char * host,char ** loginp,char ** passwordp,char * netrcfile)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