masqmail-0.2

view src/conf.c @ 3:8c55886cacd8

man pages will be maintained in troff now
author meillo@marmaro.de
date Fri, 26 Sep 2008 21:40:10 +0200
parents
children 26e34ae9a3e3
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 "masqmail.h"
21 #include "pwd.h"
22 #include "grp.h"
24 masqmail_conf conf;
26 void init_conf()
27 {
28 struct passwd *passwd;
29 struct group *group;
31 memset(&conf, 0, sizeof(masqmail_conf));
33 conf.orig_uid = getuid();
34 conf.orig_gid = getgid();
36 if((passwd = getpwnam(DEF_MAIL_USER)))
37 conf.mail_uid = passwd->pw_uid;
38 else{
39 fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
40 exit(EXIT_FAILURE);
41 }
42 if((group = getgrnam(DEF_MAIL_GROUP)))
43 conf.mail_gid = group->gr_gid;
44 else{
45 fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
46 exit(EXIT_FAILURE);
47 }
48 }
50 static gchar *true_strings[] =
51 {
52 "yes", "on", "true", NULL
53 };
55 static gchar *false_strings[] =
56 {
57 "no", "off", "false", NULL
58 };
60 static
61 gboolean 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
87 GList *parse_list_file(gchar *fname)
88 {
89 GList *list = NULL;
90 FILE *fptr;
92 if((fptr = fopen(fname, "rt"))){
93 gchar buf[256];
95 while(!feof(fptr)){
96 fgets(buf, 255, fptr);
97 if(buf[0] && (buf[0] != '#') && (buf[0] != '\n')){
98 g_strchomp(buf);
99 list = g_list_append(list, g_strdup(buf));
100 }
101 }
102 fclose(fptr);
103 }else{
104 logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
105 exit(EXIT_FAILURE);
106 }
108 return list;
109 }
111 /* given a semicolon separated string, this function
112 makes a GList out of it.
113 */
114 GList *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\n", line);
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) printf("item = %s\n", buf);
139 if(*p) p++;
140 }
141 return list;
142 }
144 static
145 GList *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
164 GList *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 foreach(list, list_node){
173 gchar *item = (gchar *)(list_node->data);
174 if(strcmp(item, "byname") == 0){
175 res_list = g_list_append(res_list, resolve_byname);
176 #ifdef ENABLE_RESOLVER
177 }else if(strcmp(item, "dns_a") == 0){
178 res_list = g_list_append(res_list, resolve_dns_a);
179 }else if(strcmp(item, "dns_mx") == 0){
180 res_list = g_list_append(res_list, resolve_dns_mx);
181 #endif
182 }else{
183 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
184 exit(EXIT_FAILURE);
185 }
186 g_free(item);
187 }
188 g_list_free(list);
189 }
190 return res_list;
191 }
193 static
194 interface *parse_interface(gchar *line, gint def_port)
195 {
196 gchar buf[256];
197 gchar *p, *q;
198 interface *iface;
200 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
202 p = line;
203 q = buf;
204 while((*p != 0) && (*p != ':') && (q < buf+255))
205 *(q++) = *(p++);
206 *q = 0;
208 iface = g_malloc(sizeof(interface));
209 iface->address = g_strdup(buf);
211 if(*p){
212 p++;
213 iface->port = atoi(p);
214 }else
215 iface->port = def_port;
217 return iface;
218 }
220 #ifdef ENABLE_IDENT /* so far used for that only */
221 static
222 struct in_addr *parse_network(gchar *line, gint def_port)
223 {
224 gchar buf[256];
225 gchar *p, *q;
226 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
227 guint n;
229 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
231 p = line;
232 q = buf;
233 while((*p != 0) && (*p != '/') && (q < buf+255))
234 *(q++) = *(p++);
235 *q = 0;
237 if((addr.s_addr = inet_addr(buf)) != INADDR_NONE){
238 if(*p){
239 guint i;
240 p++;
241 i = atoi(p);
242 if((i >= 0) && (i <= 32))
243 n = i ? ~((1 << (32 - i)) - 1) : 0;
244 else{
245 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
246 exit(EXIT_FAILURE);
247 }
248 }else
249 n = 0;
251 mask_addr.s_addr = htonl(n);
252 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
253 }else{
254 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
255 exit(EXIT_FAILURE);
256 }
258 p_net_addr = g_malloc(sizeof(struct in_addr));
259 p_net_addr->s_addr = net_addr.s_addr;
260 return p_net_addr;
261 }
262 #endif
264 static
265 gboolean eat_comments(FILE *in)
266 {
267 gint c;
269 for(c = fgetc(in); (c == '#' || isspace(c)) && c != EOF; c = fgetc(in)){
270 if(c == '#'){
271 gint c;
272 for(c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
273 }
274 }
275 if(c == EOF) return FALSE;
276 ungetc(c, in);
277 return TRUE;
278 }
280 /* after parsing, eat trailing character until LF */
281 static
282 gboolean eat_line_trailing(FILE *in)
283 {
284 gint c;
286 for(c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
287 if(c == EOF) return FALSE;
288 return TRUE;
289 }
291 static
292 gboolean eat_spaces(FILE *in)
293 {
294 gint c;
296 for(c = fgetc(in); c != EOF && isspace(c); c = fgetc(in));
297 if(c == EOF) return FALSE;
298 ungetc(c, in);
299 return TRUE;
300 }
302 static
303 gboolean read_lval(FILE *in, gchar *buf, gint size)
304 {
305 gint c;
306 gchar *ptr = buf;
308 DEBUG(6) fprintf(stderr, "read_lval()\n");
310 if(!eat_spaces(in)) return FALSE;
312 c = fgetc(in);
313 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
314 while((isalnum(c) || c == '_' || c == '-' || c == '.')
315 && (ptr < buf+size-1)
316 && (c != EOF)
317 ){
318 *ptr = c; ptr++;
319 c = fgetc(in);
320 }
321 *ptr = 0;
322 ungetc(c, in);
324 if(c == EOF){
325 fprintf(stderr, "unexpected EOF after %s\n", buf);
326 return FALSE;
327 }else if(ptr >= buf+size-1){
328 fprintf(stderr, "lval too long\n");
329 }
331 eat_spaces(in);
333 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
335 return buf[0] != 0;
336 }
338 static
339 gboolean read_rval(FILE *in, gchar *buf, gint size)
340 {
341 gint c;
342 gchar *ptr = buf;
344 DEBUG(6) fprintf(stderr, "read_rval()\n");
346 if(!eat_spaces(in)) return FALSE;
348 c = fgetc(in);
349 if(c != '\"'){
350 while((isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/' || c == '@' || c == ';')
351 && (ptr < buf+size-1)
352 && (c != EOF)
353 ){
354 *ptr = c; ptr++;
355 c = fgetc(in);
356 }
357 *ptr = 0;
358 ungetc(c, in);
359 }else{
360 gboolean escape = FALSE;
361 c = fgetc(in);
362 while(((c != '\"') || escape) && (ptr < buf+size-1)){
363 if(c != '\n'){ /* ignore line breaks */
364 if((c == '\\') && (!escape)){
365 escape = TRUE;
366 }else{
367 *ptr = c; ptr++;
368 escape = FALSE;
369 }
370 }
371 c = fgetc(in);
372 }
373 *ptr = 0;
374 }
376 eat_line_trailing(in);
378 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
380 return TRUE;
381 }
383 static
384 gboolean read_statement(FILE *in,
385 gchar *lval, gint lsize,
386 gchar *rval, gint rsize)
387 {
388 gint c;
390 DEBUG(6) fprintf(stderr, "read_statement()\n");
392 /* eat comments and empty lines: */
393 if(!eat_comments(in)) return FALSE;
395 DEBUG(6) fprintf(stderr, "read_statement() 1\n");
397 if(read_lval(in, lval, lsize)){
398 DEBUG(6) fprintf(stderr, "lval = %s\n", lval);
399 if((c = fgetc(in) == '=')){
400 if(read_rval(in, rval, rsize)){
401 DEBUG(6) fprintf(stderr, "rval = %s\n", rval);
402 return TRUE;
403 }
404 }else{
405 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
406 }
407 }
408 return FALSE;
409 }
411 gboolean read_conf(gchar *filename)
412 {
413 FILE *in;
415 conf.log_max_pri = 7;
417 conf.remote_port = 25;
419 conf.do_relay = TRUE;
421 conf.alias_local_cmp = strcmp;
423 conf.max_defer_time = 86400*4; /* 4 days */
425 if((in = fopen(filename, "r"))){
426 gchar lval[256], rval[2048];
427 while(read_statement(in, lval, 256, rval, 2048)){
428 if(strcmp(lval, "debug_level") == 0)
429 conf.debug_level = atoi(rval);
430 else if(strcmp(lval, "run_as_user") == 0){
431 if(!conf.run_as_user) /* you should not be able
432 to reset that flag */
433 conf.run_as_user = parse_boolean(rval);
434 }else if(strcmp(lval, "use_syslog") == 0)
435 conf.use_syslog = parse_boolean(rval);
436 else if(strcmp(lval, "mail_dir") == 0)
437 conf.mail_dir = g_strdup(rval);
438 else if(strcmp(lval, "lock_dir") == 0)
439 conf.lock_dir = g_strdup(rval);
440 else if(strcmp(lval, "spool_dir") == 0)
441 conf.spool_dir = g_strdup(rval);
442 else if(strcmp(lval, "log_dir") == 0)
443 conf.log_dir = g_strdup(rval);
444 else if(strcmp(lval, "host_name") == 0){
445 if(rval[0] != '/')
446 conf.host_name = g_strdup(rval);
447 else{
448 char buf[256];
449 FILE *fptr = fopen(rval, "rt");
450 if(fptr){
451 fgets(buf, 255, fptr);
452 g_strchomp(buf);
453 conf.host_name = g_strdup(buf);
454 fclose(fptr);
455 }else{
456 fprintf(stderr, "could not open %s: %s\n", rval, strerror(errno));
457 return FALSE;
458 }
459 }
460 }
461 else if(strcmp(lval, "remote_port") == 0){
462 fprintf(stderr,
463 "the remote_port option is now deprecated. Use 'mail_host' in the\n"
464 "route configuration instead. See man masqmail.route\n");
465 conf.remote_port = atoi(rval);
466 }else if(strcmp(lval, "local_hosts") == 0)
467 conf.local_hosts = parse_list(rval, FALSE);
468 else if(strcmp(lval, "local_addresses") == 0)
469 conf.local_addresses = parse_list(rval, TRUE);
470 else if(strcmp(lval, "not_local_addresses") == 0)
471 conf.not_local_addresses = parse_list(rval, TRUE);
472 else if(strcmp(lval, "local_nets") == 0)
473 conf.local_nets = parse_list(rval, FALSE);
474 else if(strcmp(lval, "do_save_envelope_to") == 0)
475 conf.do_save_envelope_to = parse_boolean(rval);
476 else if(strcmp(lval, "defer_all") == 0)
477 conf.defer_all = parse_boolean(rval);
478 else if(strcmp(lval, "do_relay") == 0)
479 conf.do_relay = parse_boolean(rval);
480 else if(strcmp(lval, "alias_file") == 0){
481 conf.alias_file = g_strdup(rval);
482 }else if(strcmp(lval, "alias_local_caseless") == 0){
483 conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
484 }else if(strcmp(lval, "mbox_default") == 0){
485 conf.mbox_default = g_strdup(rval);
486 }else if(strcmp(lval, "mbox_users") == 0){
487 conf.mbox_users = parse_list(rval, TRUE);
488 }else if(strcmp(lval, "mda_users") == 0){
489 conf.mda_users = parse_list(rval, TRUE);
490 }else if(strcmp(lval, "maildir_users") == 0){
491 conf.maildir_users = parse_list(rval, TRUE);
492 }else if(strcmp(lval, "mda") == 0){
493 conf.mda = g_strdup(rval);
494 }else if(strcmp(lval, "mda_fromline") == 0){
495 conf.mda_fromline = parse_boolean(rval);
496 }else if(strcmp(lval, "mda_fromhack") == 0){
497 conf.mda_fromhack = parse_boolean(rval);
498 }else if(strcmp(lval, "pipe_fromline") == 0){
499 conf.pipe_fromline = parse_boolean(rval);
500 }else if(strcmp(lval, "pipe_fromhack") == 0){
501 conf.pipe_fromhack = parse_boolean(rval);
502 }else if(strcmp(lval, "listen_addresses") == 0){
503 GList *node;
504 GList *tmp_list = parse_list(rval, FALSE);
506 conf.listen_addresses = NULL;
507 foreach(tmp_list, node){
508 conf.listen_addresses =
509 g_list_append(conf.listen_addresses,
510 parse_interface((gchar *)(node->data), 25));
511 g_free(node->data);
512 }
513 g_list_free(tmp_list);
514 }
515 else if(strcmp(lval, "ident_trusted_nets") == 0){
516 #ifdef ENABLE_IDENT
517 GList *node;
518 GList *tmp_list = parse_list(rval, FALSE);
520 conf.ident_trusted_nets = NULL;
521 foreach(tmp_list, node){
522 conf.ident_trusted_nets =
523 g_list_append(conf.ident_trusted_nets,
524 parse_network((gchar *)(node->data), 25));
525 g_free(node->data);
526 }
527 g_list_free(tmp_list);
528 #else
529 fprintf(stderr, "%s ignored: not compiled with ident support\n", lval);
530 #endif
531 }
532 else if((strncmp(lval, "connect_route.", 14) == 0) ||
533 (strncmp(lval, "online_routes.", 14) == 0)){
534 GList *file_list = parse_list(rval, FALSE);
535 table_pair *pair = create_pair(&(lval[14]), file_list);
536 conf.connect_routes = g_list_append(conf.connect_routes, pair);
537 }
538 else if(strcmp(lval, "local_net_route") == 0){
539 conf.local_net_routes = parse_list(rval, FALSE);
540 }
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 }
559 else if(strncmp(lval, "online_gets.", 12) == 0){
560 #ifdef ENABLE_POP3
561 GList *file_list = parse_list(rval, FALSE);
562 table_pair *pair = create_pair(&(lval[12]), file_list);
563 conf.online_gets = g_list_append(conf.online_gets, pair);
564 #else
565 fprintf(stderr, "online_gets.<name> ignored: not compiled with pop support\n");
566 #endif
567 }
568 else if(strcmp(lval, "errmsg_file") == 0)
569 conf.errmsg_file = g_strdup(rval);
570 else if(strcmp(lval, "warnmsg_file") == 0)
571 conf.warnmsg_file = g_strdup(rval);
572 else if(strcmp(lval, "warn_intervals") == 0)
573 conf.warn_intervals = parse_list(rval, FALSE);
574 else if(strcmp(lval, "max_defer_time") == 0){
575 gint dummy;
576 gint ival = time_interval(rval, &dummy);
577 if(ival < 0)
578 fprintf(stderr, "invalid time interval for 'max_defer_time': %s\n", rval);
579 else
580 conf.max_defer_time = ival;
581 }else if(strcmp(lval, "log_user") == 0)
582 conf.log_user = g_strdup(rval);
584 else
585 fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
586 }
587 fclose(in);
589 if(conf.errmsg_file == NULL)
590 conf.errmsg_file = g_strdup(DATA_DIR"/tpl/failmsg.tpl");
591 if(conf.warnmsg_file == NULL)
592 conf.warnmsg_file = g_strdup(DATA_DIR"/tpl/warnmsg.tpl");
594 if(conf.lock_dir == NULL)
595 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
597 if(conf.mbox_default == NULL)
598 conf.mbox_default = g_strdup("mbox");
600 if(conf.warn_intervals == NULL)
601 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
603 return TRUE;
604 }else
605 fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
606 return FALSE;
607 }
609 connect_route *read_route(gchar *filename, gboolean is_local_net)
610 {
611 gboolean ok = FALSE;
612 FILE *in;
614 connect_route *route = g_malloc(sizeof(connect_route));
615 memset(route, 0, sizeof(connect_route));
617 DEBUG(5) debugf("read_route, filename = %s\n", filename);
619 route->filename = g_strdup(filename);
620 route->name = g_strdup(filename); /* quick hack */
622 route->protocol = g_strdup("smtp");
623 route->expand_h_sender_address = TRUE;
625 route->is_local_net = is_local_net;
627 route->do_pipelining = TRUE;
629 if((in = fopen(route->filename, "r"))){
630 gchar lval[256], rval[2048];
631 while(read_statement(in, lval, 256, rval, 2048)){
632 if(strcmp(lval, "protocol") == 0)
633 route->protocol = g_strdup(rval);
634 else if(strcmp(lval, "mail_host") == 0)
635 route->mail_host = parse_interface(rval, conf.remote_port);
636 else if(strcmp(lval, "helo_name") == 0)
637 route->helo_name = g_strdup(rval);
638 else if(strcmp(lval, "wrapper") == 0)
639 route->wrapper = g_strdup(rval);
640 else if(strcmp(lval, "connect_error_fail") == 0)
641 route->connect_error_fail = parse_boolean(rval);
642 else if(strcmp(lval, "do_correct_helo") == 0)
643 route->do_correct_helo = parse_boolean(rval);
644 else if(strcmp(lval, "do_pipelining") == 0)
645 route->do_pipelining = parse_boolean(rval);
646 else if(strcmp(lval, "allowed_return_paths") == 0)
647 route->allowed_return_paths = parse_address_list(rval, TRUE);
648 else if(strcmp(lval, "allowed_mail_locals") == 0)
649 route->allowed_mail_locals = parse_list(rval, TRUE);
650 else if(strcmp(lval, "not_allowed_return_paths") == 0)
651 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
652 else if(strcmp(lval, "not_allowed_mail_locals") == 0)
653 route->not_allowed_mail_locals = parse_list(rval, TRUE);
654 else if(strcmp(lval, "allowed_rcpt_domains") == 0)
655 route->allowed_rcpt_domains = parse_list(rval, TRUE);
656 else if(strcmp(lval, "not_allowed_rcpt_domains") == 0)
657 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
658 else if(strcmp(lval, "set_h_from_domain") == 0)
659 route->set_h_from_domain = g_strdup(rval);
660 else if(strcmp(lval, "set_h_reply_to_domain") == 0)
661 route->set_h_reply_to_domain = g_strdup(rval);
662 else if(strcmp(lval, "set_return_path_domain") == 0)
663 route->set_return_path_domain = g_strdup(rval);
664 else if(strcmp(lval, "map_return_path_addresses") == 0){
665 GList *node, *list;
667 list = parse_list(rval, TRUE);
668 foreach(list, node){
669 gchar *item = (gchar *)(node->data);
670 table_pair *pair = parse_table_pair(item, ':');
671 address *addr = create_address((gchar *)(pair->value), TRUE);
672 g_free(pair->value);
673 pair->value = (gpointer *)addr;
674 route->map_return_path_addresses =
675 g_list_append(route->map_return_path_addresses, pair);
676 g_free(item);
677 }
678 g_list_free(list);
679 }
680 else if(strcmp(lval, "map_h_from_addresses") == 0){
681 GList *list, *node;
683 list = parse_list(rval, TRUE);
684 foreach(list, node){
685 gchar *item = (gchar *)(node->data);
686 table_pair *pair = parse_table_pair(item, ':');
687 route->map_h_from_addresses =
688 g_list_append(route->map_h_from_addresses, pair);
689 g_free(item);
690 }
691 g_list_free(list);
692 }
693 else if(strcmp(lval, "map_h_reply_to_addresses") == 0){
694 GList *list, *node;
696 list = parse_list(rval, TRUE);
697 foreach(list, node){
698 gchar *item = (gchar *)(node->data);
699 table_pair *pair = parse_table_pair(item, ':');
700 route->map_h_reply_to_addresses =
701 g_list_append(route->map_h_reply_to_addresses, pair);
702 g_free(item);
703 }
704 g_list_free(list);
705 }
706 else if(strcmp(lval, "map_h_mail_followup_to_addresses") == 0){
707 GList *list, *node;
709 list = parse_list(rval, TRUE);
710 foreach(list, node){
711 gchar *item = (gchar *)(node->data);
712 table_pair *pair = parse_table_pair(item, ':');
713 route->map_h_mail_followup_to_addresses =
714 g_list_append(route->map_h_mail_followup_to_addresses, pair);
715 g_free(item);
716 }
717 g_list_free(list);
718 }
719 else if(strcmp(lval, "expand_h_sender_domain") == 0){
720 route->expand_h_sender_domain = parse_boolean(rval);
721 }
722 else if(strcmp(lval, "expand_h_sender_address") == 0){
723 route->expand_h_sender_address = parse_boolean(rval);
724 }
725 else if(strcmp(lval, "resolve_list") == 0)
726 route->resolve_list = parse_resolve_list(rval);
727 else if(strcmp(lval, "do_ssl") == 0){
728 /* we ignore this. This option is used by sqilconf */
729 ;
730 }
731 #ifdef ENABLE_AUTH
732 else if(strcmp(lval, "auth_name") == 0){
733 route->auth_name = g_strdup(rval);
734 }
735 else if(strcmp(lval, "auth_login") == 0){
736 route->auth_login = g_strdup(rval);
737 }
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 }
755 else if(strcmp(lval, "pipe") == 0){
756 route->pipe = g_strdup(rval);
757 }
758 else if(strcmp(lval, "pipe_fromline") == 0){
759 route->pipe_fromline = parse_boolean(rval);
760 }
761 else if(strcmp(lval, "pipe_fromhack") == 0){
762 route->pipe_fromhack = parse_boolean(rval);
763 }
764 else if(strcmp(lval, "last_route") == 0){
765 route->last_route = parse_boolean(rval);
766 }
767 else
768 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
769 }
771 if(route->resolve_list == NULL){
772 if(is_local_net){
773 route->resolve_list =
774 g_list_append(NULL, resolve_byname);
775 }else{
776 #ifdef ENABLE_RESOLVER
777 route->resolve_list =
778 g_list_append(route->resolve_list, resolve_dns_mx);
779 route->resolve_list =
780 g_list_append(route->resolve_list, resolve_dns_a);
781 #endif
782 route->resolve_list =
783 g_list_append(route->resolve_list, resolve_byname);
784 }
785 }
786 fclose(in);
787 ok = TRUE;
789 /* warn user about misconfigurations: */
790 if((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)){
791 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
792 g_free(route->set_h_from_domain);
793 route->set_h_from_domain = NULL;
794 }
795 if((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)){
796 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
797 g_free(route->set_h_reply_to_domain);
798 route->set_h_reply_to_domain = NULL;
799 }
800 }else{
801 logwrite(LOG_ALERT, "could not open route file %s: %s\n",
802 route->filename, strerror(errno));
803 }
805 if(!ok){
806 g_free(route);
807 route = NULL;
808 }
810 return route;
811 }
813 static
814 void _g_list_free_all(GList *list)
815 {
816 GList *node;
817 if(list){
818 foreach(list, node)
819 g_free(node->data);
820 g_list_free(list);
821 }
822 }
824 void destroy_route(connect_route *r)
825 {
826 if(r->filename) g_free(r->filename);
827 if(r->protocol) g_free(r->protocol);
828 if(r->mail_host){
829 g_free(r->mail_host->address);
830 g_free(r->mail_host);
831 }
832 if(r->wrapper) g_free(r->wrapper);
833 if(r->helo_name) g_free(r->helo_name);
834 _g_list_free_all(r->allowed_mail_locals);
835 _g_list_free_all(r->not_allowed_mail_locals);
836 _g_list_free_all(r->allowed_rcpt_domains);
837 _g_list_free_all(r->not_allowed_rcpt_domains);
838 if(r->set_h_from_domain) g_free(r->set_h_from_domain);
839 if(r->set_h_reply_to_domain) g_free(r->set_h_reply_to_domain);
840 if(r->set_return_path_domain) g_free(r->set_return_path_domain);
841 if(r->map_h_reply_to_addresses) destroy_table(r->map_h_reply_to_addresses);
842 if(r->resolve_list) g_list_free(r->resolve_list);
843 #ifdef ENABLE_AUTH
844 if(r->auth_name) g_free(r->auth_name);
845 if(r->auth_login) g_free(r->auth_login);
846 if(r->auth_secret) g_free(r->auth_secret);
847 #endif
848 #ifdef ENABLE_POP3
849 if(r->pop3_login) g_free(r->pop3_login);
850 #endif
851 if(r->pipe) g_free(r->pipe);
852 g_free(r);
853 }
855 GList *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 destroy_route_list(GList *list)
883 {
884 GList *node;
886 foreach(list, node){
887 connect_route *route = (connect_route *)(node->data);
888 destroy_route(route);
889 }
890 g_list_free(list);
891 }
893 #ifdef ENABLE_POP3
895 get_conf *read_get_conf(gchar *filename)
896 {
897 FILE *in;
899 get_conf *gc = g_malloc(sizeof(get_conf));
900 memset(gc, 0, sizeof(get_conf));
902 gc->server_port = 110;
904 if((in = fopen(filename, "r"))){
905 gchar lval[256], rval[2048];
906 while(read_statement(in, lval, 256, rval, 2048)){
907 if(strcmp(lval, "protocol") == 0)
908 gc->protocol = g_strdup(rval);
909 else if(strcmp(lval, "server") == 0)
910 gc->server_name = g_strdup(rval);
911 else if(strcmp(lval, "port") == 0)
912 gc->server_port = atoi(rval);
913 else if(strcmp(lval, "wrapper") == 0)
914 gc->wrapper = g_strdup(rval);
915 else if(strcmp(lval, "user") == 0)
916 gc->login_user = g_strdup(rval);
917 else if(strcmp(lval, "pass") == 0)
918 gc->login_pass = g_strdup(rval);
919 else if(strcmp(lval, "address") == 0)
920 gc->address = create_address_qualified(rval, TRUE, conf.host_name);
921 else if(strcmp(lval, "return_path") == 0)
922 gc->return_path = create_address_qualified(rval, TRUE, conf.host_name);
923 else if(strcmp(lval, "do_ssl") == 0)
924 /* we ignore this. This option is used by sqilconf */
925 ;
926 else if(strcmp(lval, "do_keep") == 0)
927 gc->do_keep = parse_boolean(rval);
928 else if(strcmp(lval, "do_uidl") == 0)
929 gc->do_uidl = parse_boolean(rval);
930 else if(strcmp(lval, "do_uidl_dele") == 0)
931 gc->do_uidl_dele = parse_boolean(rval);
932 else if(strcmp(lval, "max_size") == 0)
933 gc->max_size = atoi(rval);
934 else if(strcmp(lval, "max_size_delete") == 0)
935 gc->max_size = parse_boolean(rval);
936 else if(strcmp(lval, "max_count") == 0)
937 gc->max_count = atoi(rval);
938 else if(strcmp(lval, "resolve_list") == 0)
939 gc->resolve_list = parse_resolve_list(rval);
940 else
941 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
942 }
943 fclose(in);
945 if(gc->resolve_list == NULL){
946 #ifdef ENABLE_RESOLVER
947 gc->resolve_list =
948 g_list_append(NULL, resolve_dns_a);
949 #endif
950 gc->resolve_list =
951 g_list_append(NULL, resolve_byname);
952 }
954 if(gc->protocol == NULL)
955 gc->protocol = g_strdup("pop3");
956 return gc;
957 }
958 logwrite(LOG_ALERT, "could not open get file %s: %s\n", filename, strerror(errno));
960 g_free(gc);
961 return NULL;
962 }
964 void destroy_get_conf(get_conf *gc)
965 {
966 if(gc->protocol) g_free(gc->protocol);
967 if(gc->server_name) g_free(gc->server_name);
968 if(gc->login_user) g_free(gc->login_user);
969 if(gc->login_pass) g_free(gc->login_pass);
970 if(gc->wrapper) g_free(gc->wrapper);
971 if(gc->address) destroy_address(gc->address);
972 if(gc->return_path) destroy_address(gc->return_path);
973 if(gc->resolve_list) g_list_free(gc->resolve_list);
974 g_free(gc);
975 }
977 #endif
979 connect_route *create_local_route()
980 {
981 connect_route *route;
983 route = g_malloc(sizeof(connect_route));
984 if(route){
985 memset(route, 0, sizeof(connect_route));
986 route->protocol = g_strdup("smtp");
987 route->is_local_net = TRUE;
988 route->name = g_strdup("local_net (default)");
989 route->expand_h_sender_address = TRUE;
990 route->resolve_list =
991 g_list_append(NULL, resolve_byname);
992 route->connect_error_fail = TRUE;
993 }
994 return route;
995 }