summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Dickson <steved@redhat.com>2008-12-19 14:11:09 -0500
committerSteve Dickson <steved@redhat.com>2008-12-19 14:11:09 -0500
commit58e0a308fec476361dd21f7d3856faceb6e308ee (patch)
tree9490890b9a56bad3355361c2e8454f8e89234440
parente47da19d63ea50a4e15f6ab491535d54097744de (diff)
downloadnfs-utils-58e0a308fec476361dd21f7d3856faceb6e308ee.tar.gz
nfs-utils-58e0a308fec476361dd21f7d3856faceb6e308ee.tar.xz
nfs-utils-58e0a308fec476361dd21f7d3856faceb6e308ee.zip
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 <steved@redhat.com>
-rw-r--r--support/misc/tcpwrapper.c79
1 files changed, 79 insertions, 0 deletions
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 <pwd.h>
#include <sys/types.h>
#include <sys/signal.h>
+#include <sys/queue.h>
#ifdef SYSV40
#include <netinet/in.h>
#include <rpc/rpcent.h>
@@ -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);
}