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

# Content
1 /* 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 */