masqmail

view src/conf.c @ 281:ea5f86e0a81c

modes are now enforced exclusive Other MTAs (exim, postfix) are more relaxing, but as combinations of exclusive modes are senseless we behave more obvious if we fail early. This makes understanding the behavior easier too.
author markus schnalke <meillo@marmaro.de>
date Tue, 07 Dec 2010 14:04:56 -0300
parents 82d168dd52fd
children e0de950ed497
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
20 #include <pwd.h>
21 #include <grp.h>
23 #include "masqmail.h"
25 masqmail_conf conf;
27 void
28 init_conf()
29 {
30 struct passwd *passwd;
31 struct group *group;
33 memset(&conf, 0, sizeof(masqmail_conf));
35 conf.orig_uid = getuid();
36 conf.orig_gid = getgid();
38 if ((passwd = getpwnam(DEF_MAIL_USER)))
39 conf.mail_uid = passwd->pw_uid;
40 else {
41 fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
42 exit(1);
43 }
44 if ((group = getgrnam(DEF_MAIL_GROUP)))
45 conf.mail_gid = group->gr_gid;
46 else {
47 fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
48 exit(1);
49 }
50 }
52 static gchar* true_strings[] = {
53 "yes", "on", "true", NULL
54 };
56 static gchar *false_strings[] = {
57 "no", "off", "false", NULL
58 };
60 static gboolean
61 parse_boolean(gchar * rval)
62 {
63 gchar **str;
65 DEBUG(6) fprintf(stderr, "parse_boolean: %s\n", rval);
67 str = true_strings;
68 while (*str) {
69 if (strncasecmp(*str, rval, strlen(*str)) == 0)
70 return TRUE;
71 str++;
72 }
74 str = false_strings;
75 while (*str) {
76 if (strncasecmp(*str, rval, strlen(*str)) == 0)
77 return FALSE;
78 str++;
79 }
81 fprintf(stderr, "cannot parse value '%s'\n", rval);
82 exit(1);
83 }
85 /* make a list from each line in a file */
86 static GList*
87 parse_list_file(gchar * fname)
88 {
89 GList *list = NULL;
90 FILE *fptr;
92 if ((fptr = fopen(fname, "rt")) == NULL) {
93 logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
94 exit(1);
95 }
97 gchar buf[256];
99 while (!feof(fptr)) {
100 fgets(buf, 255, fptr);
101 if (buf[0] && (buf[0] != '#') && (buf[0] != '\n')) {
102 g_strchomp(buf);
103 DEBUG(6) fprintf(stderr,"parse_list_file: item = %s\n", buf);
104 list = g_list_append(list, g_strdup(buf));
105 }
106 }
107 fclose(fptr);
109 return list;
110 }
112 /* given a semicolon separated string, this function makes a GList out of it. */
113 GList*
114 parse_list(gchar * line, gboolean read_file)
115 {
116 GList *list = NULL;
117 gchar buf[256];
118 gchar *p, *q;
120 DEBUG(6) fprintf(stderr, "parsing list %s, file?:%d\n", line, read_file);
122 p = line;
123 while (*p != '\0') {
124 q = buf;
126 while (*p && (*p != ';') && (q < buf + 255))
127 *(q++) = *(p++);
128 *q = '\0';
130 if ((buf[0] == '/') && (read_file))
131 /* item is a filename, include its contents */
132 list = g_list_concat(list, parse_list_file(buf));
133 else
134 /* just a normal item */
135 list = g_list_append(list, g_strdup(buf));
137 DEBUG(6) fprintf(stderr, "item = %s\n", buf);
139 if (*p)
140 p++;
141 }
142 return list;
143 }
145 static GList*
146 parse_address_list(gchar * line, gboolean read_file)
147 {
148 GList *plain_list = parse_list(line, read_file);
149 GList *node;
150 GList *list = NULL;
152 foreach(plain_list, node) {
153 gchar *item = (gchar *) (node->data);
154 address *addr = create_address(item, TRUE);
155 if (addr)
156 list = g_list_append(list, addr);
157 g_free(item);
158 }
159 g_list_free(plain_list);
161 return list;
162 }
164 static GList*
165 parse_resolve_list(gchar * line)
166 {
167 GList *list;
168 GList *list_node;
169 GList *res_list = NULL;
171 list = parse_list(line, FALSE);
172 if (!list) {
173 return NULL;
174 }
176 foreach(list, list_node) {
177 gchar *item = (gchar *) (list_node->data);
178 if (strcmp(item, "byname") == 0) {
179 res_list = g_list_append(res_list, resolve_byname);
180 #ifdef ENABLE_RESOLVER
181 } else if (strcmp(item, "dns_a") == 0) {
182 res_list = g_list_append(res_list, resolve_dns_a);
183 } else if (strcmp(item, "dns_mx") == 0) {
184 res_list = g_list_append(res_list, resolve_dns_mx);
185 #endif
186 } else {
187 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
188 exit(1);
189 }
190 g_free(item);
191 }
192 g_list_free(list);
193 return res_list;
194 }
196 static interface*
197 parse_interface(gchar * line, gint def_port)
198 {
199 gchar buf[256];
200 gchar *p, *q;
201 interface *iface;
203 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
205 p = line;
206 q = buf;
207 while ((*p != '\0') && (*p != ':') && (q < buf + 255))
208 *(q++) = *(p++);
209 *q = '\0';
211 iface = g_malloc(sizeof(interface));
212 iface->address = g_strdup(buf);
214 if (*p) {
215 p++;
216 iface->port = atoi(p);
217 } else
218 iface->port = def_port;
219 DEBUG(6) fprintf(stderr,"rval=%s, address:port=%s:%i\n",line, iface->address, iface->port);
221 return iface;
222 }
224 #ifdef ENABLE_IDENT /* so far used for that only */
225 static struct in_addr*
226 parse_network(gchar * line, gint def_port)
227 {
228 gchar buf[256];
229 gchar *p, *q;
230 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
231 guint n;
233 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
235 p = line;
236 q = buf;
237 while ((*p != '\0') && (*p != '/') && (q < buf + 255))
238 *(q++) = *(p++);
239 *q = '\0';
241 if ((addr.s_addr = inet_addr(buf)) == INADDR_NONE) {
242 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
243 exit(1);
244 }
246 if (*p) {
247 guint i;
248 p++;
249 i = atoi(p);
250 if ((i >= 0) && (i <= 32))
251 n = i ? ~((1 << (32 - i)) - 1) : 0;
252 else {
253 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
254 exit(1);
255 }
256 } else
257 n = 0;
259 mask_addr.s_addr = htonl(n);
260 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
262 p_net_addr = g_malloc(sizeof(struct in_addr));
263 p_net_addr->s_addr = net_addr.s_addr;
264 return p_net_addr;
265 }
266 #endif
268 static gboolean
269 eat_comments(FILE * in)
270 {
271 gint c;
273 for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
274 c = fgetc(in)) {
275 if (c == '#') {
276 gint c;
277 for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
278 }
279 }
280 if (c == EOF)
281 return FALSE;
282 ungetc(c, in);
283 return TRUE;
284 }
286 /* after parsing, eat trailing character until LF */
287 static gboolean
288 eat_line_trailing(FILE * in)
289 {
290 gint c;
292 for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
293 if (c == EOF)
294 return FALSE;
295 return TRUE;
296 }
298 static gboolean
299 eat_spaces(FILE * in)
300 {
301 gint c;
303 for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
304 /* empty */
305 }
306 if (c == EOF)
307 return FALSE;
308 ungetc(c, in);
309 return TRUE;
310 }
312 static gboolean
313 read_lval(FILE * in, gchar * buf, gint size)
314 {
315 gint c;
316 gchar *ptr = buf;
318 DEBUG(6) fprintf(stderr, "read_lval()\n");
320 if (!eat_spaces(in))
321 return FALSE;
323 c = fgetc(in);
324 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
325 while ((isalnum(c) || c == '_' || c == '-' || c == '.')
326 && (ptr < buf + size - 1)
327 && (c != EOF)) {
328 *ptr = c;
329 ptr++;
330 c = fgetc(in);
331 }
332 *ptr = '\0';
333 ungetc(c, in);
335 if (c == EOF) {
336 fprintf(stderr, "unexpected EOF after %s\n", buf);
337 return FALSE;
338 } else if (ptr >= buf + size - 1) {
339 fprintf(stderr, "lval too long\n");
340 }
342 eat_spaces(in);
344 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
346 return buf[0] != '\0';
347 }
349 static gboolean
350 read_rval(FILE * in, gchar * buf, gint size)
351 {
352 gint c;
353 gchar *ptr = buf;
355 DEBUG(6) fprintf(stderr, "read_rval()\n");
357 if (!eat_spaces(in))
358 return FALSE;
360 c = fgetc(in);
361 if (c != '\"') {
362 while ((isalnum(c) || c == '_' || c == '-' || c == '.'
363 || c == '/' || c == '@' || c == ';' || c == ':')
364 && (ptr < buf + size - 1)
365 && (c != EOF)) {
366 *ptr = c;
367 ptr++;
368 c = fgetc(in);
369 }
370 *ptr = '\0';
371 ungetc(c, in);
372 } else {
373 gboolean escape = FALSE;
374 c = fgetc(in);
375 while (((c != '\"') || escape) && (ptr < buf + size - 1)) {
376 if (c != '\n') { /* ignore line breaks */
377 if ((c == '\\') && (!escape)) {
378 escape = TRUE;
379 } else {
380 *ptr = c;
381 ptr++;
382 escape = FALSE;
383 }
384 }
385 c = fgetc(in);
386 }
387 *ptr = '\0';
388 }
390 eat_line_trailing(in);
392 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
394 return TRUE;
395 }
397 static gboolean
398 read_statement(FILE * in, gchar * lval, gint lsize, gchar * rval, gint rsize)
399 {
400 gint c;
402 DEBUG(6) fprintf(stderr, "read_statement()\n");
404 /* eat comments and empty lines: */
405 if (!eat_comments(in))
406 return FALSE;
408 if (!read_lval(in, lval, lsize)) {
409 return FALSE;
410 }
412 DEBUG(6) fprintf(stderr, " lval = %s\n", lval);
413 if ((c = fgetc(in) == '=')) {
414 if (read_rval(in, rval, rsize)) {
415 DEBUG(6) fprintf(stderr, " rval = %s\n", rval);
416 return TRUE;
417 }
418 } else {
419 DEBUG(6) fprintf(stderr," '=' expected after %s, char was '%c'\n", lval, c);
420 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
421 }
422 return FALSE;
423 }
425 gboolean
426 read_conf(gchar * filename)
427 {
428 FILE *in;
430 conf.log_max_pri = 7;
431 conf.do_relay = TRUE;
432 conf.localpartcmp = strcmp;
433 conf.max_defer_time = 86400 * 4; /* 4 days */
434 conf.max_msg_size = 0; /* no limit on msg size */
435 conf.spool_dir = SPOOL_DIR;
436 conf.mail_dir = "/var/mail";
437 /* we use 127.0.0.1 because `localhost' could be bound to some
438 other IP address. This is unlikely but could be. Using
439 127.0.0.1 is more safe. See mailing list for details */
440 conf.listen_addresses = g_list_append(NULL, parse_interface("127.0.0.1", 25));
442 if ((in = fopen(filename, "r")) == NULL) {
443 logwrite(LOG_ALERT, "could not open config file %s: %s\n", filename, strerror(errno));
444 return FALSE;
445 }
447 gchar lval[256], rval[2048];
448 while (read_statement(in, lval, 256, rval, 2048)) {
449 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
450 if (strcmp(lval, "debug_level") == 0)
451 conf.debug_level = atoi(rval);
452 else if (strcmp(lval, "run_as_user") == 0) {
453 if (!conf.run_as_user) /* you should not be able to reset that flag */
454 conf.run_as_user = parse_boolean(rval);
455 } else if (strcmp(lval, "use_syslog") == 0)
456 conf.use_syslog = parse_boolean(rval);
457 else if (strcmp(lval, "mail_dir") == 0)
458 conf.mail_dir = g_strdup(rval);
459 else if (strcmp(lval, "lock_dir") == 0)
460 conf.lock_dir = g_strdup(rval);
461 else if (strcmp(lval, "spool_dir") == 0)
462 conf.spool_dir = g_strdup(rval);
463 else if (strcmp(lval, "log_dir") == 0)
464 conf.log_dir = g_strdup(rval);
465 else if (strcmp(lval, "host_name") == 0) {
466 if (rval[0] != '/')
467 conf.host_name = g_strdup(rval);
468 else {
469 char buf[256];
470 FILE *fptr = fopen(rval, "rt");
471 if (fptr) {
472 logwrite(LOG_ALERT, "could not open %s: %s\n", rval, strerror(errno));
473 return FALSE;
474 }
475 fgets(buf, 255, fptr);
476 g_strchomp(buf);
477 conf.host_name = g_strdup(buf);
478 fclose(fptr);
479 }
480 } else if (strcmp(lval, "local_hosts") == 0)
481 conf.local_hosts = parse_list(rval, FALSE);
482 else if (strcmp(lval, "local_addresses") == 0)
483 conf.local_addresses = parse_list(rval, TRUE);
484 else if (strcmp(lval, "not_local_addresses") == 0)
485 conf.not_local_addresses = parse_list(rval, TRUE);
486 else if (strcmp(lval, "local_nets") == 0)
487 conf.local_nets = parse_list(rval, FALSE);
488 else if (strcmp(lval, "do_save_envelope_to") == 0)
489 conf.do_save_envelope_to = parse_boolean(rval);
490 else if (strcmp(lval, "defer_all") == 0)
491 conf.defer_all = parse_boolean(rval);
492 else if (strcmp(lval, "do_relay") == 0)
493 conf.do_relay = parse_boolean(rval);
494 else if (strcmp(lval, "alias_file") == 0) {
495 conf.alias_file = g_strdup(rval);
496 } else if (strcmp(lval, "caseless_matching") == 0) {
497 conf.localpartcmp = parse_boolean(rval) ? strcasecmp : strcmp;
498 } else if (strcmp(lval, "mbox_default") == 0) {
499 conf.mbox_default = g_strdup(rval);
500 } else if (strcmp(lval, "mbox_users") == 0) {
501 conf.mbox_users = parse_list(rval, TRUE);
502 } else if (strcmp(lval, "mda_users") == 0) {
503 conf.mda_users = parse_list(rval, TRUE);
504 } else if (strcmp(lval, "mda") == 0) {
505 conf.mda = g_strdup(rval);
506 } else if (strcmp(lval, "mda_fromline") == 0) {
507 conf.mda_fromline = parse_boolean(rval);
508 } else if (strcmp(lval, "mda_fromhack") == 0) {
509 conf.mda_fromhack = parse_boolean(rval);
510 } else if (strcmp(lval, "pipe_fromline") == 0) {
511 conf.pipe_fromline = parse_boolean(rval);
512 } else if (strcmp(lval, "pipe_fromhack") == 0) {
513 conf.pipe_fromhack = parse_boolean(rval);
514 } else if (strcmp(lval, "listen_addresses") == 0) {
515 GList *node;
516 GList *tmp_list = parse_list(rval, FALSE);
518 conf.listen_addresses = NULL;
519 foreach(tmp_list, node) {
520 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
521 g_free(node->data);
522 }
523 g_list_free(tmp_list);
524 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
525 #ifdef ENABLE_IDENT
526 GList *node;
527 GList *tmp_list = parse_list(rval, FALSE);
529 conf.ident_trusted_nets = NULL;
530 foreach(tmp_list, node) {
531 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
532 g_free(node->data);
533 }
534 g_list_free(tmp_list);
535 #else
536 logwrite(LOG_WARNING, "%s ignored: not compiled with ident support\n", lval);
537 #endif
538 } else if ((strncmp(lval, "connect_route.", 14) == 0)
539 || (strncmp(lval, "online_routes.", 14) == 0)) {
540 GList *file_list = parse_list(rval, FALSE);
541 table_pair *pair = create_pair(&(lval[14]), file_list);
542 conf.connect_routes = g_list_append(conf.connect_routes, pair);
543 } else if (strcmp(lval, "local_net_route") == 0) {
544 conf.local_net_routes = parse_list(rval, FALSE);
545 } else if (strcmp(lval, "online_detect") == 0)
546 conf.online_detect = g_strdup(rval);
547 else if (strcmp(lval, "online_file") == 0)
548 conf.online_file = g_strdup(rval);
549 else if (strcmp(lval, "online_pipe") == 0)
550 conf.online_pipe = g_strdup(rval);
551 else if (strcmp(lval, "do_queue") == 0)
552 conf.do_queue = parse_boolean(rval);
553 else if (strcmp(lval, "errmsg_file") == 0)
554 conf.errmsg_file = g_strdup(rval);
555 else if (strcmp(lval, "warnmsg_file") == 0)
556 conf.warnmsg_file = g_strdup(rval);
557 else if (strcmp(lval, "warn_intervals") == 0)
558 conf.warn_intervals = parse_list(rval, FALSE);
559 else if (strcmp(lval, "max_defer_time") == 0) {
560 gint ival = time_interval(rval);
561 if (ival < 0)
562 logwrite(LOG_WARNING, "invalid time interval for 'max_defer_time': %s\n", rval);
563 else
564 conf.max_defer_time = ival;
565 } else if (strcmp(lval, "log_user") == 0)
566 conf.log_user = g_strdup(rval);
567 else if(strcmp(lval, "max_msg_size") == 0) {
568 conf.max_msg_size = atol(rval);
569 DEBUG(6) fprintf(stderr,"rval=%s, conf.max_msg_size=%ld\n",
570 rval, conf.max_msg_size);
571 }
572 else
573 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
574 }
575 fclose(in);
577 if (!conf.host_name) {
578 logwrite(LOG_ALERT, "`host_name' MUST be set in masqmail.conf. See man page\n");
579 return FALSE;
580 }
582 if (conf.errmsg_file == NULL)
583 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
584 if (conf.warnmsg_file == NULL)
585 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
587 if (conf.lock_dir == NULL)
588 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
590 if (conf.mbox_default == NULL)
591 conf.mbox_default = g_strdup("mbox");
593 if (conf.warn_intervals == NULL)
594 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
596 if (!conf.local_hosts) {
597 char* shortname = strdup(conf.host_name);
598 char* p = strchr(shortname, '.');
599 if (p) {
600 *p = '\0';
601 }
602 /* we don't care if shortname and conf.host_name are the same */
603 char* local_hosts_str = g_strdup_printf("localhost;%s;%s", shortname, conf.host_name);
604 conf.local_hosts = parse_list(local_hosts_str, FALSE);
605 free(shortname);
606 free(local_hosts_str);
607 }
610 return TRUE;
611 }
613 connect_route*
614 read_route(gchar * filename, gboolean is_local_net)
615 {
616 gboolean ok = FALSE;
617 FILE *in;
619 connect_route *route = g_malloc(sizeof(connect_route));
620 memset(route, 0, sizeof(connect_route));
622 DEBUG(5) debugf("read_route, filename = %s\n", filename);
624 route->filename = g_strdup(filename);
625 route->name = g_strdup(filename); /* quick hack */
627 route->protocol = g_strdup("smtp");
628 route->expand_h_sender_address = TRUE;
630 route->is_local_net = is_local_net;
632 route->do_pipelining = TRUE;
634 if ((in = fopen(route->filename, "r")) == NULL) {
635 logwrite(LOG_ALERT, "could not open route file %s: %s\n", route->filename, strerror(errno));
636 g_free(route);
637 return NULL;
638 }
640 gchar lval[256], rval[2048];
641 while (read_statement(in, lval, 256, rval, 2048)) {
642 if (strcmp(lval, "protocol") == 0)
643 route->protocol = g_strdup(rval);
644 else if (strcmp(lval, "mail_host") == 0)
645 route->mail_host = parse_interface(rval, 25);
646 else if (strcmp(lval, "helo_name") == 0)
647 route->helo_name = g_strdup(rval);
648 else if (strcmp(lval, "wrapper") == 0)
649 route->wrapper = g_strdup(rval);
650 else if (strcmp(lval, "connect_error_fail") == 0)
651 route->connect_error_fail = parse_boolean(rval);
652 else if (strcmp(lval, "do_correct_helo") == 0)
653 route->do_correct_helo = parse_boolean(rval);
654 else if (strcmp(lval, "instant_helo") == 0)
655 route->instant_helo = parse_boolean(rval);
656 else if (strcmp(lval, "do_pipelining") == 0)
657 route->do_pipelining = parse_boolean(rval);
658 else if (strcmp(lval, "allowed_return_paths") == 0)
659 route->allowed_return_paths = parse_address_list(rval, TRUE);
660 else if (strcmp(lval, "allowed_mail_locals") == 0)
661 route->allowed_mail_locals = parse_list(rval, TRUE);
662 else if (strcmp(lval, "not_allowed_return_paths") == 0)
663 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
664 else if (strcmp(lval, "not_allowed_mail_locals") == 0)
665 route->not_allowed_mail_locals = parse_list(rval, TRUE);
666 else if (strcmp(lval, "allowed_rcpt_domains") == 0)
667 route->allowed_rcpt_domains = parse_list(rval, TRUE);
668 else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
669 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
670 else if (strcmp(lval, "set_h_from_domain") == 0)
671 route->set_h_from_domain = g_strdup(rval);
672 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
673 route->set_h_reply_to_domain = g_strdup(rval);
674 else if (strcmp(lval, "set_return_path_domain") == 0)
675 route->set_return_path_domain = g_strdup(rval);
676 else if (strcmp(lval, "map_return_path_addresses") == 0) {
677 GList *node, *list;
679 list = parse_list(rval, TRUE);
680 foreach(list, node) {
681 gchar *item = (gchar *) (node->data);
682 table_pair *pair = parse_table_pair(item, ':');
683 address *addr = create_address((gchar *) (pair->value), TRUE);
684 g_free(pair->value);
685 pair->value = (gpointer *) addr;
686 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
687 g_free(item);
688 }
689 g_list_free(list);
690 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
691 GList *list, *node;
693 list = parse_list(rval, TRUE);
694 foreach(list, node) {
695 gchar *item = (gchar *) (node->data);
696 table_pair *pair = parse_table_pair(item, ':');
697 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
698 g_free(item);
699 }
700 g_list_free(list);
701 } else if (strcmp(lval, "map_h_reply_to_addresses") == 0) {
702 GList *list, *node;
704 list = parse_list(rval, TRUE);
705 foreach(list, node) {
706 gchar *item = (gchar *) (node->data);
707 table_pair *pair = parse_table_pair(item, ':');
708 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
709 g_free(item);
710 }
711 g_list_free(list);
712 } else if (strcmp(lval, "map_h_mail_followup_to_addresses") == 0) {
713 GList *list, *node;
715 list = parse_list(rval, TRUE);
716 foreach(list, node) {
717 gchar *item = (gchar *) (node->data);
718 table_pair *pair = parse_table_pair(item, ':');
719 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
720 g_free(item);
721 }
722 g_list_free(list);
723 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
724 route->expand_h_sender_domain = parse_boolean(rval);
725 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
726 route->expand_h_sender_address = parse_boolean(rval);
727 } else if (strcmp(lval, "resolve_list") == 0)
728 route->resolve_list = parse_resolve_list(rval);
729 else if (strcmp(lval, "do_ssl") == 0) {
730 /* we ignore this. This option is used by sqilconf */
731 ;
732 }
733 #ifdef ENABLE_AUTH
734 else if (strcmp(lval, "auth_name") == 0) {
735 route->auth_name = g_strdup(rval);
736 } else if (strcmp(lval, "auth_login") == 0) {
737 route->auth_login = g_strdup(rval);
738 } else if (strcmp(lval, "auth_secret") == 0) {
739 route->auth_secret = g_strdup(rval);
740 }
741 #else
742 else if ((strcmp(lval, "auth_name") == 0)
743 || (strcmp(lval, "auth_login") == 0)
744 || (strcmp(lval, "auth_secret") == 0)) {
745 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
746 }
747 #endif
748 else if (strcmp(lval, "pipe") == 0) {
749 route->pipe = g_strdup(rval);
750 } else if (strcmp(lval, "pipe_fromline") == 0) {
751 route->pipe_fromline = parse_boolean(rval);
752 } else if (strcmp(lval, "pipe_fromhack") == 0) {
753 route->pipe_fromhack = parse_boolean(rval);
754 } else if (strcmp(lval, "last_route") == 0) {
755 route->last_route = parse_boolean(rval);
756 } else
757 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
758 }
760 if (route->resolve_list == NULL) {
761 if (is_local_net) {
762 route->resolve_list = g_list_append(NULL, resolve_byname);
763 } else {
764 #ifdef ENABLE_RESOLVER
765 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
766 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
767 #endif
768 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
769 }
770 }
771 fclose(in);
772 ok = TRUE;
774 /* warn user about misconfigurations: */
775 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
776 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
777 g_free(route->set_h_from_domain);
778 route->set_h_from_domain = NULL;
779 }
780 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
781 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
782 g_free(route->set_h_reply_to_domain);
783 route->set_h_reply_to_domain = NULL;
784 }
786 if (!ok) {
787 g_free(route);
788 route = NULL;
789 }
791 return route;
792 }
794 static void
795 _g_list_free_all(GList * list)
796 {
797 GList *node;
798 if (list) {
799 foreach(list, node)
800 g_free(node->data);
801 g_list_free(list);
802 }
803 }
805 void
806 destroy_route(connect_route * r)
807 {
808 if (r->filename)
809 g_free(r->filename);
810 if (r->protocol)
811 g_free(r->protocol);
812 if (r->mail_host) {
813 g_free(r->mail_host->address);
814 g_free(r->mail_host);
815 }
816 if (r->wrapper)
817 g_free(r->wrapper);
818 if (r->helo_name)
819 g_free(r->helo_name);
820 _g_list_free_all(r->allowed_mail_locals);
821 _g_list_free_all(r->not_allowed_mail_locals);
822 _g_list_free_all(r->allowed_rcpt_domains);
823 _g_list_free_all(r->not_allowed_rcpt_domains);
824 if (r->set_h_from_domain)
825 g_free(r->set_h_from_domain);
826 if (r->set_h_reply_to_domain)
827 g_free(r->set_h_reply_to_domain);
828 if (r->set_return_path_domain)
829 g_free(r->set_return_path_domain);
830 if (r->map_h_reply_to_addresses)
831 destroy_table(r->map_h_reply_to_addresses);
832 if (r->resolve_list)
833 g_list_free(r->resolve_list);
834 #ifdef ENABLE_AUTH
835 if (r->auth_name)
836 g_free(r->auth_name);
837 if (r->auth_login)
838 g_free(r->auth_login);
839 if (r->auth_secret)
840 g_free(r->auth_secret);
841 #endif
842 if (r->pipe)
843 g_free(r->pipe);
844 g_free(r);
845 }
847 GList*
848 read_route_list(GList * rf_list, gboolean is_local_net)
849 {
850 GList *list = NULL;
851 GList *node;
852 uid_t saved_uid, saved_gid;
854 if (!conf.run_as_user) {
855 set_euidgid(0, 0, &saved_uid, &saved_gid);
856 }
858 foreach(rf_list, node) {
859 gchar *fname = (gchar *) (node->data);
860 connect_route *route = read_route(fname, is_local_net);
861 if (route)
862 list = g_list_append(list, route);
863 else
864 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
865 }
867 /* set uid and gid back */
868 if (!conf.run_as_user) {
869 set_euidgid(saved_uid, saved_gid, NULL, NULL);
870 }
872 return list;
873 }
875 void
876 destroy_route_list(GList * list)
877 {
878 GList *node;
880 foreach(list, node) {
881 connect_route *route = (connect_route *) (node->data);
882 destroy_route(route);
883 }
884 g_list_free(list);
885 }
887 connect_route*
888 create_local_route()
889 {
890 connect_route *route;
892 route = g_malloc(sizeof(connect_route));
893 if (!route) {
894 return NULL;
895 }
896 memset(route, 0, sizeof(connect_route));
897 route->protocol = g_strdup("smtp");
898 route->is_local_net = TRUE;
899 route->name = g_strdup("default local_net_route");
900 route->expand_h_sender_address = TRUE;
901 route->resolve_list = g_list_append(NULL, resolve_byname);
902 route->connect_error_fail = TRUE;
903 return route;
904 }