Mercurial > masqmail-0.2
comparison src/conf.c @ 0:08114f7dcc23 0.2.21
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 |
parents | |
children | 26e34ae9a3e3 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:08114f7dcc23 |
---|---|
1 /* MasqMail | |
2 Copyright (C) 1999-2001 Oliver Kurth | |
3 | |
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. | |
8 | |
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. | |
13 | |
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 */ | |
18 | |
19 #include "masqmail.h" | |
20 | |
21 #include "pwd.h" | |
22 #include "grp.h" | |
23 | |
24 masqmail_conf conf; | |
25 | |
26 void init_conf() | |
27 { | |
28 struct passwd *passwd; | |
29 struct group *group; | |
30 | |
31 memset(&conf, 0, sizeof(masqmail_conf)); | |
32 | |
33 conf.orig_uid = getuid(); | |
34 conf.orig_gid = getgid(); | |
35 | |
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 } | |
49 | |
50 static gchar *true_strings[] = | |
51 { | |
52 "yes", "on", "true", NULL | |
53 }; | |
54 | |
55 static gchar *false_strings[] = | |
56 { | |
57 "no", "off", "false", NULL | |
58 }; | |
59 | |
60 static | |
61 gboolean parse_boolean(gchar *rval) | |
62 { | |
63 gchar **str; | |
64 | |
65 DEBUG(6) fprintf(stderr, "parse_boolean: %s\n", rval); | |
66 | |
67 str = true_strings; | |
68 while(*str){ | |
69 if(strncasecmp(*str, rval, strlen(*str)) == 0) | |
70 return TRUE; | |
71 str++; | |
72 } | |
73 | |
74 str = false_strings; | |
75 while(*str){ | |
76 if(strncasecmp(*str, rval, strlen(*str)) == 0) | |
77 return FALSE; | |
78 str++; | |
79 } | |
80 | |
81 fprintf(stderr, "cannot parse value '%s'\n", rval); | |
82 exit(EXIT_FAILURE); | |
83 } | |
84 | |
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; | |
91 | |
92 if((fptr = fopen(fname, "rt"))){ | |
93 gchar buf[256]; | |
94 | |
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 } | |
107 | |
108 return list; | |
109 } | |
110 | |
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; | |
119 | |
120 DEBUG(6) fprintf(stderr, "parsing list %s\n", line); | |
121 | |
122 p = line; | |
123 while(*p != 0){ | |
124 q = buf; | |
125 | |
126 while(*p && (*p != ';') && (q < buf+255)) | |
127 *(q++) = *(p++); | |
128 *q = 0; | |
129 | |
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)); | |
136 | |
137 DEBUG(6) printf("item = %s\n", buf); | |
138 | |
139 if(*p) p++; | |
140 } | |
141 return list; | |
142 } | |
143 | |
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; | |
150 | |
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); | |
159 | |
160 return list; | |
161 } | |
162 | |
163 static | |
164 GList *parse_resolve_list(gchar *line) | |
165 { | |
166 GList *list; | |
167 GList *list_node; | |
168 GList *res_list = NULL; | |
169 | |
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 } | |
192 | |
193 static | |
194 interface *parse_interface(gchar *line, gint def_port) | |
195 { | |
196 gchar buf[256]; | |
197 gchar *p, *q; | |
198 interface *iface; | |
199 | |
200 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line); | |
201 | |
202 p = line; | |
203 q = buf; | |
204 while((*p != 0) && (*p != ':') && (q < buf+255)) | |
205 *(q++) = *(p++); | |
206 *q = 0; | |
207 | |
208 iface = g_malloc(sizeof(interface)); | |
209 iface->address = g_strdup(buf); | |
210 | |
211 if(*p){ | |
212 p++; | |
213 iface->port = atoi(p); | |
214 }else | |
215 iface->port = def_port; | |
216 | |
217 return iface; | |
218 } | |
219 | |
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; | |
228 | |
229 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line); | |
230 | |
231 p = line; | |
232 q = buf; | |
233 while((*p != 0) && (*p != '/') && (q < buf+255)) | |
234 *(q++) = *(p++); | |
235 *q = 0; | |
236 | |
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; | |
250 | |
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 } | |
257 | |
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 | |
263 | |
264 static | |
265 gboolean eat_comments(FILE *in) | |
266 { | |
267 gint c; | |
268 | |
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 } | |
279 | |
280 /* after parsing, eat trailing character until LF */ | |
281 static | |
282 gboolean eat_line_trailing(FILE *in) | |
283 { | |
284 gint c; | |
285 | |
286 for(c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in)); | |
287 if(c == EOF) return FALSE; | |
288 return TRUE; | |
289 } | |
290 | |
291 static | |
292 gboolean eat_spaces(FILE *in) | |
293 { | |
294 gint c; | |
295 | |
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 } | |
301 | |
302 static | |
303 gboolean read_lval(FILE *in, gchar *buf, gint size) | |
304 { | |
305 gint c; | |
306 gchar *ptr = buf; | |
307 | |
308 DEBUG(6) fprintf(stderr, "read_lval()\n"); | |
309 | |
310 if(!eat_spaces(in)) return FALSE; | |
311 | |
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); | |
323 | |
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 } | |
330 | |
331 eat_spaces(in); | |
332 | |
333 DEBUG(6) fprintf(stderr, "lval = %s\n", buf); | |
334 | |
335 return buf[0] != 0; | |
336 } | |
337 | |
338 static | |
339 gboolean read_rval(FILE *in, gchar *buf, gint size) | |
340 { | |
341 gint c; | |
342 gchar *ptr = buf; | |
343 | |
344 DEBUG(6) fprintf(stderr, "read_rval()\n"); | |
345 | |
346 if(!eat_spaces(in)) return FALSE; | |
347 | |
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 } | |
375 | |
376 eat_line_trailing(in); | |
377 | |
378 DEBUG(6) fprintf(stderr, "rval = %s\n", buf); | |
379 | |
380 return TRUE; | |
381 } | |
382 | |
383 static | |
384 gboolean read_statement(FILE *in, | |
385 gchar *lval, gint lsize, | |
386 gchar *rval, gint rsize) | |
387 { | |
388 gint c; | |
389 | |
390 DEBUG(6) fprintf(stderr, "read_statement()\n"); | |
391 | |
392 /* eat comments and empty lines: */ | |
393 if(!eat_comments(in)) return FALSE; | |
394 | |
395 DEBUG(6) fprintf(stderr, "read_statement() 1\n"); | |
396 | |
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 } | |
410 | |
411 gboolean read_conf(gchar *filename) | |
412 { | |
413 FILE *in; | |
414 | |
415 conf.log_max_pri = 7; | |
416 | |
417 conf.remote_port = 25; | |
418 | |
419 conf.do_relay = TRUE; | |
420 | |
421 conf.alias_local_cmp = strcmp; | |
422 | |
423 conf.max_defer_time = 86400*4; /* 4 days */ | |
424 | |
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); | |
505 | |
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); | |
519 | |
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); | |
583 | |
584 else | |
585 fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval); | |
586 } | |
587 fclose(in); | |
588 | |
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"); | |
593 | |
594 if(conf.lock_dir == NULL) | |
595 conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir); | |
596 | |
597 if(conf.mbox_default == NULL) | |
598 conf.mbox_default = g_strdup("mbox"); | |
599 | |
600 if(conf.warn_intervals == NULL) | |
601 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE); | |
602 | |
603 return TRUE; | |
604 }else | |
605 fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno)); | |
606 return FALSE; | |
607 } | |
608 | |
609 connect_route *read_route(gchar *filename, gboolean is_local_net) | |
610 { | |
611 gboolean ok = FALSE; | |
612 FILE *in; | |
613 | |
614 connect_route *route = g_malloc(sizeof(connect_route)); | |
615 memset(route, 0, sizeof(connect_route)); | |
616 | |
617 DEBUG(5) debugf("read_route, filename = %s\n", filename); | |
618 | |
619 route->filename = g_strdup(filename); | |
620 route->name = g_strdup(filename); /* quick hack */ | |
621 | |
622 route->protocol = g_strdup("smtp"); | |
623 route->expand_h_sender_address = TRUE; | |
624 | |
625 route->is_local_net = is_local_net; | |
626 | |
627 route->do_pipelining = TRUE; | |
628 | |
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; | |
666 | |
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; | |
682 | |
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; | |
695 | |
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; | |
708 | |
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 } | |
770 | |
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; | |
788 | |
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 } | |
804 | |
805 if(!ok){ | |
806 g_free(route); | |
807 route = NULL; | |
808 } | |
809 | |
810 return route; | |
811 } | |
812 | |
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 } | |
823 | |
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 } | |
854 | |
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; | |
860 | |
861 if(!conf.run_as_user){ | |
862 set_euidgid(0, 0, &saved_uid, &saved_gid); | |
863 } | |
864 | |
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 } | |
873 | |
874 /* set uid and gid back */ | |
875 if(!conf.run_as_user){ | |
876 set_euidgid(saved_uid, saved_gid, NULL, NULL); | |
877 } | |
878 | |
879 return list; | |
880 } | |
881 | |
882 void destroy_route_list(GList *list) | |
883 { | |
884 GList *node; | |
885 | |
886 foreach(list, node){ | |
887 connect_route *route = (connect_route *)(node->data); | |
888 destroy_route(route); | |
889 } | |
890 g_list_free(list); | |
891 } | |
892 | |
893 #ifdef ENABLE_POP3 | |
894 | |
895 get_conf *read_get_conf(gchar *filename) | |
896 { | |
897 FILE *in; | |
898 | |
899 get_conf *gc = g_malloc(sizeof(get_conf)); | |
900 memset(gc, 0, sizeof(get_conf)); | |
901 | |
902 gc->server_port = 110; | |
903 | |
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); | |
944 | |
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 } | |
953 | |
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)); | |
959 | |
960 g_free(gc); | |
961 return NULL; | |
962 } | |
963 | |
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 } | |
976 | |
977 #endif | |
978 | |
979 connect_route *create_local_route() | |
980 { | |
981 connect_route *route; | |
982 | |
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 } |