• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/lib/socket/
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