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