2 * netrc.c -- parse the .netrc file to get hosts, accounts, and passwords
4 Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
5 Copyright assigned to Eric S. Raymond, October 2001.
7 For license terms, see the file COPYING in this directory.
9 Compile with -DSTANDALONE to test this module.
10 (Makefile.am should have a rule so you can just type "make netrc")
19 #include "fetchmail.h"
24 /* Normally defined in xstrdup.c. */
25 # define xstrdup strdup
27 /* Normally defined in xmalloc.c */
28 # define xmalloc malloc
29 # define xrealloc realloc
31 char *program_name = "netrc";
34 /* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
35 set to a ready-to-use netrc_entry, in any event. */
37 maybe_add_to_list (netrc_entry **newentry, netrc_entry **list)
43 /* We need a login name in order to add the entry to the list. */
46 /* Free any allocated space. */
56 /* Add the current machine into our list. */
61 /* Allocate a new netrc_entry structure. */
62 a = (netrc_entry *) xmalloc (sizeof (netrc_entry));
65 /* Zero the structure, so that it is ready to use. */
66 memset (a, 0, sizeof(*a));
68 /* Return the new pointers. */
75 /* Parse FILE as a .netrc file (as described in ftp(1)), and return a
76 list of entries. NULL is returned if the file could not be
79 parse_netrc (char *file)
82 char buf[POPBUFSIZE+1], *p, *tok;
83 const char *premature_token;
84 netrc_entry *current, *retval;
87 /* The latest token we've seen in the file. */
90 tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
91 } last_token = tok_nothing;
93 current = retval = NULL;
95 fp = fopen (file, "r");
98 /* Just return NULL if we can't open the file. */
102 /* Initialize the file data. */
104 premature_token = NULL;
106 /* While there are lines in the file... */
107 while (fgets(buf, sizeof(buf) - 1, fp))
111 /* Strip trailing CRLF */
112 for (p = buf + strlen(buf) - 1; (p >= buf) && isspace((unsigned char)*p); p--)
115 /* Parse the line. */
118 /* If the line is empty... */
121 if (last_token == tok_macdef) /* end of macro */
122 last_token = tok_nothing;
124 continue; /* otherwise ignore it */
127 /* If we are defining macros, then skip parsing the line. */
128 while (*p && last_token != tok_macdef)
133 /* Skip any whitespace. */
134 while (*p && isspace ((unsigned char)*p))
137 /* Discard end-of-line comments. */
143 /* Find the end of the token. */
144 while (*p && (quote_char || !isspace ((unsigned char)*p)))
148 if (quote_char == *p)
162 if (*p == '"' || *p == '\'')
172 /* Null-terminate the token, if it isn't already. */
181 current->login = (char *) xstrdup (tok);
183 premature_token = "login";
187 /* Start a new machine entry. */
188 maybe_add_to_list (¤t, &retval);
189 current->host = (char *) xstrdup (tok);
194 current->password = (char *) xstrdup (tok);
196 premature_token = "password";
199 /* We handle most of tok_macdef above. */
202 premature_token = "macdef";
205 /* We don't handle the account keyword at all. */
208 premature_token = "account";
211 /* We handle tok_nothing below this switch. */
219 GT_("%s:%d: warning: found \"%s\" before any host names\n"),
220 file, ln, premature_token);
221 premature_token = NULL;
224 if (last_token != tok_nothing)
225 /* We got a value, so reset the token state. */
226 last_token = tok_nothing;
229 /* Fetch the next token. */
230 if (!strcmp (tok, "default"))
232 maybe_add_to_list (¤t, &retval);
234 else if (!strcmp (tok, "login"))
235 last_token = tok_login;
237 else if (!strcmp (tok, "user"))
238 last_token = tok_login;
240 else if (!strcmp (tok, "macdef"))
241 last_token = tok_macdef;
243 else if (!strcmp (tok, "machine"))
244 last_token = tok_machine;
246 else if (!strcmp (tok, "password"))
247 last_token = tok_password;
249 else if (!strcmp (tok, "passwd"))
250 last_token = tok_password;
252 else if (!strcmp (tok, "account"))
253 last_token = tok_account;
257 fprintf (stderr, GT_("%s:%d: warning: unknown token \"%s\"\n"),
266 /* Finalize the last machine entry we found. */
267 maybe_add_to_list (¤t, &retval);
270 /* Reverse the order of the list so that it appears in file order. */
275 netrc_entry *saved_reference;
277 /* Change the direction of the pointers. */
278 saved_reference = current->next;
279 current->next = retval;
281 /* Advance to the next node. */
283 current = saved_reference;
290 /* Return the netrc entry from LIST corresponding to HOST. NULL is
291 returned if no such entry exists. */
293 search_netrc (netrc_entry *list, char *host, char *login)
295 /* Look for the HOST in LIST. */
298 if (list->host && !strcmp(list->host, host))
299 if (!list->login || !strcmp(list->login, login))
300 /* We found a matching entry. */
306 /* Return the matching entry, or NULL. */
311 free_netrc(netrc_entry *a) {
313 netrc_entry *n = a->next;
314 if (a->password != NULL) {
315 memset(a->password, 0x55, strlen(a->password));
326 #include <sys/types.h>
327 #include <sys/stat.h>
331 int main (int argc, char **argv)
334 char *program_name, *file, *host, *login;
335 netrc_entry *head, *a;
337 program_name = argv[0];
347 fprintf (stderr, "Usage: %s <file> [<host> <login>]\n", argv[0]);
351 if (stat (file, &sb))
353 fprintf (stderr, "%s: cannot stat %s: %s\n", argv[0], file,
358 head = parse_netrc (file);
361 fprintf (stderr, "%s: no entries found in %s\n", argv[0], file);
368 status = EXIT_SUCCESS;
370 printf("Host: %s, Login: %s\n", host, login);
372 a = search_netrc (head, host, login);
375 /* Print out the password (if any). */
378 printf("Password: %s\n", a->password);
381 status = EXIT_FAILURE;
382 fputc ('\n', stdout);
387 /* Print out the entire contents of the netrc. */
391 /* Print the host name. */
393 fputs (a->host, stdout);
395 fputs ("DEFAULT", stdout);
399 /* Print the login name. */
400 fputs (a->login, stdout);
404 /* Print the password, if there is any. */
406 fputs (a->password, stdout);
409 fputc ('\n', stdout);
417 #endif /* STANDALONE */