From 6eaacb1584c11373d96313dd17f72ab89cf5654d Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 10 Oct 2011 14:02:10 +0200 Subject: Add hostname resolution cache. --- modules/pam_access/pam_access.c | 54 ++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'modules/pam_access') 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, -- cgit v1.2.3