Daemon supports forward-DNS lookups for simple hostnames
authorWayne Davison <wayned@samba.org>
Tue, 4 Jan 2011 02:59:08 +0000 (18:59 -0800)
committerWayne Davison <wayned@samba.org>
Tue, 4 Jan 2011 03:04:06 +0000 (19:04 -0800)
in hosts deny/allow config settings.

NEWS
access.c
clientserver.c
loadparm.c
rsyncd.conf.yo

diff --git a/NEWS b/NEWS
index d116f9b..5fd125a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -77,6 +77,9 @@ Changes since 3.0.4:
     - Added the "reverse lookup" parameter to the rsync daemon config file to
       allow reverse-DNS lookups to be disabled.
 
     - Added the "reverse lookup" parameter to the rsync daemon config file to
       allow reverse-DNS lookups to be disabled.
 
+    - Added a forward-DNS lookup for the daemon's hosts allow/deny config.  Can
+      be disabled via "forward lookup" parameter (defaults to enabled).
+
     - Added a way for more than one group to be specified in the daemon's
       config file, including a way to specify that you want all of the
       specified user's groups without having to name them.  Also changed the
     - Added a way for more than one group to be specified in the daemon's
       config file, including a way to specify that you want all of the
       specified user's groups without having to name them.  Also changed the
index 9a023de..367fd44 100644 (file)
--- a/access.c
+++ b/access.c
 
 #include "rsync.h"
 
 
 #include "rsync.h"
 
-static int match_hostname(const char *host, const char *tok)
+static int allow_forward_dns;
+
+extern const char undetermined_hostname[];
+
+static int match_hostname(const char **host_ptr, const char *addr, const char *tok)
 {
 {
+       struct hostent *hp;
+       unsigned int i;
+       const char *host = *host_ptr;
+
        if (!host || !*host)
                return 0;
        if (!host || !*host)
                return 0;
-       return iwildmatch(tok, host);
+
+       /* First check if the reverse-DNS-determined hostname matches. */
+       if (iwildmatch(tok, host))
+               return 1;
+
+       if (!allow_forward_dns)
+               return 0;
+
+       /* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
+       if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")])
+               return 0;
+
+       /* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
+       if (!(hp = gethostbyname(tok)))
+               return 0;
+
+       for (i = 0; hp->h_addr_list[i] != NULL; i++) {
+               if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) {
+                       /* If reverse lookups are off, we'll use the conf-specified
+                        * hostname in preference to UNDETERMINED. */
+                       if (host == undetermined_hostname) {
+                               if (!(*host_ptr = strdup(tok)))
+                                       *host_ptr = undetermined_hostname;
+                       }
+                       return 1;
+               }
+       }
+
+       return 0;
 }
 
 static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
 }
 
 static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
@@ -70,24 +106,16 @@ static int match_address(const char *addr, const char *tok)
 #endif
        char mask[16];
        char *a = NULL, *t = NULL;
 #endif
        char mask[16];
        char *a = NULL, *t = NULL;
-       unsigned int len;
 
        if (!addr || !*addr)
                return 0;
 
        p = strchr(tok,'/');
 
        if (!addr || !*addr)
                return 0;
 
        p = strchr(tok,'/');
-       if (p) {
+       if (p)
                *p = '\0';
                *p = '\0';
-               len = p - tok;
-       } else
-               len = strlen(tok);
 
 
-       /* Fail quietly if tok is a hostname (not an address) */
-       if (strspn(tok, ".0123456789") != len
-#ifdef INET6
-           && strchr(tok, ':') == NULL
-#endif
-       ) {
+       /* Fail quietly if tok is a hostname, not an address. */
+       if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
                if (p)
                        *p = '/';
                return 0;
                if (p)
                        *p = '/';
                return 0;
@@ -210,7 +238,7 @@ static int match_address(const char *addr, const char *tok)
        return ret;
 }
 
        return ret;
 }
 
-static int access_match(const char *list, const char *addr, const char *host)
+static int access_match(const char *list, const char *addr, const char **host_ptr)
 {
        char *tok;
        char *list2 = strdup(list);
 {
        char *tok;
        char *list2 = strdup(list);
@@ -221,7 +249,7 @@ static int access_match(const char *list, const char *addr, const char *host)
        strlower(list2);
 
        for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
        strlower(list2);
 
        for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
-               if (match_hostname(host, tok) || match_address(addr, tok)) {
+               if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
                        free(list2);
                        return 1;
                }
                        free(list2);
                        return 1;
                }
@@ -231,17 +259,21 @@ static int access_match(const char *list, const char *addr, const char *host)
        return 0;
 }
 
        return 0;
 }
 
-int allow_access(const char *addr, const char *host,
-                const char *allow_list, const char *deny_list)
+int allow_access(const char *addr, const char **host_ptr, int i)
 {
 {
+       const char *allow_list = lp_hosts_allow(i);
+       const char *deny_list = lp_hosts_deny(i);
+
        if (allow_list && !*allow_list)
                allow_list = NULL;
        if (deny_list && !*deny_list)
                deny_list = NULL;
 
        if (allow_list && !*allow_list)
                allow_list = NULL;
        if (deny_list && !*deny_list)
                deny_list = NULL;
 
+       allow_forward_dns = lp_forward_lookup(i);
+
        /* If we match an allow-list item, we always allow access. */
        if (allow_list) {
        /* If we match an allow-list item, we always allow access. */
        if (allow_list) {
-               if (access_match(allow_list, addr, host))
+               if (access_match(allow_list, addr, host_ptr))
                        return 1;
                /* For an allow-list w/o a deny-list, disallow non-matches. */
                if (!deny_list)
                        return 1;
                /* For an allow-list w/o a deny-list, disallow non-matches. */
                if (!deny_list)
@@ -250,7 +282,7 @@ int allow_access(const char *addr, const char *host,
 
        /* If we match a deny-list item (and got past any allow-list
         * items), we always disallow access. */
 
        /* If we match a deny-list item (and got past any allow-list
         * items), we always disallow access. */
-       if (deny_list && access_match(deny_list, addr, host))
+       if (deny_list && access_match(deny_list, addr, host_ptr))
                return 0;
 
        /* Allow all other access. */
                return 0;
 
        /* Allow all other access. */
index 21ef01c..8b6b896 100644 (file)
@@ -515,7 +515,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
        set_env_str("RSYNC_HOST_NAME", host);
        set_env_str("RSYNC_HOST_ADDR", addr);
 
        set_env_str("RSYNC_HOST_NAME", host);
        set_env_str("RSYNC_HOST_ADDR", addr);
 
-       if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
+       if (!allow_access(addr, &host, i)) {
                rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
                        name, host, addr);
                if (!lp_list(i))
                rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
                        name, host, addr);
                if (!lp_list(i))
index 10c3345..792c3da 100644 (file)
@@ -139,6 +139,7 @@ typedef struct {
        int timeout;
 
        BOOL fake_super;
        int timeout;
 
        BOOL fake_super;
+       BOOL forward_lookup;
        BOOL ignore_errors;
        BOOL ignore_nonreadable;
        BOOL list;
        BOOL ignore_errors;
        BOOL ignore_nonreadable;
        BOOL list;
@@ -211,6 +212,7 @@ static const all_vars Defaults = {
  /* timeout; */                        0,
 
  /* fake_super; */             False,
  /* timeout; */                        0,
 
  /* fake_super; */             False,
+ /* forward_lookup; */         True,
  /* ignore_errors; */          False,
  /* ignore_nonreadable; */     False,
  /* list; */                   True,
  /* ignore_errors; */          False,
  /* ignore_nonreadable; */     False,
  /* list; */                   True,
@@ -322,6 +324,7 @@ static struct parm_struct parm_table[] =
  {"exclude",           P_STRING, P_LOCAL, &Vars.l.exclude,             NULL,0},
  {"fake super",        P_BOOL,   P_LOCAL, &Vars.l.fake_super,          NULL,0},
  {"filter",            P_STRING, P_LOCAL, &Vars.l.filter,              NULL,0},
  {"exclude",           P_STRING, P_LOCAL, &Vars.l.exclude,             NULL,0},
  {"fake super",        P_BOOL,   P_LOCAL, &Vars.l.fake_super,          NULL,0},
  {"filter",            P_STRING, P_LOCAL, &Vars.l.filter,              NULL,0},
+ {"forward lookup",    P_BOOL,   P_LOCAL, &Vars.l.forward_lookup,      NULL,0},
  {"gid",               P_STRING, P_LOCAL, &Vars.l.gid,                 NULL,0},
  {"hosts allow",       P_STRING, P_LOCAL, &Vars.l.hosts_allow,         NULL,0},
  {"hosts deny",        P_STRING, P_LOCAL, &Vars.l.hosts_deny,          NULL,0},
  {"gid",               P_STRING, P_LOCAL, &Vars.l.gid,                 NULL,0},
  {"hosts allow",       P_STRING, P_LOCAL, &Vars.l.hosts_allow,         NULL,0},
  {"hosts deny",        P_STRING, P_LOCAL, &Vars.l.hosts_deny,          NULL,0},
@@ -476,6 +479,7 @@ FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
 FN_LOCAL_INTEGER(lp_timeout, timeout)
 
 FN_LOCAL_BOOL(lp_fake_super, fake_super)
 FN_LOCAL_INTEGER(lp_timeout, timeout)
 
 FN_LOCAL_BOOL(lp_fake_super, fake_super)
+FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup)
 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
 FN_LOCAL_BOOL(lp_list, list)
 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
 FN_LOCAL_BOOL(lp_list, list)
index f96fc9e..2dbf67c 100644 (file)
@@ -532,13 +532,14 @@ quote(itemization(
   IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
   or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
   addresses which match the masked IP address will be allowed in.
   IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
   or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
   addresses which match the masked IP address will be allowed in.
-  it() a hostname. The hostname as determined by a reverse lookup will
-  be matched (case insensitive) against the pattern. Only an exact
-  match is allowed in.  This only works if "reverse lookup" is enabled
-  (the default).
-  it() a hostname pattern using wildcards. These are matched using the
-  same rules as normal unix filename matching. If the pattern matches
-  then the client is allowed in.
+  it() a hostname pattern using wildcards. If the hostname of the connecting IP
+  (as determined by a reverse lookup) matches the wildcarded name (using the
+  same rules as normal unix filename matching), the client is allowed in.  This
+  only works if "reverse lookup" is enabled (the default).
+  it() a hostname. A plain hostname is matched against the reverse DNS of the
+  connecting IP (if "reverse lookup" is enabled), and/or the IP of the given
+  hostname is matched against the connecting IP (if "forward lookup" is
+  enabled, as it is by default).  Any match will be allowed in.
 ))
 
 Note IPv6 link-local addresses can have a scope in the address specification:
 ))
 
 Note IPv6 link-local addresses can have a scope in the address specification:
@@ -578,6 +579,11 @@ lookup as soon as a client connects, so disabling it for a module will not
 avoid the lookup.  Thus, you probably want to disable it globally and then
 enable it for modules that need the information.
 
 avoid the lookup.  Thus, you probably want to disable it globally and then
 enable it for modules that need the information.
 
+dit(bf(forward lookup)) Controls whether the daemon performs a forward lookup
+on any hostname specified in an hosts allow/deny setting.  By default this is
+enabled, allowing the use of an explicit hostname that would not be returned
+by reverse DNS of the connecting IP.
+
 dit(bf(ignore errors)) This parameter tells rsyncd to
 ignore I/O errors on the daemon when deciding whether to run the delete
 phase of the transfer. Normally rsync skips the bf(--delete) step if any
 dit(bf(ignore errors)) This parameter tells rsyncd to
 ignore I/O errors on the daemon when deciding whether to run the delete
 phase of the transfer. Normally rsync skips the bf(--delete) step if any