masqmail

annotate src/conf.c @ 281:ea5f86e0a81c

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