1/* 2 Unix SMB/CIFS implementation. 3 4 check access rules for socket connections 5 6 Copyright (C) Andrew Tridgell 2004 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22 23/* 24 This module is an adaption of code from the tcpd-1.4 package written 25 by Wietse Venema, Eindhoven University of Technology, The Netherlands. 26 27 The code is used here with permission. 28 29 The code has been considerably changed from the original. Bug reports 30 should be sent to samba@samba.org 31*/ 32 33#include "includes.h" 34#include "system/network.h" 35#include "lib/socket/socket.h" 36#include "system/locale.h" 37 38#define FAIL (-1) 39#define ALLONES ((uint32_t)0xFFFFFFFF) 40 41/* masked_match - match address against netnumber/netmask */ 42static bool masked_match(TALLOC_CTX *mem_ctx, const char *tok, const char *slash, const char *s) 43{ 44 uint32_t net; 45 uint32_t mask; 46 uint32_t addr; 47 char *tok_cpy; 48 49 if ((addr = interpret_addr(s)) == INADDR_NONE) 50 return false; 51 52 tok_cpy = talloc_strdup(mem_ctx, tok); 53 tok_cpy[PTR_DIFF(slash,tok)] = '\0'; 54 net = interpret_addr(tok_cpy); 55 talloc_free(tok_cpy); 56 57 if (strlen(slash + 1) > 2) { 58 mask = interpret_addr(slash + 1); 59 } else { 60 mask = (uint32_t)((ALLONES >> atoi(slash + 1)) ^ ALLONES); 61 /* convert to network byte order */ 62 mask = htonl(mask); 63 } 64 65 if (net == INADDR_NONE || mask == INADDR_NONE) { 66 DEBUG(0,("access: bad net/mask access control: %s\n", tok)); 67 return false; 68 } 69 70 return (addr & mask) == (net & mask); 71} 72 73/* string_match - match string against token */ 74static bool string_match(TALLOC_CTX *mem_ctx, const char *tok,const char *s, char *invalid_char) 75{ 76 size_t tok_len; 77 size_t str_len; 78 const char *cut; 79 80 *invalid_char = '\0'; 81 82 /* Return true if a token has the magic value "ALL". Return 83 * FAIL if the token is "FAIL". If the token starts with a "." 84 * (domain name), return true if it matches the last fields of 85 * the string. If the token has the magic value "LOCAL", 86 * return true if the string does not contain a "." 87 * character. If the token ends on a "." (network number), 88 * return true if it matches the first fields of the 89 * string. If the token begins with a "@" (netgroup name), 90 * return true if the string is a (host) member of the 91 * netgroup. Return true if the token fully matches the 92 * string. If the token is a netnumber/netmask pair, return 93 * true if the address is a member of the specified subnet. 94 */ 95 96 if (tok[0] == '.') { /* domain: match last fields */ 97 if ((str_len = strlen(s)) > (tok_len = strlen(tok)) 98 && strcasecmp(tok, s + str_len - tok_len)==0) { 99 return true; 100 } 101 } else if (tok[0] == '@') { /* netgroup: look it up */ 102 DEBUG(0,("access: netgroup support is not available\n")); 103 return false; 104 } else if (strcmp(tok, "ALL")==0) { /* all: match any */ 105 return true; 106 } else if (strcmp(tok, "FAIL")==0) { /* fail: match any */ 107 return FAIL; 108 } else if (strcmp(tok, "LOCAL")==0) { /* local: no dots */ 109 if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) { 110 return true; 111 } 112 } else if (strcasecmp(tok, s)==0) { /* match host name or address */ 113 return true; 114 } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ 115 if (strncmp(tok, s, tok_len) == 0) 116 return true; 117 } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ 118 if (isdigit((int)s[0]) && masked_match(mem_ctx, tok, cut, s)) 119 return true; 120 } else if (strchr(tok, '*') != 0) { 121 *invalid_char = '*'; 122 } else if (strchr(tok, '?') != 0) { 123 *invalid_char = '?'; 124 } 125 return false; 126} 127 128struct client_addr { 129 const char *cname; 130 const char *caddr; 131}; 132 133/* client_match - match host name and address against token */ 134static bool client_match(TALLOC_CTX *mem_ctx, const char *tok, struct client_addr *client) 135{ 136 bool match; 137 char invalid_char = '\0'; 138 139 /* 140 * Try to match the address first. If that fails, try to match the host 141 * name if available. 142 */ 143 144 if ((match = string_match(mem_ctx, tok, client->caddr, &invalid_char)) == 0) { 145 if(invalid_char) 146 DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \ 147token '%s' in an allow/deny hosts line.\n", invalid_char, tok )); 148 149 if (client->cname[0] != 0) 150 match = string_match(mem_ctx, tok, client->cname, &invalid_char); 151 152 if(invalid_char) 153 DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \ 154token '%s' in an allow/deny hosts line.\n", invalid_char, tok )); 155 } 156 157 return (match); 158} 159 160/* list_match - match an item against a list of tokens with exceptions */ 161static bool list_match(TALLOC_CTX *mem_ctx, const char **list, struct client_addr *client) 162{ 163 bool match = false; 164 165 if (!list) 166 return false; 167 168 /* 169 * Process tokens one at a time. We have exhausted all possible matches 170 * when we reach an "EXCEPT" token or the end of the list. If we do find 171 * a match, look for an "EXCEPT" list and recurse to determine whether 172 * the match is affected by any exceptions. 173 */ 174 175 for (; *list ; list++) { 176 if (strcmp(*list, "EXCEPT")==0) /* EXCEPT: give up */ 177 break; 178 if ((match = client_match(mem_ctx, *list, client))) /* true or FAIL */ 179 break; 180 } 181 182 /* Process exceptions to true or FAIL matches. */ 183 if (match != false) { 184 while (*list && strcmp(*list, "EXCEPT")!=0) 185 list++; 186 187 for (; *list; list++) { 188 if (client_match(mem_ctx, *list, client)) /* Exception Found */ 189 return false; 190 } 191 } 192 193 return match; 194} 195 196/* return true if access should be allowed */ 197static bool allow_access_internal(TALLOC_CTX *mem_ctx, 198 const char **deny_list,const char **allow_list, 199 const char *cname, const char *caddr) 200{ 201 struct client_addr client; 202 203 client.cname = cname; 204 client.caddr = caddr; 205 206 /* if it is loopback then always allow unless specifically denied */ 207 if (strcmp(caddr, "127.0.0.1") == 0) { 208 /* 209 * If 127.0.0.1 matches both allow and deny then allow. 210 * Patch from Steve Langasek vorlon@netexpress.net. 211 */ 212 if (deny_list && 213 list_match(mem_ctx, deny_list, &client) && 214 (!allow_list || 215 !list_match(mem_ctx, allow_list, &client))) { 216 return false; 217 } 218 return true; 219 } 220 221 /* if theres no deny list and no allow list then allow access */ 222 if ((!deny_list || *deny_list == 0) && 223 (!allow_list || *allow_list == 0)) { 224 return true; 225 } 226 227 /* if there is an allow list but no deny list then allow only hosts 228 on the allow list */ 229 if (!deny_list || *deny_list == 0) 230 return list_match(mem_ctx, allow_list, &client); 231 232 /* if theres a deny list but no allow list then allow 233 all hosts not on the deny list */ 234 if (!allow_list || *allow_list == 0) 235 return !list_match(mem_ctx, deny_list, &client); 236 237 /* if there are both types of list then allow all hosts on the 238 allow list */ 239 if (list_match(mem_ctx, allow_list, &client)) 240 return true; 241 242 /* if there are both types of list and it's not on the allow then 243 allow it if its not on the deny */ 244 if (list_match(mem_ctx, deny_list, &client)) 245 return false; 246 247 return true; 248} 249 250/* return true if access should be allowed */ 251bool allow_access(TALLOC_CTX *mem_ctx, 252 const char **deny_list, const char **allow_list, 253 const char *cname, const char *caddr) 254{ 255 bool ret; 256 char *nc_cname = talloc_strdup(mem_ctx, cname); 257 char *nc_caddr = talloc_strdup(mem_ctx, caddr); 258 259 if (!nc_cname || !nc_caddr) { 260 return false; 261 } 262 263 ret = allow_access_internal(mem_ctx, deny_list, allow_list, nc_cname, nc_caddr); 264 265 talloc_free(nc_cname); 266 talloc_free(nc_caddr); 267 268 return ret; 269} 270 271/* return true if the char* contains ip addrs only. Used to avoid 272gethostbyaddr() calls */ 273 274static bool only_ipaddrs_in_list(const char** list) 275{ 276 bool only_ip = true; 277 278 if (!list) 279 return true; 280 281 for (; *list ; list++) { 282 /* factor out the special strings */ 283 if (strcmp(*list, "ALL")==0 || 284 strcmp(*list, "FAIL")==0 || 285 strcmp(*list, "EXCEPT")==0) { 286 continue; 287 } 288 289 if (!is_ipaddress(*list)) { 290 /* 291 * if we failed, make sure that it was not because the token 292 * was a network/netmask pair. Only network/netmask pairs 293 * have a '/' in them 294 */ 295 if ((strchr(*list, '/')) == NULL) { 296 only_ip = false; 297 DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list)); 298 break; 299 } 300 } 301 } 302 303 return only_ip; 304} 305 306/* return true if access should be allowed to a service for a socket */ 307bool socket_check_access(struct socket_context *sock, 308 const char *service_name, 309 const char **allow_list, const char **deny_list) 310{ 311 bool ret; 312 const char *name=""; 313 struct socket_address *addr; 314 TALLOC_CTX *mem_ctx; 315 316 if ((!deny_list || *deny_list==0) && 317 (!allow_list || *allow_list==0)) { 318 return true; 319 } 320 321 mem_ctx = talloc_init("socket_check_access"); 322 if (!mem_ctx) { 323 return false; 324 } 325 326 addr = socket_get_peer_addr(sock, mem_ctx); 327 if (!addr) { 328 DEBUG(0,("socket_check_access: Denied connection from unknown host: could not get peer address from kernel\n")); 329 talloc_free(mem_ctx); 330 return false; 331 } 332 333 /* bypass gethostbyaddr() calls if the lists only contain IP addrs */ 334 if (!only_ipaddrs_in_list(allow_list) || 335 !only_ipaddrs_in_list(deny_list)) { 336 name = socket_get_peer_name(sock, mem_ctx); 337 if (!name) { 338 name = addr->addr; 339 } 340 } 341 342 if (!addr) { 343 DEBUG(0,("socket_check_access: Denied connection from unknown host\n")); 344 talloc_free(mem_ctx); 345 return false; 346 } 347 348 ret = allow_access(mem_ctx, deny_list, allow_list, name, addr->addr); 349 350 if (ret) { 351 DEBUG(2,("socket_check_access: Allowed connection to '%s' from %s (%s)\n", 352 service_name, name, addr->addr)); 353 } else { 354 DEBUG(0,("socket_check_access: Denied connection to '%s' from %s (%s)\n", 355 service_name, name, addr->addr)); 356 } 357 358 talloc_free(mem_ctx); 359 360 return ret; 361} 362