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