Coverage Report

Created: 2022-10-16 06:45

/src/curl/lib/netrc.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 1998 - 2022, 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.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
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
#ifndef CURL_DISABLE_NETRC
27
28
#ifdef HAVE_PWD_H
29
#include <pwd.h>
30
#endif
31
32
#include <curl/curl.h>
33
#include "netrc.h"
34
#include "strtok.h"
35
#include "strcase.h"
36
37
/* The last 3 #include files should be in this order */
38
#include "curl_printf.h"
39
#include "curl_memory.h"
40
#include "memdebug.h"
41
42
/* Get user and password from .netrc when given a machine name */
43
44
enum host_lookup_state {
45
  NOTHING,
46
  HOSTFOUND,    /* the 'machine' keyword was found */
47
  HOSTVALID,    /* this is "our" machine! */
48
  MACDEF
49
};
50
51
0
#define NETRC_FILE_MISSING 1
52
0
#define NETRC_FAILED -1
53
0
#define NETRC_SUCCESS 0
54
55
/*
56
 * Returns zero on success.
57
 */
58
static int parsenetrc(const char *host,
59
                      char **loginp,
60
                      char **passwordp,
61
                      char *netrcfile)
62
0
{
63
0
  FILE *file;
64
0
  int retcode = NETRC_FILE_MISSING;
65
0
  char *login = *loginp;
66
0
  char *password = *passwordp;
67
0
  bool specific_login = (login && *login != 0);
68
0
  bool login_alloc = FALSE;
69
0
  bool password_alloc = FALSE;
70
0
  enum host_lookup_state state = NOTHING;
71
72
0
  char state_login = 0;      /* Found a login keyword */
73
0
  char state_password = 0;   /* Found a password keyword */
74
0
  int state_our_login = TRUE;  /* With specific_login, found *our* login
75
                                  name (or login-less line) */
76
77
0
  DEBUGASSERT(netrcfile);
78
79
0
  file = fopen(netrcfile, FOPEN_READTEXT);
80
0
  if(file) {
81
0
    bool done = FALSE;
82
0
    char netrcbuffer[4096];
83
0
    int  netrcbuffsize = (int)sizeof(netrcbuffer);
84
85
0
    while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
86
0
      char *tok;
87
0
      char *tok_end;
88
0
      bool quoted;
89
0
      if(state == MACDEF) {
90
0
        if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
91
0
          state = NOTHING;
92
0
        else
93
0
          continue;
94
0
      }
95
0
      tok = netrcbuffer;
96
0
      while(tok) {
97
0
        while(ISBLANK(*tok))
98
0
          tok++;
99
        /* tok is first non-space letter */
100
0
        if(!*tok || (*tok == '#'))
101
          /* end of line or the rest is a comment */
102
0
          break;
103
104
        /* leading double-quote means quoted string */
105
0
        quoted = (*tok == '\"');
106
107
0
        tok_end = tok;
108
0
        if(!quoted) {
109
0
          while(!ISSPACE(*tok_end))
110
0
            tok_end++;
111
0
          *tok_end = 0;
112
0
        }
113
0
        else {
114
0
          bool escape = FALSE;
115
0
          bool endquote = FALSE;
116
0
          char *store = tok;
117
0
          tok_end++; /* pass the leading quote */
118
0
          while(*tok_end) {
119
0
            char s = *tok_end;
120
0
            if(escape) {
121
0
              escape = FALSE;
122
0
              switch(s) {
123
0
              case 'n':
124
0
                s = '\n';
125
0
                break;
126
0
              case 'r':
127
0
                s = '\r';
128
0
                break;
129
0
              case 't':
130
0
                s = '\t';
131
0
                break;
132
0
              }
133
0
            }
134
0
            else if(s == '\\') {
135
0
              escape = TRUE;
136
0
              tok_end++;
137
0
              continue;
138
0
            }
139
0
            else if(s == '\"') {
140
0
              tok_end++; /* pass the ending quote */
141
0
              endquote = TRUE;
142
0
              break;
143
0
            }
144
0
            *store++ = s;
145
0
            tok_end++;
146
0
          }
147
0
          *store = 0;
148
0
          if(escape || !endquote) {
149
            /* bad syntax, get out */
150
0
            retcode = NETRC_FAILED;
151
0
            goto out;
152
0
          }
153
0
        }
154
155
0
        if((login && *login) && (password && *password)) {
156
0
          done = TRUE;
157
0
          break;
158
0
        }
159
160
0
        switch(state) {
161
0
        case NOTHING:
162
0
          if(strcasecompare("macdef", tok)) {
163
            /* Define a macro. A macro is defined with the specified name; its
164
               contents begin with the next .netrc line and continue until a
165
               null line (consecutive new-line characters) is encountered. */
166
0
            state = MACDEF;
167
0
          }
168
0
          else if(strcasecompare("machine", tok)) {
169
            /* the next tok is the machine name, this is in itself the
170
               delimiter that starts the stuff entered for this machine,
171
               after this we need to search for 'login' and
172
               'password'. */
173
0
            state = HOSTFOUND;
174
0
          }
175
0
          else if(strcasecompare("default", tok)) {
176
0
            state = HOSTVALID;
177
0
            retcode = NETRC_SUCCESS; /* we did find our host */
178
0
          }
179
0
          break;
180
0
        case MACDEF:
181
0
          if(!strlen(tok)) {
182
0
            state = NOTHING;
183
0
          }
184
0
          break;
185
0
        case HOSTFOUND:
186
0
          if(strcasecompare(host, tok)) {
187
            /* and yes, this is our host! */
188
0
            state = HOSTVALID;
189
0
            retcode = NETRC_SUCCESS; /* we did find our host */
190
0
          }
191
0
          else
192
            /* not our host */
193
0
            state = NOTHING;
194
0
          break;
195
0
        case HOSTVALID:
196
          /* we are now parsing sub-keywords concerning "our" host */
197
0
          if(state_login) {
198
0
            if(specific_login) {
199
0
              state_our_login = !Curl_timestrcmp(login, tok);
200
0
            }
201
0
            else if(!login || Curl_timestrcmp(login, tok)) {
202
0
              if(login_alloc) {
203
0
                free(login);
204
0
                login_alloc = FALSE;
205
0
              }
206
0
              login = strdup(tok);
207
0
              if(!login) {
208
0
                retcode = NETRC_FAILED; /* allocation failed */
209
0
                goto out;
210
0
              }
211
0
              login_alloc = TRUE;
212
0
            }
213
0
            state_login = 0;
214
0
          }
215
0
          else if(state_password) {
216
0
            if((state_our_login || !specific_login)
217
0
               && (!password || Curl_timestrcmp(password, tok))) {
218
0
              if(password_alloc) {
219
0
                free(password);
220
0
                password_alloc = FALSE;
221
0
              }
222
0
              password = strdup(tok);
223
0
              if(!password) {
224
0
                retcode = NETRC_FAILED; /* allocation failed */
225
0
                goto out;
226
0
              }
227
0
              password_alloc = TRUE;
228
0
            }
229
0
            state_password = 0;
230
0
          }
231
0
          else if(strcasecompare("login", tok))
232
0
            state_login = 1;
233
0
          else if(strcasecompare("password", tok))
234
0
            state_password = 1;
235
0
          else if(strcasecompare("machine", tok)) {
236
            /* ok, there's machine here go => */
237
0
            state = HOSTFOUND;
238
0
            state_our_login = FALSE;
239
0
          }
240
0
          break;
241
0
        } /* switch (state) */
242
0
        tok = ++tok_end;
243
0
      }
244
0
    } /* while fgets() */
245
246
0
    out:
247
0
    if(!retcode) {
248
      /* success */
249
0
      if(login_alloc) {
250
0
        if(*loginp)
251
0
          free(*loginp);
252
0
        *loginp = login;
253
0
      }
254
0
      if(password_alloc) {
255
0
        if(*passwordp)
256
0
          free(*passwordp);
257
0
        *passwordp = password;
258
0
      }
259
0
    }
260
0
    else {
261
0
      if(login_alloc)
262
0
        free(login);
263
0
      if(password_alloc)
264
0
        free(password);
265
0
    }
266
0
    fclose(file);
267
0
  }
268
269
0
  return retcode;
270
0
}
271
272
/*
273
 * @unittest: 1304
274
 *
275
 * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
276
 * in.
277
 */
278
int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
279
                    char *netrcfile)
280
0
{
281
0
  int retcode = 1;
282
0
  char *filealloc = NULL;
283
284
0
  if(!netrcfile) {
285
0
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
286
0
    char pwbuf[1024];
287
0
#endif
288
0
    char *home = NULL;
289
0
    char *homea = curl_getenv("HOME"); /* portable environment reader */
290
0
    if(homea) {
291
0
      home = homea;
292
0
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
293
0
    }
294
0
    else {
295
0
      struct passwd pw, *pw_res;
296
0
      if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
297
0
         && pw_res) {
298
0
        home = pw.pw_dir;
299
0
      }
300
#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
301
    }
302
    else {
303
      struct passwd *pw;
304
      pw = getpwuid(geteuid());
305
      if(pw) {
306
        home = pw->pw_dir;
307
      }
308
#elif defined(_WIN32)
309
    }
310
    else {
311
      homea = curl_getenv("USERPROFILE");
312
      if(homea) {
313
        home = homea;
314
      }
315
#endif
316
0
    }
317
318
0
    if(!home)
319
0
      return retcode; /* no home directory found (or possibly out of
320
                         memory) */
321
322
0
    filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR);
323
0
    if(!filealloc) {
324
0
      free(homea);
325
0
      return -1;
326
0
    }
327
0
    retcode = parsenetrc(host, loginp, passwordp, filealloc);
328
0
    free(filealloc);
329
#ifdef WIN32
330
    if(retcode == NETRC_FILE_MISSING) {
331
      /* fallback to the old-style "_netrc" file */
332
      filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR);
333
      if(!filealloc) {
334
        free(homea);
335
        return -1;
336
      }
337
      retcode = parsenetrc(host, loginp, passwordp, filealloc);
338
      free(filealloc);
339
    }
340
#endif
341
0
    free(homea);
342
0
  }
343
0
  else
344
0
    retcode = parsenetrc(host, loginp, passwordp, netrcfile);
345
0
  return retcode;
346
0
}
347
348
#endif