1 /* Read and parse the .netrc file to get hosts, accounts, and passwords.
2 Copyright (C) 1996, Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* This file used to be kept in synch with the code in Fetchmail, but
21 the latter has diverged since. */
34 #include <sys/types.h>
46 #define NETRC_FILE_NAME ".netrc"
50 static acc_t *parse_netrc PARAMS ((const char *));
52 /* Return the correct user and password, given the host, user (as
53 given in the URL), and password (as given in the URL). May return
56 If SLACK_DEFAULT is set, allow looking for a "default" account.
57 You will typically turn it off for HTTP. */
59 search_netrc (const char *host, const char **acc, const char **passwd,
63 static int processed_netrc;
70 char *home = home_dir ();
78 char *path = (char *)alloca (strlen (home) + 1
79 + strlen (NETRC_FILE_NAME) + 1);
80 sprintf (path, "%s/%s", home, NETRC_FILE_NAME);
82 err = stat (path, &buf);
84 netrc_list = parse_netrc (path);
87 /* If nothing to do... */
90 /* Acc and password found; all OK. */
93 if (!*acc && !slack_default)
95 /* Some data not given -- try finding the host. */
96 for (l = netrc_list; l; l = l->next)
100 else if (!strcasecmp (l->host, host))
107 /* Looking for password in .netrc. */
108 if (!strcmp (l->acc, *acc))
109 *passwd = l->passwd; /* usernames match; password OK */
111 *passwd = NULL; /* usernames don't match */
115 /* If password was given, use it. The account is l->acc. */
128 /* Try looking for the default account. */
129 for (l = netrc_list; l; l = l->next)
146 /* Normally, these functions would be defined by your package. */
147 # define xmalloc malloc
149 # define xstrdup strdup
151 # define xrealloc realloc
153 /* Read a line from FP. The function reallocs the storage as needed
154 to accomodate for any length of the line. Reallocs are done
155 storage exponentially, doubling the storage after each overflow to
156 minimize the number of calls to realloc() and fgets(). The newline
157 character at the end of line is retained.
159 After end-of-file is encountered without anything being read, NULL
160 is returned. NULL is also returned on error. To distinguish
161 between these two cases, use the stdio function ferror(). */
164 read_whole_line (FILE *fp)
168 char *line = (char *)xmalloc (bufsize);
170 while (fgets (line + length, bufsize - length, fp))
172 length += strlen (line + length);
174 if (line[length - 1] == '\n')
176 /* fgets() guarantees to read the whole line, or to use up the
177 space we've given it. We can double the buffer
180 line = xrealloc (line, bufsize);
182 if (length == 0 || ferror (fp))
187 if (length + 1 < bufsize)
188 /* Relieve the memory from our exponential greediness. We say
189 `length + 1' because the terminating \0 is not included in
190 LENGTH. We don't need to zero-terminate the string ourselves,
191 though, because fgets() does that. */
192 line = xrealloc (line, length + 1);
195 #endif /* STANDALONE */
197 /* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
198 set to a ready-to-use acc_t, in any event. */
200 maybe_add_to_list (acc_t **newentry, acc_t **list)
206 /* We need an account name in order to add the entry to the list. */
209 /* Free any allocated space. */
218 /* Add the current machine into our list. */
223 /* Allocate a new acc_t structure. */
224 a = (acc_t *)xmalloc (sizeof (acc_t));
227 /* Zero the structure, so that it is ready to use. */
228 memset (a, 0, sizeof(*a));
230 /* Return the new pointers. */
236 /* Helper function for the parser, shifts contents of
237 null-terminated string once character to the left.
238 Used in processing \ and " constructs in the netrc file */
240 shift_left(char *string){
243 for (p=string; *p; ++p)
247 /* Parse a .netrc file (as described in the ftp(1) manual page). */
249 parse_netrc (const char *path)
252 char *line, *p, *tok, *premature_token;
253 acc_t *current, *retval;
256 /* The latest token we've seen in the file. */
259 tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
260 } last_token = tok_nothing;
262 current = retval = NULL;
264 fp = fopen (path, "r");
267 fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
268 path, strerror (errno));
272 /* Initialize the file data. */
274 premature_token = NULL;
276 /* While there are lines in the file... */
277 while ((line = read_whole_line (fp)))
281 /* Parse the line. */
285 /* If the line is empty, then end any macro definition. */
286 if (last_token == tok_macdef && !*p)
287 /* End of macro if the line is empty. */
288 last_token = tok_nothing;
290 /* If we are defining macros, then skip parsing the line. */
291 while (*p && last_token != tok_macdef)
293 /* Skip any whitespace. */
294 while (*p && ISSPACE (*p))
297 /* Discard end-of-line comments; also, stop processing if
298 the above `while' merely skipped trailing whitespace. */
299 if (*p == '#' || !*p)
302 /* If the token starts with quotation mark, note this fact,
303 and squash the quotation character */
311 /* Find the end of the token, handling quotes and escapes. */
312 while (*p && (quote ? *p != '"' : !ISSPACE (*p))){
318 /* if field was quoted, squash the trailing quotation mark */
322 /* Null-terminate the token, if it isn't already. */
330 current->acc = xstrdup (tok);
332 premature_token = "login";
336 /* Start a new machine entry. */
337 maybe_add_to_list (¤t, &retval);
338 current->host = xstrdup (tok);
343 current->passwd = xstrdup (tok);
345 premature_token = "password";
348 /* We handle most of tok_macdef above. */
351 premature_token = "macdef";
354 /* We don't handle the account keyword at all. */
357 premature_token = "account";
360 /* We handle tok_nothing below this switch. */
367 fprintf (stderr, _("\
368 %s: %s:%d: warning: \"%s\" token appears before any machine name\n"),
369 exec_name, path, ln, premature_token);
370 premature_token = NULL;
373 if (last_token != tok_nothing)
374 /* We got a value, so reset the token state. */
375 last_token = tok_nothing;
378 /* Fetch the next token. */
379 if (!strcmp (tok, "account"))
380 last_token = tok_account;
381 else if (!strcmp (tok, "default"))
383 maybe_add_to_list (¤t, &retval);
385 else if (!strcmp (tok, "login"))
386 last_token = tok_login;
388 else if (!strcmp (tok, "macdef"))
389 last_token = tok_macdef;
391 else if (!strcmp (tok, "machine"))
392 last_token = tok_machine;
394 else if (!strcmp (tok, "password"))
395 last_token = tok_password;
398 fprintf (stderr, _("%s: %s:%d: unknown token \"%s\"\n"),
399 exec_name, path, ln, tok);
408 /* Finalize the last machine entry we found. */
409 maybe_add_to_list (¤t, &retval);
412 /* Reverse the order of the list so that it appears in file order. */
417 acc_t *saved_reference;
419 /* Change the direction of the pointers. */
420 saved_reference = current->next;
421 current->next = retval;
423 /* Advance to the next node. */
425 current = saved_reference;
432 /* Free a netrc list. */
442 FREE_MAYBE (l->passwd);
443 FREE_MAYBE (l->host);
450 #include <sys/types.h>
451 #include <sys/stat.h>
454 main (int argc, char **argv)
457 char *program_name, *file, *target;
460 if (argc < 2 || argc > 3)
462 fprintf (stderr, _("Usage: %s NETRC [HOSTNAME]\n"), argv[0]);
466 program_name = argv[0];
470 if (stat (file, &sb))
472 fprintf (stderr, _("%s: cannot stat %s: %s\n"), argv[0], file,
477 head = parse_netrc (file);
481 /* Skip if we have a target and this isn't it. */
482 if (target && a->host && strcmp (target, a->host))
490 /* Print the host name if we have no target. */
492 fputs (a->host, stdout);
494 fputs ("DEFAULT", stdout);
499 /* Print the account name. */
500 fputs (a->acc, stdout);
504 /* Print the password, if there is any. */
506 fputs (a->passwd, stdout);
509 fputc ('\n', stdout);
511 /* Exit if we found the target. */
517 /* Exit with failure if we had a target, success otherwise. */
523 #endif /* STANDALONE */