#include "includes.h"
#define FAIL (-1)
#define ALLONES ((uint32)0xFFFFFFFF)
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);
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);
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 & mask));
}
static BOOL string_match(const char *tok,const char *s, char *invalid_char)
{
size_t tok_len;
size_t str_len;
const char *cut;
*invalid_char = '\0';
if (tok[0] == '.') {
if ((str_len = strlen(s)) > (tok_len = strlen(tok))
&& strequal(tok, s + str_len - tok_len))
return (True);
} else if (tok[0] == '@') {
#ifdef HAVE_NETGROUP
static char *mydomain = NULL;
char *hostname = NULL;
BOOL netgroup_ok = False;
if (!mydomain)
yp_get_default_domain(&mydomain);
if (!mydomain) {
DEBUG(0,("Unable to get default yp domain.\n"));
return False;
}
if (!(hostname = SMB_STRDUP(s))) {
DEBUG(1,("out of memory for strdup!\n"));
return False;
}
netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n",
hostname,
mydomain,
tok+1,
BOOLSTR(netgroup_ok)));
SAFE_FREE(hostname);
if (netgroup_ok)
return(True);
#else
DEBUG(0,("access: netgroup support is not configured\n"));
return (False);
#endif
} else if (strequal(tok, "ALL")) {
return (True);
} else if (strequal(tok, "FAIL")) {
return (FAIL);
} else if (strequal(tok, "LOCAL")) {
if (strchr_m(s, '.') == 0 && !strequal(s, "unknown"))
return (True);
} else if (strequal(tok, s)) {
return (True);
} else if (tok[(tok_len = strlen(tok)) - 1] == '.') {
if (strncmp(tok, s, tok_len) == 0)
return (True);
} else if ((cut = strchr_m(tok, '/')) != 0) {
if (isdigit((int)s[0]) && masked_match(tok, cut, s))
return (True);
} else if (strchr_m(tok, '*') != 0) {
*invalid_char = '*';
} else if (strchr_m(tok, '?') != 0) {
*invalid_char = '?';
}
return (False);
}
static BOOL client_match(const char *tok, const char *item)
{
const char **client = (const char **)item;
BOOL match;
char 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 ));
if (client[0][0] != 0)
match = string_match(tok, client[0], &invalid_char);
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 ));
}
return (match);
}
static BOOL list_match(const char **list,const char *item,
BOOL (*match_fn)(const char *, const char *))
{
BOOL match = False;
if (!list)
return False;
for (; *list ; list++) {
if (strequal(*list, "EXCEPT"))
break;
if ((match = (*match_fn) (*list, item)))
break;
}
if (match != False) {
while (*list && !strequal(*list, "EXCEPT"))
list++;
for (; *list; list++) {
if ((*match_fn) (*list, item))
return False;
}
}
return (match);
}
static BOOL allow_access_internal(const char **deny_list,const char **allow_list,
const char *cname, const char *caddr)
{
const char *client[2];
client[0] = cname;
client[1] = caddr;
if (strcmp(caddr, "127.0.0.1") == 0) {
if (deny_list &&
list_match(deny_list,(const char *)client,client_match) &&
(!allow_list ||
!list_match(allow_list,(const char *)client, client_match))) {
return False;
}
return True;
}
if ((!deny_list || *deny_list == 0) &&
(!allow_list || *allow_list == 0)) {
return(True);
}
if (!deny_list || *deny_list == 0)
return(list_match(allow_list,(const char *)client,client_match));
if (!allow_list || *allow_list == 0)
return(!list_match(deny_list,(const char *)client,client_match));
if (list_match(allow_list,(const char *)client,client_match))
return (True);
if (list_match(deny_list,(const char *)client,client_match))
return (False);
return (True);
}
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;
}
static BOOL only_ipaddrs_in_list(const char** list)
{
BOOL only_ip = True;
if (!list)
return True;
for (; *list ; list++) {
if (strequal(*list, "ALL") || strequal(*list, "FAIL") ||
strequal(*list, "EXCEPT")) {
continue;
}
if (!is_ipaddress(*list)) {
if ((strchr_m(*list, '/')) == NULL) {
only_ip = False;
DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
break;
}
}
}
return only_ip;
}
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))
ret = True;
if (!ret) {
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_peer_addr(sock));
} else {
DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
ret = allow_access(deny_list,allow_list, get_peer_name(sock,True),
get_peer_addr(sock));
}
if (ret) {
DEBUG(2,("Allowed connection from %s (%s)\n",
only_ip ? "" : get_peer_name(sock,True),
get_peer_addr(sock)));
} else {
DEBUG(0,("Denied connection from %s (%s)\n",
only_ip ? "" : get_peer_name(sock,True),
get_peer_addr(sock)));
}
}
return(ret);
}