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 Wget.
6 This program 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 This program 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 this program; 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. */
35 #include <sys/types.h>
47 #define NETRC_FILE_NAME ".netrc"
51 static acc_t *parse_netrc PARAMS ((const char *));
53 /* Return the correct user and password, given the host, user (as
54 given in the URL), and password (as given in the URL). May return
57 If SLACK_DEFAULT is set, allow looking for a "default" account.
58 You will typically turn it off for HTTP. */
60 search_netrc (const char *host, const char **acc, const char **passwd,
64 static int processed_netrc;
71 char *home = home_dir();
79 char *path = (char *)alloca (strlen (home) + 1
80 + strlen (NETRC_FILE_NAME) + 1);
81 sprintf (path, "%s/%s", home, NETRC_FILE_NAME);
83 err = stat (path, &buf);
85 netrc_list = parse_netrc (path);
88 /* If nothing to do... */
91 /* Acc and password found; all OK. */
94 if (!*acc && !slack_default)
96 /* Some data not given -- try finding the host. */
97 for (l = netrc_list; l; l = l->next)
101 else if (!strcasecmp (l->host, host))
108 /* Looking for password in .netrc. */
109 if (!strcmp (l->acc, *acc))
110 *passwd = l->passwd; /* usernames match; password OK */
112 *passwd = NULL; /* usernames don't match */
116 /* If password was given, use it. The account is l->acc. */
129 /* Try looking for the default account. */
130 for (l = netrc_list; l; l = l->next)
144 /* Normally, these functions would be defined by your package. */
145 # define xmalloc malloc
147 # define xstrdup strdup
149 /* The function reads a whole line. It reads the line realloc-ing the
150 storage exponentially, doubling the storage after each overflow to
151 minimize the number of calls to realloc().
153 It is not an exemplary of correctness, since it kills off the
154 newline (and no, there is no way to know if there was a newline at
156 # define xrealloc realloc
157 # define DYNAMIC_LINE_BUFFER 40
160 read_whole_line (FILE *fp)
166 bufsize = DYNAMIC_LINE_BUFFER;
167 line = xmalloc(bufsize);
168 /* Construct the line. */
169 while ((c = getc(fp)) != EOF && c != '\n')
172 line = (char *)xrealloc(line, (bufsize <<= 1));
181 /* Check for overflow at zero-termination (no need to double the
182 buffer in this case. */
184 line = (char *)xrealloc(line, i + 1);
189 #endif /* STANDALONE */
191 /* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
192 set to a ready-to-use acc_t, in any event. */
194 maybe_add_to_list (acc_t **newentry, acc_t **list)
200 /* We need an account name in order to add the entry to the list. */
203 /* Free any allocated space. */
212 /* Add the current machine into our list. */
217 /* Allocate a new acc_t structure. */
218 a = (acc_t *)xmalloc (sizeof (acc_t));
221 /* Zero the structure, so that it is ready to use. */
222 memset (a, 0, sizeof(*a));
224 /* Return the new pointers. */
230 /* Helper function for the parser, shifts contents of
231 null-terminated string once character to the left.
232 Used in processing \ and " constructs in the netrc file */
234 shift_left(char *string){
237 for (p=string; *p; ++p)
241 /* Parse a .netrc file (as described in the ftp(1) manual page). */
243 parse_netrc (const char *path)
246 char *line, *p, *tok, *premature_token;
247 acc_t *current, *retval;
250 /* The latest token we've seen in the file. */
253 tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
254 } last_token = tok_nothing;
256 current = retval = NULL;
258 fp = fopen (path, "r");
261 fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
262 path, strerror (errno));
266 /* Initialize the file data. */
268 premature_token = NULL;
270 /* While there are lines in the file... */
271 while ((line = read_whole_line (fp)))
275 /* Parse the line. */
279 /* If the line is empty, then end any macro definition. */
280 if (last_token == tok_macdef && !*p)
281 /* End of macro if the line is empty. */
282 last_token = tok_nothing;
284 /* If we are defining macros, then skip parsing the line. */
285 while (*p && last_token != tok_macdef)
287 /* Skip any whitespace. */
288 while (*p && ISSPACE (*p))
291 /* Discard end-of-line comments. */
295 /* If the token starts with quotation mark, note this fact,
296 and squash the quotation character */
304 /* Find the end of the token, handling quotes and escapes. */
305 while (*p && (quote ? *p != '"' : !ISSPACE (*p))){
311 /* if field was quoted, squash the trailing quotation mark */
315 /* Null-terminate the token, if it isn't already. */
323 current->acc = xstrdup (tok);
325 premature_token = "login";
329 /* Start a new machine entry. */
330 maybe_add_to_list (¤t, &retval);
331 current->host = xstrdup (tok);
336 current->passwd = xstrdup (tok);
338 premature_token = "password";
341 /* We handle most of tok_macdef above. */
344 premature_token = "macdef";
347 /* We don't handle the account keyword at all. */
350 premature_token = "account";
353 /* We handle tok_nothing below this switch. */
360 fprintf (stderr, _("\
361 %s: %s:%d: warning: \"%s\" token appears before any machine name\n"),
362 exec_name, path, ln, premature_token);
363 premature_token = NULL;
366 if (last_token != tok_nothing)
367 /* We got a value, so reset the token state. */
368 last_token = tok_nothing;
371 /* Fetch the next token. */
372 if (!strcmp (tok, "account"))
373 last_token = tok_account;
374 else if (!strcmp (tok, "default"))
376 maybe_add_to_list (¤t, &retval);
378 else if (!strcmp (tok, "login"))
379 last_token = tok_login;
381 else if (!strcmp (tok, "macdef"))
382 last_token = tok_macdef;
384 else if (!strcmp (tok, "machine"))
385 last_token = tok_machine;
387 else if (!strcmp (tok, "password"))
388 last_token = tok_password;
391 fprintf (stderr, _("%s: %s:%d: unknown token \"%s\"\n"),
392 exec_name, path, ln, tok);
401 /* Finalize the last machine entry we found. */
402 maybe_add_to_list (¤t, &retval);
405 /* Reverse the order of the list so that it appears in file order. */
410 acc_t *saved_reference;
412 /* Change the direction of the pointers. */
413 saved_reference = current->next;
414 current->next = retval;
416 /* Advance to the next node. */
418 current = saved_reference;
425 /* Free a netrc list. */
435 FREE_MAYBE (l->passwd);
436 FREE_MAYBE (l->host);
443 #include <sys/types.h>
444 #include <sys/stat.h>
447 main (int argc, char **argv)
450 char *program_name, *file, *target;
453 if (argc < 2 || argc > 3)
455 fprintf (stderr, _("Usage: %s NETRC [HOSTNAME]\n"), argv[0]);
459 program_name = argv[0];
463 if (stat (file, &sb))
465 fprintf (stderr, _("%s: cannot stat %s: %s\n"), argv[0], file,
470 head = parse_netrc (file);
474 /* Skip if we have a target and this isn't it. */
475 if (target && a->host && strcmp (target, a->host))
483 /* Print the host name if we have no target. */
485 fputs (a->host, stdout);
487 fputs ("DEFAULT", stdout);
492 /* Print the account name. */
493 fputs (a->acc, stdout);
497 /* Print the password, if there is any. */
499 fputs (a->passwd, stdout);
502 fputc ('\n', stdout);
504 /* Exit if we found the target. */
510 /* Exit with failure if we had a target, success otherwise. */
516 #endif /* STANDALONE */