ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules/httpd/auth-ip.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 8677 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# User Rev Content
1 michael 3389 /* IP address authorization module for HTTP server.
2     *
3     * IRC Services is copyright (c) 1996-2009 Andrew Church.
4     * E-mail: <achurch@achurch.org>
5     * Parts written by Andrew Kempe and others.
6     * This program is free but copyrighted software; see the file GPL.txt for
7     * details.
8     */
9    
10     #include "services.h"
11     #include "modules.h"
12     #include "conffile.h"
13     #include "http.h"
14     #include <netinet/in.h>
15     #include <netdb.h>
16    
17     /*************************************************************************/
18    
19     static Module *module_httpd;
20    
21     /* List of hosts to allow/deny */
22     typedef struct {
23     char *path;
24     int pathlen; /* for convenience */
25     uint32 ip, mask; /* network byte order */
26     int allow; /* 1 = allow, 0 = deny */
27     } DirInfo;
28     static DirInfo *protected = NULL;
29     static int protected_count = 0;
30    
31     /*************************************************************************/
32     /************************ Authorization callback *************************/
33     /*************************************************************************/
34    
35     static int do_auth(Client *c, int *close_ptr)
36     {
37     int i;
38    
39     ARRAY_FOREACH (i, protected) {
40     if (strncmp(c->url, protected[i].path, protected[i].pathlen) != 0)
41     continue;
42     if ((c->ip & protected[i].mask) != protected[i].ip)
43     continue;
44     if (protected[i].allow) {
45     return HTTP_AUTH_UNDECIDED;
46     } else {
47     module_log("Denying request for %s from %s", c->url, c->address);
48     return HTTP_AUTH_DENY;
49     }
50     }
51     return HTTP_AUTH_UNDECIDED;
52     }
53    
54     /*************************************************************************/
55     /***************************** Module stuff ******************************/
56     /*************************************************************************/
57    
58     static int do_prefix(const char *filename, int linenum, char *param);
59     static int do_AllowHost(const char *filename, int linenum, char *param);
60     static int do_DenyHost(const char *filename, int linenum, char *param);
61     static int do_AllowDenyHost(const char *filename, int linenum, char *param,
62     int allow);
63     ConfigDirective module_config[] = {
64     { "AllowHost", { { CD_FUNC, 0, do_prefix },
65     { CD_FUNC, 0, do_AllowHost } } },
66     { "DenyHost", { { CD_FUNC, 0, do_prefix },
67     { CD_FUNC, 0, do_DenyHost } } },
68     { NULL }
69     };
70    
71     static char *prefix = NULL;
72    
73     /*************************************************************************/
74    
75     static int do_prefix(const char *filename, int linenum, char *param)
76     {
77     if (filename) {
78     free(prefix);
79     prefix = strdup(param);
80     if (!prefix) {
81     config_error(filename, linenum, "Out of memory");
82     return 0;
83     }
84     }
85     return 1;
86     }
87    
88     static int do_AllowHost(const char *filename, int linenum, char *param)
89     {
90     return do_AllowDenyHost(filename, linenum, param, 1);
91     }
92    
93     static int do_DenyHost(const char *filename, int linenum, char *param)
94     {
95     return do_AllowDenyHost(filename, linenum, param, 0);
96     }
97    
98     /*************************************************************************/
99    
100     static int do_AllowDenyHost(const char *filename, int linenum, char *param,
101     int allow)
102     {
103     char *s;
104     int mask = 32;
105     const uint8 *ip;
106     int recursing = 0, i;
107     DirInfo di;
108     static DirInfo *new_protected = NULL;
109     static int new_protected_count = 0;
110    
111     if (!filename) {
112     /* filename == NULL, special actions */
113     switch (linenum) {
114     case CDFUNC_INIT: /* prepare for reading */
115     free(new_protected);
116     new_protected = NULL;
117     new_protected_count = 0;
118     break;
119     case CDFUNC_SET: /* store new values in config variables */
120     if (new_protected_count >= 0) {
121     ARRAY_FOREACH (i, protected)
122     free(protected[i].path);
123     free(protected);
124     protected = new_protected;
125     protected_count = new_protected_count;
126     new_protected = NULL;
127     new_protected_count = -1; /* flag to say "don't copy again" */
128     }
129     break;
130     case CDFUNC_DECONFIG: /* clear out config variables */
131     ARRAY_FOREACH (i, protected)
132     free(protected[i].path);
133     free(protected);
134     protected = NULL;
135     protected_count = 0;
136     break;
137     } /* switch (linenum) */
138     return 1;
139     } /* if (!filename) */
140    
141     /* filename != NULL, process directive */
142    
143     if (linenum < 0) {
144     recursing = 1;
145     linenum = -linenum;
146     }
147     di.path = prefix;
148     di.pathlen = strlen(prefix);
149     prefix = NULL;
150    
151     s = strchr(param, '/');
152     if (s) {
153     *s++ = 0;
154     mask = (int)atolsafe(s, 1, 31);
155     if (mask < 1) {
156     config_error(filename, linenum, "Invalid mask length `%s'", s);
157     free(di.path);
158     return 0;
159     }
160     }
161    
162     if (strcmp(param, "*") == 0) {
163     /* All-hosts wildcard -> equivalent to 0.0.0.0/0 */
164     ip = (const uint8 *)"\0\0\0\0";
165     mask = 0;
166     } else if ((ip = pack_ip(param)) != NULL) {
167     /* IP address -> okay as is */
168     } else {
169     /* hostname -> check for double recursion, then look up and
170     * recursively add addresses */
171     #ifdef HAVE_GETHOSTBYNAME
172     struct hostent *hp;
173     #endif
174     if (recursing) {
175     config_error(filename, linenum, "BUG: double recursion (param=%s)",
176     param);
177     free(di.path);
178     return 0;
179     }
180     #ifdef HAVE_GETHOSTBYNAME
181     if ((hp = gethostbyname(param)) != NULL) {
182     if (hp->h_addrtype == AF_INET) {
183     for (i = 0; hp->h_addr_list[i]; i++) {
184     char ipbuf[16];
185     ip = (const uint8 *)hp->h_addr_list[i];
186     snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u",
187     ip[0], ip[1], ip[2], ip[3]);
188     if (strlen(ipbuf) > 15) {
189     config_error(filename, linenum,
190     "BUG: strlen(ipbuf) > 15 [%s]", ipbuf);
191     free(di.path);
192     return 0;
193     }
194     prefix = strdup(di.path);
195     if (!prefix) {
196     config_error(filename, linenum, "Out of memory");
197     free(di.path);
198     return 0;
199     }
200     if (!do_AllowDenyHost(filename, -linenum, ipbuf, allow)) {
201     free(di.path);
202     return 0;
203     }
204     }
205     free(di.path);
206     return 1; /* Success */
207     } else {
208     config_error(filename, linenum, "%s: no IPv4 addresses found",
209     param);
210     }
211     } else {
212     config_error(filename, linenum, "%s: %s", param,
213     hstrerror(h_errno));
214     }
215     #else
216     config_error(filename, linenum,
217     "gethostbyname() not available, hostnames may not be"
218     " used");
219     #endif
220     free(di.path);
221     return 0;
222     }
223    
224     di.ip = *((uint32 *)ip);
225     di.mask = mask ? htonl(0xFFFFFFFFUL << (32-mask)) : 0;
226     di.ip &= di.mask;
227     di.allow = allow;
228     ARRAY_EXTEND(new_protected);
229     new_protected[new_protected_count-1] = di;
230     return 1;
231     }
232    
233     /*************************************************************************/
234     /*************************************************************************/
235    
236     int init_module(void)
237     {
238     module_httpd = find_module("httpd/main");
239     if (!module_httpd) {
240     module_log("Main httpd module not loaded");
241     exit_module(0);
242     return 0;
243     }
244     use_module(module_httpd);
245    
246     if (!add_callback(module_httpd, "auth", do_auth)) {
247     module_log("Unable to add callback");
248     exit_module(0);
249     return 0;
250     }
251    
252     return 1;
253     }
254    
255     /*************************************************************************/
256    
257     int exit_module(int shutdown_unused)
258     {
259     if (module_httpd) {
260     remove_callback(module_httpd, "auth", do_auth);
261     unuse_module(module_httpd);
262     module_httpd = NULL;
263     }
264    
265     return 1;
266     }
267    
268     /*************************************************************************/
269    
270     /*
271     * Local variables:
272     * c-file-style: "stroustrup"
273     * c-file-offsets: ((case-label . *) (statement-case-intro . *))
274     * indent-tabs-mode: nil
275     * End:
276     *
277     * vim: expandtab shiftwidth=4:
278     */