masqmail

annotate src/conf.c @ 429:5593964ec779

Added route conditions based on the From header New route config directives: allowed_from_hdrs, denied_from_hdrs. This feature was motivated by Philipp Takacs <philipp29@t-online.de>.
author markus schnalke <meillo@marmaro.de>
date Thu, 20 Nov 2014 20:36:20 +0100
parents e972c3cbe1e0
children
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@428 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@402 148 char *ep;
meillo@317 149 address *addr = calloc(1, sizeof(address));
meillo@317 150
meillo@402 151 ep = item + strlen(item) - 1;
meillo@402 152 if (*item == '<' && *ep == '>') {
meillo@402 153 *item = '\0';
meillo@402 154 *ep = '\0';
meillo@402 155 g_strstrip(item);
meillo@317 156 }
meillo@317 157
meillo@402 158 addr->address = strdup(item);
meillo@402 159 at = strrchr(item, '@');
meillo@317 160 if (at) {
meillo@317 161 *at = '\0';
meillo@402 162 addr->local_part = strdup(item);
meillo@317 163 addr->domain = strdup(at+1);
meillo@317 164 } else {
meillo@402 165 addr->local_part = strdup(item);
meillo@330 166 /* No `@', thus any domain is okay. */
meillo@330 167 addr->domain = "*";
meillo@317 168 }
meillo@317 169 list = g_list_append(list, addr);
meillo@392 170 DEBUG(6) debugf("parse_address_glob_list: "
meillo@392 171 "read pattern `%s' `%s'\n",
meillo@317 172 addr->local_part, addr->domain);
meillo@10 173 g_free(item);
meillo@10 174 }
meillo@10 175 g_list_free(plain_list);
meillo@10 176 return list;
meillo@0 177 }
meillo@0 178
meillo@10 179 static GList*
meillo@366 180 parse_resolve_list(gchar *line)
meillo@0 181 {
meillo@10 182 GList *list;
meillo@10 183 GList *list_node;
meillo@10 184 GList *res_list = NULL;
meillo@392 185 gchar *item;
meillo@0 186
meillo@392 187 list = parse_list(line, TRUE);
meillo@28 188 if (!list) {
meillo@28 189 return NULL;
meillo@28 190 }
meillo@28 191 foreach(list, list_node) {
meillo@392 192 item = (gchar *) list_node->data;
meillo@392 193 if (strcmp(item, "byname")==0) {
meillo@28 194 res_list = g_list_append(res_list, resolve_byname);
meillo@0 195 #ifdef ENABLE_RESOLVER
meillo@392 196 } else if (strcmp(item, "dns_a")==0) {
meillo@28 197 res_list = g_list_append(res_list, resolve_dns_a);
meillo@392 198 } else if (strcmp(item, "dns_mx")==0) {
meillo@28 199 res_list = g_list_append(res_list, resolve_dns_mx);
meillo@0 200 #endif
meillo@28 201 } else {
meillo@28 202 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
meillo@262 203 exit(1);
meillo@10 204 }
meillo@28 205 g_free(item);
meillo@10 206 }
meillo@28 207 g_list_free(list);
meillo@10 208 return res_list;
meillo@0 209 }
meillo@0 210
meillo@10 211 static interface*
meillo@366 212 parse_interface(gchar *line, gint def_port)
meillo@0 213 {
meillo@392 214 gchar *cp;
meillo@392 215 interface *iface = g_malloc(sizeof(interface));
meillo@0 216
meillo@333 217 DEBUG(9) fprintf(stderr, "parse_interface: %s\n", line);
meillo@392 218 if ((cp = strchr(line, ':'))) {
meillo@392 219 *cp = '\0';
meillo@392 220 }
meillo@402 221 g_strstrip(line);
meillo@392 222 iface->address = g_strdup(line);
meillo@392 223 iface->port = (cp) ? atoi(++cp) : def_port;
meillo@412 224 DEBUG(9) fprintf(stderr, "found: address:port=%s:%u\n",
meillo@392 225 iface->address, iface->port);
meillo@10 226 return iface;
meillo@0 227 }
meillo@0 228
meillo@10 229 static gboolean
meillo@366 230 eat_comments(FILE *in)
meillo@0 231 {
meillo@10 232 gint c;
meillo@392 233 int incomment = 0;
meillo@0 234
meillo@392 235 while ((c = fgetc(in)) != EOF) {
meillo@392 236 if (incomment) {
meillo@392 237 /* eat until end of line */
meillo@392 238 if (c == '\n') {
meillo@392 239 incomment = 0;
meillo@392 240 continue;
meillo@392 241 } else {
meillo@392 242 continue;
meillo@392 243 }
meillo@392 244 } else {
meillo@392 245 /* eat whitespace and watch for comments */
meillo@392 246 if (isspace(c)) {
meillo@392 247 continue;
meillo@392 248 } else if (c == '#') {
meillo@392 249 incomment = 1;
meillo@392 250 continue;
meillo@392 251 } else {
meillo@392 252 /* found something (that's not our business) */
meillo@392 253 ungetc(c, in);
meillo@392 254 return TRUE;
meillo@392 255 }
meillo@10 256 }
meillo@10 257 }
meillo@392 258 return FALSE;
meillo@0 259 }
meillo@0 260
meillo@10 261 static gboolean
meillo@366 262 eat_spaces(FILE *in)
meillo@0 263 {
meillo@10 264 gint c;
meillo@10 265
meillo@392 266 while ((c = fgetc(in)) != EOF) {
meillo@392 267 if (!isspace(c)) {
meillo@392 268 ungetc(c, in);
meillo@392 269 return TRUE;
meillo@392 270 }
meillo@28 271 }
meillo@392 272 return FALSE;
meillo@0 273 }
meillo@0 274
meillo@10 275 static gboolean
meillo@366 276 read_lval(FILE *in, gchar *buf, gint size)
meillo@0 277 {
meillo@10 278 gint c;
meillo@10 279 gchar *ptr = buf;
meillo@0 280
meillo@333 281 DEBUG(9) fprintf(stderr, "read_lval()\n");
meillo@392 282 if (!eat_spaces(in)) {
meillo@10 283 return FALSE;
meillo@392 284 }
meillo@0 285
meillo@333 286 DEBUG(9) fprintf(stderr, "read_lval() 2\n");
meillo@392 287 while (1) {
meillo@402 288 c = fgetc(in);
meillo@402 289 if (c == EOF) {
meillo@392 290 fprintf(stderr, "unexpected EOF after %s\n", buf);
meillo@392 291 return FALSE;
meillo@392 292 }
meillo@392 293 if (ptr >= buf+size-1) {
meillo@392 294 fprintf(stderr, "lval too long\n");
meillo@392 295 break;
meillo@392 296 }
meillo@392 297 if (!isalnum(c) && c != '_' && c != '-' && c != '.') {
meillo@392 298 break;
meillo@392 299 }
meillo@392 300 *ptr++ = c;
meillo@10 301 }
meillo@14 302 *ptr = '\0';
meillo@402 303 g_strstrip(buf);
meillo@10 304 ungetc(c, in);
meillo@10 305 eat_spaces(in);
meillo@333 306 DEBUG(9) fprintf(stderr, "lval = %s\n", buf);
meillo@392 307 return *buf != '\0';
meillo@0 308 }
meillo@0 309
meillo@10 310 static gboolean
meillo@366 311 read_rval(FILE *in, gchar *buf, gint size)
meillo@0 312 {
meillo@10 313 gint c;
meillo@10 314 gchar *ptr = buf;
meillo@0 315
meillo@333 316 DEBUG(9) fprintf(stderr, "read_rval()\n");
meillo@392 317 if (!eat_spaces(in)) {
meillo@10 318 return FALSE;
meillo@392 319 }
meillo@10 320
meillo@10 321 c = fgetc(in);
meillo@394 322 if (c != '"') {
meillo@394 323 /* unquoted rval */
meillo@394 324 ungetc(c, in);
meillo@394 325 while ((c = fgetc(in)) != EOF) {
meillo@394 326 if (ptr >= buf+size-1) {
meillo@394 327 /* rval too long */
meillo@394 328 break;
meillo@394 329 }
meillo@394 330 if (!isalnum(c) && c != '_' && c != '-' &&
meillo@394 331 c != '.' && c != '/' && c != '@' &&
meillo@394 332 c != ';' && c != ':') {
meillo@394 333 break;
meillo@394 334 }
meillo@394 335 *ptr++ = c;
meillo@10 336 }
meillo@14 337 *ptr = '\0';
meillo@10 338 ungetc(c, in);
meillo@10 339 } else {
meillo@394 340 /* quoted rval */
meillo@10 341 gboolean escape = FALSE;
meillo@394 342 while ((c = fgetc(in)) != EOF) {
meillo@394 343 if (ptr >= buf+size-1) {
meillo@394 344 /* rval too long */
meillo@394 345 break;
meillo@10 346 }
meillo@394 347 if (!escape && c == '"') {
meillo@394 348 break;
meillo@394 349 }
meillo@394 350 if (!escape && c == '\\') {
meillo@394 351 escape = TRUE;
meillo@394 352 continue;
meillo@394 353 }
meillo@394 354 *ptr++ = c;
meillo@394 355 escape = FALSE;
meillo@10 356 }
meillo@14 357 *ptr = '\0';
meillo@0 358 }
meillo@402 359 g_strstrip(buf);
meillo@333 360 DEBUG(9) fprintf(stderr, "rval = %s\n", buf);
meillo@394 361 /* eat trailing of line */
meillo@394 362 while ((c = fgetc(in)) != EOF && c != '\n') {
meillo@394 363 continue;
meillo@394 364 }
meillo@10 365
meillo@10 366 return TRUE;
meillo@0 367 }
meillo@0 368
meillo@10 369 static gboolean
meillo@366 370 read_statement(FILE *in, gchar *lval, gint lsize, gchar *rval, gint rsize)
meillo@0 371 {
meillo@10 372 gint c;
meillo@0 373
meillo@333 374 DEBUG(9) fprintf(stderr, "read_statement()\n");
meillo@0 375
meillo@10 376 /* eat comments and empty lines: */
meillo@393 377 if (!eat_comments(in)) {
meillo@10 378 return FALSE;
meillo@393 379 }
meillo@28 380 if (!read_lval(in, lval, lsize)) {
meillo@28 381 return FALSE;
meillo@28 382 }
meillo@411 383 g_strstrip(lval);
meillo@411 384 DEBUG(9) fprintf(stderr, " lval = `%s'\n", lval);
meillo@393 385 if ((c = fgetc(in) != '=')) {
meillo@393 386 fprintf(stderr, "'=' expected after %s, char was '%c'\n",
meillo@393 387 lval, c);
meillo@10 388 }
meillo@393 389 if (!read_rval(in, rval, rsize)) {
meillo@393 390 return FALSE;
meillo@393 391 }
meillo@411 392 g_strstrip(rval);
meillo@411 393 DEBUG(9) fprintf(stderr, " rval = `%s'\n", rval);
meillo@393 394 return TRUE;
meillo@0 395 }
meillo@0 396
meillo@10 397 gboolean
meillo@366 398 read_conf(gchar *filename)
meillo@0 399 {
meillo@10 400 FILE *in;
meillo@393 401 gchar lval[256], rval[2048];
meillo@393 402 GList *listen_addrs_tmp = NULL;
meillo@0 403
meillo@10 404 conf.do_relay = TRUE;
meillo@244 405 conf.localpartcmp = strcmp;
meillo@10 406 conf.max_defer_time = 86400 * 4; /* 4 days */
meillo@120 407 conf.max_msg_size = 0; /* no limit on msg size */
meillo@421 408 conf.lock_dir = LOCK_DIR;
meillo@151 409 conf.spool_dir = SPOOL_DIR;
meillo@152 410 conf.mail_dir = "/var/mail";
meillo@0 411
meillo@393 412 if (!(in = fopen(filename, "r"))) {
meillo@393 413 logwrite(LOG_ALERT, "could not open config file %s: %s\n",
meillo@393 414 filename, strerror(errno));
meillo@28 415 return FALSE;
meillo@28 416 }
meillo@28 417
meillo@392 418 while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
meillo@333 419 DEBUG(9) fprintf(stderr,"read_conf(): lval=%s\n", lval);
meillo@393 420 if (strcmp(lval, "debug_level")==0) {
meillo@28 421 conf.debug_level = atoi(rval);
meillo@393 422 } else if (strcmp(lval, "run_as_user")==0) {
meillo@393 423 if (!conf.run_as_user) {
meillo@393 424 /* you should not be able to reset that flag */
meillo@28 425 conf.run_as_user = parse_boolean(rval);
meillo@393 426 }
meillo@393 427 } else if (strcmp(lval, "use_syslog")==0) {
meillo@28 428 conf.use_syslog = parse_boolean(rval);
meillo@393 429 } else if (strcmp(lval, "mail_dir")==0) {
meillo@28 430 conf.mail_dir = g_strdup(rval);
meillo@393 431 } else if (strcmp(lval, "lock_dir")==0) {
meillo@28 432 conf.lock_dir = g_strdup(rval);
meillo@393 433 } else if (strcmp(lval, "spool_dir")==0) {
meillo@28 434 conf.spool_dir = g_strdup(rval);
meillo@393 435 } else if (strcmp(lval, "log_dir")==0) {
meillo@28 436 conf.log_dir = g_strdup(rval);
meillo@393 437 } else if (strcmp(lval, "host_name")==0) {
meillo@393 438 if (rval[0] != '/') {
meillo@28 439 conf.host_name = g_strdup(rval);
meillo@393 440 } else {
meillo@28 441 char buf[256];
meillo@28 442 FILE *fptr = fopen(rval, "rt");
meillo@307 443 if (!fptr) {
meillo@393 444 logwrite(LOG_ALERT, "could not open "
meillo@393 445 "%s: %s\n", rval,
meillo@393 446 strerror(errno));
meillo@28 447 return FALSE;
meillo@10 448 }
meillo@393 449 fgets(buf, sizeof buf, fptr);
meillo@393 450 g_strstrip(buf);
meillo@28 451 conf.host_name = g_strdup(buf);
meillo@28 452 fclose(fptr);
meillo@28 453 }
meillo@393 454 } else if (strcmp(lval, "local_hosts")==0) {
meillo@392 455 conf.local_hosts = parse_list(rval, TRUE);
meillo@393 456 } else if (strcmp(lval, "local_addresses")==0) {
meillo@28 457 conf.local_addresses = parse_list(rval, TRUE);
meillo@393 458 } else if (strcmp(lval, "not_local_addresses")==0) {
meillo@28 459 conf.not_local_addresses = parse_list(rval, TRUE);
meillo@393 460 } else if (strcmp(lval, "do_save_envelope_to")==0) {
meillo@28 461 conf.do_save_envelope_to = parse_boolean(rval);
meillo@393 462 } else if (strcmp(lval, "defer_all")==0) {
meillo@28 463 conf.defer_all = parse_boolean(rval);
meillo@393 464 } else if (strcmp(lval, "do_relay")==0) {
meillo@28 465 conf.do_relay = parse_boolean(rval);
meillo@393 466 } else if (strcmp(lval, "alias_file")==0) {
meillo@28 467 conf.alias_file = g_strdup(rval);
meillo@393 468 } else if (strcmp(lval, "globalias_file")==0) {
meillo@387 469 conf.globalias_file = g_strdup(rval);
meillo@393 470 } else if (strcmp(lval, "caseless_matching")==0) {
meillo@393 471 conf.localpartcmp = parse_boolean(rval) ?
meillo@393 472 strcasecmp : strcmp;
meillo@393 473 } else if (strcmp(lval, "mbox_default")==0) {
meillo@28 474 conf.mbox_default = g_strdup(rval);
meillo@393 475 } else if (strcmp(lval, "mbox_users")==0) {
meillo@28 476 conf.mbox_users = parse_list(rval, TRUE);
meillo@393 477 } else if (strcmp(lval, "mda_users")==0) {
meillo@28 478 conf.mda_users = parse_list(rval, TRUE);
meillo@393 479 } else if (strcmp(lval, "mda")==0) {
meillo@28 480 conf.mda = g_strdup(rval);
meillo@393 481 } else if (strcmp(lval, "mda_fromline")==0) {
meillo@28 482 conf.mda_fromline = parse_boolean(rval);
meillo@393 483 } else if (strcmp(lval, "mda_fromhack")==0) {
meillo@28 484 conf.mda_fromhack = parse_boolean(rval);
meillo@393 485 } else if (strcmp(lval, "pipe_fromline")==0) {
meillo@28 486 conf.pipe_fromline = parse_boolean(rval);
meillo@393 487 } else if (strcmp(lval, "pipe_fromhack")==0) {
meillo@28 488 conf.pipe_fromhack = parse_boolean(rval);
meillo@393 489 } else if (strcmp(lval, "listen_addresses")==0) {
meillo@393 490 listen_addrs_tmp = parse_list(rval, TRUE);
meillo@393 491 } else if (strncmp(lval, "query_routes.", 13)==0) {
meillo@28 492 GList *file_list = parse_list(rval, FALSE);
meillo@354 493 table_pair *pair = create_pair(lval+13, file_list);
meillo@393 494 conf.query_routes = g_list_append(conf.query_routes,
meillo@393 495 pair);
meillo@393 496 } else if (strcmp(lval, "permanent_routes")==0) {
meillo@354 497 conf.perma_routes = parse_list(rval, FALSE);
meillo@393 498 } else if (strcmp(lval, "online_query")==0) {
meillo@310 499 conf.online_query = g_strdup(rval);
meillo@393 500 } else if (strcmp(lval, "do_queue")==0) {
meillo@28 501 conf.do_queue = parse_boolean(rval);
meillo@393 502 } else if (strcmp(lval, "errmsg_file")==0) {
meillo@28 503 conf.errmsg_file = g_strdup(rval);
meillo@393 504 } else if (strcmp(lval, "warnmsg_file")==0) {
meillo@28 505 conf.warnmsg_file = g_strdup(rval);
meillo@393 506 } else if (strcmp(lval, "warn_intervals")==0) {
meillo@392 507 conf.warn_intervals = parse_list(rval, TRUE);
meillo@393 508 } else if (strcmp(lval, "max_defer_time")==0) {
meillo@254 509 gint ival = time_interval(rval);
meillo@393 510 if (ival < 0) {
meillo@393 511 logwrite(LOG_WARNING, "invalid time interval "
meillo@393 512 "for 'max_defer_time': %s\n",
meillo@393 513 rval);
meillo@393 514 } else {
meillo@28 515 conf.max_defer_time = ival;
meillo@393 516 }
meillo@393 517 } else if (strcmp(lval, "log_user")==0) {
meillo@28 518 conf.log_user = g_strdup(rval);
meillo@393 519 } else if(strcmp(lval, "max_msg_size")==0) {
meillo@117 520 conf.max_msg_size = atol(rval);
meillo@393 521 DEBUG(9) fprintf(stderr,
meillo@393 522 "rval=%s, conf.max_msg_size=%ld\n",
meillo@117 523 rval, conf.max_msg_size);
meillo@393 524 } else {
meillo@393 525 logwrite(LOG_WARNING, "var '%s' unknown: ignored\n",
meillo@393 526 lval);
meillo@117 527 }
meillo@28 528 }
meillo@28 529 fclose(in);
meillo@0 530
meillo@156 531 if (!conf.host_name) {
meillo@393 532 logwrite(LOG_ALERT, "`host_name' MUST be set in "
meillo@393 533 "masqmail.conf. See man page\n");
meillo@156 534 return FALSE;
meillo@156 535 }
meillo@393 536 if (!conf.errmsg_file) {
meillo@28 537 conf.errmsg_file = g_strdup(DATA_DIR "/tpl/failmsg.tpl");
meillo@393 538 }
meillo@393 539 if (!conf.warnmsg_file) {
meillo@28 540 conf.warnmsg_file = g_strdup(DATA_DIR "/tpl/warnmsg.tpl");
meillo@393 541 }
meillo@393 542 if (!conf.mbox_default) {
meillo@28 543 conf.mbox_default = g_strdup("mbox");
meillo@393 544 }
meillo@393 545 if (!conf.warn_intervals) {
meillo@392 546 conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", TRUE);
meillo@393 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@393 561 if (!listen_addrs_tmp) {
meillo@393 562 conf.listen_addresses = g_list_append(NULL,
meillo@412 563 parse_interface(strdup("localhost"), 25));
meillo@393 564 } else {
meillo@393 565 GList *node;
meillo@157 566
meillo@393 567 foreach(listen_addrs_tmp, node) {
meillo@393 568 conf.listen_addresses =
meillo@393 569 g_list_append(conf.listen_addresses,
meillo@393 570 parse_interface((gchar *) node->data,
meillo@393 571 25));
meillo@393 572 g_free(node->data);
meillo@393 573 }
meillo@393 574 g_list_free(listen_addrs_tmp);
meillo@393 575 }
meillo@157 576
meillo@28 577 return TRUE;
meillo@0 578 }
meillo@0 579
meillo@10 580 connect_route*
meillo@366 581 read_route(gchar *filename, gboolean is_perma)
meillo@0 582 {
meillo@10 583 FILE *in;
meillo@393 584 connect_route *route;
meillo@393 585 gchar lval[256], rval[2048];
meillo@0 586
meillo@10 587 DEBUG(5) debugf("read_route, filename = %s\n", filename);
meillo@0 588
meillo@393 589 if (!(in = fopen(filename, "r"))) {
meillo@393 590 logwrite(LOG_ALERT, "could not open route file %s: %s\n",
meillo@393 591 filename, strerror(errno));
meillo@28 592 return NULL;
meillo@28 593 }
meillo@0 594
meillo@393 595 route = g_malloc(sizeof(connect_route));
meillo@393 596 memset(route, 0, sizeof(connect_route));
meillo@393 597 route->filename = g_strdup(filename);
meillo@393 598 route->name = route->filename; /* quick hack */
meillo@393 599 route->expand_h_sender_address = TRUE;
meillo@393 600 route->is_perma = is_perma;
meillo@393 601 route->do_pipelining = TRUE;
meillo@393 602
meillo@392 603 while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
meillo@393 604 if (strcmp(lval, "mail_host")==0) {
meillo@178 605 route->mail_host = parse_interface(rval, 25);
meillo@393 606 } else if (strcmp(lval, "helo_name")==0) {
meillo@28 607 route->helo_name = g_strdup(rval);
meillo@393 608 } else if (strcmp(lval, "wrapper")==0) {
meillo@28 609 route->wrapper = g_strdup(rval);
meillo@393 610 } else if (strcmp(lval, "connect_error_fail")==0) {
meillo@28 611 route->connect_error_fail = parse_boolean(rval);
meillo@393 612 } else if (strcmp(lval, "do_correct_helo")==0) {
meillo@28 613 route->do_correct_helo = parse_boolean(rval);
meillo@393 614 } else if (strcmp(lval, "instant_helo")==0) {
meillo@222 615 route->instant_helo = parse_boolean(rval);
meillo@393 616 } else if (strcmp(lval, "do_pipelining")==0) {
meillo@28 617 route->do_pipelining = parse_boolean(rval);
meillo@317 618
meillo@393 619 } else if (strcmp(lval, "allowed_senders")==0) {
meillo@392 620 route->allowed_senders = parse_address_glob_list(rval);
meillo@393 621 } else if (strcmp(lval, "denied_senders")==0) {
meillo@392 622 route->denied_senders = parse_address_glob_list(rval);
meillo@393 623 } else if (strcmp(lval, "allowed_recipients")==0) {
meillo@392 624 route->allowed_recipients = parse_address_glob_list(rval);
meillo@393 625 } else if (strcmp(lval, "denied_recipients")==0) {
meillo@392 626 route->denied_recipients = parse_address_glob_list(rval);
meillo@429 627 } else if (strcmp(lval, "allowed_from_hdrs")==0) {
meillo@429 628 route->allowed_from_hdrs = parse_address_glob_list(rval);
meillo@429 629 } else if (strcmp(lval, "denied_from_hdrs")==0) {
meillo@429 630 route->denied_from_hdrs = parse_address_glob_list(rval);
meillo@317 631
meillo@393 632 } else if (strcmp(lval, "set_h_from_domain")==0) {
meillo@28 633 route->set_h_from_domain = g_strdup(rval);
meillo@393 634 } else if (strcmp(lval, "set_h_reply_to_domain")==0) {
meillo@28 635 route->set_h_reply_to_domain = g_strdup(rval);
meillo@393 636 } else if (strcmp(lval, "set_return_path_domain")==0) {
meillo@28 637 route->set_return_path_domain = g_strdup(rval);
meillo@393 638 } else if (strcmp(lval, "map_return_path_addresses")==0) {
meillo@28 639 GList *node, *list;
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@393 645 address *addr = create_address(
meillo@393 646 (gchar *) (pair->value), TRUE);
meillo@28 647 g_free(pair->value);
meillo@28 648 pair->value = (gpointer *) addr;
meillo@402 649 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
meillo@28 650 g_free(item);
meillo@28 651 }
meillo@28 652 g_list_free(list);
meillo@393 653 } else if (strcmp(lval, "map_h_from_addresses")==0) {
meillo@28 654 GList *list, *node;
meillo@10 655
meillo@28 656 list = parse_list(rval, TRUE);
meillo@28 657 foreach(list, node) {
meillo@28 658 gchar *item = (gchar *) (node->data);
meillo@28 659 table_pair *pair = parse_table_pair(item, ':');
meillo@28 660 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
meillo@28 661 g_free(item);
meillo@28 662 }
meillo@28 663 g_list_free(list);
meillo@393 664 } else if (strcmp(lval, "map_h_reply_to_addresses")==0) {
meillo@28 665 GList *list, *node;
meillo@10 666
meillo@28 667 list = parse_list(rval, TRUE);
meillo@28 668 foreach(list, node) {
meillo@28 669 gchar *item = (gchar *) (node->data);
meillo@28 670 table_pair *pair = parse_table_pair(item, ':');
meillo@28 671 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
meillo@28 672 g_free(item);
meillo@10 673 }
meillo@28 674 g_list_free(list);
meillo@393 675 } else if (strcmp(lval, "map_h_mail_followup_to_addresses")==0) {
meillo@28 676 GList *list, *node;
meillo@28 677
meillo@28 678 list = parse_list(rval, TRUE);
meillo@28 679 foreach(list, node) {
meillo@28 680 gchar *item = (gchar *) (node->data);
meillo@28 681 table_pair *pair = parse_table_pair(item, ':');
meillo@28 682 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
meillo@28 683 g_free(item);
meillo@28 684 }
meillo@28 685 g_list_free(list);
meillo@393 686 } else if (strcmp(lval, "expand_h_sender_domain")==0) {
meillo@28 687 route->expand_h_sender_domain = parse_boolean(rval);
meillo@393 688 } else if (strcmp(lval, "expand_h_sender_address")==0) {
meillo@28 689 route->expand_h_sender_address = parse_boolean(rval);
meillo@393 690 } else if (strcmp(lval, "resolve_list")==0) {
meillo@28 691 route->resolve_list = parse_resolve_list(rval);
meillo@393 692 } else if (strcmp(lval, "do_ssl")==0) {
meillo@28 693 /* we ignore this. This option is used by sqilconf */
meillo@28 694 ;
meillo@10 695 #ifdef ENABLE_AUTH
meillo@393 696 } else if (strcmp(lval, "auth_name")==0) {
meillo@28 697 route->auth_name = g_strdup(rval);
meillo@393 698 } else if (strcmp(lval, "auth_login")==0) {
meillo@28 699 route->auth_login = g_strdup(rval);
meillo@393 700 } else if (strcmp(lval, "auth_secret")==0) {
meillo@28 701 route->auth_secret = g_strdup(rval);
meillo@10 702 #else
meillo@393 703 } else if ((strcmp(lval, "auth_name")==0) ||
meillo@393 704 (strcmp(lval, "auth_login")==0) ||
meillo@393 705 (strcmp(lval, "auth_secret")==0)) {
meillo@393 706 logwrite(LOG_WARNING, "%s ignored: not compiled with "
meillo@393 707 "auth support.\n", lval);
meillo@28 708 }
meillo@10 709 #endif
meillo@393 710 } else if (strcmp(lval, "pipe")==0) {
meillo@28 711 route->pipe = g_strdup(rval);
meillo@393 712 } else if (strcmp(lval, "pipe_fromline")==0) {
meillo@28 713 route->pipe_fromline = parse_boolean(rval);
meillo@393 714 } else if (strcmp(lval, "pipe_fromhack")==0) {
meillo@28 715 route->pipe_fromhack = parse_boolean(rval);
meillo@393 716 } else if (strcmp(lval, "last_route")==0) {
meillo@28 717 route->last_route = parse_boolean(rval);
meillo@393 718 } else {
meillo@393 719 logwrite(LOG_WARNING, "var '%s' unknown: ignored\n",
meillo@393 720 lval);
meillo@393 721 }
meillo@28 722 }
meillo@28 723
meillo@319 724 if (!route->resolve_list) {
meillo@28 725 #ifdef ENABLE_RESOLVER
meillo@393 726 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 727 resolve_dns_mx);
meillo@393 728 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 729 resolve_dns_a);
meillo@28 730 #endif
meillo@393 731 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 732 resolve_byname);
meillo@28 733 }
meillo@28 734 fclose(in);
meillo@10 735
meillo@393 736 /* warn user about mis-configurations: */
meillo@393 737 if (route->map_h_from_addresses && route->set_h_from_domain) {
meillo@393 738 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides "
meillo@393 739 "'set_h_from_domain'\n");
meillo@28 740 g_free(route->set_h_from_domain);
meillo@28 741 route->set_h_from_domain = NULL;
meillo@28 742 }
meillo@393 743 if (route->map_h_reply_to_addresses && route->set_h_reply_to_domain) {
meillo@393 744 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides "
meillo@393 745 "'set_h_reply_to_domain'\n");
meillo@28 746 g_free(route->set_h_reply_to_domain);
meillo@28 747 route->set_h_reply_to_domain = NULL;
meillo@10 748 }
meillo@10 749
meillo@10 750 return route;
meillo@10 751 }
meillo@10 752
meillo@10 753 static void
meillo@366 754 _g_list_free_all(GList *list)
meillo@10 755 {
meillo@10 756 GList *node;
meillo@393 757 if (!list) {
meillo@393 758 return;
meillo@10 759 }
meillo@393 760 foreach(list, node) {
meillo@393 761 g_free(node->data);
meillo@393 762 }
meillo@393 763 g_list_free(list);
meillo@10 764 }
meillo@10 765
meillo@10 766 void
meillo@366 767 destroy_route(connect_route *r)
meillo@10 768 {
meillo@393 769 if (r->filename) {
meillo@10 770 g_free(r->filename);
meillo@393 771 }
meillo@10 772 if (r->mail_host) {
meillo@10 773 g_free(r->mail_host->address);
meillo@10 774 g_free(r->mail_host);
meillo@10 775 }
meillo@393 776 if (r->wrapper) {
meillo@10 777 g_free(r->wrapper);
meillo@393 778 }
meillo@393 779 if (r->helo_name) {
meillo@10 780 g_free(r->helo_name);
meillo@393 781 }
meillo@317 782 _g_list_free_all(r->allowed_senders);
meillo@317 783 _g_list_free_all(r->denied_senders);
meillo@317 784 _g_list_free_all(r->allowed_recipients);
meillo@317 785 _g_list_free_all(r->denied_recipients);
meillo@393 786 if (r->set_h_from_domain) {
meillo@10 787 g_free(r->set_h_from_domain);
meillo@393 788 }
meillo@393 789 if (r->set_h_reply_to_domain) {
meillo@10 790 g_free(r->set_h_reply_to_domain);
meillo@393 791 }
meillo@393 792 if (r->set_return_path_domain) {
meillo@10 793 g_free(r->set_return_path_domain);
meillo@393 794 }
meillo@393 795 if (r->map_h_reply_to_addresses) {
meillo@10 796 destroy_table(r->map_h_reply_to_addresses);
meillo@393 797 }
meillo@393 798 if (r->resolve_list) {
meillo@10 799 g_list_free(r->resolve_list);
meillo@393 800 }
meillo@10 801 #ifdef ENABLE_AUTH
meillo@393 802 if (r->auth_name) {
meillo@10 803 g_free(r->auth_name);
meillo@393 804 }
meillo@393 805 if (r->auth_login) {
meillo@10 806 g_free(r->auth_login);
meillo@393 807 }
meillo@393 808 if (r->auth_secret) {
meillo@10 809 g_free(r->auth_secret);
meillo@393 810 }
meillo@10 811 #endif
meillo@393 812 if (r->pipe) {
meillo@10 813 g_free(r->pipe);
meillo@393 814 }
meillo@10 815 g_free(r);
meillo@10 816 }
meillo@10 817
meillo@10 818 GList*
meillo@366 819 read_route_list(GList *rf_list, gboolean is_perma)
meillo@10 820 {
meillo@10 821 GList *list = NULL;
meillo@10 822 GList *node;
meillo@10 823 uid_t saved_uid, saved_gid;
meillo@10 824
meillo@10 825 if (!conf.run_as_user) {
meillo@10 826 set_euidgid(0, 0, &saved_uid, &saved_gid);
meillo@10 827 }
meillo@10 828 foreach(rf_list, node) {
meillo@10 829 gchar *fname = (gchar *) (node->data);
meillo@354 830 connect_route *route = read_route(fname, is_perma);
meillo@393 831 if (route) {
meillo@10 832 list = g_list_append(list, route);
meillo@393 833 } else {
meillo@393 834 logwrite(LOG_ALERT, "could not read route "
meillo@393 835 "configuration %s\n", fname);
meillo@393 836 }
meillo@10 837 }
meillo@10 838 /* set uid and gid back */
meillo@10 839 if (!conf.run_as_user) {
meillo@10 840 set_euidgid(saved_uid, saved_gid, NULL, NULL);
meillo@10 841 }
meillo@10 842 return list;
meillo@10 843 }
meillo@10 844
meillo@10 845 void
meillo@366 846 destroy_route_list(GList *list)
meillo@10 847 {
meillo@10 848 GList *node;
meillo@10 849
meillo@10 850 foreach(list, node) {
meillo@10 851 connect_route *route = (connect_route *) (node->data);
meillo@10 852 destroy_route(route);
meillo@0 853 }
meillo@0 854 g_list_free(list);
meillo@0 855 }