• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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