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