masqmail

annotate src/conf.c @ 421:f37384470855

Changed lockdir to /var/lock/masqmail; Create lockdir and piddir on startup. Moved the lockdir out of the spool dir. (When /var/lock is a ramdisk we do well to have the lock files there.) Added the new configure option --with-lockdir to change that location. Nontheless, if we run_as_user, then lock files are always stored in the spool dir directly. Instead of installing the lockdir and piddir at installation time, we create them on startup time now if they are missing. This is necessary if lockdir or piddir are a tmpfs.
author markus schnalke <meillo@marmaro.de>
date Wed, 30 May 2012 09:38:38 +0200
parents 8a62bebda631
children e972c3cbe1e0
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@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@317 627
meillo@393 628 } else if (strcmp(lval, "set_h_from_domain")==0) {
meillo@28 629 route->set_h_from_domain = g_strdup(rval);
meillo@393 630 } else if (strcmp(lval, "set_h_reply_to_domain")==0) {
meillo@28 631 route->set_h_reply_to_domain = g_strdup(rval);
meillo@393 632 } else if (strcmp(lval, "set_return_path_domain")==0) {
meillo@28 633 route->set_return_path_domain = g_strdup(rval);
meillo@393 634 } else if (strcmp(lval, "map_return_path_addresses")==0) {
meillo@28 635 GList *node, *list;
meillo@10 636
meillo@28 637 list = parse_list(rval, TRUE);
meillo@28 638 foreach(list, node) {
meillo@28 639 gchar *item = (gchar *) (node->data);
meillo@28 640 table_pair *pair = parse_table_pair(item, ':');
meillo@393 641 address *addr = create_address(
meillo@393 642 (gchar *) (pair->value), TRUE);
meillo@28 643 g_free(pair->value);
meillo@28 644 pair->value = (gpointer *) addr;
meillo@402 645 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
meillo@28 646 g_free(item);
meillo@28 647 }
meillo@28 648 g_list_free(list);
meillo@393 649 } else if (strcmp(lval, "map_h_from_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_from_addresses = g_list_append(route->map_h_from_addresses, pair);
meillo@28 657 g_free(item);
meillo@28 658 }
meillo@28 659 g_list_free(list);
meillo@393 660 } else if (strcmp(lval, "map_h_reply_to_addresses")==0) {
meillo@28 661 GList *list, *node;
meillo@10 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_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
meillo@28 668 g_free(item);
meillo@10 669 }
meillo@28 670 g_list_free(list);
meillo@393 671 } else if (strcmp(lval, "map_h_mail_followup_to_addresses")==0) {
meillo@28 672 GList *list, *node;
meillo@28 673
meillo@28 674 list = parse_list(rval, TRUE);
meillo@28 675 foreach(list, node) {
meillo@28 676 gchar *item = (gchar *) (node->data);
meillo@28 677 table_pair *pair = parse_table_pair(item, ':');
meillo@28 678 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
meillo@28 679 g_free(item);
meillo@28 680 }
meillo@28 681 g_list_free(list);
meillo@393 682 } else if (strcmp(lval, "expand_h_sender_domain")==0) {
meillo@28 683 route->expand_h_sender_domain = parse_boolean(rval);
meillo@393 684 } else if (strcmp(lval, "expand_h_sender_address")==0) {
meillo@28 685 route->expand_h_sender_address = parse_boolean(rval);
meillo@393 686 } else if (strcmp(lval, "resolve_list")==0) {
meillo@28 687 route->resolve_list = parse_resolve_list(rval);
meillo@393 688 } else if (strcmp(lval, "do_ssl")==0) {
meillo@28 689 /* we ignore this. This option is used by sqilconf */
meillo@28 690 ;
meillo@10 691 #ifdef ENABLE_AUTH
meillo@393 692 } else if (strcmp(lval, "auth_name")==0) {
meillo@28 693 route->auth_name = g_strdup(rval);
meillo@393 694 } else if (strcmp(lval, "auth_login")==0) {
meillo@28 695 route->auth_login = g_strdup(rval);
meillo@393 696 } else if (strcmp(lval, "auth_secret")==0) {
meillo@28 697 route->auth_secret = g_strdup(rval);
meillo@10 698 #else
meillo@393 699 } else if ((strcmp(lval, "auth_name")==0) ||
meillo@393 700 (strcmp(lval, "auth_login")==0) ||
meillo@393 701 (strcmp(lval, "auth_secret")==0)) {
meillo@393 702 logwrite(LOG_WARNING, "%s ignored: not compiled with "
meillo@393 703 "auth support.\n", lval);
meillo@28 704 }
meillo@10 705 #endif
meillo@393 706 } else if (strcmp(lval, "pipe")==0) {
meillo@28 707 route->pipe = g_strdup(rval);
meillo@393 708 } else if (strcmp(lval, "pipe_fromline")==0) {
meillo@28 709 route->pipe_fromline = parse_boolean(rval);
meillo@393 710 } else if (strcmp(lval, "pipe_fromhack")==0) {
meillo@28 711 route->pipe_fromhack = parse_boolean(rval);
meillo@393 712 } else if (strcmp(lval, "last_route")==0) {
meillo@28 713 route->last_route = parse_boolean(rval);
meillo@393 714 } else {
meillo@393 715 logwrite(LOG_WARNING, "var '%s' unknown: ignored\n",
meillo@393 716 lval);
meillo@393 717 }
meillo@28 718 }
meillo@28 719
meillo@319 720 if (!route->resolve_list) {
meillo@28 721 #ifdef ENABLE_RESOLVER
meillo@393 722 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 723 resolve_dns_mx);
meillo@393 724 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 725 resolve_dns_a);
meillo@28 726 #endif
meillo@393 727 route->resolve_list = g_list_append(route->resolve_list,
meillo@393 728 resolve_byname);
meillo@28 729 }
meillo@28 730 fclose(in);
meillo@10 731
meillo@393 732 /* warn user about mis-configurations: */
meillo@393 733 if (route->map_h_from_addresses && route->set_h_from_domain) {
meillo@393 734 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides "
meillo@393 735 "'set_h_from_domain'\n");
meillo@28 736 g_free(route->set_h_from_domain);
meillo@28 737 route->set_h_from_domain = NULL;
meillo@28 738 }
meillo@393 739 if (route->map_h_reply_to_addresses && route->set_h_reply_to_domain) {
meillo@393 740 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides "
meillo@393 741 "'set_h_reply_to_domain'\n");
meillo@28 742 g_free(route->set_h_reply_to_domain);
meillo@28 743 route->set_h_reply_to_domain = NULL;
meillo@10 744 }
meillo@10 745
meillo@10 746 return route;
meillo@10 747 }
meillo@10 748
meillo@10 749 static void
meillo@366 750 _g_list_free_all(GList *list)
meillo@10 751 {
meillo@10 752 GList *node;
meillo@393 753 if (!list) {
meillo@393 754 return;
meillo@10 755 }
meillo@393 756 foreach(list, node) {
meillo@393 757 g_free(node->data);
meillo@393 758 }
meillo@393 759 g_list_free(list);
meillo@10 760 }
meillo@10 761
meillo@10 762 void
meillo@366 763 destroy_route(connect_route *r)
meillo@10 764 {
meillo@393 765 if (r->filename) {
meillo@10 766 g_free(r->filename);
meillo@393 767 }
meillo@10 768 if (r->mail_host) {
meillo@10 769 g_free(r->mail_host->address);
meillo@10 770 g_free(r->mail_host);
meillo@10 771 }
meillo@393 772 if (r->wrapper) {
meillo@10 773 g_free(r->wrapper);
meillo@393 774 }
meillo@393 775 if (r->helo_name) {
meillo@10 776 g_free(r->helo_name);
meillo@393 777 }
meillo@317 778 _g_list_free_all(r->allowed_senders);
meillo@317 779 _g_list_free_all(r->denied_senders);
meillo@317 780 _g_list_free_all(r->allowed_recipients);
meillo@317 781 _g_list_free_all(r->denied_recipients);
meillo@393 782 if (r->set_h_from_domain) {
meillo@10 783 g_free(r->set_h_from_domain);
meillo@393 784 }
meillo@393 785 if (r->set_h_reply_to_domain) {
meillo@10 786 g_free(r->set_h_reply_to_domain);
meillo@393 787 }
meillo@393 788 if (r->set_return_path_domain) {
meillo@10 789 g_free(r->set_return_path_domain);
meillo@393 790 }
meillo@393 791 if (r->map_h_reply_to_addresses) {
meillo@10 792 destroy_table(r->map_h_reply_to_addresses);
meillo@393 793 }
meillo@393 794 if (r->resolve_list) {
meillo@10 795 g_list_free(r->resolve_list);
meillo@393 796 }
meillo@10 797 #ifdef ENABLE_AUTH
meillo@393 798 if (r->auth_name) {
meillo@10 799 g_free(r->auth_name);
meillo@393 800 }
meillo@393 801 if (r->auth_login) {
meillo@10 802 g_free(r->auth_login);
meillo@393 803 }
meillo@393 804 if (r->auth_secret) {
meillo@10 805 g_free(r->auth_secret);
meillo@393 806 }
meillo@10 807 #endif
meillo@393 808 if (r->pipe) {
meillo@10 809 g_free(r->pipe);
meillo@393 810 }
meillo@10 811 g_free(r);
meillo@10 812 }
meillo@10 813
meillo@10 814 GList*
meillo@366 815 read_route_list(GList *rf_list, gboolean is_perma)
meillo@10 816 {
meillo@10 817 GList *list = NULL;
meillo@10 818 GList *node;
meillo@10 819 uid_t saved_uid, saved_gid;
meillo@10 820
meillo@10 821 if (!conf.run_as_user) {
meillo@10 822 set_euidgid(0, 0, &saved_uid, &saved_gid);
meillo@10 823 }
meillo@10 824 foreach(rf_list, node) {
meillo@10 825 gchar *fname = (gchar *) (node->data);
meillo@354 826 connect_route *route = read_route(fname, is_perma);
meillo@393 827 if (route) {
meillo@10 828 list = g_list_append(list, route);
meillo@393 829 } else {
meillo@393 830 logwrite(LOG_ALERT, "could not read route "
meillo@393 831 "configuration %s\n", fname);
meillo@393 832 }
meillo@10 833 }
meillo@10 834 /* set uid and gid back */
meillo@10 835 if (!conf.run_as_user) {
meillo@10 836 set_euidgid(saved_uid, saved_gid, NULL, NULL);
meillo@10 837 }
meillo@10 838 return list;
meillo@10 839 }
meillo@10 840
meillo@10 841 void
meillo@366 842 destroy_route_list(GList *list)
meillo@10 843 {
meillo@10 844 GList *node;
meillo@10 845
meillo@10 846 foreach(list, node) {
meillo@10 847 connect_route *route = (connect_route *) (node->data);
meillo@10 848 destroy_route(route);
meillo@0 849 }
meillo@0 850 g_list_free(list);
meillo@0 851 }