]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/misc/tcpwrapper.c
Clients IP address and host names are check on
[nfs-utils.git] / support / misc / tcpwrapper.c
index d8a742f49da0af6c9fec8a0262bcf89c8f28606f..f7fd3a9cd2d1bfe5dc13051e00bbd42c7771262c 100644 (file)
   * Computing Science, Eindhoven University of Technology, The Netherlands.
   */
 
-#include "tcpwrapper.h"
-
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <tcpwrapper.h>
 #include <unistd.h>
 #include <string.h>
 #include <rpc/rpc.h>
 #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>
 #endif
 
-static void logit();
-static void toggle_verboselog();
+static void logit(int severity, struct sockaddr_in *addr,
+                 u_long procnum, u_long prognum, char *text);
+static void toggle_verboselog(int sig);
 int     verboselog = 0;
 int     allow_severity = LOG_INFO;
 int     deny_severity = LOG_WARNING;
 
 /* A handful of macros for "readability". */
 
+#ifdef HAVE_LIBWRAP
 /* coming from libwrap.a (tcp_wrappers) */
 extern int hosts_ctl(char *daemon, char *name, char *addr, char *user);
+#else
+int hosts_ctl(char *daemon, char *name, char *addr, char *user)
+{
+       return 0;
+}
+#endif
 
 #define        legal_port(a,p) \
   (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
@@ -76,6 +87,79 @@ extern 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;
+}
+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;
@@ -85,52 +169,49 @@ 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);
-
-    if (!hp)
-       return 0;
-
-    /* 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 */
+       /* 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)
+               return DENY; /* never heard of it. misconfigured DNS? */
+
+       /* Make sure the hostent is authorative. */
+       tmpname = strdup(hp->h_name);
+       if (!tmpname)
+               return DENY;
+       hp = gethostbyname(tmpname);
+       free(tmpname);
+       if (!hp)
+               return DENY; /* never heard of it. misconfigured DNS? */
+
+       /* 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 */
 
-void    check_startup()
+void    check_startup(void)
 {
 
     /*
@@ -174,22 +255,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;
+
+       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);
 }
 
 /* check_privileged_port - additional checks for privileged-port updates */
 int
-check_privileged_port(addr, proc, prog, port)
-struct sockaddr_in *addr;
-u_long  proc;
-u_long  prog;
-u_long  port;
+check_privileged_port(struct sockaddr_in *addr,        
+                     u_long proc, u_long prog, u_long port)
 {
 #ifdef CHECK_PORT
     if (!legal_port(addr, port)) {
@@ -202,8 +289,7 @@ u_long  port;
 
 /* toggle_verboselog - toggle verbose logging flag */
 
-static void toggle_verboselog(sig)
-int     sig;
+static void toggle_verboselog(int sig)
 {
     (void) signal(sig, toggle_verboselog);
     verboselog = !verboselog;
@@ -211,12 +297,8 @@ int     sig;
 
 /* logit - report events of interest via the syslog daemon */
 
-static void logit(severity, addr, procnum, prognum, text)
-int     severity;
-struct sockaddr_in *addr;
-u_long  procnum;
-u_long  prognum;
-char   *text;
+static void logit(int severity, struct sockaddr_in *addr,
+                 u_long procnum, u_long prognum, char *text)
 {
     char   *procname;
     char    procbuf[16 + 4 * sizeof(u_long)];