1
1

* ftpfs.c (ftp_split_url): Don't expect lookup_netrc() to always

return a username.
(netrc_has_incorrect_mode): Don't free anything, it can result
in freeing some variables twice.
(find_machine): New function to find matching "machine" or
"default" token.
(lookup_netrc): Eliminate external loop - scan for login and
password, but don't fallback to another string in case of
trouble.
Этот коммит содержится в:
Pavel Roskin 2002-07-12 23:20:03 +00:00
родитель 14bac1dda4
Коммит e88191dd7c
2 изменённых файлов: 166 добавлений и 98 удалений

Просмотреть файл

@ -1,5 +1,15 @@
2002-07-12 Pavel Roskin <proski@gnu.org> 2002-07-12 Pavel Roskin <proski@gnu.org>
* ftpfs.c (ftp_split_url): Don't expect lookup_netrc() to always
return a username.
(netrc_has_incorrect_mode): Don't free anything, it can result
in freeing some variables twice.
(find_machine): New function to find matching "machine" or
"default" token.
(lookup_netrc): Eliminate external loop - scan for login and
password, but don't fallback to another string in case of
trouble.
* ftpfs.c: Introduce enum keyword_t to improve readability. * ftpfs.c: Introduce enum keyword_t to improve readability.
(netrc_next): Fix return value for unknown keywords. (netrc_next): Fix return value for unknown keywords.
(lookup_netrc): Remove special processing of "*netrc*". (lookup_netrc): Remove special processing of "*netrc*".

Просмотреть файл

@ -228,7 +228,7 @@ ftp_split_url(char *path, char **host, char **user, int *port, char **pass)
if (!*user) { if (!*user) {
if (use_netrc) if (use_netrc)
lookup_netrc (*host, user, pass); lookup_netrc (*host, user, pass);
else if (!*user)
*user = g_strdup ("anonymous"); *user = g_strdup ("anonymous");
} }
@ -1829,23 +1829,23 @@ typedef enum {
NETRC_PASSWD, NETRC_PASSWD,
NETRC_ACCOUNT, NETRC_ACCOUNT,
NETRC_MACDEF, NETRC_MACDEF,
NETRC_UNKNOWN, NETRC_UNKNOWN
NETRC_BREAK = 20
} keyword_t; } keyword_t;
static keyword_t netrc_next (void) static keyword_t netrc_next (void)
{ {
char *p; char *p;
keyword_t i; keyword_t i;
static const char * const keywords [] = { "default", "machine", static const char *const keywords[] = { "default", "machine",
"login", "password", "passwd", "account", "macdef", NULL }; "login", "password", "passwd", "account", "macdef", NULL
};
while (1) { while (1) {
netrcp = skip_separators (netrcp); netrcp = skip_separators (netrcp);
if (*netrcp != '\n') if (*netrcp != '\n')
break; break;
netrcp++; netrcp++;
} }
if (!*netrcp) if (!*netrcp)
return NETRC_NONE; return NETRC_NONE;
@ -1857,8 +1857,8 @@ static keyword_t netrc_next (void)
*p++ = *netrcp; *p++ = *netrcp;
} }
} else { } else {
for (;*netrcp != '\n' && *netrcp != '\t' && *netrcp != ' ' && for (; *netrcp != '\n' && *netrcp != '\t' && *netrcp != ' ' &&
*netrcp != ',' && *netrcp; netrcp++) { *netrcp != ',' && *netrcp; netrcp++) {
if (*netrcp == '\\') if (*netrcp == '\\')
netrcp++; netrcp++;
*p++ = *netrcp; *p++ = *netrcp;
@ -1869,35 +1869,89 @@ static keyword_t netrc_next (void)
return 0; return 0;
i = NETRC_DEFAULT; i = NETRC_DEFAULT;
while (keywords [i - 1]) { while (keywords[i - 1]) {
if (!strcmp (keywords [i - 1], buffer)) if (!strcmp (keywords[i - 1], buffer))
return i; return i;
i++; i++;
} }
return NETRC_UNKNOWN; return NETRC_UNKNOWN;
} }
static int netrc_has_incorrect_mode (char * netrcname, char * netrc) static int netrc_has_incorrect_mode (char *netrcname, char *netrc)
{ {
static int be_angry = 1; static int be_angry = 1;
struct stat mystat; struct stat mystat;
if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077)) { if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077)) {
if (be_angry) { if (be_angry) {
message_1s (1, MSG_ERROR, _("~/.netrc file has not correct mode.\n" message_1s (1, MSG_ERROR,
"Remove password or correct mode.")); _("~/.netrc file has not correct mode.\n"
"Remove password or correct mode."));
be_angry = 0; be_angry = 0;
} }
g_free (netrc);
g_free (netrcname);
return 1; return 1;
} }
return 0; return 0;
} }
/* Extract login and password from .netrc for the host */ /* Scan .netrc until we find matching "machine" or "default"
* domain is used for additional matching
* No search is done after "default" in compliance with "man netrc"
* Return 0 if found, -1 otherwise */
static int find_machine (const char *host, const char *domain)
{
keyword_t keyword;
while ((keyword = netrc_next ()) != NETRC_NONE) {
if (keyword == NETRC_DEFAULT)
return 0;
if (keyword == NETRC_MACDEF) {
/* Scan for an empty line, which concludes "macdef" */
do {
while (*netrcp && *netrcp != '\n')
netrcp++;
if (*netrcp != '\n')
break;
netrcp++;
} while (*netrcp && *netrcp != '\n');
continue;
}
if (keyword != NETRC_MACHINE)
continue;
/* Take machine name */
if (netrc_next () == NETRC_NONE)
break;
if (g_strcasecmp (host, buffer)) {
/* Try adding our domain to short names in .netrc */
char *host_domain = strchr (host, '.');
if (!host_domain)
continue;
/* Compare domain part */
if (g_strcasecmp (host_domain, domain))
continue;
/* Compare local part */
if (g_strncasecmp (host, buffer, host_domain - host))
continue;
}
return 0;
}
/* end of .netrc */
return -1;
}
/* Extract login and password from .netrc for the host.
* pass may be NULL.
* Returns 0 for success, -1 for error */
static int lookup_netrc (const char *host, char **login, char **pass) static int lookup_netrc (const char *host, char **login, char **pass)
{ {
char *netrcname; char *netrcname;
@ -1905,102 +1959,106 @@ static int lookup_netrc (const char *host, char **login, char **pass)
char hostname[MAXHOSTNAMELEN], *domain; char hostname[MAXHOSTNAMELEN], *domain;
keyword_t keyword; keyword_t keyword;
static struct rupcache { static struct rupcache {
struct rupcache *next; struct rupcache *next;
char *host; char *host;
char *login; char *login;
char *pass; char *pass;
} *rup_cache = NULL, *rupp; } *rup_cache = NULL, *rupp;
/* Initialize *login and *pass */
if (!login)
return 0;
*login = NULL;
if (pass)
*pass = NULL;
/* Look up in the cache first */ /* Look up in the cache first */
for (rupp = rup_cache; rupp != NULL; rupp = rupp->next) { for (rupp = rup_cache; rupp != NULL; rupp = rupp->next) {
/* return from cache only if host AND user match! */ if (!strcmp (host, rupp->host)) {
if ((!strcmp (host, rupp->host)) && if (rupp->login)
(rupp->login != NULL) && *login = g_strdup (rupp->login);
(*login != NULL) && if (pass && rupp->pass)
(!strcmp(rupp->login, *login))) { *pass = g_strdup (rupp->pass);
*login = g_strdup (rupp->login); return 0;
if (pass && rupp->pass != NULL)
*pass = g_strdup (rupp->pass);
return 0;
} }
} }
/* Load current .netrc */
netrcname = concat_dir_and_file (home_dir, ".netrc"); netrcname = concat_dir_and_file (home_dir, ".netrc");
netrcp = netrc = load_file (netrcname); netrcp = netrc = load_file (netrcname);
if (netrc == NULL) { if (netrc == NULL) {
g_free (netrcname); g_free (netrcname);
return 0; return 0;
} }
/* Find our own domain name */
if (gethostname (hostname, sizeof (hostname)) < 0) if (gethostname (hostname, sizeof (hostname)) < 0)
*hostname = 0; *hostname = 0;
if (!(domain = strchr (hostname, '.'))) if (!(domain = strchr (hostname, '.')))
domain = ""; domain = "";
while ((keyword = netrc_next ())) { /* Scan for "default" and matching "machine" keywords */
if (keyword == NETRC_MACHINE) { find_machine (host, domain);
char *tmp;
if (netrc_next () != NETRC_UNKNOWN) /* Scan for keywords following "default" and "machine" */
continue; while (1) {
if (g_strcasecmp (host, buffer) && int need_break = 0;
((tmp = strchr (host, '.')) == NULL || keyword = netrc_next ();
g_strcasecmp (tmp, domain) ||
g_strncasecmp (host, buffer, tmp - host) ||
buffer [tmp - host]))
continue;
} else if (keyword != NETRC_DEFAULT)
continue;
while ((keyword = netrc_next ()) > NETRC_MACHINE) { switch (keyword) {
switch (keyword) { case NETRC_LOGIN:
case NETRC_LOGIN: if (netrc_next () == NETRC_NONE) {
if (netrc_next ()) { need_break = 1;
if (*login == NULL) break;
*login = g_strdup (buffer);
else if (strcmp (*login, buffer))
keyword = NETRC_BREAK;
}
break;
case NETRC_PASSWORD:
case NETRC_PASSWD:
if (strcmp (*login, "anonymous") && strcmp (*login, "ftp") &&
netrc_has_incorrect_mode (netrcname, netrc)) {
return -1;
}
if (netrc_next () && tmp_pass == NULL)
tmp_pass = g_strdup (buffer);
break;
case NETRC_ACCOUNT:
if (netrc_has_incorrect_mode (netrcname, netrc)) {
return -1;
}
netrc_next ();
break;
case NETRC_MACDEF: /* macdef: skip it */
do {
while (*netrcp && *netrcp != '\n')
netrcp++;
if (*netrcp != '\n')
break;
netrcp++;
} while (*netrcp && *netrcp != '\n');
break;
case NETRC_NONE:
case NETRC_DEFAULT:
case NETRC_MACHINE:
case NETRC_UNKNOWN:
case NETRC_BREAK:
break;
} }
if (keyword == NETRC_BREAK)
break; /* We have another name already - should not happen */
if (*login) {
need_break = 1;
break;
}
/* We have login name now */
*login = g_strdup (buffer);
break;
case NETRC_PASSWORD:
case NETRC_PASSWD:
if (netrc_next () == NETRC_NONE) {
need_break = 1;
break;
}
/* Ignore unsafe passwords */
if (strcmp (*login, "anonymous") && strcmp (*login, "ftp")
&& netrc_has_incorrect_mode (netrcname, netrc)) {
need_break = 1;
break;
}
/* Remember password. pass may be NULL, so use tmp_pass */
if (tmp_pass == NULL)
tmp_pass = g_strdup (buffer);
break;
case NETRC_ACCOUNT:
/* "account" is followed by a token which we ignore */
if (netrc_next () == NETRC_NONE) {
need_break = 1;
break;
}
/* Ignore account, but warn user anyways */
netrc_has_incorrect_mode (netrcname, netrc);
break;
default:
/* Unexpected keyword or end of file */
need_break = 1;
break;
} }
if (keyword != NETRC_BREAK)
if (need_break)
break; break;
} }
@ -2010,12 +2068,12 @@ static int lookup_netrc (const char *host, char **login, char **pass)
rupp = g_new (struct rupcache, 1); rupp = g_new (struct rupcache, 1);
rupp->host = g_strdup (host); rupp->host = g_strdup (host);
rupp->login = rupp->pass = 0; rupp->login = rupp->pass = 0;
if (*login != NULL) { if (*login != NULL) {
rupp->login = g_strdup (*login); rupp->login = g_strdup (*login);
} }
if (tmp_pass != NULL) if (tmp_pass != NULL)
rupp->pass = g_strdup (tmp_pass); rupp->pass = g_strdup (tmp_pass);
rupp->next = rup_cache; rupp->next = rup_cache;
rup_cache = rupp; rup_cache = rupp;