~bug-zappers/ubuntu/lucid/samba/bugzapping

« back to all changes in this revision

Viewing changes to source/lib/access.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-10-15 12:31:58 UTC
  • Revision ID: james.westby@ubuntu.com-20041015123158-aokykzdqkdgy6dfx
Tags: upstream-3.0.7
ImportĀ upstreamĀ versionĀ 3.0.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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@samba.org
 
9
*/
 
10
 
 
11
#include "includes.h"
 
12
 
 
13
#define FAIL            (-1)
 
14
 
 
15
#define ALLONES  ((uint32)0xFFFFFFFF)
 
16
 
 
17
/* masked_match - match address against netnumber/netmask */
 
18
static BOOL masked_match(const char *tok, const char *slash, const char *s)
 
19
{
 
20
        uint32 net;
 
21
        uint32 mask;
 
22
        uint32 addr;
 
23
        fstring tok_cpy;
 
24
 
 
25
        if ((addr = interpret_addr(s)) == INADDR_NONE)
 
26
                return (False);
 
27
 
 
28
        fstrcpy(tok_cpy, tok);
 
29
        tok_cpy[PTR_DIFF(slash,tok)] = '\0';
 
30
        net = interpret_addr(tok_cpy);
 
31
        tok_cpy[PTR_DIFF(slash,tok)] = '/';
 
32
 
 
33
        if (strlen(slash + 1) > 2) {
 
34
                mask = interpret_addr(slash + 1);
 
35
        } else {
 
36
                mask = (uint32)((ALLONES >> atoi(slash + 1)) ^ ALLONES);
 
37
                /* convert to network byte order */
 
38
                mask = htonl(mask);
 
39
        }
 
40
 
 
41
        if (net == INADDR_NONE || mask == INADDR_NONE) {
 
42
                DEBUG(0,("access: bad net/mask access control: %s\n", tok));
 
43
                return (False);
 
44
        }
 
45
        
 
46
        return ((addr & mask) == (net & mask));
 
47
}
 
48
 
 
49
/* string_match - match string against token */
 
50
static BOOL string_match(const char *tok,const char *s, char *invalid_char)
 
51
{
 
52
        size_t     tok_len;
 
53
        size_t     str_len;
 
54
        const char   *cut;
 
55
 
 
56
        *invalid_char = '\0';
 
57
 
 
58
        /* Return True if a token has the magic value "ALL". Return
 
59
         * FAIL if the token is "FAIL". If the token starts with a "."
 
60
         * (domain name), return True if it matches the last fields of
 
61
         * the string. If the token has the magic value "LOCAL",
 
62
         * return True if the string does not contain a "."
 
63
         * character. If the token ends on a "." (network number),
 
64
         * return True if it matches the first fields of the
 
65
         * string. If the token begins with a "@" (netgroup name),
 
66
         * return True if the string is a (host) member of the
 
67
         * netgroup. Return True if the token fully matches the
 
68
         * string. If the token is a netnumber/netmask pair, return
 
69
         * True if the address is a member of the specified subnet.  
 
70
         */
 
71
 
 
72
        if (tok[0] == '.') {                    /* domain: match last fields */
 
73
                if ((str_len = strlen(s)) > (tok_len = strlen(tok))
 
74
                    && strequal(tok, s + str_len - tok_len))
 
75
                        return (True);
 
76
        } else if (tok[0] == '@') { /* netgroup: look it up */
 
77
#ifdef  HAVE_NETGROUP
 
78
                static char *mydomain = NULL;
 
79
                char *hostname = NULL;
 
80
                BOOL netgroup_ok = False;
 
81
 
 
82
                if (!mydomain)
 
83
                        yp_get_default_domain(&mydomain);
 
84
 
 
85
                if (!mydomain) {
 
86
                        DEBUG(0,("Unable to get default yp domain.\n"));
 
87
                        return False;
 
88
                }
 
89
                if (!(hostname = strdup(s))) {
 
90
                        DEBUG(1,("out of memory for strdup!\n"));
 
91
                        return False;
 
92
                }
 
93
                
 
94
                netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
 
95
                
 
96
                DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", 
 
97
                         hostname,
 
98
                         mydomain, 
 
99
                         tok+1,
 
100
                         BOOLSTR(netgroup_ok)));
 
101
 
 
102
                SAFE_FREE(hostname);
 
103
      
 
104
                if (netgroup_ok)
 
105
                        return(True);
 
106
#else
 
107
                DEBUG(0,("access: netgroup support is not configured\n"));
 
108
                return (False);
 
109
#endif
 
110
        } else if (strequal(tok, "ALL")) {      /* all: match any */
 
111
                return (True);
 
112
        } else if (strequal(tok, "FAIL")) {     /* fail: match any */
 
113
                return (FAIL);
 
114
        } else if (strequal(tok, "LOCAL")) {    /* local: no dots */
 
115
                if (strchr_m(s, '.') == 0 && !strequal(s, "unknown"))
 
116
                        return (True);
 
117
        } else if (strequal(tok, s)) {   /* match host name or address */
 
118
                return (True);
 
119
        } else if (tok[(tok_len = strlen(tok)) - 1] == '.') {   /* network */
 
120
                if (strncmp(tok, s, tok_len) == 0)
 
121
                        return (True);
 
122
        } else if ((cut = strchr_m(tok, '/')) != 0) {   /* netnumber/netmask */
 
123
                if (isdigit((int)s[0]) && masked_match(tok, cut, s))
 
124
                        return (True);
 
125
        } else if (strchr_m(tok, '*') != 0) {
 
126
                *invalid_char = '*';
 
127
        } else if (strchr_m(tok, '?') != 0) {
 
128
                *invalid_char = '?';
 
129
        }
 
130
        return (False);
 
131
}
 
132
 
 
133
/* client_match - match host name and address against token */
 
134
static BOOL client_match(const char *tok, const char *item)
 
135
{
 
136
        const char **client = (const char **)item;
 
137
        BOOL match;
 
138
        char invalid_char = '\0';
 
139
 
 
140
        /*
 
141
         * Try to match the address first. If that fails, try to match the host
 
142
         * name if available.
 
143
         */
 
144
 
 
145
        if ((match = string_match(tok, client[1], &invalid_char)) == 0) {
 
146
                if(invalid_char)
 
147
                        DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
 
148
token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
 
149
 
 
150
                if (client[0][0] != 0)
 
151
                        match = string_match(tok, client[0], &invalid_char);
 
152
 
 
153
                if(invalid_char)
 
154
                        DEBUG(0,("client_match: address match failing due to invalid character '%c' found in \
 
155
token '%s' in an allow/deny hosts line.\n", invalid_char, tok ));
 
156
        }
 
157
 
 
158
        return (match);
 
159
}
 
160
 
 
161
/* list_match - match an item against a list of tokens with exceptions */
 
162
static BOOL list_match(const char **list,const char *item,
 
163
                BOOL (*match_fn)(const char *, const char *))
 
164
{
 
165
        BOOL match = False;
 
166
 
 
167
        if (!list)
 
168
                return False;
 
169
 
 
170
        /*
 
171
         * Process tokens one at a time. We have exhausted all possible matches
 
172
         * when we reach an "EXCEPT" token or the end of the list. If we do find
 
173
         * a match, look for an "EXCEPT" list and recurse to determine whether
 
174
         * the match is affected by any exceptions.
 
175
         */
 
176
 
 
177
        for (; *list ; list++) {
 
178
                if (strequal(*list, "EXCEPT"))  /* EXCEPT: give up */
 
179
                        break;
 
180
                if ((match = (*match_fn) (*list, item)))        /* True or FAIL */
 
181
                        break;
 
182
        }
 
183
        /* Process exceptions to True or FAIL matches. */
 
184
 
 
185
        if (match != False) {
 
186
                while (*list  && !strequal(*list, "EXCEPT"))
 
187
                        list++;
 
188
 
 
189
                for (; *list; list++) {
 
190
                        if ((*match_fn) (*list, item)) /* Exception Found */
 
191
                                return False;
 
192
                }
 
193
        }
 
194
 
 
195
        return (match);
 
196
}
 
197
 
 
198
/* return true if access should be allowed */
 
199
static BOOL allow_access_internal(const char **deny_list,const char **allow_list,
 
200
                        const char *cname, const char *caddr)
 
201
{
 
202
        const char *client[2];
 
203
 
 
204
        client[0] = cname;
 
205
        client[1] = caddr;  
 
206
 
 
207
        /* if it is loopback then always allow unless specifically denied */
 
208
        if (strcmp(caddr, "127.0.0.1") == 0) {
 
209
                /*
 
210
                 * If 127.0.0.1 matches both allow and deny then allow.
 
211
                 * Patch from Steve Langasek vorlon@netexpress.net.
 
212
                 */
 
213
                if (deny_list && 
 
214
                        list_match(deny_list,(const char *)client,client_match) &&
 
215
                                (!allow_list ||
 
216
                                !list_match(allow_list,(const char *)client, client_match))) {
 
217
                        return False;
 
218
                }
 
219
                return True;
 
220
        }
 
221
 
 
222
        /* if theres no deny list and no allow list then allow access */
 
223
        if ((!deny_list || *deny_list == 0) && 
 
224
            (!allow_list || *allow_list == 0)) {
 
225
                return(True);  
 
226
        }
 
227
 
 
228
        /* if there is an allow list but no deny list then allow only hosts
 
229
           on the allow list */
 
230
        if (!deny_list || *deny_list == 0)
 
231
                return(list_match(allow_list,(const char *)client,client_match));
 
232
 
 
233
        /* if theres a deny list but no allow list then allow
 
234
           all hosts not on the deny list */
 
235
        if (!allow_list || *allow_list == 0)
 
236
                return(!list_match(deny_list,(const char *)client,client_match));
 
237
 
 
238
        /* if there are both types of list then allow all hosts on the
 
239
           allow list */
 
240
        if (list_match(allow_list,(const char *)client,client_match))
 
241
                return (True);
 
242
 
 
243
        /* if there are both types of list and it's not on the allow then
 
244
           allow it if its not on the deny */
 
245
        if (list_match(deny_list,(const char *)client,client_match))
 
246
                return (False);
 
247
        
 
248
        return (True);
 
249
}
 
250
 
 
251
/* return true if access should be allowed */
 
252
BOOL allow_access(const char **deny_list, const char **allow_list,
 
253
                  const char *cname, const char *caddr)
 
254
{
 
255
        BOOL ret;
 
256
        char *nc_cname = smb_xstrdup(cname);
 
257
        char *nc_caddr = smb_xstrdup(caddr);
 
258
        
 
259
        ret = allow_access_internal(deny_list, allow_list, nc_cname, nc_caddr);
 
260
 
 
261
        SAFE_FREE(nc_cname);
 
262
        SAFE_FREE(nc_caddr);
 
263
        return ret;
 
264
}
 
265
 
 
266
/* return true if the char* contains ip addrs only.  Used to avoid 
 
267
gethostbyaddr() calls */
 
268
 
 
269
static BOOL only_ipaddrs_in_list(const char** list)
 
270
{
 
271
        BOOL only_ip = True;
 
272
        
 
273
        if (!list)
 
274
                return True;
 
275
                        
 
276
        for (; *list ; list++) {
 
277
                /* factor out the special strings */
 
278
                if (strequal(*list, "ALL") || strequal(*list, "FAIL") || 
 
279
                    strequal(*list, "EXCEPT")) {
 
280
                        continue;
 
281
                }
 
282
                
 
283
                if (!is_ipaddress(*list)) {
 
284
                        /* 
 
285
                         * if we failed, make sure that it was not because the token
 
286
                         * was a network/netmask pair.  Only network/netmask pairs
 
287
                         * have a '/' in them
 
288
                         */
 
289
                        if ((strchr_m(*list, '/')) == NULL) {
 
290
                                only_ip = False;
 
291
                                DEBUG(3,("only_ipaddrs_in_list: list has non-ip address (%s)\n", *list));
 
292
                                break;
 
293
                        }
 
294
                }
 
295
        }
 
296
        
 
297
        return only_ip;
 
298
}
 
299
 
 
300
/* return true if access should be allowed to a service for a socket */
 
301
BOOL check_access(int sock, const char **allow_list, const char **deny_list)
 
302
{
 
303
        BOOL ret = False;
 
304
        BOOL only_ip = False;
 
305
        
 
306
        if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0))
 
307
                ret = True;
 
308
 
 
309
        if (!ret) {
 
310
                /* bypass gethostbyaddr() calls if the lists only contain IP addrs */
 
311
                if (only_ipaddrs_in_list(allow_list) && only_ipaddrs_in_list(deny_list)) {
 
312
                        only_ip = True;
 
313
                        DEBUG (3, ("check_access: no hostnames in host allow/deny list.\n"));
 
314
                        ret = allow_access(deny_list,allow_list, "", get_peer_addr(sock));
 
315
                } else {
 
316
                        DEBUG (3, ("check_access: hostnames in host allow/deny list.\n"));
 
317
                        ret = allow_access(deny_list,allow_list, get_peer_name(sock,True),
 
318
                                           get_peer_addr(sock));
 
319
                }
 
320
                
 
321
                if (ret) {
 
322
                        DEBUG(2,("Allowed connection from %s (%s)\n",
 
323
                                 only_ip ? "" : get_peer_name(sock,True),
 
324
                                 get_peer_addr(sock)));
 
325
                } else {
 
326
                        DEBUG(0,("Denied connection from %s (%s)\n",
 
327
                                 only_ip ? "" : get_peer_name(sock,True),
 
328
                                 get_peer_addr(sock)));
 
329
                }
 
330
        }
 
331
 
 
332
        return(ret);
 
333
}