]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/misc/tcpwrapper.c
tcpwrapper: Fix signage problems in the tcp_wrappers hash function
[nfs-utils.git] / support / misc / tcpwrapper.c
index f7fd3a9cd2d1bfe5dc13051e00bbd42c7771262c..6f65c1375c4b1cfa5e2b18654604f20af649ce9f 100644 (file)
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
-#include <tcpwrapper.h>
+
+#ifdef HAVE_LIBWRAP
 #include <unistd.h>
 #include <string.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
-#include <syslog.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <sys/types.h>
 #include <sys/signal.h>
 #include <sys/queue.h>
+#include <sys/stat.h>
+#include <tcpd.h>
+
+#include "tcpwrapper.h"
+#include "xlog.h"
+
 #ifdef SYSV40
 #include <netinet/in.h>
 #include <rpc/rpcent.h>
 #endif
 
-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)
-
-#define log_bad_port(addr, proc, prog) \
-  logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
-
-#define log_bad_host(addr, proc, prog) \
-  logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
-
-#define log_bad_owner(addr, proc, prog) \
-  logit(deny_severity, addr, proc, prog, ": request from non-local host")
-
-#define        log_no_forward(addr, proc, prog) \
-  logit(deny_severity, addr, proc, prog, ": request not forwarded")
-
-#define log_client(addr, proc, prog) \
-  logit(allow_severity, addr, proc, prog, "")
+static int check_files(void);
 
 #define ALLOW 1
 #define DENY 0
@@ -101,39 +72,44 @@ 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);
+static haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long);
+static void haccess_add(struct sockaddr_in *addr, u_long, int);
 
-inline unsigned int strtoint(char *str)
+static unsigned long
+strtoint(const char *str)
 {
-       unsigned int n = 0;
-       int len = strlen(str);
-       int i;
+       unsigned long i, n = 0;
+       size_t len = strlen(str);
 
-       for (i=0; i < len; i++)
-               n+=((int)str[i])*i;
+       for (i = 0; i < len; i++)
+               n += (unsigned char)str[i] * i;
 
        return n;
 }
-inline int hashint(unsigned int num)
+
+static unsigned int
+hashint(const unsigned long num)
+{
+       return (unsigned int)(num % HASH_TABLE_SIZE);
+}
+
+static unsigned int
+HASH(const char *addr, const unsigned long program)
 {
-       return num % HASH_TABLE_SIZE;
+       return hashint(strtoint(addr) + program);
 }
-#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)
+void haccess_add(struct sockaddr_in *addr, u_long prog, int access)
 {
        hash_head *head;
-       haccess_t *hptr;
-       int hash;
+       haccess_t *hptr;
+       unsigned int hash;
 
        hptr = (haccess_t *)malloc(sizeof(haccess_t));
        if (hptr == NULL)
                return;
 
-       hash = HASH(inet_ntoa(addr->sin_addr), proc, prog);
+       hash = HASH(inet_ntoa(addr->sin_addr), prog);
        head = &(haccess_tbl[hash]);
 
        hptr->access = access;
@@ -144,13 +120,13 @@ void haccess_add(struct sockaddr_in *addr, u_long proc,
        else
                TAILQ_INSERT_TAIL(&head->h_head, hptr, list);
 }
-haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long proc, u_long prog)
+haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long prog)
 {
        hash_head *head;
-       haccess_t *hptr;
-       int hash;
+       haccess_t *hptr;
+       unsigned int hash;
 
-       hash = HASH(inet_ntoa(addr->sin_addr), proc, prog);
+       hash = HASH(inet_ntoa(addr->sin_addr), prog);
        head = &(haccess_tbl[hash]);
 
        TAILQ_FOREACH(hptr, &head->h_head, list) {
@@ -160,181 +136,93 @@ haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long proc, u_long prog)
        return NULL;
 }
 
+static void
+logit(const struct sockaddr_in *sin)
+{
+       char buf[INET_ADDRSTRLEN];
+
+       xlog_warn("connect from %s denied: request from unauthorized host",
+                       inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)));
+               
+}
+
 int
 good_client(daemon, addr)
 char *daemon;
 struct sockaddr_in *addr;
 {
-    struct hostent *hp;
-    char **sp;
-    char *tmpname;
-
-       /* 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 (!*sp)
-           return DENY; /* it was a FAKE. */
+       struct request_info req;
 
-       /* Check the official name and address. */
-       if (hosts_ctl(daemon, hp->h_name, inet_ntoa(addr->sin_addr), "") == DENY)
-               return DENY;
+       request_init(&req, RQ_DAEMON, daemon, RQ_CLIENT_SIN, addr, 0);
+       sock_methods(&req);
 
-       /* Now check aliases. */
-       for (sp = hp->h_aliases; *sp ; sp++) {
-               if (hosts_ctl(daemon, *sp, inet_ntoa(addr->sin_addr), "") == DENY)
-               return DENY;
-       }
+       if (hosts_access(&req)) 
+               return ALLOW;
 
-   return ALLOW;
+       return DENY;
 }
 
-/* check_startup - additional startup code */
+/* check_files - check to see if either access files have changed */
 
-void    check_startup(void)
+static int check_files()
 {
+       static time_t allow_mtime, deny_mtime;
+       struct stat astat, dstat;
+       int changed = 0;
 
-    /*
-     * Give up root privileges so that we can never allocate a privileged
-     * port when forwarding an rpc request.
-     *
-     * Fix 8/3/00 Philipp Knirsch: First lookup our rpc user. If we find it,
-     * switch to that uid, otherwise simply resue the old bin user and print
-     * out a warning in syslog.
-     */
-
-    struct passwd *pwent;
-
-    pwent = getpwnam("rpc");
-    if (pwent == NULL) {
-        syslog(LOG_WARNING, "user rpc not found, reverting to user bin");
-        if (setuid(1) == -1) {
-            syslog(LOG_ERR, "setuid(1) failed: %m");
-            exit(1);
-        }
-    }
-    else {
-        if (setuid(pwent->pw_uid) == -1) {
-            syslog(LOG_WARNING, "setuid() to rpc user failed: %m");
-            if (setuid(1) == -1) {
-                syslog(LOG_ERR, "setuid(1) failed: %m");
-                exit(1);
-            }
-        }
-    }
-
-    (void) signal(SIGINT, toggle_verboselog);
-}
+       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;
 
-/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
+       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
+ * @daemon: pointer to '\0'-terminated ASCII string containing name of the
+ *             daemon requesting the access check
+ * @addr: pointer to socket address containing address of caller
+ * @prog: RPC program number caller is attempting to access
+ *
+ * Returns TRUE if the caller is allowed access; otherwise FALSE is returned.
+ */
 int
-check_default(daemon, addr, proc, prog)
-char *daemon;
-struct sockaddr_in *addr;
-u_long  proc;
-u_long  prog;
+check_default(char *daemon, struct sockaddr_in *addr, u_long prog)
 {
        haccess_t *acc = NULL;
+       int changed = check_files();
 
-       acc = haccess_lookup(addr, proc, prog);
-       if (acc)
+       acc = haccess_lookup(addr, prog);
+       if (acc && changed == 0)
                return (acc->access);
 
-       if (!(from_local(addr) || good_client(daemon, addr))) {
-               log_bad_host(addr, proc, prog);
-               haccess_add(addr, proc, prog, FALSE);
+       if (!(from_local((struct sockaddr *)addr) || good_client(daemon, addr))) {
+               logit(addr);
+               if (acc)
+                       acc->access = FALSE;
+               else 
+                       haccess_add(addr, prog, FALSE);
                return (FALSE);
        }
-       if (verboselog)
-               log_client(addr, proc, prog);
 
-       haccess_add(addr, proc, prog, TRUE);
-    return (TRUE);
-}
+       if (acc)
+               acc->access = TRUE;
+       else 
+               haccess_add(addr, prog, TRUE);
 
-/* check_privileged_port - additional checks for privileged-port updates */
-int
-check_privileged_port(struct sockaddr_in *addr,        
-                     u_long proc, u_long prog, u_long port)
-{
-#ifdef CHECK_PORT
-    if (!legal_port(addr, port)) {
-       log_bad_port(addr, proc, prog);
-       return (FALSE);
-    }
-#endif
     return (TRUE);
 }
 
-/* toggle_verboselog - toggle verbose logging flag */
-
-static void toggle_verboselog(int sig)
-{
-    (void) signal(sig, toggle_verboselog);
-    verboselog = !verboselog;
-}
-
-/* logit - report events of interest via the syslog daemon */
-
-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)];
-    char   *progname;
-    char    progbuf[16 + 4 * sizeof(u_long)];
-    struct rpcent *rpc;
-
-    /*
-     * Fork off a process or the portmap daemon might hang while
-     * getrpcbynumber() or syslog() does its thing.
-     *
-     * Don't forget to wait for the children, too...
-     */
-
-    if (fork() == 0) {
-
-       /* Try to map program number to name. */
-
-       if (prognum == 0) {
-           progname = "";
-       } else if ((rpc = getrpcbynumber((int) prognum))) {
-           progname = rpc->r_name;
-       } else {
-           snprintf(progname = progbuf, sizeof (progbuf),
-                    "prog (%lu)", prognum);
-       }
-
-       /* Try to map procedure number to name. */
-
-       snprintf(procname = procbuf, sizeof (procbuf),
-                "proc (%lu)", (u_long) procnum);
-
-       /* Write syslog record. */
-
-       syslog(severity, "connect from %s to %s in %s%s",
-              inet_ntoa(addr->sin_addr), procname, progname, text);
-       exit(0);
-    }
-}
+#endif /* HAVE_LIBWRAP */