masqmail
view src/conf.c @ 323:29de6a1c4538
Fixed an important bug with folded headers!
g_strconcat() returns a *copy* of the string, but hdr->value still
pointed to the old header (which probably was a memory leak, too).
If the folded part had been quite small it was likely that the new
string was at the same position as the old one, thus making everything
go well. But if pretty long headers were folded several times it was
likely that the new string was allocated somewhere else in memory,
thus breaking things. In result mails to lots of recipients (folded
header) were frequently only sent to the ones in the first line. Sorry
for the inconvenience.
author | meillo@marmaro.de |
---|---|
date | Fri, 03 Jun 2011 09:47:27 +0200 |
parents | 55b7bde95d37 |
children | 5ce2b1280679 |
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 /* Split the addrs at '@' into local_part and domain. Without an '@'
146 everything is local_part. Create address structs, which are put
147 into a list and returned.
148 This funktion is used for lists of addrs containing globbing chars (* and ?).
149 We don't need valid RFC821 addresses here, just patterns to match against.
150 */
151 static GList*
152 parse_address_glob_list(gchar * line, gboolean read_file)
153 {
154 GList *plain_list = parse_list(line, read_file);
155 GList *node;
156 GList *list = NULL;
158 foreach(plain_list, node) {
159 gchar *item = (gchar *) (node->data);
160 char* at;
161 char* p;
162 address *addr = calloc(1, sizeof(address));
164 for (p=item+strlen(item)-1; isspace(*p) || *p=='>'; p--) {
165 *p = '\0';
166 }
167 for (p=item; isspace(*p) || *p=='<'; p++) {
168 }
170 addr->address = strdup(p);
171 at = strrchr(p, '@');
172 if (at) {
173 *at = '\0';
174 addr->local_part = strdup(p);
175 addr->domain = strdup(at+1);
176 } else {
177 addr->local_part = strdup(p);
178 addr->domain = "";
179 }
180 list = g_list_append(list, addr);
181 DEBUG(6) debugf("parse_address_glob_list: read pattern `%s' `%s'\n",
182 addr->local_part, addr->domain);
183 g_free(item);
184 }
185 g_list_free(plain_list);
186 return list;
187 }
189 static GList*
190 parse_resolve_list(gchar * line)
191 {
192 GList *list;
193 GList *list_node;
194 GList *res_list = NULL;
196 list = parse_list(line, FALSE);
197 if (!list) {
198 return NULL;
199 }
201 foreach(list, list_node) {
202 gchar *item = (gchar *) (list_node->data);
203 if (strcmp(item, "byname") == 0) {
204 res_list = g_list_append(res_list, resolve_byname);
205 #ifdef ENABLE_RESOLVER
206 } else if (strcmp(item, "dns_a") == 0) {
207 res_list = g_list_append(res_list, resolve_dns_a);
208 } else if (strcmp(item, "dns_mx") == 0) {
209 res_list = g_list_append(res_list, resolve_dns_mx);
210 #endif
211 } else {
212 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
213 exit(1);
214 }
215 g_free(item);
216 }
217 g_list_free(list);
218 return res_list;
219 }
221 static interface*
222 parse_interface(gchar * line, gint def_port)
223 {
224 gchar buf[256];
225 gchar *p, *q;
226 interface *iface;
228 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
230 p = line;
231 q = buf;
232 while ((*p != '\0') && (*p != ':') && (q < buf + 255))
233 *(q++) = *(p++);
234 *q = '\0';
236 iface = g_malloc(sizeof(interface));
237 iface->address = g_strdup(buf);
239 if (*p) {
240 p++;
241 iface->port = atoi(p);
242 } else
243 iface->port = def_port;
244 DEBUG(6) fprintf(stderr,"rval=%s, address:port=%s:%i\n",line, iface->address, iface->port);
246 return iface;
247 }
249 #ifdef ENABLE_IDENT /* so far used for that only */
250 static struct in_addr*
251 parse_network(gchar * line, gint def_port)
252 {
253 gchar buf[256];
254 gchar *p, *q;
255 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
256 guint n;
258 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
260 p = line;
261 q = buf;
262 while ((*p != '\0') && (*p != '/') && (q < buf + 255))
263 *(q++) = *(p++);
264 *q = '\0';
266 if ((addr.s_addr = inet_addr(buf)) == INADDR_NONE) {
267 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
268 exit(1);
269 }
271 if (*p) {
272 guint i;
273 p++;
274 i = atoi(p);
275 if ((i >= 0) && (i <= 32))
276 n = i ? ~((1 << (32 - i)) - 1) : 0;
277 else {
278 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
279 exit(1);
280 }
281 } else
282 n = 0;
284 mask_addr.s_addr = htonl(n);
285 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
287 p_net_addr = g_malloc(sizeof(struct in_addr));
288 p_net_addr->s_addr = net_addr.s_addr;
289 return p_net_addr;
290 }
291 #endif
293 static gboolean
294 eat_comments(FILE * in)
295 {
296 gint c;
298 for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
299 c = fgetc(in)) {
300 if (c == '#') {
301 gint c;
302 for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
303 }
304 }
305 if (c == EOF)
306 return FALSE;
307 ungetc(c, in);
308 return TRUE;
309 }
311 /* after parsing, eat trailing character until LF */
312 static gboolean
313 eat_line_trailing(FILE * in)
314 {
315 gint c;
317 for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
318 if (c == EOF)
319 return FALSE;
320 return TRUE;
321 }
323 static gboolean
324 eat_spaces(FILE * in)
325 {
326 gint c;
328 for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
329 /* empty */
330 }
331 if (c == EOF)
332 return FALSE;
333 ungetc(c, in);
334 return TRUE;
335 }
337 static gboolean
338 read_lval(FILE * in, gchar * buf, gint size)
339 {
340 gint c;
341 gchar *ptr = buf;
343 DEBUG(6) fprintf(stderr, "read_lval()\n");
345 if (!eat_spaces(in))
346 return FALSE;
348 c = fgetc(in);
349 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
350 while ((isalnum(c) || c == '_' || c == '-' || c == '.')
351 && (ptr < buf + size - 1)
352 && (c != EOF)) {
353 *ptr = c;
354 ptr++;
355 c = fgetc(in);
356 }
357 *ptr = '\0';
358 ungetc(c, in);
360 if (c == EOF) {
361 fprintf(stderr, "unexpected EOF after %s\n", buf);
362 return FALSE;
363 } else if (ptr >= buf + size - 1) {
364 fprintf(stderr, "lval too long\n");
365 }
367 eat_spaces(in);
369 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
371 return buf[0] != '\0';
372 }
374 static gboolean
375 read_rval(FILE * in, gchar * buf, gint size)
376 {
377 gint c;
378 gchar *ptr = buf;
380 DEBUG(6) fprintf(stderr, "read_rval()\n");
382 if (!eat_spaces(in))
383 return FALSE;
385 c = fgetc(in);
386 if (c != '\"') {
387 while ((isalnum(c) || c == '_' || c == '-' || c == '.'
388 || c == '/' || c == '@' || c == ';' || c == ':')
389 && (ptr < buf + size - 1)
390 && (c != EOF)) {
391 *ptr = c;
392 ptr++;
393 c = fgetc(in);
394 }
395 *ptr = '\0';
396 ungetc(c, in);
397 } else {
398 gboolean escape = FALSE;
399 c = fgetc(in);
400 while (((c != '\"') || escape) && (ptr < buf + size - 1)) {
401 if (c != '\n') { /* ignore line breaks */
402 if ((c == '\\') && (!escape)) {
403 escape = TRUE;
404 } else {
405 *ptr = c;
406 ptr++;
407 escape = FALSE;
408 }
409 }
410 c = fgetc(in);
411 }
412 *ptr = '\0';
413 }
415 eat_line_trailing(in);
417 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
419 return TRUE;
420 }
422 static gboolean
423 read_statement(FILE * in, gchar * lval, gint lsize, gchar * rval, gint rsize)
424 {
425 gint c;
427 DEBUG(6) fprintf(stderr, "read_statement()\n");
429 /* eat comments and empty lines: */
430 if (!eat_comments(in))
431 return FALSE;
433 if (!read_lval(in, lval, lsize)) {
434 return FALSE;
435 }
437 DEBUG(6) fprintf(stderr, " lval = %s\n", lval);
438 if ((c = fgetc(in) == '=')) {
439 if (read_rval(in, rval, rsize)) {
440 DEBUG(6) fprintf(stderr, " rval = %s\n", rval);
441 return TRUE;
442 }
443 } else {
444 DEBUG(6) fprintf(stderr," '=' expected after %s, char was '%c'\n", lval, c);
445 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
446 }
447 return FALSE;
448 }
450 gboolean
451 read_conf(gchar * filename)
452 {
453 FILE *in;
455 conf.log_max_pri = 7;
456 conf.do_relay = TRUE;
457 conf.localpartcmp = strcmp;
458 conf.max_defer_time = 86400 * 4; /* 4 days */
459 conf.max_msg_size = 0; /* no limit on msg size */
460 conf.spool_dir = SPOOL_DIR;
461 conf.mail_dir = "/var/mail";
462 /* we use 127.0.0.1 because `localhost' could be bound to some
463 other IP address. This is unlikely but could be. Using
464 127.0.0.1 is more safe. See mailing list for details */
465 conf.listen_addresses = g_list_append(NULL, parse_interface("127.0.0.1", 25));
467 if ((in = fopen(filename, "r")) == NULL) {
468 logwrite(LOG_ALERT, "could not open config file %s: %s\n", filename, strerror(errno));
469 return FALSE;
470 }
472 gchar lval[256], rval[2048];
473 while (read_statement(in, lval, 256, rval, 2048)) {
474 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
475 if (strcmp(lval, "debug_level") == 0)
476 conf.debug_level = atoi(rval);
477 else if (strcmp(lval, "run_as_user") == 0) {
478 if (!conf.run_as_user) /* you should not be able to reset that flag */
479 conf.run_as_user = parse_boolean(rval);
480 } else if (strcmp(lval, "use_syslog") == 0)
481 conf.use_syslog = parse_boolean(rval);
482 else if (strcmp(lval, "mail_dir") == 0)
483 conf.mail_dir = g_strdup(rval);
484 else if (strcmp(lval, "lock_dir") == 0)
485 conf.lock_dir = g_strdup(rval);
486 else if (strcmp(lval, "spool_dir") == 0)
487 conf.spool_dir = g_strdup(rval);
488 else if (strcmp(lval, "log_dir") == 0)
489 conf.log_dir = g_strdup(rval);
490 else if (strcmp(lval, "host_name") == 0) {
491 if (rval[0] != '/')
492 conf.host_name = g_strdup(rval);
493 else {
494 char buf[256];
495 FILE *fptr = fopen(rval, "rt");
496 if (!fptr) {
497 logwrite(LOG_ALERT, "could not open %s: %s\n", rval, strerror(errno));
498 return FALSE;
499 }
500 fgets(buf, 255, fptr);
501 g_strchomp(buf);
502 conf.host_name = g_strdup(buf);
503 fclose(fptr);
504 }
505 } else if (strcmp(lval, "local_hosts") == 0)
506 conf.local_hosts = parse_list(rval, FALSE);
507 else if (strcmp(lval, "local_addresses") == 0)
508 conf.local_addresses = parse_list(rval, TRUE);
509 else if (strcmp(lval, "not_local_addresses") == 0)
510 conf.not_local_addresses = parse_list(rval, TRUE);
511 else if (strcmp(lval, "local_nets") == 0)
512 conf.local_nets = parse_list(rval, FALSE);
513 else if (strcmp(lval, "do_save_envelope_to") == 0)
514 conf.do_save_envelope_to = parse_boolean(rval);
515 else if (strcmp(lval, "defer_all") == 0)
516 conf.defer_all = parse_boolean(rval);
517 else if (strcmp(lval, "do_relay") == 0)
518 conf.do_relay = parse_boolean(rval);
519 else if (strcmp(lval, "alias_file") == 0) {
520 conf.alias_file = g_strdup(rval);
521 } else if (strcmp(lval, "caseless_matching") == 0) {
522 conf.localpartcmp = parse_boolean(rval) ? strcasecmp : strcmp;
523 } else if (strcmp(lval, "mbox_default") == 0) {
524 conf.mbox_default = g_strdup(rval);
525 } else if (strcmp(lval, "mbox_users") == 0) {
526 conf.mbox_users = parse_list(rval, TRUE);
527 } else if (strcmp(lval, "mda_users") == 0) {
528 conf.mda_users = parse_list(rval, TRUE);
529 } else if (strcmp(lval, "mda") == 0) {
530 conf.mda = g_strdup(rval);
531 } else if (strcmp(lval, "mda_fromline") == 0) {
532 conf.mda_fromline = parse_boolean(rval);
533 } else if (strcmp(lval, "mda_fromhack") == 0) {
534 conf.mda_fromhack = parse_boolean(rval);
535 } else if (strcmp(lval, "pipe_fromline") == 0) {
536 conf.pipe_fromline = parse_boolean(rval);
537 } else if (strcmp(lval, "pipe_fromhack") == 0) {
538 conf.pipe_fromhack = parse_boolean(rval);
539 } else if (strcmp(lval, "listen_addresses") == 0) {
540 GList *node;
541 GList *tmp_list = parse_list(rval, FALSE);
543 conf.listen_addresses = NULL;
544 foreach(tmp_list, node) {
545 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
546 g_free(node->data);
547 }
548 g_list_free(tmp_list);
549 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
550 #ifdef ENABLE_IDENT
551 GList *node;
552 GList *tmp_list = parse_list(rval, FALSE);
554 conf.ident_trusted_nets = NULL;
555 foreach(tmp_list, node) {
556 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
557 g_free(node->data);
558 }
559 g_list_free(tmp_list);
560 #else
561 logwrite(LOG_WARNING, "%s ignored: not compiled with ident support\n", lval);
562 #endif
563 } else if ((strncmp(lval, "connect_route.", 14) == 0)
564 || (strncmp(lval, "online_routes.", 14) == 0)) {
565 GList *file_list = parse_list(rval, FALSE);
566 table_pair *pair = create_pair(&(lval[14]), file_list);
567 conf.connect_routes = g_list_append(conf.connect_routes, pair);
568 } else if (strcmp(lval, "local_net_route") == 0) {
569 conf.local_net_routes = parse_list(rval, FALSE);
570 } else if (strcmp(lval, "online_query") == 0)
571 conf.online_query = g_strdup(rval);
572 else if (strcmp(lval, "do_queue") == 0)
573 conf.do_queue = parse_boolean(rval);
574 else if (strcmp(lval, "errmsg_file") == 0)
575 conf.errmsg_file = g_strdup(rval);
576 else if (strcmp(lval, "warnmsg_file") == 0)
577 conf.warnmsg_file = g_strdup(rval);
578 else if (strcmp(lval, "warn_intervals") == 0)
579 conf.warn_intervals = parse_list(rval, FALSE);
580 else if (strcmp(lval, "max_defer_time") == 0) {
581 gint ival = time_interval(rval);
582 if (ival < 0)
583 logwrite(LOG_WARNING, "invalid time interval for 'max_defer_time': %s\n", rval);
584 else
585 conf.max_defer_time = ival;
586 } else if (strcmp(lval, "log_user") == 0)
587 conf.log_user = g_strdup(rval);
588 else if(strcmp(lval, "max_msg_size") == 0) {
589 conf.max_msg_size = atol(rval);
590 DEBUG(6) fprintf(stderr,"rval=%s, conf.max_msg_size=%ld\n",
591 rval, conf.max_msg_size);
592 }
593 else
594 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
595 }
596 fclose(in);
598 if (!conf.host_name) {
599 logwrite(LOG_ALERT, "`host_name' MUST be set in masqmail.conf. See man page\n");
600 return FALSE;
601 }
603 if (conf.errmsg_file == NULL)
604 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
605 if (conf.warnmsg_file == NULL)
606 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
608 if (conf.lock_dir == NULL)
609 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
611 if (conf.mbox_default == NULL)
612 conf.mbox_default = g_strdup("mbox");
614 if (conf.warn_intervals == NULL)
615 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
617 if (!conf.local_hosts) {
618 char* shortname = strdup(conf.host_name);
619 char* p = strchr(shortname, '.');
620 if (p) {
621 *p = '\0';
622 }
623 /* we don't care if shortname and conf.host_name are the same */
624 char* local_hosts_str = g_strdup_printf("localhost;%s;%s", shortname, conf.host_name);
625 conf.local_hosts = parse_list(local_hosts_str, FALSE);
626 free(shortname);
627 free(local_hosts_str);
628 }
631 return TRUE;
632 }
634 connect_route*
635 read_route(gchar * filename, gboolean is_local_net)
636 {
637 gboolean ok = FALSE;
638 FILE *in;
640 connect_route *route = g_malloc(sizeof(connect_route));
641 memset(route, 0, sizeof(connect_route));
643 DEBUG(5) debugf("read_route, filename = %s\n", filename);
645 route->filename = g_strdup(filename);
646 route->name = g_strdup(filename); /* quick hack */
648 route->expand_h_sender_address = TRUE;
650 route->is_local_net = is_local_net;
652 route->do_pipelining = TRUE;
654 if ((in = fopen(route->filename, "r")) == NULL) {
655 logwrite(LOG_ALERT, "could not open route file %s: %s\n", route->filename, strerror(errno));
656 g_free(route);
657 return NULL;
658 }
660 gchar lval[256], rval[2048];
661 while (read_statement(in, lval, 256, rval, 2048)) {
662 if (strcmp(lval, "mail_host") == 0)
663 route->mail_host = parse_interface(rval, 25);
664 else if (strcmp(lval, "helo_name") == 0)
665 route->helo_name = g_strdup(rval);
666 else if (strcmp(lval, "wrapper") == 0)
667 route->wrapper = g_strdup(rval);
668 else if (strcmp(lval, "connect_error_fail") == 0)
669 route->connect_error_fail = parse_boolean(rval);
670 else if (strcmp(lval, "do_correct_helo") == 0)
671 route->do_correct_helo = parse_boolean(rval);
672 else if (strcmp(lval, "instant_helo") == 0)
673 route->instant_helo = parse_boolean(rval);
674 else if (strcmp(lval, "do_pipelining") == 0)
675 route->do_pipelining = parse_boolean(rval);
677 else if (strcmp(lval, "allowed_senders") == 0)
678 route->allowed_senders = parse_address_glob_list(rval, TRUE);
679 else if (strcmp(lval, "denied_senders") == 0)
680 route->denied_senders = parse_address_glob_list(rval, TRUE);
681 else if (strcmp(lval, "allowed_recipients") == 0)
682 route->allowed_recipients = parse_address_glob_list(rval, TRUE);
683 else if (strcmp(lval, "denied_recipients") == 0)
684 route->denied_recipients = parse_address_glob_list(rval, TRUE);
686 else if (strcmp(lval, "set_h_from_domain") == 0)
687 route->set_h_from_domain = g_strdup(rval);
688 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
689 route->set_h_reply_to_domain = g_strdup(rval);
690 else if (strcmp(lval, "set_return_path_domain") == 0)
691 route->set_return_path_domain = g_strdup(rval);
692 else if (strcmp(lval, "map_return_path_addresses") == 0) {
693 GList *node, *list;
695 list = parse_list(rval, TRUE);
696 foreach(list, node) {
697 gchar *item = (gchar *) (node->data);
698 table_pair *pair = parse_table_pair(item, ':');
699 address *addr = create_address((gchar *) (pair->value), TRUE);
700 g_free(pair->value);
701 pair->value = (gpointer *) addr;
702 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
703 g_free(item);
704 }
705 g_list_free(list);
706 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
707 GList *list, *node;
709 list = parse_list(rval, TRUE);
710 foreach(list, node) {
711 gchar *item = (gchar *) (node->data);
712 table_pair *pair = parse_table_pair(item, ':');
713 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
714 g_free(item);
715 }
716 g_list_free(list);
717 } else if (strcmp(lval, "map_h_reply_to_addresses") == 0) {
718 GList *list, *node;
720 list = parse_list(rval, TRUE);
721 foreach(list, node) {
722 gchar *item = (gchar *) (node->data);
723 table_pair *pair = parse_table_pair(item, ':');
724 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
725 g_free(item);
726 }
727 g_list_free(list);
728 } else if (strcmp(lval, "map_h_mail_followup_to_addresses") == 0) {
729 GList *list, *node;
731 list = parse_list(rval, TRUE);
732 foreach(list, node) {
733 gchar *item = (gchar *) (node->data);
734 table_pair *pair = parse_table_pair(item, ':');
735 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
736 g_free(item);
737 }
738 g_list_free(list);
739 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
740 route->expand_h_sender_domain = parse_boolean(rval);
741 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
742 route->expand_h_sender_address = parse_boolean(rval);
743 } else if (strcmp(lval, "resolve_list") == 0)
744 route->resolve_list = parse_resolve_list(rval);
745 else if (strcmp(lval, "do_ssl") == 0) {
746 /* we ignore this. This option is used by sqilconf */
747 ;
748 }
749 #ifdef ENABLE_AUTH
750 else if (strcmp(lval, "auth_name") == 0) {
751 route->auth_name = g_strdup(rval);
752 } else if (strcmp(lval, "auth_login") == 0) {
753 route->auth_login = g_strdup(rval);
754 } else if (strcmp(lval, "auth_secret") == 0) {
755 route->auth_secret = g_strdup(rval);
756 }
757 #else
758 else if ((strcmp(lval, "auth_name") == 0)
759 || (strcmp(lval, "auth_login") == 0)
760 || (strcmp(lval, "auth_secret") == 0)) {
761 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
762 }
763 #endif
764 else if (strcmp(lval, "pipe") == 0) {
765 route->pipe = g_strdup(rval);
766 } else if (strcmp(lval, "pipe_fromline") == 0) {
767 route->pipe_fromline = parse_boolean(rval);
768 } else if (strcmp(lval, "pipe_fromhack") == 0) {
769 route->pipe_fromhack = parse_boolean(rval);
770 } else if (strcmp(lval, "last_route") == 0) {
771 route->last_route = parse_boolean(rval);
772 } else
773 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
774 }
776 if (!route->resolve_list) {
777 #ifdef ENABLE_RESOLVER
778 if (!is_local_net) {
779 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
780 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
781 }
782 #endif
783 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
784 }
785 fclose(in);
786 ok = TRUE;
788 /* warn user about misconfigurations: */
789 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
790 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
791 g_free(route->set_h_from_domain);
792 route->set_h_from_domain = NULL;
793 }
794 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
795 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
796 g_free(route->set_h_reply_to_domain);
797 route->set_h_reply_to_domain = NULL;
798 }
800 if (!ok) {
801 g_free(route);
802 route = NULL;
803 }
805 return route;
806 }
808 static void
809 _g_list_free_all(GList * list)
810 {
811 GList *node;
812 if (list) {
813 foreach(list, node)
814 g_free(node->data);
815 g_list_free(list);
816 }
817 }
819 void
820 destroy_route(connect_route * r)
821 {
822 if (r->filename)
823 g_free(r->filename);
824 if (r->mail_host) {
825 g_free(r->mail_host->address);
826 g_free(r->mail_host);
827 }
828 if (r->wrapper)
829 g_free(r->wrapper);
830 if (r->helo_name)
831 g_free(r->helo_name);
832 _g_list_free_all(r->allowed_senders);
833 _g_list_free_all(r->denied_senders);
834 _g_list_free_all(r->allowed_recipients);
835 _g_list_free_all(r->denied_recipients);
836 if (r->set_h_from_domain)
837 g_free(r->set_h_from_domain);
838 if (r->set_h_reply_to_domain)
839 g_free(r->set_h_reply_to_domain);
840 if (r->set_return_path_domain)
841 g_free(r->set_return_path_domain);
842 if (r->map_h_reply_to_addresses)
843 destroy_table(r->map_h_reply_to_addresses);
844 if (r->resolve_list)
845 g_list_free(r->resolve_list);
846 #ifdef ENABLE_AUTH
847 if (r->auth_name)
848 g_free(r->auth_name);
849 if (r->auth_login)
850 g_free(r->auth_login);
851 if (r->auth_secret)
852 g_free(r->auth_secret);
853 #endif
854 if (r->pipe)
855 g_free(r->pipe);
856 g_free(r);
857 }
859 GList*
860 read_route_list(GList * rf_list, gboolean is_local_net)
861 {
862 GList *list = NULL;
863 GList *node;
864 uid_t saved_uid, saved_gid;
866 if (!conf.run_as_user) {
867 set_euidgid(0, 0, &saved_uid, &saved_gid);
868 }
870 foreach(rf_list, node) {
871 gchar *fname = (gchar *) (node->data);
872 connect_route *route = read_route(fname, is_local_net);
873 if (route)
874 list = g_list_append(list, route);
875 else
876 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
877 }
879 /* set uid and gid back */
880 if (!conf.run_as_user) {
881 set_euidgid(saved_uid, saved_gid, NULL, NULL);
882 }
884 return list;
885 }
887 void
888 destroy_route_list(GList * list)
889 {
890 GList *node;
892 foreach(list, node) {
893 connect_route *route = (connect_route *) (node->data);
894 destroy_route(route);
895 }
896 g_list_free(list);
897 }
899 connect_route*
900 create_local_route()
901 {
902 connect_route *route;
904 route = g_malloc(sizeof(connect_route));
905 if (!route) {
906 return NULL;
907 }
908 memset(route, 0, sizeof(connect_route));
909 route->is_local_net = TRUE;
910 route->name = g_strdup("default local_net_route");
911 route->expand_h_sender_address = TRUE;
912 route->resolve_list = g_list_append(NULL, resolve_byname);
913 route->connect_error_fail = TRUE;
914 return route;
915 }