masqmail-0.2

view src/conf.c @ 75:257a9e6d1a8e

fixed correct processing of mails with data lines longer 4096 chars Mail messages with lines longer than 4096 chars were already read correctly, i.e. the spool files were correct. This commit fixes the reading of spool files with long lines. The old behavior was that the message body was truncated right before the first line longer 4096 chars. The number comes from MAX_DATALINE.
author meillo@marmaro.de
date Wed, 16 Jun 2010 19:06:34 +0200
parents a8f3424347dc
children a80ebfa16cd5
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 list = g_list_append(list, g_strdup(buf));
103 }
104 }
105 fclose(fptr);
107 return list;
108 }
110 /* given a semicolon separated string, this function makes a GList out of it. */
111 GList*
112 parse_list(gchar * line, gboolean read_file)
113 {
114 GList *list = NULL;
115 gchar buf[256];
116 gchar *p, *q;
118 DEBUG(6) fprintf(stderr, "parsing list %s\n", line);
120 p = line;
121 while (*p != '\0') {
122 q = buf;
124 while (*p && (*p != ';') && (q < buf + 255))
125 *(q++) = *(p++);
126 *q = '\0';
128 if ((buf[0] == '/') && (read_file))
129 /* item is a filename, include its contents */
130 list = g_list_concat(list, parse_list_file(buf));
131 else
132 /* just a normal item */
133 list = g_list_append(list, g_strdup(buf));
135 DEBUG(6) printf("item = %s\n", buf);
137 if (*p)
138 p++;
139 }
140 return list;
141 }
143 static GList*
144 parse_address_list(gchar * line, gboolean read_file)
145 {
146 GList *plain_list = parse_list(line, read_file);
147 GList *node;
148 GList *list = NULL;
150 foreach(plain_list, node) {
151 gchar *item = (gchar *) (node->data);
152 address *addr = create_address(item, TRUE);
153 if (addr)
154 list = g_list_append(list, addr);
155 g_free(item);
156 }
157 g_list_free(plain_list);
159 return list;
160 }
162 static GList*
163 parse_resolve_list(gchar * line)
164 {
165 GList *list;
166 GList *list_node;
167 GList *res_list = NULL;
169 list = parse_list(line, FALSE);
170 if (!list) {
171 return NULL;
172 }
174 foreach(list, list_node) {
175 gchar *item = (gchar *) (list_node->data);
176 if (strcmp(item, "byname") == 0) {
177 res_list = g_list_append(res_list, resolve_byname);
178 #ifdef ENABLE_RESOLVER
179 } else if (strcmp(item, "dns_a") == 0) {
180 res_list = g_list_append(res_list, resolve_dns_a);
181 } else if (strcmp(item, "dns_mx") == 0) {
182 res_list = g_list_append(res_list, resolve_dns_mx);
183 #endif
184 } else {
185 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
186 exit(EXIT_FAILURE);
187 }
188 g_free(item);
189 }
190 g_list_free(list);
191 return res_list;
192 }
194 static interface*
195 parse_interface(gchar * line, gint def_port)
196 {
197 gchar buf[256];
198 gchar *p, *q;
199 interface *iface;
201 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
203 p = line;
204 q = buf;
205 while ((*p != '\0') && (*p != ':') && (q < buf + 255))
206 *(q++) = *(p++);
207 *q = '\0';
209 iface = g_malloc(sizeof(interface));
210 iface->address = g_strdup(buf);
212 if (*p) {
213 p++;
214 iface->port = atoi(p);
215 } else
216 iface->port = def_port;
218 return iface;
219 }
221 #ifdef ENABLE_IDENT /* so far used for that only */
222 static struct in_addr*
223 parse_network(gchar * line, gint def_port)
224 {
225 gchar buf[256];
226 gchar *p, *q;
227 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
228 guint n;
230 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
232 p = line;
233 q = buf;
234 while ((*p != '\0') && (*p != '/') && (q < buf + 255))
235 *(q++) = *(p++);
236 *q = '\0';
238 if ((addr.s_addr = inet_addr(buf)) == INADDR_NONE) {
239 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
240 exit(EXIT_FAILURE);
241 }
243 if (*p) {
244 guint i;
245 p++;
246 i = atoi(p);
247 if ((i >= 0) && (i <= 32))
248 n = i ? ~((1 << (32 - i)) - 1) : 0;
249 else {
250 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
251 exit(EXIT_FAILURE);
252 }
253 } else
254 n = 0;
256 mask_addr.s_addr = htonl(n);
257 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
259 p_net_addr = g_malloc(sizeof(struct in_addr));
260 p_net_addr->s_addr = net_addr.s_addr;
261 return p_net_addr;
262 }
263 #endif
265 static gboolean
266 eat_comments(FILE * in)
267 {
268 gint c;
270 for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
271 c = fgetc(in)) {
272 if (c == '#') {
273 gint c;
274 for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
275 }
276 }
277 if (c == EOF)
278 return FALSE;
279 ungetc(c, in);
280 return TRUE;
281 }
283 /* after parsing, eat trailing character until LF */
284 static gboolean
285 eat_line_trailing(FILE * in)
286 {
287 gint c;
289 for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
290 if (c == EOF)
291 return FALSE;
292 return TRUE;
293 }
295 static gboolean
296 eat_spaces(FILE * in)
297 {
298 gint c;
300 for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
301 /* empty */
302 }
303 if (c == EOF)
304 return FALSE;
305 ungetc(c, in);
306 return TRUE;
307 }
309 static gboolean
310 read_lval(FILE * in, gchar * buf, gint size)
311 {
312 gint c;
313 gchar *ptr = buf;
315 DEBUG(6) fprintf(stderr, "read_lval()\n");
317 if (!eat_spaces(in))
318 return FALSE;
320 c = fgetc(in);
321 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
322 while ((isalnum(c) || c == '_' || c == '-' || c == '.')
323 && (ptr < buf + size - 1)
324 && (c != EOF)) {
325 *ptr = c;
326 ptr++;
327 c = fgetc(in);
328 }
329 *ptr = '\0';
330 ungetc(c, in);
332 if (c == EOF) {
333 fprintf(stderr, "unexpected EOF after %s\n", buf);
334 return FALSE;
335 } else if (ptr >= buf + size - 1) {
336 fprintf(stderr, "lval too long\n");
337 }
339 eat_spaces(in);
341 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
343 return buf[0] != '\0';
344 }
346 static gboolean
347 read_rval(FILE * in, gchar * buf, gint size)
348 {
349 gint c;
350 gchar *ptr = buf;
352 DEBUG(6) fprintf(stderr, "read_rval()\n");
354 if (!eat_spaces(in))
355 return FALSE;
357 c = fgetc(in);
358 if (c != '\"') {
359 while ((isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/' || c == '@' || c == ';')
360 && (ptr < buf + size - 1)
361 && (c != EOF)) {
362 *ptr = c;
363 ptr++;
364 c = fgetc(in);
365 }
366 *ptr = '\0';
367 ungetc(c, in);
368 } else {
369 gboolean escape = FALSE;
370 c = fgetc(in);
371 while (((c != '\"') || escape) && (ptr < buf + size - 1)) {
372 if (c != '\n') { /* ignore line breaks */
373 if ((c == '\\') && (!escape)) {
374 escape = TRUE;
375 } else {
376 *ptr = c;
377 ptr++;
378 escape = FALSE;
379 }
380 }
381 c = fgetc(in);
382 }
383 *ptr = '\0';
384 }
386 eat_line_trailing(in);
388 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
390 return TRUE;
391 }
393 static gboolean
394 read_statement(FILE * in, gchar * lval, gint lsize, gchar * rval, gint rsize)
395 {
396 gint c;
398 DEBUG(6) fprintf(stderr, "read_statement()\n");
400 /* eat comments and empty lines: */
401 if (!eat_comments(in))
402 return FALSE;
404 DEBUG(6) fprintf(stderr, "read_statement() 1\n");
406 if (!read_lval(in, lval, lsize)) {
407 return FALSE;
408 }
410 DEBUG(6) fprintf(stderr, "lval = %s\n", lval);
411 if ((c = fgetc(in) == '=')) {
412 if (read_rval(in, rval, rsize)) {
413 DEBUG(6) fprintf(stderr, "rval = %s\n", rval);
414 return TRUE;
415 }
416 } else {
417 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
418 }
419 return FALSE;
420 }
422 gboolean
423 read_conf(gchar * filename)
424 {
425 FILE *in;
427 conf.log_max_pri = 7;
428 conf.remote_port = 25;
429 conf.do_relay = TRUE;
430 conf.alias_local_cmp = strcmp;
431 conf.max_defer_time = 86400 * 4; /* 4 days */
433 if ((in = fopen(filename, "r")) == NULL) {
434 fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
435 return FALSE;
436 }
438 gchar lval[256], rval[2048];
439 while (read_statement(in, lval, 256, rval, 2048)) {
440 if (strcmp(lval, "debug_level") == 0)
441 conf.debug_level = atoi(rval);
442 else if (strcmp(lval, "run_as_user") == 0) {
443 if (!conf.run_as_user) /* you should not be able to reset that flag */
444 conf.run_as_user = parse_boolean(rval);
445 } else if (strcmp(lval, "use_syslog") == 0)
446 conf.use_syslog = parse_boolean(rval);
447 else if (strcmp(lval, "mail_dir") == 0)
448 conf.mail_dir = g_strdup(rval);
449 else if (strcmp(lval, "lock_dir") == 0)
450 conf.lock_dir = g_strdup(rval);
451 else if (strcmp(lval, "spool_dir") == 0)
452 conf.spool_dir = g_strdup(rval);
453 else if (strcmp(lval, "log_dir") == 0)
454 conf.log_dir = g_strdup(rval);
455 else if (strcmp(lval, "host_name") == 0) {
456 if (rval[0] != '/')
457 conf.host_name = g_strdup(rval);
458 else {
459 char buf[256];
460 FILE *fptr = fopen(rval, "rt");
461 if (fptr) {
462 fprintf(stderr, "could not open %s: %s\n", rval, strerror(errno));
463 return FALSE;
464 }
465 fgets(buf, 255, fptr);
466 g_strchomp(buf);
467 conf.host_name = g_strdup(buf);
468 fclose(fptr);
469 }
470 } else if (strcmp(lval, "remote_port") == 0) {
471 fprintf(stderr, "the remote_port option is now deprecated. Use 'mail_host' in the\n"
472 "route configuration instead. See man masqmail.route\n");
473 conf.remote_port = atoi(rval);
474 } else if (strcmp(lval, "local_hosts") == 0)
475 conf.local_hosts = parse_list(rval, FALSE);
476 else if (strcmp(lval, "local_addresses") == 0)
477 conf.local_addresses = parse_list(rval, TRUE);
478 else if (strcmp(lval, "not_local_addresses") == 0)
479 conf.not_local_addresses = parse_list(rval, TRUE);
480 else if (strcmp(lval, "local_nets") == 0)
481 conf.local_nets = parse_list(rval, FALSE);
482 else if (strcmp(lval, "do_save_envelope_to") == 0)
483 conf.do_save_envelope_to = parse_boolean(rval);
484 else if (strcmp(lval, "defer_all") == 0)
485 conf.defer_all = parse_boolean(rval);
486 else if (strcmp(lval, "do_relay") == 0)
487 conf.do_relay = parse_boolean(rval);
488 else if (strcmp(lval, "alias_file") == 0) {
489 conf.alias_file = g_strdup(rval);
490 } else if (strcmp(lval, "alias_local_caseless") == 0) {
491 conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
492 } else if (strcmp(lval, "mbox_default") == 0) {
493 conf.mbox_default = g_strdup(rval);
494 } else if (strcmp(lval, "mbox_users") == 0) {
495 conf.mbox_users = parse_list(rval, TRUE);
496 } else if (strcmp(lval, "mda_users") == 0) {
497 conf.mda_users = parse_list(rval, TRUE);
498 } else if (strcmp(lval, "maildir_users") == 0) {
499 conf.maildir_users = parse_list(rval, TRUE);
500 } else if (strcmp(lval, "mda") == 0) {
501 conf.mda = g_strdup(rval);
502 } else if (strcmp(lval, "mda_fromline") == 0) {
503 conf.mda_fromline = parse_boolean(rval);
504 } else if (strcmp(lval, "mda_fromhack") == 0) {
505 conf.mda_fromhack = parse_boolean(rval);
506 } else if (strcmp(lval, "pipe_fromline") == 0) {
507 conf.pipe_fromline = parse_boolean(rval);
508 } else if (strcmp(lval, "pipe_fromhack") == 0) {
509 conf.pipe_fromhack = parse_boolean(rval);
510 } else if (strcmp(lval, "listen_addresses") == 0) {
511 GList *node;
512 GList *tmp_list = parse_list(rval, FALSE);
514 conf.listen_addresses = NULL;
515 foreach(tmp_list, node) {
516 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
517 g_free(node->data);
518 }
519 g_list_free(tmp_list);
520 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
521 #ifdef ENABLE_IDENT
522 GList *node;
523 GList *tmp_list = parse_list(rval, FALSE);
525 conf.ident_trusted_nets = NULL;
526 foreach(tmp_list, node) {
527 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
528 g_free(node->data);
529 }
530 g_list_free(tmp_list);
531 #else
532 fprintf(stderr, "%s ignored: not compiled with ident support\n", lval);
533 #endif
534 } else if ((strncmp(lval, "connect_route.", 14) == 0)
535 || (strncmp(lval, "online_routes.", 14) == 0)) {
536 GList *file_list = parse_list(rval, FALSE);
537 table_pair *pair = create_pair(&(lval[14]), file_list);
538 conf.connect_routes = g_list_append(conf.connect_routes, pair);
539 } else if (strcmp(lval, "local_net_route") == 0) {
540 conf.local_net_routes = parse_list(rval, FALSE);
541 } else if (strcmp(lval, "online_detect") == 0)
542 conf.online_detect = g_strdup(rval);
543 else if (strcmp(lval, "online_file") == 0)
544 conf.online_file = g_strdup(rval);
545 else if (strcmp(lval, "online_pipe") == 0)
546 conf.online_pipe = g_strdup(rval);
547 else if (strcmp(lval, "mserver_iface") == 0)
548 conf.mserver_iface = parse_interface(rval, 224);
549 else if (strcmp(lval, "do_queue") == 0)
550 conf.do_queue = parse_boolean(rval);
551 else if (strncmp(lval, "get.", 4) == 0) {
552 #ifdef ENABLE_POP3
553 table_pair *pair = create_pair_string(&(lval[4]), rval);
554 conf.get_names = g_list_append(conf.get_names, pair);
555 #else
556 fprintf(stderr, "get.<name> ignored: not compiled with pop support\n");
557 #endif
558 } else if (strncmp(lval, "online_gets.", 12) == 0) {
559 #ifdef ENABLE_POP3
560 GList *file_list = parse_list(rval, FALSE);
561 table_pair *pair = create_pair(&(lval[12]), file_list);
562 conf.online_gets = g_list_append(conf.online_gets, pair);
563 #else
564 fprintf(stderr, "online_gets.<name> ignored: not compiled with pop support\n");
565 #endif
566 } else if (strcmp(lval, "errmsg_file") == 0)
567 conf.errmsg_file = g_strdup(rval);
568 else if (strcmp(lval, "warnmsg_file") == 0)
569 conf.warnmsg_file = g_strdup(rval);
570 else if (strcmp(lval, "warn_intervals") == 0)
571 conf.warn_intervals = parse_list(rval, FALSE);
572 else if (strcmp(lval, "max_defer_time") == 0) {
573 gint dummy;
574 gint ival = time_interval(rval, &dummy);
575 if (ival < 0)
576 fprintf(stderr, "invalid time interval for 'max_defer_time': %s\n", rval);
577 else
578 conf.max_defer_time = ival;
579 } else if (strcmp(lval, "log_user") == 0)
580 conf.log_user = g_strdup(rval);
582 else
583 fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
584 }
585 fclose(in);
587 if (conf.errmsg_file == NULL)
588 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
589 if (conf.warnmsg_file == NULL)
590 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
592 if (conf.lock_dir == NULL)
593 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
595 if (conf.mbox_default == NULL)
596 conf.mbox_default = g_strdup("mbox");
598 if (conf.warn_intervals == NULL)
599 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
601 return TRUE;
602 }
604 connect_route*
605 read_route(gchar * filename, gboolean is_local_net)
606 {
607 gboolean ok = FALSE;
608 FILE *in;
610 connect_route *route = g_malloc(sizeof(connect_route));
611 memset(route, 0, sizeof(connect_route));
613 DEBUG(5) debugf("read_route, filename = %s\n", filename);
615 route->filename = g_strdup(filename);
616 route->name = g_strdup(filename); /* quick hack */
618 route->protocol = g_strdup("smtp");
619 route->expand_h_sender_address = TRUE;
621 route->is_local_net = is_local_net;
623 route->do_pipelining = TRUE;
625 if ((in = fopen(route->filename, "r")) == NULL) {
626 logwrite(LOG_ALERT, "could not open route file %s: %s\n", route->filename, strerror(errno));
627 g_free(route);
628 return NULL;
629 }
631 gchar lval[256], rval[2048];
632 while (read_statement(in, lval, 256, rval, 2048)) {
633 if (strcmp(lval, "protocol") == 0)
634 route->protocol = g_strdup(rval);
635 else if (strcmp(lval, "mail_host") == 0)
636 route->mail_host = parse_interface(rval, conf.remote_port);
637 else if (strcmp(lval, "helo_name") == 0)
638 route->helo_name = g_strdup(rval);
639 else if (strcmp(lval, "wrapper") == 0)
640 route->wrapper = g_strdup(rval);
641 else if (strcmp(lval, "connect_error_fail") == 0)
642 route->connect_error_fail = parse_boolean(rval);
643 else if (strcmp(lval, "do_correct_helo") == 0)
644 route->do_correct_helo = parse_boolean(rval);
645 else if (strcmp(lval, "do_pipelining") == 0)
646 route->do_pipelining = parse_boolean(rval);
647 else if (strcmp(lval, "allowed_return_paths") == 0)
648 route->allowed_return_paths = parse_address_list(rval, TRUE);
649 else if (strcmp(lval, "allowed_mail_locals") == 0)
650 route->allowed_mail_locals = parse_list(rval, TRUE);
651 else if (strcmp(lval, "not_allowed_return_paths") == 0)
652 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
653 else if (strcmp(lval, "not_allowed_mail_locals") == 0)
654 route->not_allowed_mail_locals = parse_list(rval, TRUE);
655 else if (strcmp(lval, "allowed_rcpt_domains") == 0)
656 route->allowed_rcpt_domains = parse_list(rval, TRUE);
657 else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
658 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
659 else if (strcmp(lval, "set_h_from_domain") == 0)
660 route->set_h_from_domain = g_strdup(rval);
661 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
662 route->set_h_reply_to_domain = g_strdup(rval);
663 else if (strcmp(lval, "set_return_path_domain") == 0)
664 route->set_return_path_domain = g_strdup(rval);
665 else if (strcmp(lval, "map_return_path_addresses") == 0) {
666 GList *node, *list;
668 list = parse_list(rval, TRUE);
669 foreach(list, node) {
670 gchar *item = (gchar *) (node->data);
671 table_pair *pair = parse_table_pair(item, ':');
672 address *addr = create_address((gchar *) (pair->value), TRUE);
673 g_free(pair->value);
674 pair->value = (gpointer *) addr;
675 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
676 g_free(item);
677 }
678 g_list_free(list);
679 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
680 GList *list, *node;
682 list = parse_list(rval, TRUE);
683 foreach(list, node) {
684 gchar *item = (gchar *) (node->data);
685 table_pair *pair = parse_table_pair(item, ':');
686 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
687 g_free(item);
688 }
689 g_list_free(list);
690 } else if (strcmp(lval, "map_h_reply_to_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_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
698 g_free(item);
699 }
700 g_list_free(list);
701 } else if (strcmp(lval, "map_h_mail_followup_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_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
709 g_free(item);
710 }
711 g_list_free(list);
712 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
713 route->expand_h_sender_domain = parse_boolean(rval);
714 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
715 route->expand_h_sender_address = parse_boolean(rval);
716 } else if (strcmp(lval, "resolve_list") == 0)
717 route->resolve_list = parse_resolve_list(rval);
718 else if (strcmp(lval, "do_ssl") == 0) {
719 /* we ignore this. This option is used by sqilconf */
720 ;
721 }
722 #ifdef ENABLE_AUTH
723 else if (strcmp(lval, "auth_name") == 0) {
724 route->auth_name = g_strdup(rval);
725 } else if (strcmp(lval, "auth_login") == 0) {
726 route->auth_login = g_strdup(rval);
727 } else if (strcmp(lval, "auth_secret") == 0) {
728 route->auth_secret = g_strdup(rval);
729 }
730 #else
731 else if ((strcmp(lval, "auth_name") == 0)
732 || (strcmp(lval, "auth_login") == 0)
733 || (strcmp(lval, "auth_secret") == 0)) {
734 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
735 }
736 #endif
737 else if (strcmp(lval, "pop3_login") == 0) {
738 #ifdef ENABLE_POP3
739 route->pop3_login = g_strdup(rval);
740 #else
741 logwrite(LOG_WARNING, "pop3_login ignored: not compiled with pop support.\n");
742 #endif
743 } else if (strcmp(lval, "pipe") == 0) {
744 route->pipe = g_strdup(rval);
745 } else if (strcmp(lval, "pipe_fromline") == 0) {
746 route->pipe_fromline = parse_boolean(rval);
747 } else if (strcmp(lval, "pipe_fromhack") == 0) {
748 route->pipe_fromhack = parse_boolean(rval);
749 } else if (strcmp(lval, "last_route") == 0) {
750 route->last_route = parse_boolean(rval);
751 } else
752 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
753 }
755 if (route->resolve_list == NULL) {
756 if (is_local_net) {
757 route->resolve_list = g_list_append(NULL, resolve_byname);
758 } else {
759 #ifdef ENABLE_RESOLVER
760 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
761 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
762 #endif
763 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
764 }
765 }
766 fclose(in);
767 ok = TRUE;
769 /* warn user about misconfigurations: */
770 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
771 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
772 g_free(route->set_h_from_domain);
773 route->set_h_from_domain = NULL;
774 }
775 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
776 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
777 g_free(route->set_h_reply_to_domain);
778 route->set_h_reply_to_domain = NULL;
779 }
781 if (!ok) {
782 g_free(route);
783 route = NULL;
784 }
786 return route;
787 }
789 static void
790 _g_list_free_all(GList * list)
791 {
792 GList *node;
793 if (list) {
794 foreach(list, node)
795 g_free(node->data);
796 g_list_free(list);
797 }
798 }
800 void
801 destroy_route(connect_route * r)
802 {
803 if (r->filename)
804 g_free(r->filename);
805 if (r->protocol)
806 g_free(r->protocol);
807 if (r->mail_host) {
808 g_free(r->mail_host->address);
809 g_free(r->mail_host);
810 }
811 if (r->wrapper)
812 g_free(r->wrapper);
813 if (r->helo_name)
814 g_free(r->helo_name);
815 _g_list_free_all(r->allowed_mail_locals);
816 _g_list_free_all(r->not_allowed_mail_locals);
817 _g_list_free_all(r->allowed_rcpt_domains);
818 _g_list_free_all(r->not_allowed_rcpt_domains);
819 if (r->set_h_from_domain)
820 g_free(r->set_h_from_domain);
821 if (r->set_h_reply_to_domain)
822 g_free(r->set_h_reply_to_domain);
823 if (r->set_return_path_domain)
824 g_free(r->set_return_path_domain);
825 if (r->map_h_reply_to_addresses)
826 destroy_table(r->map_h_reply_to_addresses);
827 if (r->resolve_list)
828 g_list_free(r->resolve_list);
829 #ifdef ENABLE_AUTH
830 if (r->auth_name)
831 g_free(r->auth_name);
832 if (r->auth_login)
833 g_free(r->auth_login);
834 if (r->auth_secret)
835 g_free(r->auth_secret);
836 #endif
837 #ifdef ENABLE_POP3
838 if (r->pop3_login)
839 g_free(r->pop3_login);
840 #endif
841 if (r->pipe)
842 g_free(r->pipe);
843 g_free(r);
844 }
846 GList*
847 read_route_list(GList * rf_list, gboolean is_local_net)
848 {
849 GList *list = NULL;
850 GList *node;
851 uid_t saved_uid, saved_gid;
853 if (!conf.run_as_user) {
854 set_euidgid(0, 0, &saved_uid, &saved_gid);
855 }
857 foreach(rf_list, node) {
858 gchar *fname = (gchar *) (node->data);
859 connect_route *route = read_route(fname, is_local_net);
860 if (route)
861 list = g_list_append(list, route);
862 else
863 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
864 }
866 /* set uid and gid back */
867 if (!conf.run_as_user) {
868 set_euidgid(saved_uid, saved_gid, NULL, NULL);
869 }
871 return list;
872 }
874 void
875 destroy_route_list(GList * list)
876 {
877 GList *node;
879 foreach(list, node) {
880 connect_route *route = (connect_route *) (node->data);
881 destroy_route(route);
882 }
883 g_list_free(list);
884 }
886 #ifdef ENABLE_POP3
888 get_conf*
889 read_get_conf(gchar * filename)
890 {
891 FILE *in;
893 get_conf *gc = g_malloc(sizeof(get_conf));
894 memset(gc, 0, sizeof(get_conf));
896 gc->server_port = 110;
898 if ((in = fopen(filename, "r")) == NULL) {
899 logwrite(LOG_ALERT, "could not open get file %s: %s\n", filename, strerror(errno));
900 g_free(gc);
901 return NULL;
902 }
904 gchar lval[256], rval[2048];
905 while (read_statement(in, lval, 256, rval, 2048)) {
906 if (strcmp(lval, "protocol") == 0)
907 gc->protocol = g_strdup(rval);
908 else if (strcmp(lval, "server") == 0)
909 gc->server_name = g_strdup(rval);
910 else if (strcmp(lval, "port") == 0)
911 gc->server_port = atoi(rval);
912 else if (strcmp(lval, "wrapper") == 0)
913 gc->wrapper = g_strdup(rval);
914 else if (strcmp(lval, "user") == 0)
915 gc->login_user = g_strdup(rval);
916 else if (strcmp(lval, "pass") == 0)
917 gc->login_pass = g_strdup(rval);
918 else if (strcmp(lval, "address") == 0)
919 gc->address = create_address_qualified(rval, TRUE, conf.host_name);
920 else if (strcmp(lval, "return_path") == 0)
921 gc->return_path = create_address_qualified(rval, TRUE, conf.host_name);
922 else if (strcmp(lval, "do_ssl") == 0)
923 /* we ignore this. This option is used by sqilconf */
924 ;
925 else if (strcmp(lval, "do_keep") == 0)
926 gc->do_keep = parse_boolean(rval);
927 else if (strcmp(lval, "do_uidl") == 0)
928 gc->do_uidl = parse_boolean(rval);
929 else if (strcmp(lval, "do_uidl_dele") == 0)
930 gc->do_uidl_dele = parse_boolean(rval);
931 else if (strcmp(lval, "max_size") == 0)
932 gc->max_size = atoi(rval);
933 else if (strcmp(lval, "max_size_delete") == 0)
934 gc->max_size = parse_boolean(rval);
935 else if (strcmp(lval, "max_count") == 0)
936 gc->max_count = atoi(rval);
937 else if (strcmp(lval, "resolve_list") == 0)
938 gc->resolve_list = parse_resolve_list(rval);
939 else
940 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
941 }
942 fclose(in);
944 if (gc->resolve_list == NULL) {
945 #ifdef ENABLE_RESOLVER
946 gc->resolve_list = g_list_append(NULL, resolve_dns_a);
947 #endif
948 gc->resolve_list = g_list_append(NULL, resolve_byname);
949 }
951 if (gc->protocol == NULL)
952 gc->protocol = g_strdup("pop3");
953 return gc;
954 }
956 void
957 destroy_get_conf(get_conf * gc)
958 {
959 if (gc->protocol)
960 g_free(gc->protocol);
961 if (gc->server_name)
962 g_free(gc->server_name);
963 if (gc->login_user)
964 g_free(gc->login_user);
965 if (gc->login_pass)
966 g_free(gc->login_pass);
967 if (gc->wrapper)
968 g_free(gc->wrapper);
969 if (gc->address)
970 destroy_address(gc->address);
971 if (gc->return_path)
972 destroy_address(gc->return_path);
973 if (gc->resolve_list)
974 g_list_free(gc->resolve_list);
975 g_free(gc);
976 }
978 #endif
980 connect_route*
981 create_local_route()
982 {
983 connect_route *route;
985 route = g_malloc(sizeof(connect_route));
986 if (!route) {
987 return NULL;
988 }
989 memset(route, 0, sizeof(connect_route));
990 route->protocol = g_strdup("smtp");
991 route->is_local_net = TRUE;
992 route->name = g_strdup("local_net (default)");
993 route->expand_h_sender_address = TRUE;
994 route->resolve_list = g_list_append(NULL, resolve_byname);
995 route->connect_error_fail = TRUE;
996 return route;
997 }