X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=support%2Fmisc%2Ftcpwrapper.c;h=e9eb1df91a3063c39f3e8b348125e0d92f09ee2d;hp=e4f453bc93c6a95ca2de560b865037064751ae54;hb=4cacc965afc4fb03a465ffcc6cb3078aeadc3818;hpb=ad1fc3feae447685a8ec8c7db0ad913fe3c4de5c diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c index e4f453b..e9eb1df 100644 --- a/support/misc/tcpwrapper.c +++ b/support/misc/tcpwrapper.c @@ -44,6 +44,12 @@ #include #include #include +#include +#include +#include + +#include "xlog.h" + #ifdef SYSV40 #include #include @@ -52,6 +58,8 @@ static void logit(int severity, struct sockaddr_in *addr, u_long procnum, u_long prognum, char *text); static void toggle_verboselog(int sig); +static int check_files(void); + int verboselog = 0; int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; @@ -86,6 +94,79 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user) #define log_client(addr, proc, prog) \ logit(allow_severity, addr, proc, prog, "") +#define ALLOW 1 +#define DENY 0 + +typedef struct _haccess_t { + TAILQ_ENTRY(_haccess_t) list; + int access; + struct in_addr addr; +} haccess_t; + +#define HASH_TABLE_SIZE 1021 +typedef struct _hash_head { + TAILQ_HEAD(host_list, _haccess_t) h_head; +} hash_head; +hash_head haccess_tbl[HASH_TABLE_SIZE]; +static haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long, u_long); +static void haccess_add(struct sockaddr_in *addr, u_long, u_long, int); + +inline unsigned int strtoint(char *str) +{ + unsigned int n = 0; + int len = strlen(str); + int i; + + for (i=0; i < len; i++) + n+=((int)str[i])*i; + + return n; +} +static inline int hashint(unsigned int num) +{ + return num % HASH_TABLE_SIZE; +} +#define HASH(_addr, _proc, _prog) \ + hashint((strtoint((_addr))+(_proc)+(_prog))) + +void haccess_add(struct sockaddr_in *addr, u_long proc, + u_long prog, int access) +{ + hash_head *head; + haccess_t *hptr; + int hash; + + hptr = (haccess_t *)malloc(sizeof(haccess_t)); + if (hptr == NULL) + return; + + hash = HASH(inet_ntoa(addr->sin_addr), proc, prog); + head = &(haccess_tbl[hash]); + + hptr->access = access; + hptr->addr.s_addr = addr->sin_addr.s_addr; + + if (TAILQ_EMPTY(&head->h_head)) + TAILQ_INSERT_HEAD(&head->h_head, hptr, list); + else + TAILQ_INSERT_TAIL(&head->h_head, hptr, list); +} +haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long proc, u_long prog) +{ + hash_head *head; + haccess_t *hptr; + int hash; + + hash = HASH(inet_ntoa(addr->sin_addr), proc, prog); + head = &(haccess_tbl[hash]); + + TAILQ_FOREACH(hptr, &head->h_head, list) { + if (hptr->addr.s_addr == addr->sin_addr.s_addr) + return hptr; + } + return NULL; +} + int good_client(daemon, addr) char *daemon; @@ -95,47 +176,54 @@ struct sockaddr_in *addr; char **sp; char *tmpname; - /* Check the IP address first. */ - if (hosts_ctl(daemon, "", inet_ntoa(addr->sin_addr), "")) - return 1; - - /* Check the hostname. */ - hp = gethostbyaddr ((const char *) &(addr->sin_addr), - sizeof (addr->sin_addr), AF_INET); + /* First check the address. */ + if (hosts_ctl(daemon, "", inet_ntoa(addr->sin_addr), "") == DENY) + return DENY; + + /* Now do the hostname lookup */ + hp = gethostbyaddr ((const char *) &(addr->sin_addr), + sizeof (addr->sin_addr), AF_INET); + if (!hp) { + xlog(L_WARNING, + "Warning: Client IP address '%s' not found in host lookup", + inet_ntoa(addr->sin_addr)); + return DENY; /* never heard of it. misconfigured DNS? */ + } - if (!hp) - return 0; + /* Make sure the hostent is authorative. */ + tmpname = strdup(hp->h_name); + if (!tmpname) { + xlog(L_WARNING, "Warning: No memory for Host access check"); + return DENY; + } + hp = gethostbyname(tmpname); + if (!hp) { + xlog(L_WARNING, + "Warning: Client hostname '%s' not found in host lookup", tmpname); + free(tmpname); + return DENY; /* never heard of it. misconfigured DNS? */ + } + free(tmpname); - /* must make sure the hostent is authorative. */ - tmpname = alloca (strlen (hp->h_name) + 1); - strcpy (tmpname, hp->h_name); - hp = gethostbyname(tmpname); - if (hp) { - /* now make sure the "addr->sin_addr" is on the list */ + /* Now make sure the address is on the list */ for (sp = hp->h_addr_list ; *sp ; sp++) { - if (memcmp(*sp, &(addr->sin_addr), hp->h_length)==0) - break; + if (memcmp(*sp, &(addr->sin_addr), hp->h_length) == 0) + break; } if (!*sp) - /* it was a FAKE. */ - return 0; - } - else - /* never heard of it. misconfigured DNS? */ - return 0; - - /* Check the official name first. */ - if (hosts_ctl(daemon, hp->h_name, "", "")) - return 1; - - /* Check aliases. */ - for (sp = hp->h_aliases; *sp ; sp++) { - if (hosts_ctl(daemon, *sp, "", "")) - return 1; - } - - /* No match */ - return 0; + return DENY; /* it was a FAKE. */ + + /* Check the official name and address. */ + if (hosts_ctl(daemon, hp->h_name, inet_ntoa(addr->sin_addr), "") == DENY) + return DENY; + + /* Now check aliases. */ + for (sp = hp->h_aliases; *sp ; sp++) { + if (hosts_ctl(daemon, *sp, inet_ntoa(addr->sin_addr), "") == DENY) + return DENY; + } + + return ALLOW; } /* check_startup - additional startup code */ @@ -175,6 +263,33 @@ void check_startup(void) (void) signal(SIGINT, toggle_verboselog); } +/* check_files - check to see if either access files have changed */ + +static int check_files() +{ + static time_t allow_mtime, deny_mtime; + struct stat astat, dstat; + int changed = 0; + + if (stat("/etc/hosts.allow", &astat) < 0) + astat.st_mtime = 0; + if (stat("/etc/hosts.deny", &dstat) < 0) + dstat.st_mtime = 0; + + if(!astat.st_mtime || !dstat.st_mtime) + return changed; + + if (astat.st_mtime != allow_mtime) + changed = 1; + else if (dstat.st_mtime != deny_mtime) + changed = 1; + + allow_mtime = astat.st_mtime; + deny_mtime = dstat.st_mtime; + + return changed; +} + /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */ int @@ -184,12 +299,28 @@ struct sockaddr_in *addr; u_long proc; u_long prog; { - if (!(from_local(addr) || good_client(daemon, addr))) { - log_bad_host(addr, proc, prog); - return (FALSE); - } - if (verboselog) - log_client(addr, proc, prog); + haccess_t *acc = NULL; + int changed = check_files(); + + acc = haccess_lookup(addr, proc, prog); + if (acc && changed == 0) + return (acc->access); + + if (!(from_local(addr) || good_client(daemon, addr))) { + log_bad_host(addr, proc, prog); + if (acc) + acc->access = FALSE; + else + haccess_add(addr, proc, prog, FALSE); + return (FALSE); + } + if (verboselog) + log_client(addr, proc, prog); + + if (acc) + acc->access = TRUE; + else + haccess_add(addr, proc, prog, TRUE); return (TRUE); }