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