From: Steve Dickson Date: Fri, 19 Dec 2008 19:11:09 +0000 (-0500) Subject: Clients IP address and host names are check on X-Git-Tag: nfs-utils-1-1-5~38 X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=58e0a308fec476361dd21f7d3856faceb6e308ee;p=nfs-utils.git Clients IP address and host names are check on every RPC request, to both mountd and statd when TCP wrappers are enabled. To help this process scale better the access rights are stored in a hash table, which are hashed per IP address, RPC program and procudure numbers. Signed-off-by: Steve Dickson --- diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c index ceea5ce..f7fd3a9 100644 --- a/support/misc/tcpwrapper.c +++ b/support/misc/tcpwrapper.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef SYSV40 #include #include @@ -89,6 +90,76 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user) #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; +} +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; @@ -184,13 +255,21 @@ struct sockaddr_in *addr; u_long proc; u_long prog; { + haccess_t *acc = NULL; + + acc = haccess_lookup(addr, proc, prog); + if (acc) + return (acc->access); + if (!(from_local(addr) || good_client(daemon, addr))) { log_bad_host(addr, proc, prog); + haccess_add(addr, proc, prog, FALSE); return (FALSE); } if (verboselog) log_client(addr, proc, prog); + haccess_add(addr, proc, prog, TRUE); return (TRUE); }