Imported Upstream version 7.53.1
[platform/upstream/curl.git] / lib / netrc.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, 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  */
53 int Curl_parsenetrc(const char *host,
54                     char **loginp,
55                     char **passwordp,
56                     char *netrcfile)
57 {
58   FILE *file;
59   int retcode=1;
60   int specific_login = (*loginp && **loginp != 0);
61   bool netrc_alloc = FALSE;
62   enum host_lookup_state state=NOTHING;
63
64   char state_login=0;      /* Found a login keyword */
65   char state_password=0;   /* Found a password keyword */
66   int state_our_login=FALSE;  /* With specific_login, found *our* login name */
67
68 #define NETRC DOT_CHAR "netrc"
69
70   if(!netrcfile) {
71     bool home_alloc = FALSE;
72     char *home = curl_getenv("HOME"); /* portable environment reader */
73     if(home) {
74       home_alloc = TRUE;
75 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
76     }
77     else {
78       struct passwd pw, *pw_res;
79       char pwbuf[1024];
80       if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
81          && pw_res) {
82         home = strdup(pw.pw_dir);
83         if(!home)
84           return CURLE_OUT_OF_MEMORY;
85         home_alloc = TRUE;
86       }
87 #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
88     }
89     else {
90       struct passwd *pw;
91       pw= getpwuid(geteuid());
92       if(pw) {
93         home = pw->pw_dir;
94       }
95 #endif
96     }
97
98     if(!home)
99       return retcode; /* no home directory found (or possibly out of memory) */
100
101     netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
102     if(home_alloc)
103       free(home);
104     if(!netrcfile) {
105       return -1;
106     }
107     netrc_alloc = TRUE;
108   }
109
110   file = fopen(netrcfile, FOPEN_READTEXT);
111   if(netrc_alloc)
112     free(netrcfile);
113   if(file) {
114     char *tok;
115     char *tok_buf;
116     bool done=FALSE;
117     char netrcbuffer[256];
118     int  netrcbuffsize = (int)sizeof(netrcbuffer);
119
120     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
121       tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
122       while(!done && tok) {
123
124         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
125           done=TRUE;
126           break;
127         }
128
129         switch(state) {
130         case NOTHING:
131           if(strcasecompare("machine", tok)) {
132             /* the next tok is the machine name, this is in itself the
133                delimiter that starts the stuff entered for this machine,
134                after this we need to search for 'login' and
135                'password'. */
136             state=HOSTFOUND;
137           }
138           else if(strcasecompare("default", tok)) {
139             state=HOSTVALID;
140             retcode=0; /* we did find our host */
141           }
142           break;
143         case HOSTFOUND:
144           if(strcasecompare(host, tok)) {
145             /* and yes, this is our host! */
146             state=HOSTVALID;
147             retcode=0; /* we did find our host */
148           }
149           else
150             /* not our host */
151             state=NOTHING;
152           break;
153         case HOSTVALID:
154           /* we are now parsing sub-keywords concerning "our" host */
155           if(state_login) {
156             if(specific_login) {
157               state_our_login = strcasecompare(*loginp, tok);
158             }
159             else {
160               free(*loginp);
161               *loginp = strdup(tok);
162               if(!*loginp) {
163                 retcode = -1; /* allocation failed */
164                 goto out;
165               }
166             }
167             state_login=0;
168           }
169           else if(state_password) {
170             if(state_our_login || !specific_login) {
171               free(*passwordp);
172               *passwordp = strdup(tok);
173               if(!*passwordp) {
174                 retcode = -1; /* allocation failed */
175                 goto out;
176               }
177             }
178             state_password=0;
179           }
180           else if(strcasecompare("login", tok))
181             state_login=1;
182           else if(strcasecompare("password", tok))
183             state_password=1;
184           else if(strcasecompare("machine", tok)) {
185             /* ok, there's machine here go => */
186             state = HOSTFOUND;
187             state_our_login = FALSE;
188           }
189           break;
190         } /* switch (state) */
191
192         tok = strtok_r(NULL, " \t\n", &tok_buf);
193       } /* while(tok) */
194     } /* while fgets() */
195
196     out:
197     fclose(file);
198   }
199
200   return retcode;
201 }