masqmail

view src/conf.c @ 214:ecd8d737d78e

removed the old manual because it is really outdated now In masqmail's 0.3 branch, so much changed that the old manual causes more harm than it improves the distribution. Most content is covered by the man pages anyway. You'll still find the old manual on masqmail's homepage.
author meillo@marmaro.de
date Mon, 19 Jul 2010 14:06:08 +0200
parents 4fd237550525
children 8cddc65765bd
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include <pwd.h>
20 #include <grp.h>
22 #include "masqmail.h"
24 masqmail_conf conf;
26 void
27 init_conf()
28 {
29 struct passwd *passwd;
30 struct group *group;
32 memset(&conf, 0, sizeof(masqmail_conf));
34 conf.orig_uid = getuid();
35 conf.orig_gid = getgid();
37 if ((passwd = getpwnam(DEF_MAIL_USER)))
38 conf.mail_uid = passwd->pw_uid;
39 else {
40 fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
41 exit(EXIT_FAILURE);
42 }
43 if ((group = getgrnam(DEF_MAIL_GROUP)))
44 conf.mail_gid = group->gr_gid;
45 else {
46 fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
47 exit(EXIT_FAILURE);
48 }
49 }
51 static gchar* true_strings[] = {
52 "yes", "on", "true", NULL
53 };
55 static gchar *false_strings[] = {
56 "no", "off", "false", NULL
57 };
59 static gboolean
60 parse_boolean(gchar * rval)
61 {
62 gchar **str;
64 DEBUG(6) fprintf(stderr, "parse_boolean: %s\n", rval);
66 str = true_strings;
67 while (*str) {
68 if (strncasecmp(*str, rval, strlen(*str)) == 0)
69 return TRUE;
70 str++;
71 }
73 str = false_strings;
74 while (*str) {
75 if (strncasecmp(*str, rval, strlen(*str)) == 0)
76 return FALSE;
77 str++;
78 }
80 fprintf(stderr, "cannot parse value '%s'\n", rval);
81 exit(EXIT_FAILURE);
82 }
84 /* make a list from each line in a file */
85 static GList*
86 parse_list_file(gchar * fname)
87 {
88 GList *list = NULL;
89 FILE *fptr;
91 if ((fptr = fopen(fname, "rt")) == NULL) {
92 logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
93 exit(EXIT_FAILURE);
94 }
96 gchar buf[256];
98 while (!feof(fptr)) {
99 fgets(buf, 255, fptr);
100 if (buf[0] && (buf[0] != '#') && (buf[0] != '\n')) {
101 g_strchomp(buf);
102 DEBUG(6) fprintf(stderr,"parse_list_file: item = %s\n", buf);
103 list = g_list_append(list, g_strdup(buf));
104 }
105 }
106 fclose(fptr);
108 return list;
109 }
111 /* given a semicolon separated string, this function makes a GList out of it. */
112 GList*
113 parse_list(gchar * line, gboolean read_file)
114 {
115 GList *list = NULL;
116 gchar buf[256];
117 gchar *p, *q;
119 DEBUG(6) fprintf(stderr, "parsing list %s, file?:%d\n", line, read_file);
121 p = line;
122 while (*p != '\0') {
123 q = buf;
125 while (*p && (*p != ';') && (q < buf + 255))
126 *(q++) = *(p++);
127 *q = '\0';
129 if ((buf[0] == '/') && (read_file))
130 /* item is a filename, include its contents */
131 list = g_list_concat(list, parse_list_file(buf));
132 else
133 /* just a normal item */
134 list = g_list_append(list, g_strdup(buf));
136 DEBUG(6) fprintf(stderr, "item = %s\n", buf);
138 if (*p)
139 p++;
140 }
141 return list;
142 }
144 static GList*
145 parse_address_list(gchar * line, gboolean read_file)
146 {
147 GList *plain_list = parse_list(line, read_file);
148 GList *node;
149 GList *list = NULL;
151 foreach(plain_list, node) {
152 gchar *item = (gchar *) (node->data);
153 address *addr = create_address(item, TRUE);
154 if (addr)
155 list = g_list_append(list, addr);
156 g_free(item);
157 }
158 g_list_free(plain_list);
160 return list;
161 }
163 static GList*
164 parse_resolve_list(gchar * line)
165 {
166 GList *list;
167 GList *list_node;
168 GList *res_list = NULL;
170 list = parse_list(line, FALSE);
171 if (!list) {
172 return NULL;
173 }
175 foreach(list, list_node) {
176 gchar *item = (gchar *) (list_node->data);
177 if (strcmp(item, "byname") == 0) {
178 res_list = g_list_append(res_list, resolve_byname);
179 #ifdef ENABLE_RESOLVER
180 } else if (strcmp(item, "dns_a") == 0) {
181 res_list = g_list_append(res_list, resolve_dns_a);
182 } else if (strcmp(item, "dns_mx") == 0) {
183 res_list = g_list_append(res_list, resolve_dns_mx);
184 #endif
185 } else {
186 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
187 exit(EXIT_FAILURE);
188 }
189 g_free(item);
190 }
191 g_list_free(list);
192 return res_list;
193 }
195 static interface*
196 parse_interface(gchar * line, gint def_port)
197 {
198 gchar buf[256];
199 gchar *p, *q;
200 interface *iface;
202 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
204 p = line;
205 q = buf;
206 while ((*p != '\0') && (*p != ':') && (q < buf + 255))
207 *(q++) = *(p++);
208 *q = '\0';
210 iface = g_malloc(sizeof(interface));
211 iface->address = g_strdup(buf);
213 if (*p) {
214 p++;
215 iface->port = atoi(p);
216 } else
217 iface->port = def_port;
218 DEBUG(6) fprintf(stderr,"rval=%s, address:port=%s:%i\n",line, iface->address, iface->port);
220 return iface;
221 }
223 #ifdef ENABLE_IDENT /* so far used for that only */
224 static struct in_addr*
225 parse_network(gchar * line, gint def_port)
226 {
227 gchar buf[256];
228 gchar *p, *q;
229 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
230 guint n;
232 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
234 p = line;
235 q = buf;
236 while ((*p != '\0') && (*p != '/') && (q < buf + 255))
237 *(q++) = *(p++);
238 *q = '\0';
240 if ((addr.s_addr = inet_addr(buf)) == INADDR_NONE) {
241 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
242 exit(EXIT_FAILURE);
243 }
245 if (*p) {
246 guint i;
247 p++;
248 i = atoi(p);
249 if ((i >= 0) && (i <= 32))
250 n = i ? ~((1 << (32 - i)) - 1) : 0;
251 else {
252 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
253 exit(EXIT_FAILURE);
254 }
255 } else
256 n = 0;
258 mask_addr.s_addr = htonl(n);
259 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
261 p_net_addr = g_malloc(sizeof(struct in_addr));
262 p_net_addr->s_addr = net_addr.s_addr;
263 return p_net_addr;
264 }
265 #endif
267 static gboolean
268 eat_comments(FILE * in)
269 {
270 gint c;
272 for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
273 c = fgetc(in)) {
274 if (c == '#') {
275 gint c;
276 for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
277 }
278 }
279 if (c == EOF)
280 return FALSE;
281 ungetc(c, in);
282 return TRUE;
283 }
285 /* after parsing, eat trailing character until LF */
286 static gboolean
287 eat_line_trailing(FILE * in)
288 {
289 gint c;
291 for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
292 if (c == EOF)
293 return FALSE;
294 return TRUE;
295 }
297 static gboolean
298 eat_spaces(FILE * in)
299 {
300 gint c;
302 for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
303 /* empty */
304 }
305 if (c == EOF)
306 return FALSE;
307 ungetc(c, in);
308 return TRUE;
309 }
311 static gboolean
312 read_lval(FILE * in, gchar * buf, gint size)
313 {
314 gint c;
315 gchar *ptr = buf;
317 DEBUG(6) fprintf(stderr, "read_lval()\n");
319 if (!eat_spaces(in))
320 return FALSE;
322 c = fgetc(in);
323 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
324 while ((isalnum(c) || c == '_' || c == '-' || c == '.')
325 && (ptr < buf + size - 1)
326 && (c != EOF)) {
327 *ptr = c;
328 ptr++;
329 c = fgetc(in);
330 }
331 *ptr = '\0';
332 ungetc(c, in);
334 if (c == EOF) {
335 fprintf(stderr, "unexpected EOF after %s\n", buf);
336 return FALSE;
337 } else if (ptr >= buf + size - 1) {
338 fprintf(stderr, "lval too long\n");
339 }
341 eat_spaces(in);
343 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
345 return buf[0] != '\0';
346 }
348 static gboolean
349 read_rval(FILE * in, gchar * buf, gint size)
350 {
351 gint c;
352 gchar *ptr = buf;
354 DEBUG(6) fprintf(stderr, "read_rval()\n");
356 if (!eat_spaces(in))
357 return FALSE;
359 c = fgetc(in);
360 if (c != '\"') {
361 while ((isalnum(c) || c == '_' || c == '-' || c == '.'
362 || c == '/' || c == '@' || c == ';' || c == ':')
363 && (ptr < buf + size - 1)
364 && (c != EOF)) {
365 *ptr = c;
366 ptr++;
367 c = fgetc(in);
368 }
369 *ptr = '\0';
370 ungetc(c, in);
371 } else {
372 gboolean escape = FALSE;
373 c = fgetc(in);
374 while (((c != '\"') || escape) && (ptr < buf + size - 1)) {
375 if (c != '\n') { /* ignore line breaks */
376 if ((c == '\\') && (!escape)) {
377 escape = TRUE;
378 } else {
379 *ptr = c;
380 ptr++;
381 escape = FALSE;
382 }
383 }
384 c = fgetc(in);
385 }
386 *ptr = '\0';
387 }
389 eat_line_trailing(in);
391 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
393 return TRUE;
394 }
396 static gboolean
397 read_statement(FILE * in, gchar * lval, gint lsize, gchar * rval, gint rsize)
398 {
399 gint c;
401 DEBUG(6) fprintf(stderr, "read_statement()\n");
403 /* eat comments and empty lines: */
404 if (!eat_comments(in))
405 return FALSE;
407 if (!read_lval(in, lval, lsize)) {
408 return FALSE;
409 }
411 DEBUG(6) fprintf(stderr, " lval = %s\n", lval);
412 if ((c = fgetc(in) == '=')) {
413 if (read_rval(in, rval, rsize)) {
414 DEBUG(6) fprintf(stderr, " rval = %s\n", rval);
415 return TRUE;
416 }
417 } else {
418 DEBUG(6) fprintf(stderr," '=' expected after %s, char was '%c'\n", lval, c);
419 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
420 }
421 return FALSE;
422 }
424 gboolean
425 read_conf(gchar * filename)
426 {
427 FILE *in;
429 conf.log_max_pri = 7;
430 conf.do_relay = TRUE;
431 conf.alias_local_cmp = strcmp;
432 conf.max_defer_time = 86400 * 4; /* 4 days */
433 conf.max_msg_size = 0; /* no limit on msg size */
434 conf.spool_dir = SPOOL_DIR;
435 conf.mail_dir = "/var/mail";
436 /* we use 127.0.0.1 because `localhost' could be bound to some
437 other IP address. This is unlikely but could be. Using
438 127.0.0.1 is more safe. See mailing list for details */
439 conf.listen_addresses = g_list_append(NULL, parse_interface("127.0.0.1", 25));
441 if ((in = fopen(filename, "r")) == NULL) {
442 logwrite(LOG_ALERT, "could not open config file %s: %s\n", filename, strerror(errno));
443 return FALSE;
444 }
446 gchar lval[256], rval[2048];
447 while (read_statement(in, lval, 256, rval, 2048)) {
448 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
449 if (strcmp(lval, "debug_level") == 0)
450 conf.debug_level = atoi(rval);
451 else if (strcmp(lval, "run_as_user") == 0) {
452 if (!conf.run_as_user) /* you should not be able to reset that flag */
453 conf.run_as_user = parse_boolean(rval);
454 } else if (strcmp(lval, "use_syslog") == 0)
455 conf.use_syslog = parse_boolean(rval);
456 else if (strcmp(lval, "mail_dir") == 0)
457 conf.mail_dir = g_strdup(rval);
458 else if (strcmp(lval, "lock_dir") == 0)
459 conf.lock_dir = g_strdup(rval);
460 else if (strcmp(lval, "spool_dir") == 0)
461 conf.spool_dir = g_strdup(rval);
462 else if (strcmp(lval, "log_dir") == 0)
463 conf.log_dir = g_strdup(rval);
464 else if (strcmp(lval, "host_name") == 0) {
465 if (rval[0] != '/')
466 conf.host_name = g_strdup(rval);
467 else {
468 char buf[256];
469 FILE *fptr = fopen(rval, "rt");
470 if (fptr) {
471 logwrite(LOG_ALERT, "could not open %s: %s\n", rval, strerror(errno));
472 return FALSE;
473 }
474 fgets(buf, 255, fptr);
475 g_strchomp(buf);
476 conf.host_name = g_strdup(buf);
477 fclose(fptr);
478 }
479 } else if (strcmp(lval, "local_hosts") == 0)
480 conf.local_hosts = parse_list(rval, FALSE);
481 else if (strcmp(lval, "local_addresses") == 0)
482 conf.local_addresses = parse_list(rval, TRUE);
483 else if (strcmp(lval, "not_local_addresses") == 0)
484 conf.not_local_addresses = parse_list(rval, TRUE);
485 else if (strcmp(lval, "local_nets") == 0)
486 conf.local_nets = parse_list(rval, FALSE);
487 else if (strcmp(lval, "do_save_envelope_to") == 0)
488 conf.do_save_envelope_to = parse_boolean(rval);
489 else if (strcmp(lval, "defer_all") == 0)
490 conf.defer_all = parse_boolean(rval);
491 else if (strcmp(lval, "do_relay") == 0)
492 conf.do_relay = parse_boolean(rval);
493 else if (strcmp(lval, "alias_file") == 0) {
494 conf.alias_file = g_strdup(rval);
495 } else if (strcmp(lval, "alias_local_caseless") == 0) {
496 conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
497 } else if (strcmp(lval, "mbox_default") == 0) {
498 conf.mbox_default = g_strdup(rval);
499 } else if (strcmp(lval, "mbox_users") == 0) {
500 conf.mbox_users = parse_list(rval, TRUE);
501 } else if (strcmp(lval, "mda_users") == 0) {
502 conf.mda_users = parse_list(rval, TRUE);
503 } else if (strcmp(lval, "mda") == 0) {
504 conf.mda = g_strdup(rval);
505 } else if (strcmp(lval, "mda_fromline") == 0) {
506 conf.mda_fromline = parse_boolean(rval);
507 } else if (strcmp(lval, "mda_fromhack") == 0) {
508 conf.mda_fromhack = parse_boolean(rval);
509 } else if (strcmp(lval, "pipe_fromline") == 0) {
510 conf.pipe_fromline = parse_boolean(rval);
511 } else if (strcmp(lval, "pipe_fromhack") == 0) {
512 conf.pipe_fromhack = parse_boolean(rval);
513 } else if (strcmp(lval, "listen_addresses") == 0) {
514 GList *node;
515 GList *tmp_list = parse_list(rval, FALSE);
517 conf.listen_addresses = NULL;
518 foreach(tmp_list, node) {
519 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
520 g_free(node->data);
521 }
522 g_list_free(tmp_list);
523 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
524 #ifdef ENABLE_IDENT
525 GList *node;
526 GList *tmp_list = parse_list(rval, FALSE);
528 conf.ident_trusted_nets = NULL;
529 foreach(tmp_list, node) {
530 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
531 g_free(node->data);
532 }
533 g_list_free(tmp_list);
534 #else
535 logwrite(LOG_WARNING, "%s ignored: not compiled with ident support\n", lval);
536 #endif
537 } else if ((strncmp(lval, "connect_route.", 14) == 0)
538 || (strncmp(lval, "online_routes.", 14) == 0)) {
539 GList *file_list = parse_list(rval, FALSE);
540 table_pair *pair = create_pair(&(lval[14]), file_list);
541 conf.connect_routes = g_list_append(conf.connect_routes, pair);
542 } else if (strcmp(lval, "local_net_route") == 0) {
543 conf.local_net_routes = parse_list(rval, FALSE);
544 } else if (strcmp(lval, "online_detect") == 0)
545 conf.online_detect = g_strdup(rval);
546 else if (strcmp(lval, "online_file") == 0)
547 conf.online_file = g_strdup(rval);
548 else if (strcmp(lval, "online_pipe") == 0)
549 conf.online_pipe = g_strdup(rval);
550 else if (strcmp(lval, "do_queue") == 0)
551 conf.do_queue = parse_boolean(rval);
552 else if (strcmp(lval, "errmsg_file") == 0)
553 conf.errmsg_file = g_strdup(rval);
554 else if (strcmp(lval, "warnmsg_file") == 0)
555 conf.warnmsg_file = g_strdup(rval);
556 else if (strcmp(lval, "warn_intervals") == 0)
557 conf.warn_intervals = parse_list(rval, FALSE);
558 else if (strcmp(lval, "max_defer_time") == 0) {
559 gint dummy;
560 gint ival = time_interval(rval, &dummy);
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, "do_pipelining") == 0)
655 route->do_pipelining = parse_boolean(rval);
656 else if (strcmp(lval, "allowed_return_paths") == 0)
657 route->allowed_return_paths = parse_address_list(rval, TRUE);
658 else if (strcmp(lval, "allowed_mail_locals") == 0)
659 route->allowed_mail_locals = parse_list(rval, TRUE);
660 else if (strcmp(lval, "not_allowed_return_paths") == 0)
661 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
662 else if (strcmp(lval, "not_allowed_mail_locals") == 0)
663 route->not_allowed_mail_locals = parse_list(rval, TRUE);
664 else if (strcmp(lval, "allowed_rcpt_domains") == 0)
665 route->allowed_rcpt_domains = parse_list(rval, TRUE);
666 else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
667 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
668 else if (strcmp(lval, "set_h_from_domain") == 0)
669 route->set_h_from_domain = g_strdup(rval);
670 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
671 route->set_h_reply_to_domain = g_strdup(rval);
672 else if (strcmp(lval, "set_return_path_domain") == 0)
673 route->set_return_path_domain = g_strdup(rval);
674 else if (strcmp(lval, "map_return_path_addresses") == 0) {
675 GList *node, *list;
677 list = parse_list(rval, TRUE);
678 foreach(list, node) {
679 gchar *item = (gchar *) (node->data);
680 table_pair *pair = parse_table_pair(item, ':');
681 address *addr = create_address((gchar *) (pair->value), TRUE);
682 g_free(pair->value);
683 pair->value = (gpointer *) addr;
684 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
685 g_free(item);
686 }
687 g_list_free(list);
688 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
689 GList *list, *node;
691 list = parse_list(rval, TRUE);
692 foreach(list, node) {
693 gchar *item = (gchar *) (node->data);
694 table_pair *pair = parse_table_pair(item, ':');
695 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
696 g_free(item);
697 }
698 g_list_free(list);
699 } else if (strcmp(lval, "map_h_reply_to_addresses") == 0) {
700 GList *list, *node;
702 list = parse_list(rval, TRUE);
703 foreach(list, node) {
704 gchar *item = (gchar *) (node->data);
705 table_pair *pair = parse_table_pair(item, ':');
706 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
707 g_free(item);
708 }
709 g_list_free(list);
710 } else if (strcmp(lval, "map_h_mail_followup_to_addresses") == 0) {
711 GList *list, *node;
713 list = parse_list(rval, TRUE);
714 foreach(list, node) {
715 gchar *item = (gchar *) (node->data);
716 table_pair *pair = parse_table_pair(item, ':');
717 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
718 g_free(item);
719 }
720 g_list_free(list);
721 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
722 route->expand_h_sender_domain = parse_boolean(rval);
723 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
724 route->expand_h_sender_address = parse_boolean(rval);
725 } else if (strcmp(lval, "resolve_list") == 0)
726 route->resolve_list = parse_resolve_list(rval);
727 else if (strcmp(lval, "do_ssl") == 0) {
728 /* we ignore this. This option is used by sqilconf */
729 ;
730 }
731 #ifdef ENABLE_AUTH
732 else if (strcmp(lval, "auth_name") == 0) {
733 route->auth_name = g_strdup(rval);
734 } else if (strcmp(lval, "auth_login") == 0) {
735 route->auth_login = g_strdup(rval);
736 } else if (strcmp(lval, "auth_secret") == 0) {
737 route->auth_secret = g_strdup(rval);
738 }
739 #else
740 else if ((strcmp(lval, "auth_name") == 0)
741 || (strcmp(lval, "auth_login") == 0)
742 || (strcmp(lval, "auth_secret") == 0)) {
743 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
744 }
745 #endif
746 else if (strcmp(lval, "pipe") == 0) {
747 route->pipe = g_strdup(rval);
748 } else if (strcmp(lval, "pipe_fromline") == 0) {
749 route->pipe_fromline = parse_boolean(rval);
750 } else if (strcmp(lval, "pipe_fromhack") == 0) {
751 route->pipe_fromhack = parse_boolean(rval);
752 } else if (strcmp(lval, "last_route") == 0) {
753 route->last_route = parse_boolean(rval);
754 } else
755 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
756 }
758 if (route->resolve_list == NULL) {
759 if (is_local_net) {
760 route->resolve_list = g_list_append(NULL, resolve_byname);
761 } else {
762 #ifdef ENABLE_RESOLVER
763 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
764 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
765 #endif
766 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
767 }
768 }
769 fclose(in);
770 ok = TRUE;
772 /* warn user about misconfigurations: */
773 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
774 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
775 g_free(route->set_h_from_domain);
776 route->set_h_from_domain = NULL;
777 }
778 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
779 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
780 g_free(route->set_h_reply_to_domain);
781 route->set_h_reply_to_domain = NULL;
782 }
784 if (!ok) {
785 g_free(route);
786 route = NULL;
787 }
789 return route;
790 }
792 static void
793 _g_list_free_all(GList * list)
794 {
795 GList *node;
796 if (list) {
797 foreach(list, node)
798 g_free(node->data);
799 g_list_free(list);
800 }
801 }
803 void
804 destroy_route(connect_route * r)
805 {
806 if (r->filename)
807 g_free(r->filename);
808 if (r->protocol)
809 g_free(r->protocol);
810 if (r->mail_host) {
811 g_free(r->mail_host->address);
812 g_free(r->mail_host);
813 }
814 if (r->wrapper)
815 g_free(r->wrapper);
816 if (r->helo_name)
817 g_free(r->helo_name);
818 _g_list_free_all(r->allowed_mail_locals);
819 _g_list_free_all(r->not_allowed_mail_locals);
820 _g_list_free_all(r->allowed_rcpt_domains);
821 _g_list_free_all(r->not_allowed_rcpt_domains);
822 if (r->set_h_from_domain)
823 g_free(r->set_h_from_domain);
824 if (r->set_h_reply_to_domain)
825 g_free(r->set_h_reply_to_domain);
826 if (r->set_return_path_domain)
827 g_free(r->set_return_path_domain);
828 if (r->map_h_reply_to_addresses)
829 destroy_table(r->map_h_reply_to_addresses);
830 if (r->resolve_list)
831 g_list_free(r->resolve_list);
832 #ifdef ENABLE_AUTH
833 if (r->auth_name)
834 g_free(r->auth_name);
835 if (r->auth_login)
836 g_free(r->auth_login);
837 if (r->auth_secret)
838 g_free(r->auth_secret);
839 #endif
840 if (r->pipe)
841 g_free(r->pipe);
842 g_free(r);
843 }
845 GList*
846 read_route_list(GList * rf_list, gboolean is_local_net)
847 {
848 GList *list = NULL;
849 GList *node;
850 uid_t saved_uid, saved_gid;
852 if (!conf.run_as_user) {
853 set_euidgid(0, 0, &saved_uid, &saved_gid);
854 }
856 foreach(rf_list, node) {
857 gchar *fname = (gchar *) (node->data);
858 connect_route *route = read_route(fname, is_local_net);
859 if (route)
860 list = g_list_append(list, route);
861 else
862 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
863 }
865 /* set uid and gid back */
866 if (!conf.run_as_user) {
867 set_euidgid(saved_uid, saved_gid, NULL, NULL);
868 }
870 return list;
871 }
873 void
874 destroy_route_list(GList * list)
875 {
876 GList *node;
878 foreach(list, node) {
879 connect_route *route = (connect_route *) (node->data);
880 destroy_route(route);
881 }
882 g_list_free(list);
883 }
885 connect_route*
886 create_local_route()
887 {
888 connect_route *route;
890 route = g_malloc(sizeof(connect_route));
891 if (!route) {
892 return NULL;
893 }
894 memset(route, 0, sizeof(connect_route));
895 route->protocol = g_strdup("smtp");
896 route->is_local_net = TRUE;
897 route->name = g_strdup("local_net (default)");
898 route->expand_h_sender_address = TRUE;
899 route->resolve_list = g_list_append(NULL, resolve_byname);
900 route->connect_error_fail = TRUE;
901 return route;
902 }