sync 3.0 into HEAD for the last time
[tprouty/samba.git] / source / lib / access.c
index b3d183848406ef9e7fadec106b56a29b26a883d0..a874c8b1e2065e01a06c898ff4510bfbd85a5192 100644 (file)
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
 #define        FAIL            (-1)
 
+#define ALLONES  ((uint32)0xFFFFFFFF)
+
 /* masked_match - match address against netnumber/netmask */
-static int masked_match(char *tok, char *slash, char *s)
+static BOOL masked_match(const char *tok, const char *slash, const char *s)
 {
        uint32 net;
        uint32 mask;
        uint32 addr;
+       fstring tok_cpy;
 
        if ((addr = interpret_addr(s)) == INADDR_NONE)
                return (False);
-       *slash = 0;
-       net = interpret_addr(tok);
-       *slash = '/';
-       if (net == INADDR_NONE || 
-           (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
+
+       fstrcpy(tok_cpy, tok);
+       tok_cpy[PTR_DIFF(slash,tok)] = '\0';
+       net = interpret_addr(tok_cpy);
+       tok_cpy[PTR_DIFF(slash,tok)] = '/';
+
+        if (strlen(slash + 1) > 2) {
+                mask = interpret_addr(slash + 1);
+        } else {
+               mask = (uint32)((ALLONES >> atoi(slash + 1)) ^ ALLONES);
+               /* convert to network byte order */
+               mask = htonl(mask);
+        }
+
+       if (net == INADDR_NONE || mask == INADDR_NONE) {
                DEBUG(0,("access: bad net/mask access control: %s\n", tok));
                return (False);
        }
+       
        return ((addr & mask) == net);
 }
 
 /* string_match - match string against token */
-static int string_match(char *tok,char *s, char *invalid_char)
+static BOOL string_match(const char *tok,const char *s, char *invalid_char)
 {
        size_t     tok_len;
        size_t     str_len;
-       char   *cut;
+       const char   *cut;
 
        *invalid_char = '\0';
 
@@ -54,7 +66,8 @@ static int string_match(char *tok,char *s, char *invalid_char)
         * return True if the string is a (host) member of the
         * netgroup. Return True if the token fully matches the
         * string. If the token is a netnumber/netmask pair, return
-        * True if the address is a member of the specified subnet.  */
+        * True if the address is a member of the specified subnet.  
+        */
 
        if (tok[0] == '.') {                    /* domain: match last fields */
                if ((str_len = strlen(s)) > (tok_len = strlen(tok))
@@ -66,7 +79,8 @@ static int string_match(char *tok,char *s, char *invalid_char)
                char *hostname = NULL;
                BOOL netgroup_ok = False;
 
-               if (!mydomain) yp_get_default_domain(&mydomain);
+               if (!mydomain)
+                       yp_get_default_domain(&mydomain);
 
                if (!mydomain) {
                        DEBUG(0,("Unable to get default yp domain.\n"));
@@ -87,7 +101,8 @@ static int string_match(char *tok,char *s, char *invalid_char)
 
                SAFE_FREE(hostname);
       
-               if (netgroup_ok) return(True);
+               if (netgroup_ok)
+                       return(True);
 #else
                DEBUG(0,("access: netgroup support is not configured\n"));
                return (False);
@@ -115,20 +130,19 @@ static int string_match(char *tok,char *s, char *invalid_char)
        return (False);
 }
 
-
 /* client_match - match host name and address against token */
-static int client_match(char *tok,char *item)
+static BOOL client_match(const char *tok, const char *item)
 {
-    char **client = (char **)item;
-    int     match;
+       const char **client = (const char **)item;
+       BOOL match;
        char invalid_char = '\0';
 
-    /*
-     * Try to match the address first. If that fails, try to match the host
-     * name if available.
-     */
+       /*
+        * Try to match the address first. If that fails, try to match the host
+        * name if available.
+        */
 
-    if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
+       if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
                if(invalid_char)
                        DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
 token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
@@ -141,58 +155,65 @@ token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
 token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
        }
 
-    return (match);
+       return (match);
 }
 
 /* list_match - match an item against a list of tokens with exceptions */
-static int list_match(char **list,char *item, int (*match_fn)(char *, char *))
+static BOOL list_match(const char **list,const char *item,
+               BOOL (*match_fn)(const char *, const char *))
 {
-    int     match = False;
-
-    if (!list) return False;
-
-    /*
-     * Process tokens one at a time. We have exhausted all possible matches
-     * when we reach an "EXCEPT" token or the end of the list. If we do find
-     * a match, look for an "EXCEPT" list and recurse to determine whether
-     * the match is affected by any exceptions.
-     */
-
-    for (; *list ; list++) {
-       if (strcasecmp(*list, "EXCEPT") == 0)   /* EXCEPT: give up */
-           break;
-       if ((match = (*match_fn) (*list, item)))        /* True or FAIL */
-           break;
-    }
-    /* Process exceptions to True or FAIL matches. */
-
-    if (match != False) {
-       while (*list  && strcasecmp(*list, "EXCEPT"))
-               list++;
-
-       for (; *list; list++) {
-               if ((*match_fn) (*list, item)) /* Exception Found */
-                       return False;
+       BOOL match = False;
+
+       if (!list)
+               return False;
+
+       /*
+        * Process tokens one at a time. We have exhausted all possible matches
+        * when we reach an "EXCEPT" token or the end of the list. If we do find
+        * a match, look for an "EXCEPT" list and recurse to determine whether
+        * the match is affected by any exceptions.
+        */
+
+       for (; *list ; list++) {
+               if (strcasecmp(*list, "EXCEPT") == 0)   /* EXCEPT: give up */
+                       break;
+               if ((match = (*match_fn) (*list, item)))        /* True or FAIL */
+                       break;
        }
-    }
+       /* Process exceptions to True or FAIL matches. */
 
-    return (match);
-}
+       if (match != False) {
+               while (*list  && strcasecmp(*list, "EXCEPT"))
+                       list++;
 
+               for (; *list; list++) {
+                       if ((*match_fn) (*list, item)) /* Exception Found */
+                               return False;
+               }
+       }
+
+       return (match);
+}
 
 /* return true if access should be allowed */
-BOOL allow_access(char **deny_list,char **allow_list,
-                 char *cname,char *caddr)
+static BOOL allow_access_internal(const char **deny_list,const char **allow_list,
+                       const char *cname, const char *caddr)
 {
-       char *client[2];
+       const char *client[2];
 
        client[0] = cname;
        client[1] = caddr;  
 
        /* if it is loopback then always allow unless specifically denied */
        if (strcmp(caddr, "127.0.0.1") == 0) {
+               /*
+                * If 127.0.0.1 matches both allow and deny then allow.
+                * Patch from Steve Langasek vorlon@netexpress.net.
+                */
                if (deny_list && 
-                   list_match(deny_list,(char *)client,client_match)) {
+                       list_match(deny_list,(const char *)client,client_match) &&
+                               (!allow_list ||
+                               !list_match(allow_list,(const char *)client, client_match))) {
                        return False;
                }
                return True;
@@ -207,53 +228,65 @@ BOOL allow_access(char **deny_list,char **allow_list,
        /* if there is an allow list but no deny list then allow only hosts
           on the allow list */
        if (!deny_list || *deny_list == 0)
-               return(list_match(allow_list,(char *)client,client_match));
+               return(list_match(allow_list,(const char *)client,client_match));
 
        /* if theres a deny list but no allow list then allow
           all hosts not on the deny list */
        if (!allow_list || *allow_list == 0)
-               return(!list_match(deny_list,(char *)client,client_match));
+               return(!list_match(deny_list,(const char *)client,client_match));
 
-       /* if there are both type of list then allow all hosts on the
+       /* if there are both types of list then allow all hosts on the
            allow list */
-       if (list_match(allow_list,(char *)client,client_match))
+       if (list_match(allow_list,(const char *)client,client_match))
                return (True);
 
-       /* if there are both type of list and it's not on the allow then
+       /* if there are both types of list and it's not on the allow then
           allow it if its not on the deny */
-       if (list_match(deny_list,(char *)client,client_match))
+       if (list_match(deny_list,(const char *)client,client_match))
                return (False);
        
        return (True);
 }
 
+/* return true if access should be allowed */
+BOOL allow_access(const char **deny_list, const char **allow_list,
+                 const char *cname, const char *caddr)
+{
+       BOOL ret;
+       char *nc_cname = smb_xstrdup(cname);
+       char *nc_caddr = smb_xstrdup(caddr);
+       
+       ret = allow_access_internal(deny_list, allow_list, nc_cname, nc_caddr);
+
+       SAFE_FREE(nc_cname);
+       SAFE_FREE(nc_caddr);
+       return ret;
+}
+
 /* return true if the char* contains ip addrs only.  Used to avoid 
 gethostbyaddr() calls */
-static BOOL only_ipaddrs_in_list(char** list)
+
+static BOOL only_ipaddrs_in_list(const char** list)
 {
-       BOOL            only_ip = True;
+       BOOL only_ip = True;
        
-       if (!list) return True;
+       if (!list)
+               return True;
                        
-       for (; *list ; list++) 
-       {
+       for (; *list ; list++) {
                /* factor out the special strings */
                if (!strcasecmp(*list, "ALL") || !strcasecmp(*list, "FAIL") || 
-                   !strcasecmp(*list, "EXCEPT"))
-               {
+                   !strcasecmp(*list, "EXCEPT")) {
                        continue;
                }
                
-               if (!is_ipaddress(*list))
-               {
-                       char *p;
+               if (!is_ipaddress(*list)) {
                        /* 
                         * if we failed, make sure that it was not because the token
                         * was a network/netmask pair.  Only network/netmask pairs
                         * have a '/' in them
                         */
-                       if ((p=strchr_m(*list, '/')) == NULL)
-                       {
+                       if ((strchr_m(*list, '/')) == NULL) {
                                only_ip = False;
                                DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
                                break;
@@ -265,42 +298,33 @@ static BOOL only_ipaddrs_in_list(char** list)
 }
 
 /* return true if access should be allowed to a service for a socket */
-BOOL check_access(int sock, char **allow_list, char **deny_list)
+BOOL check_access(int sock, const char **allow_list, const char **deny_list)
 {
        BOOL ret = False;
        BOOL only_ip = False;
        
-       if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0)) 
-       {
+       if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
                ret = True;
-       }
 
-       if (!ret) 
-       {
+       if (!ret) {
                /* bypass gethostbyaddr() calls if the lists only contain IP addrs */
-               if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list))
-               {
+               if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list)) {
                        only_ip = True;
                        DEBUG (3, ("check_access: no hostnames in host allow/deny list.\n"));
                        ret = allow_access(deny_list,allow_list, "", get_socket_addr(sock));
-               }
-               else
-               {
+               } else {
                        DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
-                       ret = allow_access(deny_list,allow_list, get_socket_name(sock),
+                       ret = allow_access(deny_list,allow_list, get_socket_name(sock,True),
                                           get_socket_addr(sock));
                }
                
-               if (ret) 
-               {
+               if (ret) {
                        DEBUG(2,("Allowed connection from %s (%s)\n",
-                                only_ip ? "" : get_socket_name(sock),
+                                only_ip ? "" : get_socket_name(sock,True),
                                 get_socket_addr(sock)));
-               } 
-               else 
-               {
+               } else {
                        DEBUG(0,("Denied connection from %s (%s)\n",
-                                only_ip ? "" : get_socket_name(sock),
+                                only_ip ? "" : get_socket_name(sock,True),
                                 get_socket_addr(sock)));
                }
        }