-/* netrc.c -- parse the .netrc file to get hosts, accounts, and passwords
- Copyright (C) 1996, Free Software Foundation, Inc.
+/*
+ * netrc.c -- parse the .netrc file to get hosts, accounts, and passwords
+ *
Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+ Copyright assigned to Eric S. Raymond, October 2001.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Compile with -DSTANDALONE to test this module. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif /* HAVE_CONFIG_H */
-
-/* If SYSTEM_WGETRC is defined in config.h, then we assume we are being
- compiled as a part of Wget. That means we make special Wget-specific
- modifications to the code (at least until we settle on a cleaner
- library interface). */
-/* FIXME - eliminate all WGET_HACKS conditionals by massaging Wget. */
-#ifdef SYSTEM_WGETRC
-# define WGET_HACKS 1
-#endif
+ For license terms, see the file COPYING in this directory.
-/* If CLIENT_TIMEOUT is defined in config.h, then we assume we are being
- compiled as a part of fetchmail. */
-/* FIXME - eliminate all FETCHMAIL_HACKS conditionals by fixing fetchmail. */
-#ifdef CLIENT_TIMEOUT
-# define FETCHMAIL_HACKS 1
-#endif
+ Compile with -DSTANDALONE to test this module.
+ (Makefile.am should have a rule so you can just type "make netrc")
+*/
+
+#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define textdomain(Domain)
-# define _(Text) Text
-#endif
+#include <string.h>
+#include "fetchmail.h"
#include "netrc.h"
+#include "i18n.h"
#ifdef STANDALONE
/* Normally defined in xstrdup.c. */
/* Normally defined in xmalloc.c */
# define xmalloc malloc
# define xrealloc realloc
-#endif
-#if defined(STANDALONE) || defined(WGET_HACKS) || defined(FETCHMAIL_HACKS)
-/* We need to implement our own dynamic strings. */
-typedef struct
-{
- int ds_length;
- char *ds_string;
-} dynamic_string;
-#else
-/* We must be part of libit, or another GNU program, so assume that we have
- the ERROR function */
-# define HAVE_ERROR 1
-# include "error.h"
-# include "dstring.h"
+const char *program_name = "netrc";
#endif
-#define DS_INIT_LENGTH 40
-
-#ifdef WGET_HACKS
-/* Wget uses different naming conventions. */
-# define xmalloc nmalloc
-# define xstrdup nstrdup
-# define xrealloc nrealloc
-
-/* Wget has read_whole_line defined in utils.c */
-# include "utils.h"
-
-/* Temporary dynamic string (dstring.c from libit)-like interface to
- using read_whole_line. */
-#define ds_init(string, size) ((string)->ds_string = NULL)
-#define ds_destroy(string) free ((string)->ds_string)
-
-/* We use read_whole_line to implement ds_fgets. */
-static char *
-ds_fgets (FILE *f, dynamic_string *s)
-{
- free (s->ds_string);
- s->ds_string = read_whole_line (f);
- return s->ds_string;
-}
-#endif /* WGET_HACKS */
-
-#ifdef FETCHMAIL_HACKS
-/* fetchmail, too, is not consistent with the xmalloc functions. */
-# define xrealloc realloc
-# define xstrdup strdup
-#endif
-
-#if defined(STANDALONE) || defined(FETCHMAIL_HACKS)
-/* Bits and pieces of Tom Tromey's dstring.c, taken from libit-0.2. */
-
-/* Initialize dynamic string STRING with space for SIZE characters. */
-
-void
-ds_init (string, size)
- dynamic_string *string;
- int size;
-{
- string->ds_length = size;
- string->ds_string = (char *) xmalloc (size);
-}
-
-/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */
-
-void
-ds_resize (string, size)
- dynamic_string *string;
- int size;
-{
- if (size > string->ds_length)
- {
- string->ds_length = size;
- string->ds_string = (char *) xrealloc ((char *) string->ds_string, size);
- }
-}
-
-/* Delete dynamic string. */
-
-void
-ds_destroy (string)
- dynamic_string *string;
-{
- free (string->ds_string);
- string->ds_string = NULL;
-}
-
-/* Dynamic string S gets a string terminated by the EOS character
- (which is removed) from file F. S will increase
- in size during the function if the string from F is longer than
- the current size of S.
- Return NULL if end of file is detected. Otherwise,
- Return a pointer to the null-terminated string in S. */
-
-char *
-ds_fgetstr (f, s, eos)
- FILE *f;
- dynamic_string *s;
- char eos;
-{
- int insize; /* Amount needed for line. */
- int strsize; /* Amount allocated for S. */
- int next_ch;
-
- /* Initialize. */
- insize = 0;
- strsize = s->ds_length;
-
- /* Read the input string. */
- next_ch = getc (f);
- while (next_ch != eos && next_ch != EOF)
- {
- if (insize >= strsize - 1)
- {
- ds_resize (s, strsize * 2 + 2);
- strsize = s->ds_length;
- }
- s->ds_string[insize++] = next_ch;
- next_ch = getc (f);
- }
- s->ds_string[insize++] = '\0';
-
- if (insize == 1 && next_ch == EOF)
- return NULL;
- else
- return s->ds_string;
-}
-
-char *
-ds_fgets (f, s)
- FILE *f;
- dynamic_string *s;
-{
- return ds_fgetstr (f, s, '\n');
-}
-#endif /* !STANDALONE */
-
-
/* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
set to a ready-to-use netrc_entry, in any event. */
static void
-maybe_add_to_list (newentry, list)
- netrc_entry **newentry;
- netrc_entry **list;
+maybe_add_to_list (netrc_entry **newentry, netrc_entry **list)
{
- netrc_entry *a, *l;
- a = *newentry;
- l = *list;
+ netrc_entry *a, *l;
+ a = *newentry;
+ l = *list;
- /* We need an account name in order to add the entry to the list. */
- if (a && ! a->account)
+ /* We need a login name in order to add the entry to the list. */
+ if (a && ! a->login)
{
- /* Free any allocated space. */
- free (a->host);
- free (a->account);
- free (a->password);
+ /* Free any allocated space. */
+ if (a->host)
+ free (a->host);
+ if (a->password)
+ free (a->password);
}
- else
+ else
{
- if (a)
+ if (a)
{
- /* Add the current machine into our list. */
- a->next = l;
- l = a;
+ /* Add the current machine into our list. */
+ a->next = l;
+ l = a;
}
- /* Allocate a new netrc_entry structure. */
- a = (netrc_entry *) xmalloc (sizeof (netrc_entry));
+ /* Allocate a new netrc_entry structure. */
+ a = (netrc_entry *) xmalloc (sizeof (netrc_entry));
}
- /* Zero the structure, so that it is ready to use. */
- memset (a, 0, sizeof(*a));
+ /* Zero the structure, so that it is ready to use. */
+ memset (a, 0, sizeof(*a));
- /* Return the new pointers. */
- *newentry = a;
- *list = l;
- return;
+ /* Return the new pointers. */
+ *newentry = a;
+ *list = l;
+ return;
}
list of entries. NULL is returned if the file could not be
parsed. */
netrc_entry *
-parse_netrc (file)
- char *file;
+parse_netrc (char *file)
{
- FILE *fp;
- char *p, *tok, *premature_token;
- netrc_entry *current, *retval;
- dynamic_string line;
- int ln;
-
- /* The latest token we've seen in the file. */
- enum
- {
- tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
- } last_token = tok_nothing;
-
- current = retval = NULL;
-
- fp = fopen (file, "r");
- if (!fp)
+ FILE *fp;
+ char buf[POPBUFSIZE+1], *p, *tok;
+ const char *premature_token;
+ netrc_entry *current, *retval;
+ int ln;
+
+ /* The latest token we've seen in the file. */
+ enum
{
- /* Just return NULL if we can't open the file. */
- return NULL;
+ tok_nothing, tok_account, tok_login, tok_macdef, tok_machine, tok_password
+ } last_token = tok_nothing;
+
+ current = retval = NULL;
+
+ fp = fopen (file, "r");
+ if (!fp)
+ {
+ /* Just return NULL if we can't open the file. */
+ return NULL;
}
- /* Initialize the file data. */
- ln = 0;
- premature_token = NULL;
+ /* Initialize the file data. */
+ ln = 0;
+ premature_token = NULL;
- /* While there are lines in the file... */
- ds_init (&line, DS_INIT_LENGTH);
- while (ds_fgets (fp, &line))
+ /* While there are lines in the file... */
+ while (fgets(buf, sizeof(buf) - 1, fp))
{
- ln ++;
+ ln++;
- /* Parse the line. */
- p = line.ds_string;
+ /* Strip trailing CRLF */
+ for (p = buf + strlen(buf) - 1; (p >= buf) && isspace((unsigned char)*p); p--)
+ *p = '\0';
- /* If the line is empty, then end any macro definition. */
- if (last_token == tok_macdef && !*p)
- /* End of macro if the line is empty. */
- last_token = tok_nothing;
+ /* Parse the line. */
+ p = buf;
- /* If we are defining macros, then skip parsing the line. */
- while (*p && last_token != tok_macdef)
+ /* If the line is empty... */
+ if (!*p)
{
- /* Skip any whitespace. */
- while (*p && isspace (*p))
- p ++;
+ if (last_token == tok_macdef) /* end of macro */
+ last_token = tok_nothing;
+ else
+ continue; /* otherwise ignore it */
+ }
- /* Discard end-of-line comments. */
- if (*p == '#')
- break;
+ /* If we are defining macros, then skip parsing the line. */
+ while (*p && last_token != tok_macdef)
+ {
+ char quote_char = 0;
+ char *pp;
+
+ /* Skip any whitespace. */
+ while (*p && isspace ((unsigned char)*p))
+ p++;
- tok = p;
+ /* Discard end-of-line comments. */
+ if (*p == '#')
+ break;
- /* Find the end of the token. */
- while (*p && !isspace (*p))
- p ++;
+ tok = pp = p;
- /* Null-terminate the token, if it isn't already. */
- if (*p)
- *p ++ = '\0';
+ /* Find the end of the token. */
+ while (*p && (quote_char || !isspace ((unsigned char)*p)))
+ {
+ if (quote_char)
+ {
+ if (quote_char == *p)
+ {
+ quote_char = 0;
+ p ++;
+ }
+ else
+ {
+ *pp = *p;
+ p ++;
+ pp ++;
+ }
+ }
+ else
+ {
+ if (*p == '"' || *p == '\'')
+ quote_char = *p;
+ else
+ {
+ *pp = *p;
+ pp ++;
+ }
+ p ++;
+ }
+ }
+ /* Null-terminate the token, if it isn't already. */
+ if (*p)
+ *p ++ = '\0';
+ *pp = 0;
- switch (last_token)
+ switch (last_token)
{
case tok_login:
- if (current)
- current->account = (char *) xstrdup (tok);
- else
- premature_token = "login";
- break;
+ if (current)
+ current->login = (char *) xstrdup (tok);
+ else
+ premature_token = "login";
+ break;
case tok_machine:
- /* Start a new machine entry. */
- maybe_add_to_list (¤t, &retval);
- current->host = (char *) xstrdup (tok);
- break;
+ /* Start a new machine entry. */
+ maybe_add_to_list (¤t, &retval);
+ current->host = (char *) xstrdup (tok);
+ break;
case tok_password:
- if (current)
- current->password = (char *) xstrdup (tok);
- else
- premature_token = "password";
- break;
+ if (current)
+ current->password = (char *) xstrdup (tok);
+ else
+ premature_token = "password";
+ break;
- /* We handle most of tok_macdef above. */
+ /* We handle most of tok_macdef above. */
case tok_macdef:
- if (!current)
- premature_token = "macdef";
- break;
+ if (!current)
+ premature_token = "macdef";
+ break;
- /* We don't handle the account keyword at all. */
+ /* We don't handle the account keyword at all. */
case tok_account:
- if (!current)
- premature_token = "account";
- break;
+ if (!current)
+ premature_token = "account";
+ break;
- /* We handle tok_nothing below this switch. */
+ /* We handle tok_nothing below this switch. */
case tok_nothing:
- break;
+ break;
}
- if (premature_token)
+ if (premature_token)
{
-#ifdef HAVE_ERROR
- error_at_line (0, 0, file, ln,
- _("warning: found \"%s\" before any host names"),
- premature_token);
-#else
- fprintf (stderr,
- "%s:%d: warning: found \"%s\" before any host names\n",
- file, ln, premature_token);
-#endif
- premature_token = NULL;
+ fprintf (stderr,
+ GT_("%s:%d: warning: found \"%s\" before any host names\n"),
+ file, ln, premature_token);
+ premature_token = NULL;
}
- if (last_token != tok_nothing)
- /* We got a value, so reset the token state. */
- last_token = tok_nothing;
- else
+ if (last_token != tok_nothing)
+ /* We got a value, so reset the token state. */
+ last_token = tok_nothing;
+ else
{
- /* Fetch the next token. */
- if (!strcmp (tok, "account"))
- last_token = tok_account;
-
- if (!strcmp (tok, "default"))
+ /* Fetch the next token. */
+ if (!strcmp (tok, "default"))
{
- maybe_add_to_list (¤t, &retval);
+ maybe_add_to_list (¤t, &retval);
}
- else if (!strcmp (tok, "login"))
- last_token = tok_login;
+ else if (!strcmp (tok, "login"))
+ last_token = tok_login;
+
+ else if (!strcmp (tok, "user"))
+ last_token = tok_login;
+
+ else if (!strcmp (tok, "macdef"))
+ last_token = tok_macdef;
+
+ else if (!strcmp (tok, "machine"))
+ last_token = tok_machine;
- else if (!strcmp (tok, "macdef"))
- last_token = tok_macdef;
+ else if (!strcmp (tok, "password"))
+ last_token = tok_password;
- else if (!strcmp (tok, "machine"))
- last_token = tok_machine;
+ else if (!strcmp (tok, "passwd"))
+ last_token = tok_password;
- else if (!strcmp (tok, "password"))
- last_token = tok_password;
+ else if (!strcmp (tok, "account"))
+ last_token = tok_account;
- else
+ else
{
- fprintf (stderr, _("%s:%d: warning: unknown token \"%s\"\n"),
- file, ln, tok);
+ fprintf (stderr, GT_("%s:%d: warning: unknown token \"%s\"\n"),
+ file, ln, tok);
}
}
}
}
- ds_destroy (&line);
- fclose (fp);
+ fclose (fp);
- /* Finalize the last machine entry we found. */
- maybe_add_to_list (¤t, &retval);
- free (current);
+ /* Finalize the last machine entry we found. */
+ maybe_add_to_list (¤t, &retval);
+ free (current);
- /* Reverse the order of the list so that it appears in file order. */
- current = retval;
- retval = NULL;
- while (current)
+ /* Reverse the order of the list so that it appears in file order. */
+ current = retval;
+ retval = NULL;
+ while (current)
{
- netrc_entry *saved_reference;
+ netrc_entry *saved_reference;
- /* Change the direction of the pointers. */
- saved_reference = current->next;
- current->next = retval;
+ /* Change the direction of the pointers. */
+ saved_reference = current->next;
+ current->next = retval;
- /* Advance to the next node. */
- retval = current;
- current = saved_reference;
+ /* Advance to the next node. */
+ retval = current;
+ current = saved_reference;
}
- return retval;
+ return retval;
}
/* Return the netrc entry from LIST corresponding to HOST. NULL is
returned if no such entry exists. */
netrc_entry *
-search_netrc (list, host)
- netrc_entry *list;
- char *host;
+search_netrc (netrc_entry *list, char *host, char *login)
{
- /* Look for the HOST in LIST. */
- while (list)
+ /* Look for the HOST in LIST. */
+ while (list)
{
- if (!list->host)
- /* We hit the default entry. */
- break;
+ if (list->host && !strcmp(list->host, host))
+ if (!list->login || !strcmp(list->login, login))
+ /* We found a matching entry. */
+ break;
- else if (!strcmp (list->host, host))
- /* We found a matching entry. */
- break;
-
- list = list->next;
+ list = list->next;
}
- /* Return the matching entry, or NULL. */
- return list;
+ /* Return the matching entry, or NULL. */
+ return list;
}
+void
+free_netrc(netrc_entry *a) {
+ while(a) {
+ netrc_entry *n = a->next;
+ if (a->password != NULL) {
+ memset(a->password, 0x55, strlen(a->password));
+ free(a->password);
+ }
+ xfree(a->login);
+ xfree(a->host);
+ xfree(a);
+ a = n;
+ }
+}
#ifdef STANDALONE
#include <sys/types.h>
#include <sys/stat.h>
-extern int errno;
+#include <errno.h>
-int
-main (argc, argv)
- int argc;
- char **argv;
+int main (int argc, char **argv)
{
- struct stat sb;
- char *program_name, *file, *target;
- netrc_entry *head, *a;
-
- if (argc < 2)
- {
- fprintf (stderr, "Usage: %s NETRC [HOSTNAME]...\n", argv[0]);
- exit (1);
+ struct stat sb;
+ char *file, *host, *login;
+ netrc_entry *head, *a;
+
+ program_name = argv[0];
+ file = argv[1];
+ host = argv[2];
+ login = argv[3];
+
+ switch (argc) {
+ case 2:
+ case 4:
+ break;
+ default:
+ fprintf (stderr, "Usage: %s <file> [<host> <login>]\n", argv[0]);
+ exit(EXIT_FAILURE);
}
- program_name = argv[0];
- file = argv[1];
- target = argv[2];
-
- if (stat (file, &sb))
+ if (stat (file, &sb))
{
- fprintf (stderr, "%s: cannot stat %s: %s\n", argv[0], file,
- strerror (errno));
- exit (1);
+ fprintf (stderr, "%s: cannot stat %s: %s\n", argv[0], file,
+ strerror (errno));
+ exit (1);
}
- head = parse_netrc (file);
- if (!head)
+ head = parse_netrc (file);
+ if (!head)
{
- fprintf (stderr, "%s: no entries found in %s\n", argv[0], file);
- exit (1);
+ fprintf (stderr, "%s: no entries found in %s\n", argv[0], file);
+ exit (1);
}
- if (argc > 2)
+ if (host && login)
{
- int i, status;
- status = 0;
- for (i = 2; i < argc; i++)
- {
- /* Print out the host that we are checking for. */
- fputs (argv[i], stdout);
+ int status;
+ status = EXIT_SUCCESS;
- a = search_netrc (head, argv[i]);
- if (a)
+ printf("Host: %s, Login: %s\n", host, login);
+
+ a = search_netrc (head, host, login);
+ if (a)
+ {
+ /* Print out the password (if any). */
+ if (a->password)
{
- /* Print out the account and password (if any). */
- fputc (' ', stdout);
- fputs (a->account, stdout);
- if (a->password)
- {
- fputc (' ', stdout);
- fputs (a->password, stdout);
- }
+ printf("Password: %s\n", a->password);
}
- else
- status = 1;
+ } else
+ status = EXIT_FAILURE;
+ fputc ('\n', stdout);
- fputc ('\n', stdout);
- }
- exit (status);
+ exit (status);
}
- /* Print out the entire contents of the netrc. */
- a = head;
- while (a)
+ /* Print out the entire contents of the netrc. */
+ a = head;
+ while (a)
{
- /* Print the host name. */
- if (a->host)
- fputs (a->host, stdout);
- else
- fputs ("DEFAULT", stdout);
+ /* Print the host name. */
+ if (a->host)
+ fputs (a->host, stdout);
+ else
+ fputs ("DEFAULT", stdout);
- fputc (' ', stdout);
+ fputc (' ', stdout);
- /* Print the account name. */
- fputs (a->account, stdout);
+ /* Print the login name. */
+ fputs (a->login, stdout);
- if (a->password)
+ if (a->password)
{
- /* Print the password, if there is any. */
- fputc (' ', stdout);
- fputs (a->password, stdout);
+ /* Print the password, if there is any. */
+ fputc (' ', stdout);
+ fputs (a->password, stdout);
}
- fputc ('\n', stdout);
- a = a->next;
+ fputc ('\n', stdout);
+ a = a->next;
}
- exit (0);
+ free_netrc(head);
+
+ exit (0);
}
#endif /* STANDALONE */