masqmail-0.2

view src/conf.c @ 162:52c82d755215

replaced the MD5 implementation with the one of Solar Designer Until now, the sample code of RFC 1321 was used. It had an ugly license. Now we use the implementation of Solar Designer, which is in the Public Domain. http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
author meillo@marmaro.de
date Sun, 18 Jul 2010 22:01:04 +0200
parents cd59a5b4d3dd
children 349518b940db
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.remote_port = 25;
431 conf.do_relay = TRUE;
432 conf.alias_local_cmp = strcmp;
433 conf.max_defer_time = 86400 * 4; /* 4 days */
434 conf.max_msg_size = 0; /* no limit on msg size */
436 if ((in = fopen(filename, "r")) == NULL) {
437 fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
438 return FALSE;
439 }
441 gchar lval[256], rval[2048];
442 while (read_statement(in, lval, 256, rval, 2048)) {
443 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
444 if (strcmp(lval, "debug_level") == 0)
445 conf.debug_level = atoi(rval);
446 else if (strcmp(lval, "run_as_user") == 0) {
447 if (!conf.run_as_user) /* you should not be able to reset that flag */
448 conf.run_as_user = parse_boolean(rval);
449 } else if (strcmp(lval, "use_syslog") == 0)
450 conf.use_syslog = parse_boolean(rval);
451 else if (strcmp(lval, "mail_dir") == 0)
452 conf.mail_dir = g_strdup(rval);
453 else if (strcmp(lval, "lock_dir") == 0)
454 conf.lock_dir = g_strdup(rval);
455 else if (strcmp(lval, "spool_dir") == 0)
456 conf.spool_dir = g_strdup(rval);
457 else if (strcmp(lval, "log_dir") == 0)
458 conf.log_dir = g_strdup(rval);
459 else if (strcmp(lval, "host_name") == 0) {
460 if (rval[0] != '/')
461 conf.host_name = g_strdup(rval);
462 else {
463 char buf[256];
464 FILE *fptr = fopen(rval, "rt");
465 if (fptr) {
466 fprintf(stderr, "could not open %s: %s\n", rval, strerror(errno));
467 return FALSE;
468 }
469 fgets(buf, 255, fptr);
470 g_strchomp(buf);
471 conf.host_name = g_strdup(buf);
472 fclose(fptr);
473 }
474 } else if (strcmp(lval, "remote_port") == 0) {
475 fprintf(stderr, "the remote_port option is now deprecated. Use 'mail_host' in the\n"
476 "route configuration instead. See man masqmail.route\n");
477 conf.remote_port = atoi(rval);
478 } else if (strcmp(lval, "local_hosts") == 0)
479 conf.local_hosts = parse_list(rval, FALSE);
480 else if (strcmp(lval, "local_addresses") == 0)
481 conf.local_addresses = parse_list(rval, TRUE);
482 else if (strcmp(lval, "not_local_addresses") == 0)
483 conf.not_local_addresses = parse_list(rval, TRUE);
484 else if (strcmp(lval, "local_nets") == 0)
485 conf.local_nets = parse_list(rval, FALSE);
486 else if (strcmp(lval, "do_save_envelope_to") == 0)
487 conf.do_save_envelope_to = parse_boolean(rval);
488 else if (strcmp(lval, "defer_all") == 0)
489 conf.defer_all = parse_boolean(rval);
490 else if (strcmp(lval, "do_relay") == 0)
491 conf.do_relay = parse_boolean(rval);
492 else if (strcmp(lval, "alias_file") == 0) {
493 conf.alias_file = g_strdup(rval);
494 } else if (strcmp(lval, "alias_local_caseless") == 0) {
495 conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
496 } else if (strcmp(lval, "mbox_default") == 0) {
497 conf.mbox_default = g_strdup(rval);
498 } else if (strcmp(lval, "mbox_users") == 0) {
499 conf.mbox_users = parse_list(rval, TRUE);
500 } else if (strcmp(lval, "mda_users") == 0) {
501 conf.mda_users = parse_list(rval, TRUE);
502 } else if (strcmp(lval, "maildir_users") == 0) {
503 conf.maildir_users = parse_list(rval, TRUE);
504 } else if (strcmp(lval, "mda") == 0) {
505 conf.mda = g_strdup(rval);
506 } else if (strcmp(lval, "mda_fromline") == 0) {
507 conf.mda_fromline = parse_boolean(rval);
508 } else if (strcmp(lval, "mda_fromhack") == 0) {
509 conf.mda_fromhack = parse_boolean(rval);
510 } else if (strcmp(lval, "pipe_fromline") == 0) {
511 conf.pipe_fromline = parse_boolean(rval);
512 } else if (strcmp(lval, "pipe_fromhack") == 0) {
513 conf.pipe_fromhack = parse_boolean(rval);
514 } else if (strcmp(lval, "listen_addresses") == 0) {
515 GList *node;
516 GList *tmp_list = parse_list(rval, FALSE);
518 conf.listen_addresses = NULL;
519 foreach(tmp_list, node) {
520 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
521 g_free(node->data);
522 }
523 g_list_free(tmp_list);
524 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
525 #ifdef ENABLE_IDENT
526 GList *node;
527 GList *tmp_list = parse_list(rval, FALSE);
529 conf.ident_trusted_nets = NULL;
530 foreach(tmp_list, node) {
531 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
532 g_free(node->data);
533 }
534 g_list_free(tmp_list);
535 #else
536 fprintf(stderr, "%s ignored: not compiled with ident support\n", lval);
537 #endif
538 } else if ((strncmp(lval, "connect_route.", 14) == 0)
539 || (strncmp(lval, "online_routes.", 14) == 0)) {
540 GList *file_list = parse_list(rval, FALSE);
541 table_pair *pair = create_pair(&(lval[14]), file_list);
542 conf.connect_routes = g_list_append(conf.connect_routes, pair);
543 } else if (strcmp(lval, "local_net_route") == 0) {
544 conf.local_net_routes = parse_list(rval, FALSE);
545 } else if (strcmp(lval, "online_detect") == 0)
546 conf.online_detect = g_strdup(rval);
547 else if (strcmp(lval, "online_file") == 0)
548 conf.online_file = g_strdup(rval);
549 else if (strcmp(lval, "online_pipe") == 0)
550 conf.online_pipe = g_strdup(rval);
551 else if (strcmp(lval, "mserver_iface") == 0)
552 conf.mserver_iface = parse_interface(rval, 224);
553 else if (strcmp(lval, "do_queue") == 0)
554 conf.do_queue = parse_boolean(rval);
555 else if (strncmp(lval, "get.", 4) == 0) {
556 #ifdef ENABLE_POP3
557 table_pair *pair = create_pair_string(&(lval[4]), rval);
558 conf.get_names = g_list_append(conf.get_names, pair);
559 #else
560 fprintf(stderr, "get.<name> ignored: not compiled with pop support\n");
561 #endif
562 } else if (strncmp(lval, "online_gets.", 12) == 0) {
563 #ifdef ENABLE_POP3
564 GList *file_list = parse_list(rval, FALSE);
565 table_pair *pair = create_pair(&(lval[12]), file_list);
566 conf.online_gets = g_list_append(conf.online_gets, pair);
567 #else
568 fprintf(stderr, "online_gets.<name> ignored: not compiled with pop support\n");
569 #endif
570 } else if (strcmp(lval, "errmsg_file") == 0)
571 conf.errmsg_file = g_strdup(rval);
572 else if (strcmp(lval, "warnmsg_file") == 0)
573 conf.warnmsg_file = g_strdup(rval);
574 else if (strcmp(lval, "warn_intervals") == 0)
575 conf.warn_intervals = parse_list(rval, FALSE);
576 else if (strcmp(lval, "max_defer_time") == 0) {
577 gint dummy;
578 gint ival = time_interval(rval, &dummy);
579 if (ival < 0)
580 fprintf(stderr, "invalid time interval for 'max_defer_time': %s\n", rval);
581 else
582 conf.max_defer_time = ival;
583 } else if (strcmp(lval, "log_user") == 0)
584 conf.log_user = g_strdup(rval);
585 else if(strcmp(lval, "max_msg_size") == 0) {
586 conf.max_msg_size = atol(rval);
587 DEBUG(6) fprintf(stderr,"rval=%s, conf.max_msg_size=%ld\n",
588 rval, conf.max_msg_size);
589 }
590 else
591 fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
592 }
593 fclose(in);
595 if (conf.errmsg_file == NULL)
596 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
597 if (conf.warnmsg_file == NULL)
598 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
600 if (conf.lock_dir == NULL)
601 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
603 if (conf.mbox_default == NULL)
604 conf.mbox_default = g_strdup("mbox");
606 if (conf.warn_intervals == NULL)
607 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
609 return TRUE;
610 }
612 connect_route*
613 read_route(gchar * filename, gboolean is_local_net)
614 {
615 gboolean ok = FALSE;
616 FILE *in;
618 connect_route *route = g_malloc(sizeof(connect_route));
619 memset(route, 0, sizeof(connect_route));
621 DEBUG(5) debugf("read_route, filename = %s\n", filename);
623 route->filename = g_strdup(filename);
624 route->name = g_strdup(filename); /* quick hack */
626 route->protocol = g_strdup("smtp");
627 route->expand_h_sender_address = TRUE;
629 route->is_local_net = is_local_net;
631 route->do_pipelining = TRUE;
633 if ((in = fopen(route->filename, "r")) == NULL) {
634 logwrite(LOG_ALERT, "could not open route file %s: %s\n", route->filename, strerror(errno));
635 g_free(route);
636 return NULL;
637 }
639 gchar lval[256], rval[2048];
640 while (read_statement(in, lval, 256, rval, 2048)) {
641 if (strcmp(lval, "protocol") == 0)
642 route->protocol = g_strdup(rval);
643 else if (strcmp(lval, "mail_host") == 0)
644 route->mail_host = parse_interface(rval, conf.remote_port);
645 else if (strcmp(lval, "helo_name") == 0)
646 route->helo_name = g_strdup(rval);
647 else if (strcmp(lval, "wrapper") == 0)
648 route->wrapper = g_strdup(rval);
649 else if (strcmp(lval, "connect_error_fail") == 0)
650 route->connect_error_fail = parse_boolean(rval);
651 else if (strcmp(lval, "do_correct_helo") == 0)
652 route->do_correct_helo = parse_boolean(rval);
653 else if (strcmp(lval, "do_pipelining") == 0)
654 route->do_pipelining = parse_boolean(rval);
655 else if (strcmp(lval, "allowed_return_paths") == 0)
656 route->allowed_return_paths = parse_address_list(rval, TRUE);
657 else if (strcmp(lval, "allowed_mail_locals") == 0)
658 route->allowed_mail_locals = parse_list(rval, TRUE);
659 else if (strcmp(lval, "not_allowed_return_paths") == 0)
660 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
661 else if (strcmp(lval, "not_allowed_mail_locals") == 0)
662 route->not_allowed_mail_locals = parse_list(rval, TRUE);
663 else if (strcmp(lval, "allowed_rcpt_domains") == 0)
664 route->allowed_rcpt_domains = parse_list(rval, TRUE);
665 else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
666 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
667 else if (strcmp(lval, "set_h_from_domain") == 0)
668 route->set_h_from_domain = g_strdup(rval);
669 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
670 route->set_h_reply_to_domain = g_strdup(rval);
671 else if (strcmp(lval, "set_return_path_domain") == 0)
672 route->set_return_path_domain = g_strdup(rval);
673 else if (strcmp(lval, "map_return_path_addresses") == 0) {
674 GList *node, *list;
676 list = parse_list(rval, TRUE);
677 foreach(list, node) {
678 gchar *item = (gchar *) (node->data);
679 table_pair *pair = parse_table_pair(item, ':');
680 address *addr = create_address((gchar *) (pair->value), TRUE);
681 g_free(pair->value);
682 pair->value = (gpointer *) addr;
683 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
684 g_free(item);
685 }
686 g_list_free(list);
687 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
688 GList *list, *node;
690 list = parse_list(rval, TRUE);
691 foreach(list, node) {
692 gchar *item = (gchar *) (node->data);
693 table_pair *pair = parse_table_pair(item, ':');
694 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
695 g_free(item);
696 }
697 g_list_free(list);
698 } else if (strcmp(lval, "map_h_reply_to_addresses") == 0) {
699 GList *list, *node;
701 list = parse_list(rval, TRUE);
702 foreach(list, node) {
703 gchar *item = (gchar *) (node->data);
704 table_pair *pair = parse_table_pair(item, ':');
705 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
706 g_free(item);
707 }
708 g_list_free(list);
709 } else if (strcmp(lval, "map_h_mail_followup_to_addresses") == 0) {
710 GList *list, *node;
712 list = parse_list(rval, TRUE);
713 foreach(list, node) {
714 gchar *item = (gchar *) (node->data);
715 table_pair *pair = parse_table_pair(item, ':');
716 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
717 g_free(item);
718 }
719 g_list_free(list);
720 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
721 route->expand_h_sender_domain = parse_boolean(rval);
722 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
723 route->expand_h_sender_address = parse_boolean(rval);
724 } else if (strcmp(lval, "resolve_list") == 0)
725 route->resolve_list = parse_resolve_list(rval);
726 else if (strcmp(lval, "do_ssl") == 0) {
727 /* we ignore this. This option is used by sqilconf */
728 ;
729 }
730 #ifdef ENABLE_AUTH
731 else if (strcmp(lval, "auth_name") == 0) {
732 route->auth_name = g_strdup(rval);
733 } else if (strcmp(lval, "auth_login") == 0) {
734 route->auth_login = g_strdup(rval);
735 } else if (strcmp(lval, "auth_secret") == 0) {
736 route->auth_secret = g_strdup(rval);
737 }
738 #else
739 else if ((strcmp(lval, "auth_name") == 0)
740 || (strcmp(lval, "auth_login") == 0)
741 || (strcmp(lval, "auth_secret") == 0)) {
742 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
743 }
744 #endif
745 else if (strcmp(lval, "pop3_login") == 0) {
746 #ifdef ENABLE_POP3
747 route->pop3_login = g_strdup(rval);
748 #else
749 logwrite(LOG_WARNING, "pop3_login ignored: not compiled with pop support.\n");
750 #endif
751 } else if (strcmp(lval, "pipe") == 0) {
752 route->pipe = g_strdup(rval);
753 } else if (strcmp(lval, "pipe_fromline") == 0) {
754 route->pipe_fromline = parse_boolean(rval);
755 } else if (strcmp(lval, "pipe_fromhack") == 0) {
756 route->pipe_fromhack = parse_boolean(rval);
757 } else if (strcmp(lval, "last_route") == 0) {
758 route->last_route = parse_boolean(rval);
759 } else
760 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
761 }
763 if (route->resolve_list == NULL) {
764 if (is_local_net) {
765 route->resolve_list = g_list_append(NULL, resolve_byname);
766 } else {
767 #ifdef ENABLE_RESOLVER
768 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
769 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
770 #endif
771 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
772 }
773 }
774 fclose(in);
775 ok = TRUE;
777 /* warn user about misconfigurations: */
778 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
779 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
780 g_free(route->set_h_from_domain);
781 route->set_h_from_domain = NULL;
782 }
783 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
784 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
785 g_free(route->set_h_reply_to_domain);
786 route->set_h_reply_to_domain = NULL;
787 }
789 if (!ok) {
790 g_free(route);
791 route = NULL;
792 }
794 return route;
795 }
797 static void
798 _g_list_free_all(GList * list)
799 {
800 GList *node;
801 if (list) {
802 foreach(list, node)
803 g_free(node->data);
804 g_list_free(list);
805 }
806 }
808 void
809 destroy_route(connect_route * r)
810 {
811 if (r->filename)
812 g_free(r->filename);
813 if (r->protocol)
814 g_free(r->protocol);
815 if (r->mail_host) {
816 g_free(r->mail_host->address);
817 g_free(r->mail_host);
818 }
819 if (r->wrapper)
820 g_free(r->wrapper);
821 if (r->helo_name)
822 g_free(r->helo_name);
823 _g_list_free_all(r->allowed_mail_locals);
824 _g_list_free_all(r->not_allowed_mail_locals);
825 _g_list_free_all(r->allowed_rcpt_domains);
826 _g_list_free_all(r->not_allowed_rcpt_domains);
827 if (r->set_h_from_domain)
828 g_free(r->set_h_from_domain);
829 if (r->set_h_reply_to_domain)
830 g_free(r->set_h_reply_to_domain);
831 if (r->set_return_path_domain)
832 g_free(r->set_return_path_domain);
833 if (r->map_h_reply_to_addresses)
834 destroy_table(r->map_h_reply_to_addresses);
835 if (r->resolve_list)
836 g_list_free(r->resolve_list);
837 #ifdef ENABLE_AUTH
838 if (r->auth_name)
839 g_free(r->auth_name);
840 if (r->auth_login)
841 g_free(r->auth_login);
842 if (r->auth_secret)
843 g_free(r->auth_secret);
844 #endif
845 #ifdef ENABLE_POP3
846 if (r->pop3_login)
847 g_free(r->pop3_login);
848 #endif
849 if (r->pipe)
850 g_free(r->pipe);
851 g_free(r);
852 }
854 GList*
855 read_route_list(GList * rf_list, gboolean is_local_net)
856 {
857 GList *list = NULL;
858 GList *node;
859 uid_t saved_uid, saved_gid;
861 if (!conf.run_as_user) {
862 set_euidgid(0, 0, &saved_uid, &saved_gid);
863 }
865 foreach(rf_list, node) {
866 gchar *fname = (gchar *) (node->data);
867 connect_route *route = read_route(fname, is_local_net);
868 if (route)
869 list = g_list_append(list, route);
870 else
871 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
872 }
874 /* set uid and gid back */
875 if (!conf.run_as_user) {
876 set_euidgid(saved_uid, saved_gid, NULL, NULL);
877 }
879 return list;
880 }
882 void
883 destroy_route_list(GList * list)
884 {
885 GList *node;
887 foreach(list, node) {
888 connect_route *route = (connect_route *) (node->data);
889 destroy_route(route);
890 }
891 g_list_free(list);
892 }
894 #ifdef ENABLE_POP3
896 get_conf*
897 read_get_conf(gchar * filename)
898 {
899 FILE *in;
901 get_conf *gc = g_malloc(sizeof(get_conf));
902 memset(gc, 0, sizeof(get_conf));
904 gc->server_port = 110;
906 if ((in = fopen(filename, "r")) == NULL) {
907 logwrite(LOG_ALERT, "could not open get file %s: %s\n", filename, strerror(errno));
908 g_free(gc);
909 return NULL;
910 }
912 gchar lval[256], rval[2048];
913 while (read_statement(in, lval, 256, rval, 2048)) {
914 if (strcmp(lval, "protocol") == 0)
915 gc->protocol = g_strdup(rval);
916 else if (strcmp(lval, "server") == 0)
917 gc->server_name = g_strdup(rval);
918 else if (strcmp(lval, "port") == 0)
919 gc->server_port = atoi(rval);
920 else if (strcmp(lval, "wrapper") == 0)
921 gc->wrapper = g_strdup(rval);
922 else if (strcmp(lval, "user") == 0)
923 gc->login_user = g_strdup(rval);
924 else if (strcmp(lval, "pass") == 0)
925 gc->login_pass = g_strdup(rval);
926 else if (strcmp(lval, "address") == 0)
927 gc->address = create_address_qualified(rval, TRUE, conf.host_name);
928 else if (strcmp(lval, "return_path") == 0)
929 gc->return_path = create_address_qualified(rval, TRUE, conf.host_name);
930 else if (strcmp(lval, "do_ssl") == 0)
931 /* we ignore this. This option is used by sqilconf */
932 ;
933 else if (strcmp(lval, "do_keep") == 0)
934 gc->do_keep = parse_boolean(rval);
935 else if (strcmp(lval, "do_uidl") == 0)
936 gc->do_uidl = parse_boolean(rval);
937 else if (strcmp(lval, "do_uidl_dele") == 0)
938 gc->do_uidl_dele = parse_boolean(rval);
939 else if (strcmp(lval, "max_size") == 0)
940 gc->max_size = atoi(rval);
941 else if (strcmp(lval, "max_size_delete") == 0)
942 gc->max_size_delete = parse_boolean(rval);
943 else if (strcmp(lval, "max_count") == 0)
944 gc->max_count = atoi(rval);
945 else if (strcmp(lval, "resolve_list") == 0)
946 gc->resolve_list = parse_resolve_list(rval);
947 else
948 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
949 }
950 fclose(in);
952 if (gc->resolve_list == NULL) {
953 #ifdef ENABLE_RESOLVER
954 gc->resolve_list = g_list_append(NULL, resolve_dns_a);
955 #endif
956 gc->resolve_list = g_list_append(NULL, resolve_byname);
957 }
959 if (gc->protocol == NULL)
960 gc->protocol = g_strdup("pop3");
961 return gc;
962 }
964 void
965 destroy_get_conf(get_conf * gc)
966 {
967 if (gc->protocol)
968 g_free(gc->protocol);
969 if (gc->server_name)
970 g_free(gc->server_name);
971 if (gc->login_user)
972 g_free(gc->login_user);
973 if (gc->login_pass)
974 g_free(gc->login_pass);
975 if (gc->wrapper)
976 g_free(gc->wrapper);
977 if (gc->address)
978 destroy_address(gc->address);
979 if (gc->return_path)
980 destroy_address(gc->return_path);
981 if (gc->resolve_list)
982 g_list_free(gc->resolve_list);
983 g_free(gc);
984 }
986 #endif
988 connect_route*
989 create_local_route()
990 {
991 connect_route *route;
993 route = g_malloc(sizeof(connect_route));
994 if (!route) {
995 return NULL;
996 }
997 memset(route, 0, sizeof(connect_route));
998 route->protocol = g_strdup("smtp");
999 route->is_local_net = TRUE;
1000 route->name = g_strdup("local_net (default)");
1001 route->expand_h_sender_address = TRUE;
1002 route->resolve_list = g_list_append(NULL, resolve_byname);
1003 route->connect_error_fail = TRUE;
1004 return route;