summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--modules/pam_access/pam_access.c54
2 files changed, 45 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index 07f9f8b9..80cda12c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2011-10-10 Tomas Mraz <tm@t8m.info>
+
+ * modules/pam_access/pam_access.c: Add hostname resolution
+ cache.
+ (user_match): Clear the cache in fake_item.
+ (from_match): If from is not hostname, do not try to resolve it.
+ Cache the getaddrinfo() result.
+ (network_netmask_match): Cache the getaddrinfo() result.
+ (pam_sm_authenticate): Free the getaddrinfo() result.
+
2011-09-30 Tomas Mraz <tm@t8m.info>
* doc/man/pam.conf-syntax.xml: Improve documentation of the
diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c
index 472116c3..35b7d058 100644
--- a/modules/pam_access/pam_access.c
+++ b/modules/pam_access/pam_access.c
@@ -106,6 +106,8 @@ struct login_info {
const char *fs; /* field separator */
const char *sep; /* list-element separator */
int from_remote_host; /* If PAM_RHOST was used for from */
+ struct addrinfo *res; /* Cached DNS resolution of from */
+ int gai_rv; /* Cached retval of getaddrinfo */
};
/* Parse module config arguments */
@@ -168,7 +170,7 @@ static int user_match (pam_handle_t *, char *, struct login_info *);
static int group_match (pam_handle_t *, const char *, const char *, int);
static int from_match (pam_handle_t *, char *, struct login_info *);
static int string_match (pam_handle_t *, const char *, const char *, int);
-static int network_netmask_match (pam_handle_t *, const char *, const char *, int);
+static int network_netmask_match (pam_handle_t *, const char *, const char *, struct login_info *);
/* isipaddr - find out if string provided is an IP address or not */
@@ -530,9 +532,16 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item)
return NO;
memcpy (&fake_item, item, sizeof(fake_item));
fake_item.from = item->hostname;
+ fake_item.gai_rv = 0;
+ fake_item.res = NULL;
+ fake_item.from_remote_host = 1; /* hostname should be resolvable */
*at = 0;
- return (user_match (pamh, tok, item) &&
- from_match (pamh, at + 1, &fake_item));
+ if (!user_match (pamh, tok, item))
+ return NO;
+ rv = from_match (pamh, at + 1, &fake_item);
+ if (fake_item.gai_rv == 0 && fake_item.res)
+ freeaddrinfo(fake_item.res);
+ return rv;
} else if (tok[0] == '@') { /* netgroup */
const char *hostname = NULL;
if (tok[1] == '@') { /* add hostname to netgroup match */
@@ -616,22 +625,24 @@ from_match (pam_handle_t *pamh UNUSED, char *tok, struct login_info *item)
if ((str_len = strlen(string)) > (tok_len = strlen(tok))
&& strcasecmp(tok, string + str_len - tok_len) == 0)
return (YES);
- } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no PAM_RHOSTS */
- if (item->from_remote_host == 0)
+ } else if (item->from_remote_host == 0) { /* local: no PAM_RHOSTS */
+ if (strcasecmp(tok, "LOCAL") == 0)
return (YES);
} else if (tok[(tok_len = strlen(tok)) - 1] == '.') {
- struct addrinfo *res;
struct addrinfo hint;
memset (&hint, '\0', sizeof (hint));
hint.ai_flags = AI_CANONNAME;
hint.ai_family = AF_INET;
- if (getaddrinfo (string, NULL, &hint, &res) != 0)
+ if (item->gai_rv != 0)
+ return NO;
+ else if (!item->res &&
+ (item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0)
return NO;
else
{
- struct addrinfo *runp = res;
+ struct addrinfo *runp = item->res;
while (runp != NULL)
{
@@ -647,17 +658,15 @@ from_match (pam_handle_t *pamh UNUSED, char *tok, struct login_info *item)
if (strncmp(tok, buf, tok_len) == 0)
{
- freeaddrinfo (res);
return YES;
}
}
runp = runp->ai_next;
}
- freeaddrinfo (res);
}
} else {
/* Assume network/netmask with a IP of a host. */
- if (network_netmask_match(pamh, tok, string, item->debug))
+ if (network_netmask_match(pamh, tok, string, item))
return YES;
}
@@ -700,13 +709,13 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
*/
static int
network_netmask_match (pam_handle_t *pamh,
- const char *tok, const char *string, int debug)
+ const char *tok, const char *string, struct login_info *item)
{
char *netmask_ptr;
char netmask_string[MAXHOSTNAMELEN + 1];
int addr_type;
- if (debug)
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG,
"network_netmask_match: tok=%s, item=%s", tok, string);
/* OK, check if tok is of type addr/mask */
@@ -751,18 +760,20 @@ network_netmask_match (pam_handle_t *pamh,
if (isipaddr(string, NULL, NULL) != YES)
{
/* Assume network/netmask with a name of a host. */
- struct addrinfo *res;
struct addrinfo hint;
memset (&hint, '\0', sizeof (hint));
hint.ai_flags = AI_CANONNAME;
hint.ai_family = AF_UNSPEC;
- if (getaddrinfo (string, NULL, &hint, &res) != 0)
+ if (item->gai_rv != 0)
+ return NO;
+ else if (!item->res &&
+ (item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0)
return NO;
else
{
- struct addrinfo *runp = res;
+ struct addrinfo *runp = item->res;
while (runp != NULL)
{
@@ -776,12 +787,10 @@ network_netmask_match (pam_handle_t *pamh,
if (are_addresses_equal(buf, tok, netmask_ptr))
{
- freeaddrinfo (res);
return YES;
}
runp = runp->ai_next;
}
- freeaddrinfo (res);
}
}
else
@@ -803,6 +812,7 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
const char *from;
struct passwd *user_pw;
char hostname[MAXHOSTNAMELEN + 1];
+ int rv;
/* set username */
@@ -819,6 +829,7 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
/*
* Bundle up the arguments to avoid unnecessary clumsiness later on.
*/
+ memset(&loginfo, '\0', sizeof(loginfo));
loginfo.user = user_pw;
loginfo.config_file = PAM_ACCESS_CONFIG;
@@ -889,7 +900,12 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
loginfo.hostname = NULL;
}
- if (login_access(pamh, &loginfo)) {
+ rv = login_access(pamh, &loginfo);
+
+ if (loginfo.gai_rv == 0 && loginfo.res)
+ freeaddrinfo(loginfo.res);
+
+ if (rv) {
return (PAM_SUCCESS);
} else {
pam_syslog(pamh, LOG_ERR,