1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 #include <time.h>
5 #include "ipsvd_check.h"
6 #include "ipsvd_log.h"
7 #include "ipsvd_fmt.h"
8 #include "error.h"
9 #include "stralloc.h"
10 #include "strerr.h"
11 #include "byte.h"
12 #include "scan.h"
13 #include "str.h"
14 #include "openreadclose.h"
15 #include "open.h"
16 #include "cdb.h"
17 #include "pathexec.h"
18 #include "dns.h"
19 #include "ip4.h"
20
21 extern const char *progname;
22 static stralloc sa ={0};
23 static stralloc ips ={0};
24 static stralloc fqdn ={0};
25 static stralloc msg ={0};
26 static stralloc forwardfn ={0};
27 static stralloc moredata ={0};
28 static char *forward =0;
29 unsigned long phccmax;
30 char *phccmsg;
31
32 static struct cdb c;
33 static int fd;
34 static uint32 dlen;
35
ipsvd_instruct(stralloc * inst,stralloc * match,char * ip)36 int ipsvd_instruct(stralloc *inst, stralloc *match, char *ip) {
37 char *insts;
38 unsigned int instslen;
39 int delim;
40 int i, j;
41 int rc =IPSVD_DEFAULT;
42
43 if (inst->s && inst->len) {
44 insts =inst->s; instslen =inst->len;
45 while ((i =byte_chr(insts, instslen, 0)) < instslen) {
46 switch(*insts) {
47 case '+':
48 if ((delim =str_chr(insts, '=')) <= 1) break; /* empty inst */
49 if (insts[delim] == '=') {
50 insts[delim] =0;
51 if (! pathexec_env(insts +1, insts +delim +1)) return(-1);
52 insts[delim] ='=';
53 }
54 else if (! pathexec_env(insts +1, 0)) return(-1);
55 break;
56 case 'C':
57 if (! phccmax) break;
58 delim =scan_ulong(insts +1, &phccmax);
59 if (insts[delim +1] == ':') {
60 if (ipsvd_fmt_msg(&msg, insts +delim +2) == -1) return(-1);
61 if (! stralloc_0(&msg)) return(-1);
62 phccmsg =msg.s;
63 }
64 break;
65 case '=':
66 if (ip && (rc != IPSVD_INSTRUCT)) {
67 unsigned int next;
68
69 rc =IPSVD_DENY;
70 next =str_chr(insts +1, ':'); ++next;
71 if ((next == 2) && (insts[1] == '0')) {
72 if (! stralloc_copys(&sa, ip)) return(-1);
73 }
74 else
75 if (! stralloc_copyb(&sa, insts +1, next -1)) return(-1);
76 if (insts[next] != 0) ++next;
77
78 if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
79 if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1) {
80 if (! stralloc_0(&sa)) return(-1);
81 strerr_warn5(progname, ": warning: ",
82 "unable to look up ip address: ", sa.s,
83 ": ", &strerr_sys);
84 break;
85 }
86 if (ips.len < 4) {
87 if (! stralloc_0(&sa)) return(-1);
88 strerr_warn4(progname, ": warning: ",
89 "unable to look up ip address: ", sa.s, 0);
90 break;
91 }
92 for (j =0; j +4 <= ips.len; j +=4) {
93 char tmp[IP4_FMT];
94
95 tmp[ipsvd_fmt_ip(tmp, ips.s +j)] =0;
96 if (str_equal(tmp, ip)) {
97 inst->len =insts -inst->s +i +1;
98 if (insts[next]) {
99 forward =insts +next;
100 return(IPSVD_FORWARD);
101 }
102 return(IPSVD_INSTRUCT);
103 }
104 }
105 }
106 break;
107 case 0: case '#': /* skip empty line and comment */
108 break;
109 default:
110 strerr_warn6(progname, ": warning: ",
111 "bad instruction: ", match->s, ": ", insts, 0);
112 }
113 insts +=i +1;
114 instslen -=i +1;
115 }
116 }
117 if (rc == IPSVD_DEFAULT) return(IPSVD_INSTRUCT);
118 return(rc);
119 }
120
ipsvd_check_direntry(stralloc * d,stralloc * m,char * ip,time_t now,unsigned long t,int * rc)121 int ipsvd_check_direntry(stralloc *d, stralloc *m, char *ip,
122 time_t now, unsigned long t, int *rc) {
123 int i;
124 struct stat s;
125
126 if (stat(m->s, &s) != -1) {
127 if (t && (s.st_mode & S_IWUSR) && (now >= s.st_atime))
128 if ((now -s.st_atime) >= t) {
129 if (unlink(m->s) == -1)
130 strerr_warn4(progname, ": warning: unable to unlink: ", m->s, ": ",
131 &strerr_sys);
132 return(0);
133 }
134 if (! (s.st_mode & S_IXUSR) && ! (s.st_mode & S_IRUSR)) {
135 *rc =IPSVD_DENY; return(1);
136 }
137 if (s.st_mode & S_IXUSR) {
138 if (openreadclose(m->s, d, 256) <= 0) return(-1);
139 if (d->len && (d->s[d->len -1] == '\n')) d->len--;
140 if (! stralloc_0(d)) return(-1);
141 *rc =IPSVD_EXEC;
142 return(1);
143 }
144 if (s.st_mode & S_IRUSR) {
145 if (openreadclose(m->s, d, 256) <= 0) return(-1);
146 if (d->len && (d->s[d->len -1] == '\n')) d->len--;
147 for (i =0; i < d->len; i++) if (d->s[i] == '\n') d->s[i] =0;
148 if (! stralloc_0(d)) return(-1);
149 if ((*rc =ipsvd_instruct(d, m, ip)) == -1) return(-1);
150 return(1);
151 }
152 if (! stralloc_copys(m, "")) return(-1);
153 if (! stralloc_0(m)) return(-1);
154 *rc =IPSVD_DEFAULT;
155 return(1);
156 }
157 else if (errno != error_noent) return(-1);
158 return(0);
159 }
160
ipsvd_check_dir(stralloc * data,stralloc * match,char * dir,char * ip,char * name,unsigned long timeout)161 int ipsvd_check_dir(stralloc *data, stralloc *match, char *dir,
162 char *ip, char *name, unsigned long timeout) {
163 struct stat s;
164 int i;
165 int rc;
166 int ok;
167 int base;
168 time_t now =0;
169
170 if (stat(dir, &s) == -1) return(IPSVD_ERR);
171 if (timeout) now =time((time_t*)0);
172 if (! stralloc_copys(match, dir)) return(-1);
173 if (! stralloc_cats(match, "/")) return(-1);
174 base =match->len;
175 /* ip */
176 if (ip) {
177 if (! stralloc_cats(match, ip)) return(-1);
178 if (! stralloc_0(match)) return(-1);
179 data->len =0;
180 for (;;) {
181 ok =ipsvd_check_direntry(data, match, ip, now, timeout, &rc);
182 if (ok == -1) return(-1);
183 if (ok) {
184 if (rc == IPSVD_FORWARD) goto forwarded;
185 return(rc);
186 }
187 if ((i =byte_rchr(match->s, match->len, '.')) == match->len) break;
188 if (i <= base) break;
189 match->s[i] =0; match->len =i +1;
190 }
191 }
192 /* host */
193 if (name) {
194 for (;;) {
195 if (! *name || (*name == '.')) break;
196 match->len =base;
197 if (! stralloc_cats(match, name)) return(-1);
198 if (! stralloc_0(match)) return(-1);
199
200 ok =ipsvd_check_direntry(data, match, ip, now, timeout, &rc);
201 if (ok == -1) return(-1);
202 if (ok) {
203 if (rc == IPSVD_FORWARD) goto forwarded;
204 return(rc);
205 }
206 if ((i =byte_chr(name, str_len(name), '.')) == str_len(name)) break;
207 name +=i +1;
208 }
209 }
210 /* default */
211 match->len =base;
212 if (! stralloc_cats(match, "0")) return(-1);
213 if (! stralloc_0(match)) return(-1);
214
215 ok =ipsvd_check_direntry(data, match, ip, now, timeout, &rc);
216 if (ok == -1) return(-1);
217 if (ok) {
218 if (rc == IPSVD_FORWARD) goto forwarded;
219 return(rc);
220 }
221 if (! stralloc_copys(match, "")) return(-1);
222 if (! stralloc_0(match)) return(-1);
223 return(IPSVD_DEFAULT);
224
225 forwarded:
226 if (! stralloc_copyb(&forwardfn, match->s, base)) return(-1);
227 if (! stralloc_cats(&forwardfn, forward)) return(-1);
228 if (! stralloc_0(&forwardfn)) return(-1);
229 ok =ipsvd_check_direntry(&moredata, &forwardfn, 0, now, timeout, &rc);
230 if (ok == -1) return(-1);
231 --match->len;
232 if (! stralloc_cats(match, ",")) return(-1);
233 if (! stralloc_cats(match, forwardfn.s +base)) return(-1);
234 if (! stralloc_0(match)) return(-1);
235 if (ok) {
236 if (rc == IPSVD_EXEC)
237 data->len =0;
238 else
239 data->s[data->len -1] =',';
240 if (! stralloc_cat(data, &moredata)) return(-1);
241 return(rc);
242 }
243 strerr_warn4(progname, ": warning: ", match->s, ": not found", 0);
244 return(IPSVD_DENY);
245 }
246
ipsvd_check_cdbentry(stralloc * d,stralloc * m,char * ip,int * rc)247 int ipsvd_check_cdbentry(stralloc *d, stralloc *m, char *ip, int *rc) {
248 switch(cdb_find(&c, m->s, m->len -1)) {
249 case -1: return(-1);
250 case 1:
251 dlen =cdb_datalen(&c);
252 if (! stralloc_ready(d, dlen)) return(-1);
253 if (cdb_read(&c, d->s, dlen, cdb_datapos(&c)) == -1) return(-1);
254 if (! dlen) return(-1);
255 switch(d->s[dlen -1]) {
256 case 'D':
257 *rc =IPSVD_DENY;
258 return(1);
259 case 'X':
260 d->s[dlen -1] =0; d->len =dlen;
261 *rc =IPSVD_EXEC;
262 return(1);
263 case 'I':
264 d->s[dlen -1] =0; d->len =dlen;
265 if ((*rc =ipsvd_instruct(d, m, ip)) == -1) return(-1);
266 return(1);
267 }
268 }
269 return(0);
270 }
271
ipsvd_check_cdb(stralloc * data,stralloc * match,char * cdb,char * ip,char * name,unsigned long unused)272 int ipsvd_check_cdb(stralloc *data, stralloc *match, char *cdb,
273 char *ip, char *name, unsigned long unused) {
274 int ok;
275 int i;
276 int rc;
277
278 if ((fd =open_read(cdb)) == -1) return(IPSVD_ERR);
279 cdb_init(&c, fd);
280 if (! stralloc_copys(match, ip)) return(-1);
281 if (! stralloc_0(match)) return(-1);
282 data->len =0;
283 /* ip */
284 for (;;) {
285 ok =ipsvd_check_cdbentry(data, match, ip, &rc);
286 if (ok == -1) return(-1);
287 if (ok) {
288 if (rc == IPSVD_FORWARD) goto forwarded;
289 close(fd);
290 return(rc);
291 }
292 if ((i =byte_rchr(match->s, match->len, '.')) == match->len) break;
293 match->s[i] =0; match->len =i +1;
294 }
295 /* host */
296 if (name) {
297 for (;;) {
298 if (! *name || (*name == '.')) break;
299 if (! stralloc_copys(match, name)) return(-1);
300 if (! stralloc_0(match)) return(-1);
301 ok =ipsvd_check_cdbentry(data, match, ip, &rc);
302 if (ok == -1) return(-1);
303 if (ok) {
304 if (rc == IPSVD_FORWARD) goto forwarded;
305 close(fd);
306 return(rc);
307 }
308 if ((i =byte_chr(name, str_len(name), '.')) == str_len(name)) break;
309 name +=i +1;
310 }
311 }
312 /* default */
313 if (! stralloc_copys(match, "0")) return(-1);
314 if (! stralloc_0(match)) return(-1);
315 ok =ipsvd_check_cdbentry(data, match, ip, &rc);
316 if (ok == -1) return(-1);
317 if (ok) {
318 if (rc == IPSVD_FORWARD) goto forwarded;
319 close(fd);
320 return(rc);
321 }
322 if (! stralloc_copys(match, "")) return(-1);
323 if (! stralloc_0(match)) return(-1);
324 close(fd);
325 return(IPSVD_DEFAULT);
326
327 forwarded:
328 if (! stralloc_copys(&forwardfn, forward)) return(-1);
329 if (! stralloc_0(&forwardfn)) return(-1);
330 ok =ipsvd_check_cdbentry(&moredata, &forwardfn, 0, &rc);
331 close(fd);
332 if (ok == -1) return(-1);
333 --match->len;
334 if (! stralloc_cats(match, ",")) return(-1);
335 if (! stralloc_cats(match, forwardfn.s)) return(-1);
336 if (! stralloc_0(match)) return(-1);
337 if (ok) {
338 if (rc == IPSVD_EXEC)
339 data->len =0;
340 else
341 data->s[data->len -1] =',';
342 if (! stralloc_cat(data, &moredata)) return(-1);
343 return(rc);
344 }
345 strerr_warn4(progname, ": warning: ", match->s, ": not found", 0);
346 return(IPSVD_DENY);
347 }
348
ipsvd_check(int c,stralloc * data,stralloc * match,char * db,char * ip,char * name,unsigned long timeout)349 int ipsvd_check(int c, stralloc *data, stralloc *match, char *db,
350 char *ip, char *name, unsigned long timeout) {
351 if (c)
352 return(ipsvd_check_cdb(data, match, db, ip, name, 0));
353 else
354 return(ipsvd_check_dir(data, match, db, ip, name, timeout));
355 }
356