masqmail-0.2

view src/conf.c @ 179:ec3fe72a3e99

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:52:17 +0200
parents 349518b940db
children
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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(EXIT_FAILURE);
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.remote_port = 25;
432 conf.do_relay = TRUE;
433 conf.alias_local_cmp = strcmp;
434 conf.max_defer_time = 86400 * 4; /* 4 days */
435 conf.max_msg_size = 0; /* no limit on msg size */
437 if ((in = fopen(filename, "r")) == NULL) {
438 fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
439 return FALSE;
440 }
442 gchar lval[256], rval[2048];
443 while (read_statement(in, lval, 256, rval, 2048)) {
444 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
445 if (strcmp(lval, "debug_level") == 0)
446 conf.debug_level = atoi(rval);
447 else if (strcmp(lval, "run_as_user") == 0) {
448 if (!conf.run_as_user) /* you should not be able to reset that flag */
449 conf.run_as_user = parse_boolean(rval);
450 } else if (strcmp(lval, "use_syslog") == 0)
451 conf.use_syslog = parse_boolean(rval);
452 else if (strcmp(lval, "mail_dir") == 0)
453 conf.mail_dir = g_strdup(rval);
454 else if (strcmp(lval, "lock_dir") == 0)
455 conf.lock_dir = g_strdup(rval);
456 else if (strcmp(lval, "spool_dir") == 0)
457 conf.spool_dir = g_strdup(rval);
458 else if (strcmp(lval, "log_dir") == 0)
459 conf.log_dir = g_strdup(rval);
460 else if (strcmp(lval, "host_name") == 0) {
461 if (rval[0] != '/')
462 conf.host_name = g_strdup(rval);
463 else {
464 char buf[256];
465 FILE *fptr = fopen(rval, "rt");
466 if (fptr) {
467 fprintf(stderr, "could not open %s: %s\n", rval, strerror(errno));
468 return FALSE;
469 }
470 fgets(buf, 255, fptr);
471 g_strchomp(buf);
472 conf.host_name = g_strdup(buf);
473 fclose(fptr);
474 }
475 } else if (strcmp(lval, "remote_port") == 0) {
476 fprintf(stderr, "the remote_port option is now deprecated. Use 'mail_host' in the\n"
477 "route configuration instead. See man masqmail.route\n");
478 conf.remote_port = atoi(rval);
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, "maildir_users") == 0) {
504 conf.maildir_users = parse_list(rval, TRUE);
505 } else if (strcmp(lval, "mda") == 0) {
506 conf.mda = g_strdup(rval);
507 } else if (strcmp(lval, "mda_fromline") == 0) {
508 conf.mda_fromline = parse_boolean(rval);
509 } else if (strcmp(lval, "mda_fromhack") == 0) {
510 conf.mda_fromhack = parse_boolean(rval);
511 } else if (strcmp(lval, "pipe_fromline") == 0) {
512 conf.pipe_fromline = parse_boolean(rval);
513 } else if (strcmp(lval, "pipe_fromhack") == 0) {
514 conf.pipe_fromhack = parse_boolean(rval);
515 } else if (strcmp(lval, "listen_addresses") == 0) {
516 GList *node;
517 GList *tmp_list = parse_list(rval, FALSE);
519 conf.listen_addresses = NULL;
520 foreach(tmp_list, node) {
521 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
522 g_free(node->data);
523 }
524 g_list_free(tmp_list);
525 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
526 #ifdef ENABLE_IDENT
527 GList *node;
528 GList *tmp_list = parse_list(rval, FALSE);
530 conf.ident_trusted_nets = NULL;
531 foreach(tmp_list, node) {
532 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
533 g_free(node->data);
534 }
535 g_list_free(tmp_list);
536 #else
537 fprintf(stderr, "%s ignored: not compiled with ident support\n", lval);
538 #endif
539 } else if ((strncmp(lval, "connect_route.", 14) == 0)
540 || (strncmp(lval, "online_routes.", 14) == 0)) {
541 GList *file_list = parse_list(rval, FALSE);
542 table_pair *pair = create_pair(&(lval[14]), file_list);
543 conf.connect_routes = g_list_append(conf.connect_routes, pair);
544 } else if (strcmp(lval, "local_net_route") == 0) {
545 conf.local_net_routes = parse_list(rval, FALSE);
546 } else if (strcmp(lval, "online_detect") == 0)
547 conf.online_detect = g_strdup(rval);
548 else if (strcmp(lval, "online_file") == 0)
549 conf.online_file = g_strdup(rval);
550 else if (strcmp(lval, "online_pipe") == 0)
551 conf.online_pipe = g_strdup(rval);
552 else if (strcmp(lval, "mserver_iface") == 0)
553 conf.mserver_iface = parse_interface(rval, 224);
554 else if (strcmp(lval, "do_queue") == 0)
555 conf.do_queue = parse_boolean(rval);
556 else if (strncmp(lval, "get.", 4) == 0) {
557 #ifdef ENABLE_POP3
558 table_pair *pair = create_pair_string(&(lval[4]), rval);
559 conf.get_names = g_list_append(conf.get_names, pair);
560 #else
561 fprintf(stderr, "get.<name> ignored: not compiled with pop support\n");
562 #endif
563 } else if (strncmp(lval, "online_gets.", 12) == 0) {
564 #ifdef ENABLE_POP3
565 GList *file_list = parse_list(rval, FALSE);
566 table_pair *pair = create_pair(&(lval[12]), file_list);
567 conf.online_gets = g_list_append(conf.online_gets, pair);
568 #else
569 fprintf(stderr, "online_gets.<name> ignored: not compiled with pop support\n");
570 #endif
571 } else if (strcmp(lval, "errmsg_file") == 0)
572 conf.errmsg_file = g_strdup(rval);
573 else if (strcmp(lval, "warnmsg_file") == 0)
574 conf.warnmsg_file = g_strdup(rval);
575 else if (strcmp(lval, "warn_intervals") == 0)
576 conf.warn_intervals = parse_list(rval, FALSE);
577 else if (strcmp(lval, "max_defer_time") == 0) {
578 gint dummy;
579 gint ival = time_interval(rval, &dummy);
580 if (ival < 0)
581 fprintf(stderr, "invalid time interval for 'max_defer_time': %s\n", rval);
582 else
583 conf.max_defer_time = ival;
584 } else if (strcmp(lval, "log_user") == 0)
585 conf.log_user = g_strdup(rval);
586 else if(strcmp(lval, "max_msg_size") == 0) {
587 conf.max_msg_size = atol(rval);
588 DEBUG(6) fprintf(stderr,"rval=%s, conf.max_msg_size=%ld\n",
589 rval, conf.max_msg_size);
590 }
591 else
592 fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
593 }
594 fclose(in);
596 if (conf.errmsg_file == NULL)
597 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
598 if (conf.warnmsg_file == NULL)
599 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
601 if (conf.lock_dir == NULL)
602 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
604 if (conf.mbox_default == NULL)
605 conf.mbox_default = g_strdup("mbox");
607 if (conf.warn_intervals == NULL)
608 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
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, conf.remote_port);
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, "pop3_login") == 0) {
749 #ifdef ENABLE_POP3
750 route->pop3_login = g_strdup(rval);
751 #else
752 logwrite(LOG_WARNING, "pop3_login ignored: not compiled with pop support.\n");
753 #endif
754 } else if (strcmp(lval, "pipe") == 0) {
755 route->pipe = g_strdup(rval);
756 } else if (strcmp(lval, "pipe_fromline") == 0) {
757 route->pipe_fromline = parse_boolean(rval);
758 } else if (strcmp(lval, "pipe_fromhack") == 0) {
759 route->pipe_fromhack = parse_boolean(rval);
760 } else if (strcmp(lval, "last_route") == 0) {
761 route->last_route = parse_boolean(rval);
762 } else
763 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
764 }
766 if (route->resolve_list == NULL) {
767 if (is_local_net) {
768 route->resolve_list = g_list_append(NULL, resolve_byname);
769 } else {
770 #ifdef ENABLE_RESOLVER
771 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
772 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
773 #endif
774 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
775 }
776 }
777 fclose(in);
778 ok = TRUE;
780 /* warn user about misconfigurations: */
781 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
782 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
783 g_free(route->set_h_from_domain);
784 route->set_h_from_domain = NULL;
785 }
786 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
787 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
788 g_free(route->set_h_reply_to_domain);
789 route->set_h_reply_to_domain = NULL;
790 }
792 if (!ok) {
793 g_free(route);
794 route = NULL;
795 }
797 return route;
798 }
800 static void
801 _g_list_free_all(GList * list)
802 {
803 GList *node;
804 if (list) {
805 foreach(list, node)
806 g_free(node->data);
807 g_list_free(list);
808 }
809 }
811 void
812 destroy_route(connect_route * r)
813 {
814 if (r->filename)
815 g_free(r->filename);
816 if (r->protocol)
817 g_free(r->protocol);
818 if (r->mail_host) {
819 g_free(r->mail_host->address);
820 g_free(r->mail_host);
821 }
822 if (r->wrapper)
823 g_free(r->wrapper);
824 if (r->helo_name)
825 g_free(r->helo_name);
826 _g_list_free_all(r->allowed_mail_locals);
827 _g_list_free_all(r->not_allowed_mail_locals);
828 _g_list_free_all(r->allowed_rcpt_domains);
829 _g_list_free_all(r->not_allowed_rcpt_domains);
830 if (r->set_h_from_domain)
831 g_free(r->set_h_from_domain);
832 if (r->set_h_reply_to_domain)
833 g_free(r->set_h_reply_to_domain);
834 if (r->set_return_path_domain)
835 g_free(r->set_return_path_domain);
836 if (r->map_h_reply_to_addresses)
837 destroy_table(r->map_h_reply_to_addresses);
838 if (r->resolve_list)
839 g_list_free(r->resolve_list);
840 #ifdef ENABLE_AUTH
841 if (r->auth_name)
842 g_free(r->auth_name);
843 if (r->auth_login)
844 g_free(r->auth_login);
845 if (r->auth_secret)
846 g_free(r->auth_secret);
847 #endif
848 #ifdef ENABLE_POP3
849 if (r->pop3_login)
850 g_free(r->pop3_login);
851 #endif
852 if (r->pipe)
853 g_free(r->pipe);
854 g_free(r);
855 }
857 GList*
858 read_route_list(GList * rf_list, gboolean is_local_net)
859 {
860 GList *list = NULL;
861 GList *node;
862 uid_t saved_uid, saved_gid;
864 if (!conf.run_as_user) {
865 set_euidgid(0, 0, &saved_uid, &saved_gid);
866 }
868 foreach(rf_list, node) {
869 gchar *fname = (gchar *) (node->data);
870 connect_route *route = read_route(fname, is_local_net);
871 if (route)
872 list = g_list_append(list, route);
873 else
874 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
875 }
877 /* set uid and gid back */
878 if (!conf.run_as_user) {
879 set_euidgid(saved_uid, saved_gid, NULL, NULL);
880 }
882 return list;
883 }
885 void
886 destroy_route_list(GList * list)
887 {
888 GList *node;
890 foreach(list, node) {
891 connect_route *route = (connect_route *) (node->data);
892 destroy_route(route);
893 }
894 g_list_free(list);
895 }
897 #ifdef ENABLE_POP3
899 get_conf*
900 read_get_conf(gchar * filename)
901 {
902 FILE *in;
904 get_conf *gc = g_malloc(sizeof(get_conf));
905 memset(gc, 0, sizeof(get_conf));
907 gc->server_port = 110;
909 if ((in = fopen(filename, "r")) == NULL) {
910 logwrite(LOG_ALERT, "could not open get file %s: %s\n", filename, strerror(errno));
911 g_free(gc);
912 return NULL;
913 }
915 gchar lval[256], rval[2048];
916 while (read_statement(in, lval, 256, rval, 2048)) {
917 if (strcmp(lval, "protocol") == 0)
918 gc->protocol = g_strdup(rval);
919 else if (strcmp(lval, "server") == 0)
920 gc->server_name = g_strdup(rval);
921 else if (strcmp(lval, "port") == 0)
922 gc->server_port = atoi(rval);
923 else if (strcmp(lval, "wrapper") == 0)
924 gc->wrapper = g_strdup(rval);
925 else if (strcmp(lval, "user") == 0)
926 gc->login_user = g_strdup(rval);
927 else if (strcmp(lval, "pass") == 0)
928 gc->login_pass = g_strdup(rval);
929 else if (strcmp(lval, "address") == 0)
930 gc->address = create_address_qualified(rval, TRUE, conf.host_name);
931 else if (strcmp(lval, "return_path") == 0)
932 gc->return_path = create_address_qualified(rval, TRUE, conf.host_name);
933 else if (strcmp(lval, "do_ssl") == 0)
934 /* we ignore this. This option is used by sqilconf */
935 ;
936 else if (strcmp(lval, "do_keep") == 0)
937 gc->do_keep = parse_boolean(rval);
938 else if (strcmp(lval, "do_uidl") == 0)
939 gc->do_uidl = parse_boolean(rval);
940 else if (strcmp(lval, "do_uidl_dele") == 0)
941 gc->do_uidl_dele = parse_boolean(rval);
942 else if (strcmp(lval, "max_size") == 0)
943 gc->max_size = atoi(rval);
944 else if (strcmp(lval, "max_size_delete") == 0)
945 gc->max_size_delete = parse_boolean(rval);
946 else if (strcmp(lval, "max_count") == 0)
947 gc->max_count = atoi(rval);
948 else if (strcmp(lval, "resolve_list") == 0)
949 gc->resolve_list = parse_resolve_list(rval);
950 else
951 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
952 }
953 fclose(in);
955 if (gc->resolve_list == NULL) {
956 #ifdef ENABLE_RESOLVER
957 gc->resolve_list = g_list_append(NULL, resolve_dns_a);
958 #endif
959 gc->resolve_list = g_list_append(NULL, resolve_byname);
960 }
962 if (gc->protocol == NULL)
963 gc->protocol = g_strdup("pop3");
964 return gc;
965 }
967 void
968 destroy_get_conf(get_conf * gc)
969 {
970 if (gc->protocol)
971 g_free(gc->protocol);
972 if (gc->server_name)
973 g_free(gc->server_name);
974 if (gc->login_user)
975 g_free(gc->login_user);
976 if (gc->login_pass)
977 g_free(gc->login_pass);
978 if (gc->wrapper)
979 g_free(gc->wrapper);
980 if (gc->address)
981 destroy_address(gc->address);
982 if (gc->return_path)
983 destroy_address(gc->return_path);
984 if (gc->resolve_list)
985 g_list_free(gc->resolve_list);
986 g_free(gc);
987 }
989 #endif
991 connect_route*
992 create_local_route()
993 {
994 connect_route *route;
996 route = g_malloc(sizeof(connect_route));
997 if (!route) {
998 return NULL;
999 }
1000 memset(route, 0, sizeof(connect_route));
1001 route->protocol = g_strdup("smtp");
1002 route->is_local_net = TRUE;
1003 route->name = g_strdup("local_net (default)");
1004 route->expand_h_sender_address = TRUE;
1005 route->resolve_list = g_list_append(NULL, resolve_byname);
1006 route->connect_error_fail = TRUE;
1007 return route;