masqmail

view src/conf.c @ 421:f37384470855

Changed lockdir to /var/lock/masqmail; Create lockdir and piddir on startup. Moved the lockdir out of the spool dir. (When /var/lock is a ramdisk we do well to have the lock files there.) Added the new configure option --with-lockdir to change that location. Nontheless, if we run_as_user, then lock files are always stored in the spool dir directly. Instead of installing the lockdir and piddir at installation time, we create them on startup time now if they are missing. This is necessary if lockdir or piddir are a tmpfs.
author markus schnalke <meillo@marmaro.de>
date Wed, 30 May 2012 09:38:38 +0200
parents 8a62bebda631
children e972c3cbe1e0
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 1999-2001 Oliver Kurth
4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include <pwd.h>
22 #include <grp.h>
24 #include "masqmail.h"
26 masqmail_conf conf;
28 void
29 init_conf()
30 {
31 struct passwd *passwd;
32 struct group *group;
34 if (!(passwd = getpwnam(DEF_MAIL_USER))) {
35 fprintf(stderr, "user %s not found! (terminating)\n",
36 DEF_MAIL_USER);
37 exit(1);
38 }
39 if (!(group = getgrnam(DEF_MAIL_GROUP))) {
40 fprintf(stderr, "group %s not found! (terminating)\n",
41 DEF_MAIL_GROUP);
42 exit(1);
43 }
44 memset(&conf, 0, sizeof(masqmail_conf));
45 conf.orig_uid = getuid();
46 conf.orig_gid = getgid();
47 conf.mail_uid = passwd->pw_uid;
48 conf.mail_gid = group->gr_gid;
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(9) fprintf(stderr, "parse_boolean: %s\n", rval);
65 for (str = true_strings; *str; str++) {
66 if (strncasecmp(*str, rval, strlen(*str))==0) {
67 return TRUE;
68 }
69 }
70 for (str = false_strings; *str; str++) {
71 if (strncasecmp(*str, rval, strlen(*str))==0) {
72 return FALSE;
73 }
74 }
75 fprintf(stderr, "cannot parse value '%s'\n", rval);
76 exit(1);
77 }
79 /*
80 ** make a list from the lines of a file
81 */
82 static GList*
83 parse_list_file(const gchar *fname)
84 {
85 GList *list = NULL;
86 FILE *fptr;
87 gchar buf[256];
89 if (!(fptr = fopen(fname, "rt"))) {
90 logwrite(LOG_ALERT, "could not open %s for reading: %s\n",
91 fname, strerror(errno));
92 exit(1);
93 }
94 while (!fgets(buf, sizeof buf, fptr)) {
95 g_strstrip(buf);
96 if (!*buf || *buf == '#') {
97 continue;
98 }
99 DEBUG(9) fprintf(stderr, "parse_list_file: item = %s\n", buf);
100 list = g_list_append(list, g_strdup(buf));
101 }
102 fclose(fptr);
104 return list;
105 }
107 /*
108 ** given a semicolon separated string, this function makes a GList out of it.
109 */
110 static GList*
111 parse_list(gchar *line, gboolean read_file)
112 {
113 GList *list = NULL;
114 gchar *tok;
116 DEBUG(9) fprintf(stderr, "parsing list %s, file?:%d\n",
117 line, read_file);
118 for (tok = strtok(strdup(line), ";"); tok; tok = strtok(NULL, ";")) {
119 DEBUG(9) fprintf(stderr, "item = %s\n", tok);
120 if (read_file && *tok == '/') {
121 /* item is a filename, include its contents */
122 list = g_list_concat(list, parse_list_file(tok));
123 } else {
124 /* just a normal item */
125 list = g_list_append(list, g_strdup(tok));
126 }
127 }
128 return list;
129 }
131 /*
132 ** Split the addrs at '@' into local_part and domain. Without an '@'
133 ** everything is local_part. Create and return a list of address structs.
134 ** This funktion is used for lists of addrs containing globbing chars
135 ** (* and ?). We don't need valid RFC821 addresses here, just patterns
136 ** to match against.
137 */
138 static GList*
139 parse_address_glob_list(gchar *line)
140 {
141 GList *plain_list = parse_list(line, TRUE);
142 GList *node;
143 GList *list = NULL;
145 foreach(plain_list, node) {
146 gchar *item = (gchar *) (node->data);
147 char *at;
148 char *ep;
149 address *addr = calloc(1, sizeof(address));
151 ep = item + strlen(item) - 1;
152 if (*item == '<' && *ep == '>') {
153 *item = '\0';
154 *ep = '\0';
155 g_strstrip(item);
156 }
158 addr->address = strdup(item);
159 at = strrchr(item, '@');
160 if (at) {
161 *at = '\0';
162 addr->local_part = strdup(item);
163 addr->domain = strdup(at+1);
164 } else {
165 addr->local_part = strdup(item);
166 /* No `@', thus any domain is okay. */
167 addr->domain = "*";
168 }
169 list = g_list_append(list, addr);
170 DEBUG(6) debugf("parse_address_glob_list: "
171 "read pattern `%s' `%s'\n",
172 addr->local_part, addr->domain);
173 g_free(item);
174 }
175 g_list_free(plain_list);
176 return list;
177 }
179 static GList*
180 parse_resolve_list(gchar *line)
181 {
182 GList *list;
183 GList *list_node;
184 GList *res_list = NULL;
185 gchar *item;
187 list = parse_list(line, TRUE);
188 if (!list) {
189 return NULL;
190 }
191 foreach(list, list_node) {
192 item = (gchar *) list_node->data;
193 if (strcmp(item, "byname")==0) {
194 res_list = g_list_append(res_list, resolve_byname);
195 #ifdef ENABLE_RESOLVER
196 } else if (strcmp(item, "dns_a")==0) {
197 res_list = g_list_append(res_list, resolve_dns_a);
198 } else if (strcmp(item, "dns_mx")==0) {
199 res_list = g_list_append(res_list, resolve_dns_mx);
200 #endif
201 } else {
202 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
203 exit(1);
204 }
205 g_free(item);
206 }
207 g_list_free(list);
208 return res_list;
209 }
211 static interface*
212 parse_interface(gchar *line, gint def_port)
213 {
214 gchar *cp;
215 interface *iface = g_malloc(sizeof(interface));
217 DEBUG(9) fprintf(stderr, "parse_interface: %s\n", line);
218 if ((cp = strchr(line, ':'))) {
219 *cp = '\0';
220 }
221 g_strstrip(line);
222 iface->address = g_strdup(line);
223 iface->port = (cp) ? atoi(++cp) : def_port;
224 DEBUG(9) fprintf(stderr, "found: address:port=%s:%u\n",
225 iface->address, iface->port);
226 return iface;
227 }
229 static gboolean
230 eat_comments(FILE *in)
231 {
232 gint c;
233 int incomment = 0;
235 while ((c = fgetc(in)) != EOF) {
236 if (incomment) {
237 /* eat until end of line */
238 if (c == '\n') {
239 incomment = 0;
240 continue;
241 } else {
242 continue;
243 }
244 } else {
245 /* eat whitespace and watch for comments */
246 if (isspace(c)) {
247 continue;
248 } else if (c == '#') {
249 incomment = 1;
250 continue;
251 } else {
252 /* found something (that's not our business) */
253 ungetc(c, in);
254 return TRUE;
255 }
256 }
257 }
258 return FALSE;
259 }
261 static gboolean
262 eat_spaces(FILE *in)
263 {
264 gint c;
266 while ((c = fgetc(in)) != EOF) {
267 if (!isspace(c)) {
268 ungetc(c, in);
269 return TRUE;
270 }
271 }
272 return FALSE;
273 }
275 static gboolean
276 read_lval(FILE *in, gchar *buf, gint size)
277 {
278 gint c;
279 gchar *ptr = buf;
281 DEBUG(9) fprintf(stderr, "read_lval()\n");
282 if (!eat_spaces(in)) {
283 return FALSE;
284 }
286 DEBUG(9) fprintf(stderr, "read_lval() 2\n");
287 while (1) {
288 c = fgetc(in);
289 if (c == EOF) {
290 fprintf(stderr, "unexpected EOF after %s\n", buf);
291 return FALSE;
292 }
293 if (ptr >= buf+size-1) {
294 fprintf(stderr, "lval too long\n");
295 break;
296 }
297 if (!isalnum(c) && c != '_' && c != '-' && c != '.') {
298 break;
299 }
300 *ptr++ = c;
301 }
302 *ptr = '\0';
303 g_strstrip(buf);
304 ungetc(c, in);
305 eat_spaces(in);
306 DEBUG(9) fprintf(stderr, "lval = %s\n", buf);
307 return *buf != '\0';
308 }
310 static gboolean
311 read_rval(FILE *in, gchar *buf, gint size)
312 {
313 gint c;
314 gchar *ptr = buf;
316 DEBUG(9) fprintf(stderr, "read_rval()\n");
317 if (!eat_spaces(in)) {
318 return FALSE;
319 }
321 c = fgetc(in);
322 if (c != '"') {
323 /* unquoted rval */
324 ungetc(c, in);
325 while ((c = fgetc(in)) != EOF) {
326 if (ptr >= buf+size-1) {
327 /* rval too long */
328 break;
329 }
330 if (!isalnum(c) && c != '_' && c != '-' &&
331 c != '.' && c != '/' && c != '@' &&
332 c != ';' && c != ':') {
333 break;
334 }
335 *ptr++ = c;
336 }
337 *ptr = '\0';
338 ungetc(c, in);
339 } else {
340 /* quoted rval */
341 gboolean escape = FALSE;
342 while ((c = fgetc(in)) != EOF) {
343 if (ptr >= buf+size-1) {
344 /* rval too long */
345 break;
346 }
347 if (!escape && c == '"') {
348 break;
349 }
350 if (!escape && c == '\\') {
351 escape = TRUE;
352 continue;
353 }
354 *ptr++ = c;
355 escape = FALSE;
356 }
357 *ptr = '\0';
358 }
359 g_strstrip(buf);
360 DEBUG(9) fprintf(stderr, "rval = %s\n", buf);
361 /* eat trailing of line */
362 while ((c = fgetc(in)) != EOF && c != '\n') {
363 continue;
364 }
366 return TRUE;
367 }
369 static gboolean
370 read_statement(FILE *in, gchar *lval, gint lsize, gchar *rval, gint rsize)
371 {
372 gint c;
374 DEBUG(9) fprintf(stderr, "read_statement()\n");
376 /* eat comments and empty lines: */
377 if (!eat_comments(in)) {
378 return FALSE;
379 }
380 if (!read_lval(in, lval, lsize)) {
381 return FALSE;
382 }
383 g_strstrip(lval);
384 DEBUG(9) fprintf(stderr, " lval = `%s'\n", lval);
385 if ((c = fgetc(in) != '=')) {
386 fprintf(stderr, "'=' expected after %s, char was '%c'\n",
387 lval, c);
388 }
389 if (!read_rval(in, rval, rsize)) {
390 return FALSE;
391 }
392 g_strstrip(rval);
393 DEBUG(9) fprintf(stderr, " rval = `%s'\n", rval);
394 return TRUE;
395 }
397 gboolean
398 read_conf(gchar *filename)
399 {
400 FILE *in;
401 gchar lval[256], rval[2048];
402 GList *listen_addrs_tmp = NULL;
404 conf.do_relay = TRUE;
405 conf.localpartcmp = strcmp;
406 conf.max_defer_time = 86400 * 4; /* 4 days */
407 conf.max_msg_size = 0; /* no limit on msg size */
408 conf.lock_dir = LOCK_DIR;
409 conf.spool_dir = SPOOL_DIR;
410 conf.mail_dir = "/var/mail";
412 if (!(in = fopen(filename, "r"))) {
413 logwrite(LOG_ALERT, "could not open config file %s: %s\n",
414 filename, strerror(errno));
415 return FALSE;
416 }
418 while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
419 DEBUG(9) fprintf(stderr,"read_conf(): lval=%s\n", lval);
420 if (strcmp(lval, "debug_level")==0) {
421 conf.debug_level = atoi(rval);
422 } else if (strcmp(lval, "run_as_user")==0) {
423 if (!conf.run_as_user) {
424 /* you should not be able to reset that flag */
425 conf.run_as_user = parse_boolean(rval);
426 }
427 } else if (strcmp(lval, "use_syslog")==0) {
428 conf.use_syslog = parse_boolean(rval);
429 } else if (strcmp(lval, "mail_dir")==0) {
430 conf.mail_dir = g_strdup(rval);
431 } else if (strcmp(lval, "lock_dir")==0) {
432 conf.lock_dir = g_strdup(rval);
433 } else if (strcmp(lval, "spool_dir")==0) {
434 conf.spool_dir = g_strdup(rval);
435 } else if (strcmp(lval, "log_dir")==0) {
436 conf.log_dir = g_strdup(rval);
437 } else if (strcmp(lval, "host_name")==0) {
438 if (rval[0] != '/') {
439 conf.host_name = g_strdup(rval);
440 } else {
441 char buf[256];
442 FILE *fptr = fopen(rval, "rt");
443 if (!fptr) {
444 logwrite(LOG_ALERT, "could not open "
445 "%s: %s\n", rval,
446 strerror(errno));
447 return FALSE;
448 }
449 fgets(buf, sizeof buf, fptr);
450 g_strstrip(buf);
451 conf.host_name = g_strdup(buf);
452 fclose(fptr);
453 }
454 } else if (strcmp(lval, "local_hosts")==0) {
455 conf.local_hosts = parse_list(rval, TRUE);
456 } else if (strcmp(lval, "local_addresses")==0) {
457 conf.local_addresses = parse_list(rval, TRUE);
458 } else if (strcmp(lval, "not_local_addresses")==0) {
459 conf.not_local_addresses = parse_list(rval, TRUE);
460 } else if (strcmp(lval, "do_save_envelope_to")==0) {
461 conf.do_save_envelope_to = parse_boolean(rval);
462 } else if (strcmp(lval, "defer_all")==0) {
463 conf.defer_all = parse_boolean(rval);
464 } else if (strcmp(lval, "do_relay")==0) {
465 conf.do_relay = parse_boolean(rval);
466 } else if (strcmp(lval, "alias_file")==0) {
467 conf.alias_file = g_strdup(rval);
468 } else if (strcmp(lval, "globalias_file")==0) {
469 conf.globalias_file = g_strdup(rval);
470 } else if (strcmp(lval, "caseless_matching")==0) {
471 conf.localpartcmp = parse_boolean(rval) ?
472 strcasecmp : strcmp;
473 } else if (strcmp(lval, "mbox_default")==0) {
474 conf.mbox_default = g_strdup(rval);
475 } else if (strcmp(lval, "mbox_users")==0) {
476 conf.mbox_users = parse_list(rval, TRUE);
477 } else if (strcmp(lval, "mda_users")==0) {
478 conf.mda_users = parse_list(rval, TRUE);
479 } else if (strcmp(lval, "mda")==0) {
480 conf.mda = g_strdup(rval);
481 } else if (strcmp(lval, "mda_fromline")==0) {
482 conf.mda_fromline = parse_boolean(rval);
483 } else if (strcmp(lval, "mda_fromhack")==0) {
484 conf.mda_fromhack = parse_boolean(rval);
485 } else if (strcmp(lval, "pipe_fromline")==0) {
486 conf.pipe_fromline = parse_boolean(rval);
487 } else if (strcmp(lval, "pipe_fromhack")==0) {
488 conf.pipe_fromhack = parse_boolean(rval);
489 } else if (strcmp(lval, "listen_addresses")==0) {
490 listen_addrs_tmp = parse_list(rval, TRUE);
491 } else if (strncmp(lval, "query_routes.", 13)==0) {
492 GList *file_list = parse_list(rval, FALSE);
493 table_pair *pair = create_pair(lval+13, file_list);
494 conf.query_routes = g_list_append(conf.query_routes,
495 pair);
496 } else if (strcmp(lval, "permanent_routes")==0) {
497 conf.perma_routes = parse_list(rval, FALSE);
498 } else if (strcmp(lval, "online_query")==0) {
499 conf.online_query = g_strdup(rval);
500 } else if (strcmp(lval, "do_queue")==0) {
501 conf.do_queue = parse_boolean(rval);
502 } else if (strcmp(lval, "errmsg_file")==0) {
503 conf.errmsg_file = g_strdup(rval);
504 } else if (strcmp(lval, "warnmsg_file")==0) {
505 conf.warnmsg_file = g_strdup(rval);
506 } else if (strcmp(lval, "warn_intervals")==0) {
507 conf.warn_intervals = parse_list(rval, TRUE);
508 } else if (strcmp(lval, "max_defer_time")==0) {
509 gint ival = time_interval(rval);
510 if (ival < 0) {
511 logwrite(LOG_WARNING, "invalid time interval "
512 "for 'max_defer_time': %s\n",
513 rval);
514 } else {
515 conf.max_defer_time = ival;
516 }
517 } else if (strcmp(lval, "log_user")==0) {
518 conf.log_user = g_strdup(rval);
519 } else if(strcmp(lval, "max_msg_size")==0) {
520 conf.max_msg_size = atol(rval);
521 DEBUG(9) fprintf(stderr,
522 "rval=%s, conf.max_msg_size=%ld\n",
523 rval, conf.max_msg_size);
524 } else {
525 logwrite(LOG_WARNING, "var '%s' unknown: ignored\n",
526 lval);
527 }
528 }
529 fclose(in);
531 if (!conf.host_name) {
532 logwrite(LOG_ALERT, "`host_name' MUST be set in "
533 "masqmail.conf. See man page\n");
534 return FALSE;
535 }
536 if (!conf.errmsg_file) {
537 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
538 }
539 if (!conf.warnmsg_file) {
540 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
541 }
542 if (!conf.mbox_default) {
543 conf.mbox_default = g_strdup("mbox");
544 }
545 if (!conf.warn_intervals) {
546 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", TRUE);
547 }
548 if (!conf.local_hosts) {
549 char *shortname = strdup(conf.host_name);
550 char *p = strchr(shortname, '.');
551 if (p) {
552 *p = '\0';
553 }
554 /* don't care if shortname and conf.host_name are the same */
555 char *local_hosts_str = g_strdup_printf("localhost;%s;%s",
556 shortname, conf.host_name);
557 conf.local_hosts = parse_list(local_hosts_str, TRUE);
558 free(shortname);
559 free(local_hosts_str);
560 }
561 if (!listen_addrs_tmp) {
562 conf.listen_addresses = g_list_append(NULL,
563 parse_interface(strdup("localhost"), 25));
564 } else {
565 GList *node;
567 foreach(listen_addrs_tmp, node) {
568 conf.listen_addresses =
569 g_list_append(conf.listen_addresses,
570 parse_interface((gchar *) node->data,
571 25));
572 g_free(node->data);
573 }
574 g_list_free(listen_addrs_tmp);
575 }
577 return TRUE;
578 }
580 connect_route*
581 read_route(gchar *filename, gboolean is_perma)
582 {
583 FILE *in;
584 connect_route *route;
585 gchar lval[256], rval[2048];
587 DEBUG(5) debugf("read_route, filename = %s\n", filename);
589 if (!(in = fopen(filename, "r"))) {
590 logwrite(LOG_ALERT, "could not open route file %s: %s\n",
591 filename, strerror(errno));
592 return NULL;
593 }
595 route = g_malloc(sizeof(connect_route));
596 memset(route, 0, sizeof(connect_route));
597 route->filename = g_strdup(filename);
598 route->name = route->filename; /* quick hack */
599 route->expand_h_sender_address = TRUE;
600 route->is_perma = is_perma;
601 route->do_pipelining = TRUE;
603 while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
604 if (strcmp(lval, "mail_host")==0) {
605 route->mail_host = parse_interface(rval, 25);
606 } else if (strcmp(lval, "helo_name")==0) {
607 route->helo_name = g_strdup(rval);
608 } else if (strcmp(lval, "wrapper")==0) {
609 route->wrapper = g_strdup(rval);
610 } else if (strcmp(lval, "connect_error_fail")==0) {
611 route->connect_error_fail = parse_boolean(rval);
612 } else if (strcmp(lval, "do_correct_helo")==0) {
613 route->do_correct_helo = parse_boolean(rval);
614 } else if (strcmp(lval, "instant_helo")==0) {
615 route->instant_helo = parse_boolean(rval);
616 } else if (strcmp(lval, "do_pipelining")==0) {
617 route->do_pipelining = parse_boolean(rval);
619 } else if (strcmp(lval, "allowed_senders")==0) {
620 route->allowed_senders = parse_address_glob_list(rval);
621 } else if (strcmp(lval, "denied_senders")==0) {
622 route->denied_senders = parse_address_glob_list(rval);
623 } else if (strcmp(lval, "allowed_recipients")==0) {
624 route->allowed_recipients = parse_address_glob_list(rval);
625 } else if (strcmp(lval, "denied_recipients")==0) {
626 route->denied_recipients = parse_address_glob_list(rval);
628 } else if (strcmp(lval, "set_h_from_domain")==0) {
629 route->set_h_from_domain = g_strdup(rval);
630 } else if (strcmp(lval, "set_h_reply_to_domain")==0) {
631 route->set_h_reply_to_domain = g_strdup(rval);
632 } else if (strcmp(lval, "set_return_path_domain")==0) {
633 route->set_return_path_domain = g_strdup(rval);
634 } else if (strcmp(lval, "map_return_path_addresses")==0) {
635 GList *node, *list;
637 list = parse_list(rval, TRUE);
638 foreach(list, node) {
639 gchar *item = (gchar *) (node->data);
640 table_pair *pair = parse_table_pair(item, ':');
641 address *addr = create_address(
642 (gchar *) (pair->value), TRUE);
643 g_free(pair->value);
644 pair->value = (gpointer *) addr;
645 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
646 g_free(item);
647 }
648 g_list_free(list);
649 } else if (strcmp(lval, "map_h_from_addresses")==0) {
650 GList *list, *node;
652 list = parse_list(rval, TRUE);
653 foreach(list, node) {
654 gchar *item = (gchar *) (node->data);
655 table_pair *pair = parse_table_pair(item, ':');
656 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
657 g_free(item);
658 }
659 g_list_free(list);
660 } else if (strcmp(lval, "map_h_reply_to_addresses")==0) {
661 GList *list, *node;
663 list = parse_list(rval, TRUE);
664 foreach(list, node) {
665 gchar *item = (gchar *) (node->data);
666 table_pair *pair = parse_table_pair(item, ':');
667 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
668 g_free(item);
669 }
670 g_list_free(list);
671 } else if (strcmp(lval, "map_h_mail_followup_to_addresses")==0) {
672 GList *list, *node;
674 list = parse_list(rval, TRUE);
675 foreach(list, node) {
676 gchar *item = (gchar *) (node->data);
677 table_pair *pair = parse_table_pair(item, ':');
678 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
679 g_free(item);
680 }
681 g_list_free(list);
682 } else if (strcmp(lval, "expand_h_sender_domain")==0) {
683 route->expand_h_sender_domain = parse_boolean(rval);
684 } else if (strcmp(lval, "expand_h_sender_address")==0) {
685 route->expand_h_sender_address = parse_boolean(rval);
686 } else if (strcmp(lval, "resolve_list")==0) {
687 route->resolve_list = parse_resolve_list(rval);
688 } else if (strcmp(lval, "do_ssl")==0) {
689 /* we ignore this. This option is used by sqilconf */
690 ;
691 #ifdef ENABLE_AUTH
692 } else if (strcmp(lval, "auth_name")==0) {
693 route->auth_name = g_strdup(rval);
694 } else if (strcmp(lval, "auth_login")==0) {
695 route->auth_login = g_strdup(rval);
696 } else if (strcmp(lval, "auth_secret")==0) {
697 route->auth_secret = g_strdup(rval);
698 #else
699 } else if ((strcmp(lval, "auth_name")==0) ||
700 (strcmp(lval, "auth_login")==0) ||
701 (strcmp(lval, "auth_secret")==0)) {
702 logwrite(LOG_WARNING, "%s ignored: not compiled with "
703 "auth support.\n", lval);
704 }
705 #endif
706 } else if (strcmp(lval, "pipe")==0) {
707 route->pipe = g_strdup(rval);
708 } else if (strcmp(lval, "pipe_fromline")==0) {
709 route->pipe_fromline = parse_boolean(rval);
710 } else if (strcmp(lval, "pipe_fromhack")==0) {
711 route->pipe_fromhack = parse_boolean(rval);
712 } else if (strcmp(lval, "last_route")==0) {
713 route->last_route = parse_boolean(rval);
714 } else {
715 logwrite(LOG_WARNING, "var '%s' unknown: ignored\n",
716 lval);
717 }
718 }
720 if (!route->resolve_list) {
721 #ifdef ENABLE_RESOLVER
722 route->resolve_list = g_list_append(route->resolve_list,
723 resolve_dns_mx);
724 route->resolve_list = g_list_append(route->resolve_list,
725 resolve_dns_a);
726 #endif
727 route->resolve_list = g_list_append(route->resolve_list,
728 resolve_byname);
729 }
730 fclose(in);
732 /* warn user about mis-configurations: */
733 if (route->map_h_from_addresses && route->set_h_from_domain) {
734 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides "
735 "'set_h_from_domain'\n");
736 g_free(route->set_h_from_domain);
737 route->set_h_from_domain = NULL;
738 }
739 if (route->map_h_reply_to_addresses && route->set_h_reply_to_domain) {
740 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides "
741 "'set_h_reply_to_domain'\n");
742 g_free(route->set_h_reply_to_domain);
743 route->set_h_reply_to_domain = NULL;
744 }
746 return route;
747 }
749 static void
750 _g_list_free_all(GList *list)
751 {
752 GList *node;
753 if (!list) {
754 return;
755 }
756 foreach(list, node) {
757 g_free(node->data);
758 }
759 g_list_free(list);
760 }
762 void
763 destroy_route(connect_route *r)
764 {
765 if (r->filename) {
766 g_free(r->filename);
767 }
768 if (r->mail_host) {
769 g_free(r->mail_host->address);
770 g_free(r->mail_host);
771 }
772 if (r->wrapper) {
773 g_free(r->wrapper);
774 }
775 if (r->helo_name) {
776 g_free(r->helo_name);
777 }
778 _g_list_free_all(r->allowed_senders);
779 _g_list_free_all(r->denied_senders);
780 _g_list_free_all(r->allowed_recipients);
781 _g_list_free_all(r->denied_recipients);
782 if (r->set_h_from_domain) {
783 g_free(r->set_h_from_domain);
784 }
785 if (r->set_h_reply_to_domain) {
786 g_free(r->set_h_reply_to_domain);
787 }
788 if (r->set_return_path_domain) {
789 g_free(r->set_return_path_domain);
790 }
791 if (r->map_h_reply_to_addresses) {
792 destroy_table(r->map_h_reply_to_addresses);
793 }
794 if (r->resolve_list) {
795 g_list_free(r->resolve_list);
796 }
797 #ifdef ENABLE_AUTH
798 if (r->auth_name) {
799 g_free(r->auth_name);
800 }
801 if (r->auth_login) {
802 g_free(r->auth_login);
803 }
804 if (r->auth_secret) {
805 g_free(r->auth_secret);
806 }
807 #endif
808 if (r->pipe) {
809 g_free(r->pipe);
810 }
811 g_free(r);
812 }
814 GList*
815 read_route_list(GList *rf_list, gboolean is_perma)
816 {
817 GList *list = NULL;
818 GList *node;
819 uid_t saved_uid, saved_gid;
821 if (!conf.run_as_user) {
822 set_euidgid(0, 0, &saved_uid, &saved_gid);
823 }
824 foreach(rf_list, node) {
825 gchar *fname = (gchar *) (node->data);
826 connect_route *route = read_route(fname, is_perma);
827 if (route) {
828 list = g_list_append(list, route);
829 } else {
830 logwrite(LOG_ALERT, "could not read route "
831 "configuration %s\n", fname);
832 }
833 }
834 /* set uid and gid back */
835 if (!conf.run_as_user) {
836 set_euidgid(saved_uid, saved_gid, NULL, NULL);
837 }
838 return list;
839 }
841 void
842 destroy_route_list(GList *list)
843 {
844 GList *node;
846 foreach(list, node) {
847 connect_route *route = (connect_route *) (node->data);
848 destroy_route(route);
849 }
850 g_list_free(list);
851 }