72
|
1 /*
|
|
2
|
|
3 Copyright (c) 2004 Carl Byington - 510 Software Group, released under
|
|
4 the GPL version 2 or any later version at your choice available at
|
|
5 http://www.fsf.org/licenses/gpl.txt
|
|
6
|
|
7 */
|
|
8
|
|
9 #include "includes.h"
|
71
|
10
|
73
|
11 static char* context_version="$Id$";
|
71
|
12
|
|
13 char *token_black;
|
|
14 char *token_content;
|
|
15 char *token_context;
|
|
16 char *token_dccfrom;
|
|
17 char *token_dccto;
|
|
18 char *token_default;
|
|
19 char *token_dnsbl;
|
|
20 char *token_dnsbll;
|
|
21 char *token_envfrom;
|
|
22 char *token_envto;
|
|
23 char *token_filter;
|
|
24 char *token_host_limit;
|
|
25 char *token_html_limit;
|
|
26 char *token_html_tags;
|
|
27 char *token_ignore;
|
|
28 char *token_include;
|
|
29 char *token_inherit;
|
|
30 char *token_lbrace;
|
75
|
31 char *token_mailhost;
|
71
|
32 char *token_many;
|
|
33 char *token_off;
|
75
|
34 char *token_ok2;
|
71
|
35 char *token_ok;
|
|
36 char *token_on;
|
|
37 char *token_rbrace;
|
|
38 char *token_semi;
|
|
39 char *token_soft;
|
75
|
40 char *token_substitute;
|
71
|
41 char *token_tld;
|
|
42 char *token_unknown;
|
|
43 char *token_white;
|
|
44
|
|
45 string_set all_strings; // owns all the strings, only modified by the config loader thread
|
75
|
46 const int maxlen = 1000;
|
71
|
47
|
|
48 DNSBL::DNSBL(char *n, char *s, char *m) {
|
|
49 name = n;
|
|
50 suffix = s;
|
|
51 message = m;
|
|
52 }
|
|
53
|
|
54
|
|
55 CONFIG::CONFIG() {
|
|
56 reference_count = 0;
|
|
57 generation = 0;
|
|
58 load_time = 0;
|
|
59 default_context = NULL;
|
|
60 }
|
|
61
|
|
62
|
|
63 CONFIG::~CONFIG() {
|
|
64 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
|
|
65 CONTEXT *c = *i;
|
|
66 delete c;
|
|
67 }
|
|
68 }
|
|
69
|
|
70
|
|
71 void CONFIG::add_context(CONTEXTP con) {
|
|
72 contexts.push_back(con);
|
|
73 if (!default_context && !con->get_parent()) {
|
|
74 // first global context
|
|
75 default_context = con;
|
|
76 }
|
|
77 }
|
|
78
|
|
79
|
75
|
80 void CONFIG::add_to(char *to, CONTEXTP con) {
|
|
81 context_map::iterator i = env_to.find(to);
|
71
|
82 if (i != env_to.end()) {
|
75
|
83 CONTEXTP c = (*i).second;
|
|
84 if ((c != con) && (c != con->get_parent())) {
|
|
85 char oldname[maxlen];
|
|
86 char newname[maxlen];
|
|
87 char *oldn = c->get_full_name(oldname, maxlen);
|
|
88 char *newn = con->get_full_name(newname, maxlen);
|
|
89 char buf[maxlen*3];
|
|
90 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to);
|
|
91 my_syslog(buf);
|
|
92 }
|
71
|
93 }
|
75
|
94 env_to[to] = con;
|
|
95 }
|
|
96
|
|
97
|
|
98 CONTEXTP CONFIG::find_context(char *to) {
|
|
99 context_map::iterator i = env_to.find(to);
|
|
100 if (i != env_to.end()) return (*i).second; // found user@domain.tld key
|
71
|
101 char *x = strchr(to, '@');
|
|
102 if (x) {
|
|
103 x++;
|
|
104 i = env_to.find(x);
|
75
|
105 if (i != env_to.end()) return (*i).second; // found domain.tld key
|
|
106 char y = *x;
|
|
107 *x = '\0';
|
|
108 i = env_to.find(to);
|
|
109 *x = y;
|
|
110 if (i != env_to.end()) return (*i).second; // found user@ key
|
71
|
111 }
|
75
|
112 return default_context;
|
71
|
113 }
|
|
114
|
|
115
|
|
116 void CONFIG::dump() {
|
|
117 if (default_context) default_context->dump();
|
|
118 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
|
|
119 CONTEXTP c = *i;
|
|
120 CONTEXTP p = c->get_parent();
|
|
121 if (!p && (c != default_context)) c->dump();
|
|
122 }
|
75
|
123 char buf[maxlen];
|
|
124 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) {
|
|
125 char *to = (*i).first;
|
|
126 CONTEXTP con = (*i).second;
|
|
127 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen));
|
|
128 }
|
71
|
129 }
|
|
130
|
|
131
|
|
132 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) {
|
|
133 parent = parent_;
|
|
134 name = name_;
|
|
135 env_from_default = (parent) ? token_inherit : token_unknown;
|
|
136 content_filtering = (parent) ? parent->content_filtering : false;
|
|
137 content_suffix = NULL;
|
|
138 content_message = NULL;
|
75
|
139 host_limit = (parent) ? parent->host_limit : 0;
|
71
|
140 host_limit_message = NULL;
|
75
|
141 host_random = (parent) ? parent->host_random : false;
|
|
142 tag_limit = (parent) ? parent->tag_limit : 0;
|
71
|
143 tag_limit_message = NULL;
|
|
144 }
|
|
145
|
|
146
|
|
147 CONTEXT::~CONTEXT() {
|
|
148 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) {
|
|
149 DNSBLP d = (*i).second;
|
|
150 // delete the underlying DNSBL objects.
|
|
151 delete d;
|
|
152 }
|
|
153 }
|
|
154
|
|
155
|
|
156 char *CONTEXT::get_full_name(char *buffer, int size) {
|
|
157 if (!parent) return name;
|
|
158 char buf[maxlen];
|
|
159 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name);
|
|
160 return buffer;
|
|
161 }
|
|
162
|
|
163
|
|
164 bool CONTEXT::cover_env_to(char *to) {
|
|
165 char buffer[maxlen];
|
|
166 char *x = strchr(to, '@');
|
|
167 if (x) x++;
|
|
168 else x = to;
|
75
|
169 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@
|
71
|
170 string_set::iterator i = env_to.find(x);
|
|
171 if (i != env_to.end()) return true;
|
75
|
172 return false;
|
71
|
173 }
|
|
174
|
|
175
|
|
176 char *CONTEXT::find_from(char *from) {
|
|
177 string_map::iterator i = env_from.find(from);
|
75
|
178 if (i != env_from.end()) return (*i).second; // found user@domain.tld key
|
71
|
179 char *x = strchr(from, '@');
|
|
180 if (x) {
|
|
181 x++;
|
|
182 i = env_from.find(x);
|
75
|
183 if (i != env_from.end()) return (*i).second; // found domain.tld key
|
|
184 char y = *x;
|
|
185 *x = '\0';
|
|
186 i = env_from.find(from);
|
|
187 *x = y;
|
|
188 if (i != env_from.end()) return (*i).second; // found user@ key
|
71
|
189 }
|
|
190 if ((env_from_default == token_inherit) && parent) {
|
|
191 return parent->find_from(from);
|
|
192 }
|
75
|
193 return (env_from_default == token_inherit) ? token_unknown : env_from_default;
|
71
|
194 }
|
|
195
|
|
196
|
75
|
197 CONTEXTP CONTEXT::find_context(char *from) {
|
|
198 context_map::iterator i = env_from_context.find(from);
|
|
199 if (i != env_from_context.end()) return (*i).second; // found user@domain.tld key
|
71
|
200 char *x = strchr(from, '@');
|
|
201 if (x) {
|
|
202 x++;
|
75
|
203 i = env_from_context.find(x);
|
|
204 if (i != env_from_context.end()) return (*i).second; // found domain.tld key
|
|
205 char y = *x;
|
|
206 *x = '\0';
|
|
207 i = env_from_context.find(from);
|
|
208 *x = y;
|
|
209 if (i != env_from_context.end()) return (*i).second; // found user@ key
|
71
|
210 }
|
|
211 return this;
|
|
212 }
|
|
213
|
|
214
|
|
215 CONTEXTP CONTEXT::find_from_context_name(char *name) {
|
|
216 context_map::iterator i = children.find(name);
|
|
217 if (i != children.end()) return (*i).second;
|
|
218 return NULL;
|
|
219 }
|
|
220
|
|
221
|
|
222 DNSBLP CONTEXT::find_dnsbl(char *name) {
|
|
223 dnsblp_map::iterator i = dnsbl_names.find(name);
|
|
224 if (i != dnsbl_names.end()) return (*i).second;
|
|
225 if (parent) return parent->find_dnsbl(name);
|
|
226 return NULL;
|
|
227 }
|
|
228
|
|
229
|
72
|
230 bool CONTEXT::acceptable_content(recorder &memory, char *&msg) {
|
|
231 if (memory.excessive_bad_tags(tag_limit)) {
|
|
232 msg = tag_limit_message;
|
|
233 return false;
|
|
234 }
|
|
235 if (!host_random && memory.excessive_hosts(host_limit)) {
|
|
236 msg = host_limit_message;
|
|
237 return false;
|
|
238 }
|
|
239 }
|
|
240
|
|
241
|
71
|
242 void CONTEXT::dump(int level) {
|
|
243 char indent[maxlen];
|
|
244 int i = min(maxlen-1, level*4);
|
|
245 memset(indent, ' ', i);
|
|
246 indent[i] = '\0';
|
75
|
247 char buf[maxlen];
|
|
248 char *fullname = get_full_name(buf,maxlen);
|
|
249 printf("%s context %s { \t// %s\n", indent, name, fullname);
|
71
|
250
|
|
251 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) {
|
|
252 char *n = (*i).first;
|
|
253 DNSBL &d = *(*i).second;
|
|
254 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message);
|
|
255 }
|
|
256
|
|
257 if (!dnsbl_list.empty()) {
|
|
258 printf("%s dnsbl_list", indent);
|
|
259 for (dnsblp_list::iterator i=dnsbl_list.begin(); i!=dnsbl_list.end(); i++) {
|
|
260 DNSBL &d = *(*i);
|
|
261 printf(" %s", d.name);
|
|
262 }
|
|
263 printf("; \n");
|
|
264 }
|
|
265
|
|
266 if (content_filtering) {
|
|
267 printf("%s content on { \n", indent, env_from_default);
|
|
268 if (content_suffix) {
|
|
269 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message);
|
|
270 }
|
|
271 if (!content_host_ignore.empty()) {
|
|
272 printf("%s ignore { \n", indent);
|
|
273 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) {
|
|
274 printf("%s %s; \n", indent, *i);
|
|
275 }
|
|
276 printf("%s }; \n", indent);
|
|
277 }
|
|
278 if (!content_tlds.empty()) {
|
|
279 printf("%s tld { \n", indent);
|
|
280 printf("%s ", indent);
|
|
281 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) {
|
|
282 printf("%s; ", *i);
|
|
283 }
|
|
284 printf("\n%s }; \n", indent);
|
|
285 }
|
|
286 if (!html_tags.empty()) {
|
|
287 printf("%s html_tags { \n", indent);
|
|
288 printf("%s ", indent);
|
|
289 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) {
|
|
290 printf("%s; ", *i);
|
|
291 }
|
|
292 printf("\n%s }; \n", indent);
|
|
293 }
|
|
294 if (host_limit_message) {
|
|
295 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message);
|
|
296 }
|
|
297 else if (host_random) {
|
|
298 printf("%s host_limit soft %d; \n", indent, host_limit);
|
|
299 }
|
|
300 else {
|
|
301 printf("%s host_limit off; \n", indent);
|
|
302 }
|
|
303 if (tag_limit_message) {
|
75
|
304 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message);
|
71
|
305 }
|
|
306 else {
|
75
|
307 printf("%s html_limit off; \n", indent);
|
71
|
308 }
|
|
309 printf("%s }; \n", indent);
|
|
310 }
|
|
311 else {
|
|
312 printf("%s content off {}; \n", indent, env_from_default);
|
|
313 }
|
|
314
|
75
|
315 printf("%s env_to { \t// %s\n", indent, fullname);
|
71
|
316 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) {
|
|
317 printf("%s %s; \n", indent, *i);
|
|
318 }
|
|
319 printf("%s }; \n", indent);
|
|
320
|
|
321 for (context_map::iterator i=children.begin(); i!=children.end(); i++) {
|
|
322 CONTEXTP c = (*i).second;
|
|
323 c->dump(level+1);
|
|
324 }
|
|
325
|
75
|
326 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname);
|
71
|
327 if (!env_from.empty()) {
|
|
328 printf("%s // white/black/unknown \n", indent);
|
|
329 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) {
|
|
330 char *f = (*i).first;
|
|
331 char *t = (*i).second;
|
75
|
332 printf("%s %s \t%s; \n", indent, f, t);
|
71
|
333 }
|
|
334 }
|
|
335 if (!env_from_context.empty()) {
|
|
336 printf("%s // child contexts \n", indent);
|
|
337 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) {
|
|
338 char *f = (*j).first;
|
|
339 CONTEXTP t = (*j).second;
|
75
|
340 printf("%s %s \t%s; \n", indent, f, t->name);
|
71
|
341 }
|
|
342 }
|
|
343 printf("%s }; \n", indent);
|
|
344
|
|
345 printf("%s }; \n", indent);
|
|
346 }
|
|
347
|
|
348
|
|
349 ////////////////////////////////////////////////
|
|
350 // helper to discard the strings held by a string_set
|
|
351 //
|
74
|
352 void discard(string_set &s) {
|
71
|
353 for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
|
|
354 free(*i);
|
|
355 }
|
|
356 s.clear();
|
|
357 }
|
|
358
|
|
359
|
|
360 ////////////////////////////////////////////////
|
|
361 // helper to register a string in a string set
|
|
362 //
|
|
363 char* register_string(string_set &s, char *name) {
|
|
364 string_set::iterator i = s.find(name);
|
|
365 if (i != s.end()) return *i;
|
|
366 char *x = strdup(name);
|
|
367 s.insert(x);
|
|
368 return x;
|
|
369 }
|
|
370
|
|
371
|
|
372 ////////////////////////////////////////////////
|
|
373 // register a global string
|
|
374 //
|
|
375 char* register_string(char *name) {
|
|
376 return register_string(all_strings, name);
|
|
377 }
|
|
378
|
|
379
|
|
380 ////////////////////////////////////////////////
|
|
381 //
|
|
382 bool tsa(TOKEN &tok, char *token);
|
|
383 bool tsa(TOKEN &tok, char *token) {
|
|
384 char *have = tok.next();
|
|
385 if (have == token) return true;
|
|
386 tok.token_error(token, have);
|
|
387 return false;
|
|
388 }
|
|
389
|
|
390
|
|
391 ////////////////////////////////////////////////
|
|
392 //
|
|
393 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me);
|
|
394 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
|
|
395 char *name = tok.next();
|
|
396 char *suf = tok.next();
|
|
397 char *msg = tok.next();
|
|
398 if (!tsa(tok, token_semi)) return false;
|
|
399 DNSBLP dns = new DNSBL(name, suf, msg);
|
|
400 me.add_dnsbl(name, dns);
|
|
401 return true;
|
|
402 }
|
|
403
|
|
404
|
|
405 ////////////////////////////////////////////////
|
|
406 //
|
|
407 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me);
|
|
408 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
|
|
409 while (true) {
|
|
410 char *have = tok.next();
|
|
411 if (!have) break;
|
|
412 if (have == token_semi) break;
|
|
413 DNSBLP dns = me.find_dnsbl(have);
|
|
414 if (dns) {
|
|
415 me.add_dnsbl(dns);
|
|
416 }
|
|
417 else {
|
|
418 tok.token_error("dnsbl name", have);
|
|
419 return false;
|
|
420 }
|
|
421 }
|
|
422 return true;
|
|
423 }
|
|
424
|
|
425
|
|
426 ////////////////////////////////////////////////
|
|
427 //
|
|
428 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me);
|
|
429 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
|
75
|
430 bool topdefault = (!me.get_parent()) && (!dc.default_context);
|
71
|
431 char *setting = tok.next();
|
|
432 if (setting == token_on) {
|
|
433 me.set_content_filtering(true);
|
|
434 }
|
|
435 else if (setting == token_off) {
|
|
436 me.set_content_filtering(false);
|
|
437 }
|
|
438 else {
|
|
439 tok.token_error("on/off", setting);
|
|
440 return false;
|
|
441 }
|
|
442 if (!tsa(tok, token_lbrace)) return false;
|
|
443 while (true) {
|
|
444 char *have = tok.next();
|
|
445 if (!have) break;
|
|
446 if (have == token_filter) {
|
75
|
447 char *suffix = tok.next();
|
|
448 char *messag = tok.next();
|
|
449 if (topdefault) {
|
|
450 me.set_content_suffix(suffix);
|
|
451 me.set_content_message(messag);
|
|
452 }
|
71
|
453 if (!tsa(tok, token_semi)) return false;
|
75
|
454 if (!topdefault) tok.token_error("content filters may only be speciried in the top default context");
|
71
|
455 }
|
|
456 else if (have == token_ignore) {
|
|
457 if (!tsa(tok, token_lbrace)) return false;
|
|
458 while (true) {
|
|
459 if (!have) break;
|
|
460 char *have = tok.next();
|
|
461 if (have == token_rbrace) {
|
|
462 break; // done
|
|
463 }
|
|
464 else {
|
|
465 me.add_ignore(have);
|
|
466 }
|
|
467 }
|
|
468 if (!tsa(tok, token_semi)) return false;
|
|
469 }
|
|
470 else if (have == token_tld) {
|
|
471 if (!tsa(tok, token_lbrace)) return false;
|
|
472 while (true) {
|
|
473 char *have = tok.next();
|
|
474 if (!have) break;
|
|
475 if (have == token_rbrace) {
|
|
476 break; // done
|
|
477 }
|
|
478 else {
|
75
|
479 if (topdefault) me.add_tld(have);
|
71
|
480 }
|
|
481 }
|
|
482 if (!tsa(tok, token_semi)) return false;
|
75
|
483 if (!topdefault) tok.token_error("tld values may only be specified in the top default context");
|
71
|
484 }
|
|
485 else if (have == token_html_limit) {
|
|
486 have = tok.next();
|
|
487 if (have == token_on) {
|
|
488 me.set_tag_limit(tok.nextint());
|
|
489 me.set_tag_message(tok.next());
|
|
490 }
|
|
491 else if (have == token_off) {
|
|
492 me.set_tag_limit(0);
|
|
493 me.set_tag_message(NULL);
|
|
494 }
|
|
495 else {
|
|
496 tok.token_error("on/off", have);
|
|
497 return false;
|
|
498 }
|
|
499 if (!tsa(tok, token_semi)) return false;
|
|
500 }
|
|
501 else if (have == token_html_tags) {
|
|
502 if (!tsa(tok, token_lbrace)) return false;
|
|
503 while (true) {
|
|
504 char *have = tok.next();
|
|
505 if (!have) break;
|
|
506 if (have == token_rbrace) {
|
|
507 break; // done
|
|
508 }
|
|
509 else {
|
75
|
510 if (topdefault) me.add_tag(have);
|
71
|
511 }
|
|
512 }
|
|
513 if (!tsa(tok, token_semi)) return false;
|
75
|
514 if (!topdefault) tok.token_error("html tags may only be specified in the top default context");
|
71
|
515 }
|
|
516 else if (have == token_host_limit) {
|
|
517 have = tok.next();
|
|
518 if (have == token_on) {
|
|
519 me.set_host_limit(tok.nextint());
|
|
520 me.set_host_message(tok.next());
|
|
521 me.set_host_random(false);
|
|
522 }
|
|
523 else if (have == token_off) {
|
|
524 me.set_host_limit(0);
|
|
525 me.set_host_message(NULL);
|
|
526 me.set_host_random(false);
|
|
527 }
|
|
528 else if (have == token_soft) {
|
|
529 me.set_host_limit(tok.nextint());
|
|
530 me.set_host_message(NULL);
|
|
531 me.set_host_random(true);
|
|
532 }
|
|
533 else {
|
|
534 tok.token_error("on/off/soft", have);
|
|
535 return false;
|
|
536 }
|
|
537 if (!tsa(tok, token_semi)) return false;
|
|
538 }
|
|
539 else if (have == token_rbrace) {
|
|
540 break; // done
|
|
541 }
|
|
542 else {
|
|
543 tok.token_error("content keyword", have);
|
|
544 return false;
|
|
545 }
|
|
546 }
|
|
547 return tsa(tok, token_semi);
|
|
548 }
|
|
549
|
|
550
|
|
551 ////////////////////////////////////////////////
|
|
552 //
|
|
553 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me);
|
|
554 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
|
|
555 if (!tsa(tok, token_lbrace)) return false;
|
|
556 while (true) {
|
|
557 char *have = tok.next();
|
|
558 if (!have) break;
|
|
559 if (have == token_rbrace) break;
|
|
560 if (have == token_semi) {
|
|
561 // optional separators
|
|
562 }
|
|
563 else if (have == token_dccto) {
|
|
564 char *flavor = tok.next();
|
|
565 if (!tsa(tok, token_lbrace)) return false;
|
|
566 bool keeping = false;
|
|
567 while (true) {
|
|
568 char *have = tok.next();
|
|
569 if (!have) break;
|
|
570 if (have == token_rbrace) break;
|
|
571 if (have == flavor) {
|
|
572 keeping = true;
|
|
573 continue;
|
|
574 }
|
|
575 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) {
|
|
576 keeping = false;
|
|
577 continue;
|
|
578 }
|
|
579 if (have == token_envto) {
|
|
580 have = tok.next();
|
|
581 if (keeping) {
|
|
582 if (me.allow_env_to(have)) {
|
|
583 me.add_to(have);
|
|
584 dc.add_to(have, &me);
|
|
585 }
|
|
586 }
|
|
587 }
|
75
|
588 else if (have == token_substitute) {
|
|
589 if (tok.next() == token_mailhost) {
|
|
590 have = tok.next();
|
|
591 if (keeping) {
|
|
592 if (me.allow_env_to(have)) {
|
|
593 me.add_to(have);
|
|
594 dc.add_to(have, &me);
|
|
595 }
|
|
596 }
|
|
597 }
|
|
598 }
|
71
|
599 tok.skipeol();
|
|
600 }
|
|
601 }
|
|
602 else if (me.allow_env_to(have)) {
|
|
603 me.add_to(have);
|
|
604 dc.add_to(have, &me);
|
|
605 }
|
|
606 else {
|
75
|
607 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have);
|
71
|
608 return false;
|
|
609 }
|
|
610 }
|
|
611 return tsa(tok, token_semi);
|
|
612 }
|
|
613
|
|
614
|
|
615 ////////////////////////////////////////////////
|
|
616 //
|
|
617 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me);
|
|
618 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
|
|
619 char *st = tok.next();
|
75
|
620 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) {
|
71
|
621 me.set_from_default(st);
|
|
622 }
|
|
623 else {
|
|
624 tok.push(st);
|
|
625 }
|
|
626 if (!tsa(tok, token_lbrace)) return false;
|
|
627 while (true) {
|
|
628 char *have = tok.next();
|
|
629 if (!have) break;
|
|
630 if (have == token_rbrace) break;
|
|
631 if (have == token_semi) {
|
|
632 // optional separators
|
|
633 }
|
|
634 else if (have == token_dccfrom) {
|
|
635 if (!tsa(tok, token_lbrace)) return false;
|
|
636 bool keeping = false;
|
|
637 bool many = false;
|
|
638 while (true) {
|
|
639 char *have = tok.next();
|
|
640 if (!have) break;
|
|
641 if (have == token_rbrace) break;
|
|
642 if (have == token_ok) {
|
|
643 keeping = true;
|
|
644 many = false;
|
|
645 continue;
|
|
646 }
|
|
647 else if (have == token_many) {
|
|
648 keeping = true;
|
|
649 many = true;
|
|
650 continue;
|
|
651 }
|
|
652 else if (have == token_ok2) {
|
|
653 keeping = false;
|
|
654 continue;
|
|
655 }
|
|
656 if (have == token_envfrom) {
|
|
657 have = tok.next();
|
|
658 if (keeping) {
|
|
659 me.add_from(have, (many) ? token_black : token_white);
|
|
660 }
|
|
661 }
|
75
|
662 else if (have == token_substitute) {
|
|
663 if (tok.next() == token_mailhost) {
|
|
664 have = tok.next();
|
|
665 me.add_from(have, (many) ? token_black : token_white);
|
|
666 }
|
|
667 }
|
71
|
668 tok.skipeol();
|
|
669 }
|
|
670 }
|
|
671 else {
|
|
672 // may be a valid email address or domain name
|
|
673 char *st = tok.next();
|
|
674 if ((st == token_black) || (st == token_white) || (st == token_unknown)) {
|
|
675 me.add_from(have, st);
|
|
676 }
|
|
677 else {
|
|
678 CONTEXTP con = me.find_from_context_name(st);
|
|
679 if (con) {
|
|
680 me.add_from_context(have, con);
|
|
681 }
|
|
682 else {
|
|
683 tok.token_error("white/black/unknown or child context name", st);
|
|
684 return false;
|
|
685 }
|
|
686 }
|
|
687 }
|
|
688 }
|
|
689 return tsa(tok, token_semi);
|
|
690 }
|
|
691
|
|
692
|
|
693 ////////////////////////////////////////////////
|
|
694 //
|
|
695 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent);
|
|
696 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) {
|
|
697 char *name = tok.next();
|
|
698 if (!tsa(tok, token_lbrace)) return false;
|
|
699 CONTEXTP con = new CONTEXT(parent, name);
|
|
700
|
|
701 while (true) {
|
|
702 char *have = tok.next();
|
|
703 if (!have) break;
|
|
704 if (have == token_rbrace) break; // done
|
|
705 if (have == token_dnsbl) {
|
|
706 if (!parse_dnsbl(tok, dc, *con)) return false;
|
|
707 }
|
|
708 else if (have == token_dnsbll) {
|
|
709 if (!parse_dnsbll(tok, dc, *con)) return false;
|
|
710 }
|
|
711 else if (have == token_content) {
|
|
712 if (!parse_content(tok, dc, *con)) return false;
|
|
713 }
|
|
714 else if (have == token_envto) {
|
|
715 if (!parse_envto(tok, dc, *con)) return false;
|
|
716 }
|
|
717 else if (have == token_envfrom) {
|
|
718 if (!parse_envfrom(tok, dc, *con)) return false;
|
|
719 }
|
|
720 else if (have == token_context) {
|
|
721 if (!parse_context(tok, dc, con)) return false;
|
|
722 }
|
|
723 else {
|
|
724 tok.token_error("context keyword", have);
|
|
725 return false;
|
|
726 }
|
|
727 }
|
|
728
|
|
729 if (!tsa(tok, token_semi)) {
|
|
730 delete con;
|
|
731 return false;
|
|
732 }
|
|
733 dc.add_context(con);
|
|
734 if (parent) parent->add_context(con);
|
|
735 return true;
|
|
736 }
|
|
737
|
|
738
|
|
739 ////////////////////////////////////////////////
|
|
740 // parse a config file
|
|
741 //
|
|
742 bool load_conf(CONFIG &dc, char *fn) {
|
|
743 TOKEN tok(fn, &dc.config_files);
|
|
744 while (true) {
|
|
745 char *have = tok.next();
|
|
746 if (!have) break;
|
|
747 if (have == token_context) {
|
|
748 if (!parse_context(tok, dc, NULL)) {
|
|
749 return false;
|
|
750 }
|
|
751 }
|
|
752 else {
|
|
753 tok.token_error(token_context, have);
|
|
754 return false;
|
|
755 }
|
|
756 }
|
72
|
757 return (dc.default_context) ? true : false;
|
71
|
758 }
|
|
759
|
|
760
|
|
761 ////////////////////////////////////////////////
|
|
762 // init the tokens
|
|
763 //
|
|
764 void token_init() {
|
|
765 token_black = register_string("black");
|
|
766 token_content = register_string("content");
|
|
767 token_context = register_string("context");
|
|
768 token_dccfrom = register_string("dcc_from");
|
|
769 token_dccto = register_string("dcc_to");
|
|
770 token_default = register_string("default");
|
|
771 token_dnsbl = register_string("dnsbl");
|
|
772 token_dnsbll = register_string("dnsbl_list");
|
|
773 token_envfrom = register_string("env_from");
|
|
774 token_envto = register_string("env_to");
|
|
775 token_filter = register_string("filter");
|
|
776 token_host_limit = register_string("host_limit");
|
|
777 token_html_limit = register_string("html_limit");
|
|
778 token_html_tags = register_string("html_tags");
|
|
779 token_ignore = register_string("ignore");
|
|
780 token_include = register_string("include");
|
|
781 token_inherit = register_string("inherit");
|
|
782 token_lbrace = register_string("{");
|
75
|
783 token_mailhost = register_string("mail_host");
|
71
|
784 token_many = register_string("many");
|
|
785 token_off = register_string("off");
|
|
786 token_ok = register_string("ok");
|
|
787 token_ok2 = register_string("ok2");
|
|
788 token_on = register_string("on");
|
|
789 token_rbrace = register_string("}");
|
|
790 token_semi = register_string(";");
|
|
791 token_soft = register_string("soft");
|
75
|
792 token_substitute = register_string("substitute");
|
71
|
793 token_tld = register_string("tld");
|
|
794 token_unknown = register_string("unknown");
|
|
795 token_white = register_string("white");
|
|
796 }
|