masqmail

annotate src/conf.c @ 392:c5fd796ea06e

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