1 /* Read and parse the .netrc file to get hosts, accounts, and passwords.
2 Copyright (C) 1996, 2007, 2008, 2009, 2010, 2011 Free Software
5 This file is part of GNU Wget.
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Wget. If not, see <http://www.gnu.org/licenses/>.
20 Additional permission under GNU GPL version 3 section 7
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work. */
31 /* This file used to be kept in synch with the code in Fetchmail, but
32 the latter has diverged since. */
45 #define NETRC_FILE_NAME ".netrc"
49 static acc_t *parse_netrc (const char *);
51 /* Return the correct user and password, given the host, user (as
52 given in the URL), and password (as given in the URL). May return
55 If SLACK_DEFAULT is set, allow looking for a "default" account.
56 You will typically turn it off for HTTP. */
58 search_netrc (const char *host, const char **acc, const char **passwd,
62 static int processed_netrc;
73 char *path = "SYS$LOGIN:.netrc";
78 err = stat (path, &buf);
80 netrc_list = parse_netrc (path);
84 char *home = home_dir ();
92 char *path = (char *)alloca (strlen (home) + 1
93 + strlen (NETRC_FILE_NAME) + 1);
94 sprintf (path, "%s/%s", home, NETRC_FILE_NAME);
96 err = stat (path, &buf);
98 netrc_list = parse_netrc (path);
101 #endif /* def __VMS [else] */
103 /* If nothing to do... */
106 /* Acc and password found; all OK. */
109 /* Some data not given -- try finding the host. */
110 for (l = netrc_list; l; l = l->next)
114 else if (!strcasecmp (l->host, host))
121 /* Looking for password in .netrc. */
122 if (!strcmp (l->acc, *acc))
123 *passwd = l->passwd; /* usernames match; password OK */
125 *passwd = NULL; /* usernames don't match */
129 /* If password was given, use it. The account is l->acc. */
142 /* Try looking for the default account. */
143 for (l = netrc_list; l; l = l->next)
160 /* Normally, these functions would be defined by your package. */
161 # define xmalloc malloc
163 # define xstrdup strdup
165 # define xrealloc realloc
167 /* Read a line from FP. The function reallocs the storage as needed
168 to accomodate for any length of the line. Reallocs are done
169 storage exponentially, doubling the storage after each overflow to
170 minimize the number of calls to realloc() and fgets(). The newline
171 character at the end of line is retained.
173 After end-of-file is encountered without anything being read, NULL
174 is returned. NULL is also returned on error. To distinguish
175 between these two cases, use the stdio function ferror(). */
178 read_whole_line (FILE *fp)
182 char *line = xmalloc (bufsize);
184 while (fgets (line + length, bufsize - length, fp))
186 length += strlen (line + length);
188 if (line[length - 1] == '\n')
190 /* fgets() guarantees to read the whole line, or to use up the
191 space we've given it. We can double the buffer
194 line = xrealloc (line, bufsize);
196 if (length == 0 || ferror (fp))
201 if (length + 1 < bufsize)
202 /* Relieve the memory from our exponential greediness. We say
203 `length + 1' because the terminating \0 is not included in
204 LENGTH. We don't need to zero-terminate the string ourselves,
205 though, because fgets() does that. */
206 line = xrealloc (line, length + 1);
209 #endif /* STANDALONE */
211 /* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
212 set to a ready-to-use acc_t, in any event. */
214 maybe_add_to_list (acc_t **newentry, acc_t **list)
220 /* We need an account name in order to add the entry to the list. */
223 /* Free any allocated space. */
224 xfree_null (a->host);
226 xfree_null (a->passwd);
232 /* Add the current machine into our list. */
237 /* Allocate a new acc_t structure. */
238 a = xmalloc (sizeof (acc_t));
241 /* Zero the structure, so that it is ready to use. */
242 memset (a, 0, sizeof(*a));
244 /* Return the new pointers. */
250 /* Helper function for the parser, shifts contents of
251 null-terminated string once character to the left.
252 Used in processing \ and " constructs in the netrc file */
254 shift_left(char *string)
258 for (p=string; *p; ++p)
262 /* Parse a .netrc file (as described in the ftp(1) manual page). */
264 parse_netrc (const char *path)
267 char *line, *p, *tok;
268 const char *premature_token;
269 acc_t *current, *retval;
272 /* The latest token we've seen in the file. */
275 tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
276 } last_token = tok_nothing;
278 current = retval = NULL;
280 fp = fopen (path, "r");
283 fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
284 path, strerror (errno));
288 /* Initialize the file data. */
290 premature_token = NULL;
292 /* While there are lines in the file... */
293 while ((line = read_whole_line (fp)) != NULL)
297 /* Parse the line. */
301 /* Skip leading whitespace. */
302 while (*p && c_isspace (*p))
305 /* If the line is empty, then end any macro definition. */
306 if (last_token == tok_macdef && !*p)
307 /* End of macro if the line is empty. */
308 last_token = tok_nothing;
310 /* If we are defining macros, then skip parsing the line. */
311 while (*p && last_token != tok_macdef)
313 /* Skip any whitespace. */
314 while (*p && c_isspace (*p))
317 /* Discard end-of-line comments; also, stop processing if
318 the above `while' merely skipped trailing whitespace. */
319 if (*p == '#' || !*p)
322 /* If the token starts with quotation mark, note this fact,
323 and squash the quotation character */
331 /* Find the end of the token, handling quotes and escapes. */
332 while (*p && (qmark ? *p != '"' : !c_isspace (*p))){
338 /* If field was quoted, squash the trailing quotation mark
339 and reset qmark flag. */
346 /* Null-terminate the token, if it isn't already. */
354 current->acc = xstrdup (tok);
356 premature_token = "login";
360 /* Start a new machine entry. */
361 maybe_add_to_list (¤t, &retval);
362 current->host = xstrdup (tok);
367 current->passwd = xstrdup (tok);
369 premature_token = "password";
372 /* We handle most of tok_macdef above. */
375 premature_token = "macdef";
378 /* We don't handle the account keyword at all. */
381 premature_token = "account";
384 /* We handle tok_nothing below this switch. */
391 fprintf (stderr, _("\
392 %s: %s:%d: warning: %s token appears before any machine name\n"),
393 exec_name, path, ln, quote (premature_token));
394 premature_token = NULL;
397 if (last_token != tok_nothing)
398 /* We got a value, so reset the token state. */
399 last_token = tok_nothing;
402 /* Fetch the next token. */
403 if (!strcmp (tok, "account"))
404 last_token = tok_account;
405 else if (!strcmp (tok, "default"))
407 maybe_add_to_list (¤t, &retval);
409 else if (!strcmp (tok, "login"))
410 last_token = tok_login;
412 else if (!strcmp (tok, "macdef"))
413 last_token = tok_macdef;
415 else if (!strcmp (tok, "machine"))
416 last_token = tok_machine;
418 else if (!strcmp (tok, "password"))
419 last_token = tok_password;
422 fprintf (stderr, _("%s: %s:%d: unknown token \"%s\"\n"),
423 exec_name, path, ln, tok);
432 /* Finalize the last machine entry we found. */
433 maybe_add_to_list (¤t, &retval);
436 /* Reverse the order of the list so that it appears in file order. */
441 acc_t *saved_reference;
443 /* Change the direction of the pointers. */
444 saved_reference = current->next;
445 current->next = retval;
447 /* Advance to the next node. */
449 current = saved_reference;
456 /* Free a netrc list. */
466 xfree_null (l->passwd);
467 xfree_null (l->host);
474 #include <sys/types.h>
475 #include <sys/stat.h>
478 main (int argc, char **argv)
481 char *program_name, *file, *target;
484 if (argc < 2 || argc > 3)
486 fprintf (stderr, _("Usage: %s NETRC [HOSTNAME]\n"), argv[0]);
490 program_name = argv[0];
494 if (stat (file, &sb))
496 fprintf (stderr, _("%s: cannot stat %s: %s\n"), argv[0], file,
501 head = parse_netrc (file);
505 /* Skip if we have a target and this isn't it. */
506 if (target && a->host && strcmp (target, a->host))
514 /* Print the host name if we have no target. */
516 fputs (a->host, stdout);
518 fputs ("DEFAULT", stdout);
523 /* Print the account name. */
524 fputs (a->acc, stdout);
528 /* Print the password, if there is any. */
530 fputs (a->passwd, stdout);
533 fputc ('\n', stdout);
535 /* Exit if we found the target. */
541 /* Exit with failure if we had a target, success otherwise. */
547 #endif /* STANDALONE */