1/* 2 This module is an adaption of code from the tcpd-1.4 package written 3 by Wietse Venema, Eindhoven University of Technology, The Netherlands. 4 5 The code is used here with permission. 6 7 The code has been considerably changed from the original. Bug reports 8 should be sent to samba-bugs@samba.org 9*/ 10 11#include "includes.h" 12 13extern int DEBUGLEVEL; 14 15/* Delimiters for lists of daemons or clients. */ 16static char *sep = ", \t"; 17 18#define FAIL (-1) 19 20/* masked_match - match address against netnumber/netmask */ 21static int masked_match(char *tok, char *slash, char *s) 22{ 23 uint32 net; 24 uint32 mask; 25 uint32 addr; 26 27 if ((addr = interpret_addr(s)) == INADDR_NONE) 28 return (False); 29 *slash = 0; 30 net = interpret_addr(tok); 31 *slash = '/'; 32 if (net == INADDR_NONE || 33 (mask = interpret_addr(slash + 1)) == INADDR_NONE) { 34 DEBUG(0,("access: bad net/mask access control: %s\n", tok)); 35 return (False); 36 } 37 return ((addr & mask) == net); 38} 39 40/* string_match - match string against token */ 41static int string_match(char *tok,char *s, char *invalid_char) 42{ 43 size_t tok_len; 44 size_t str_len; 45 char *cut; 46 47 *invalid_char = '\0'; 48 49 /* Return True if a token has the magic value "ALL". Return 50 * FAIL if the token is "FAIL". If the token starts with a "." 51 * (domain name), return True if it matches the last fields of 52 * the string. If the token has the magic value "LOCAL", 53 * return True if the string does not contain a "." 54 * character. If the token ends on a "." (network number), 55 * return True if it matches the first fields of the 56 * string. If the token begins with a "@" (netgroup name), 57 * return True if the string is a (host) member of the 58 * netgroup. Return True if the token fully matches the 59 * string. If the token is a netnumber/netmask pair, return 60 * True if the address is a member of the specified subnet. */ 61 62 if (tok[0] == '.') { /* domain: match last fields */ 63 if ((str_len = strlen(s)) > (tok_len = strlen(tok)) 64 && strcasecmp(tok, s + str_len - tok_len) == 0) 65 return (True); 66 } else if (tok[0] == '@') { /* netgroup: look it up */ 67#ifdef HAVE_NETGROUP 68 static char *mydomain = NULL; 69 char *hostname = NULL; 70 BOOL netgroup_ok = False; 71 72 if (!mydomain) yp_get_default_domain(&mydomain); 73 74 if (!mydomain) { 75 DEBUG(0,("Unable to get default yp domain.\n")); 76 return False; 77 } 78 if (!(hostname = strdup(s))) { 79 DEBUG(1,("out of memory for strdup!\n")); 80 return False; 81 } 82 83 netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); 84 85 DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", 86 hostname, 87 mydomain, 88 tok+1, 89 BOOLSTR(netgroup_ok))); 90 91 free(hostname); 92 93 if (netgroup_ok) return(True); 94#else 95 DEBUG(0,("access: netgroup support is not configured\n")); 96 return (False); 97#endif 98 } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ 99 return (True); 100 } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ 101 return (FAIL); 102 } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ 103 if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) 104 return (True); 105 } else if (!strcasecmp(tok, s)) { /* match host name or address */ 106 return (True); 107 } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ 108 if (strncmp(tok, s, tok_len) == 0) 109 return (True); 110 } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ 111 if (isdigit((int)s[0]) && masked_match(tok, cut, s)) 112 return (True); 113 } else if (strchr(tok, '*') != 0) { 114 *invalid_char = '*'; 115 } else if (strchr(tok, '?') != 0) { 116 *invalid_char = '?'; 117 } 118 return (False); 119} 120 121 122/* client_match - match host name and address against token */ 123static int client_match(char *tok,char *item) 124{ 125 char **client = (char **)item; 126 int match; 127 char invalid_char = '\0'; 128 129 /* 130 * Try to match the address first. If that fails, try to match the host 131 * name if available. 132 */ 133 134 if ((match = string_match(tok, client[1], &invalid_char)) == 0) { 135 if(invalid_char) 136 DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \ 137token '%s' in an allow/deny hosts line.\n", invalid_char, tok )); 138 139 if (client[0][0] != 0) 140 match = string_match(tok, client[0], &invalid_char); 141 142 if(invalid_char) 143 DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \ 144token '%s' in an allow/deny hosts line.\n", invalid_char, tok )); 145 } 146 147 return (match); 148} 149 150/* list_match - match an item against a list of tokens with exceptions */ 151/* (All modifications are marked with the initials "jkf") */ 152static int list_match(char *list,char *item, int (*match_fn)(char *, char *)) 153{ 154 char *tok; 155 char *listcopy; /* jkf */ 156 int match = False; 157 158 /* 159 * jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match() 160 * overwriting the list given as its first parameter. 161 */ 162 163 /* jkf -- can get called recursively with NULL list */ 164 listcopy = (list == 0) ? (char *)0 : strdup(list); 165 166 /* 167 * Process tokens one at a time. We have exhausted all possible matches 168 * when we reach an "EXCEPT" token or the end of the list. If we do find 169 * a match, look for an "EXCEPT" list and recurse to determine whether 170 * the match is affected by any exceptions. 171 */ 172 173 for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) { 174 if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ 175 break; 176 if ((match = (*match_fn) (tok, item))) /* True or FAIL */ 177 break; 178 } 179 /* Process exceptions to True or FAIL matches. */ 180 181 if (match != False) { 182 while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) 183 /* VOID */ ; 184 if (tok == 0 || list_match((char *) 0, item, match_fn) == False) { 185 if (listcopy != 0) free(listcopy); /* jkf */ 186 return (match); 187 } 188 } 189 190 if (listcopy != 0) free(listcopy); /* jkf */ 191 return (False); 192} 193 194 195/* return true if access should be allowed */ 196BOOL allow_access(char *deny_list,char *allow_list, 197 char *cname,char *caddr) 198{ 199 char *client[2]; 200 201 client[0] = cname; 202 client[1] = caddr; 203 204 /* if it is loopback then always allow unless specifically denied */ 205 if (strcmp(caddr, "127.0.0.1") == 0) { 206 if (deny_list && 207 list_match(deny_list,(char *)client,client_match)) { 208 return False; 209 } 210 return True; 211 } 212 213 /* if theres no deny list and no allow list then allow access */ 214 if ((!deny_list || *deny_list == 0) && 215 (!allow_list || *allow_list == 0)) { 216 return(True); 217 } 218 219 /* if there is an allow list but no deny list then allow only hosts 220 on the allow list */ 221 if (!deny_list || *deny_list == 0) 222 return(list_match(allow_list,(char *)client,client_match)); 223 224 /* if theres a deny list but no allow list then allow 225 all hosts not on the deny list */ 226 if (!allow_list || *allow_list == 0) 227 return(!list_match(deny_list,(char *)client,client_match)); 228 229 /* if there are both type of list then allow all hosts on the 230 allow list */ 231 if (list_match(allow_list,(char *)client,client_match)) 232 return (True); 233 234 /* if there are both type of list and it's not on the allow then 235 allow it if its not on the deny */ 236 if (list_match(deny_list,(char *)client,client_match)) 237 return (False); 238 239 return (True); 240} 241 242/* return true if access should be allowed to a service for a socket */ 243BOOL check_access(int sock, char *allow_list, char *deny_list) 244{ 245 BOOL ret = False; 246 247 if (deny_list) deny_list = strdup(deny_list); 248 if (allow_list) allow_list = strdup(allow_list); 249 250 if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0)) { 251 ret = True; 252 } 253 254 if (!ret) { 255 if (allow_access(deny_list,allow_list, 256 client_name(sock),client_addr(sock))) { 257 DEBUG(2,("Allowed connection from %s (%s)\n", 258 client_name(sock),client_addr(sock))); 259 ret = True; 260 } else { 261 DEBUG(0,("Denied connection from %s (%s)\n", 262 client_name(sock),client_addr(sock))); 263 } 264 } 265 266 if (deny_list) free(deny_list); 267 if (allow_list) free(allow_list); 268 return(ret); 269} 270