masqmail

annotate src/conf.c @ 222:8cddc65765bd

added support for STARTTLS wrappers added the route config option `instant_helo' which causes masqmail, as SMTP client, not to wait for the server's 220 greeting. Instead if says EHLO right at once. You'll need this for STARTTLS wrappers that usually eat the greeting line.
author meillo@marmaro.de
date Fri, 23 Jul 2010 10:57:53 +0200
parents 0241aaccfcdb
children 996b53a50f55
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 1999-2001 Oliver Kurth
meillo@0 3
meillo@0 4 This program is free software; you can redistribute it and/or modify
meillo@0 5 it under the terms of the GNU General Public License as published by
meillo@0 6 the Free Software Foundation; either version 2 of the License, or
meillo@0 7 (at your option) any later version.
meillo@0 8
meillo@0 9 This program is distributed in the hope that it will be useful,
meillo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 12 GNU General Public License for more details.
meillo@0 13
meillo@0 14 You should have received a copy of the GNU General Public License
meillo@0 15 along with this program; if not, write to the Free Software
meillo@0 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0 17 */
meillo@0 18
meillo@13 19 #include <pwd.h>
meillo@13 20 #include <grp.h>
meillo@13 21
meillo@0 22 #include "masqmail.h"
meillo@0 23
meillo@0 24 masqmail_conf conf;
meillo@0 25
meillo@10 26 void
meillo@10 27 init_conf()
meillo@0 28 {
meillo@10 29 struct passwd *passwd;
meillo@10 30 struct group *group;
meillo@0 31
meillo@10 32 memset(&conf, 0, sizeof(masqmail_conf));
meillo@0 33
meillo@10 34 conf.orig_uid = getuid();
meillo@10 35 conf.orig_gid = getgid();
meillo@0 36
meillo@10 37 if ((passwd = getpwnam(DEF_MAIL_USER)))
meillo@10 38 conf.mail_uid = passwd->pw_uid;
meillo@10 39 else {
meillo@10 40 fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
meillo@10 41 exit(EXIT_FAILURE);
meillo@10 42 }
meillo@10 43 if ((group = getgrnam(DEF_MAIL_GROUP)))
meillo@10 44 conf.mail_gid = group->gr_gid;
meillo@10 45 else {
meillo@10 46 fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
meillo@10 47 exit(EXIT_FAILURE);
meillo@10 48 }
meillo@0 49 }
meillo@0 50
meillo@10 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@10 60 parse_boolean(gchar * rval)
meillo@0 61 {
meillo@10 62 gchar **str;
meillo@0 63
meillo@10 64 DEBUG(6) fprintf(stderr, "parse_boolean: %s\n", rval);
meillo@0 65
meillo@10 66 str = true_strings;
meillo@10 67 while (*str) {
meillo@10 68 if (strncasecmp(*str, rval, strlen(*str)) == 0)
meillo@10 69 return TRUE;
meillo@10 70 str++;
meillo@10 71 }
meillo@0 72
meillo@10 73 str = false_strings;
meillo@10 74 while (*str) {
meillo@10 75 if (strncasecmp(*str, rval, strlen(*str)) == 0)
meillo@10 76 return FALSE;
meillo@10 77 str++;
meillo@10 78 }
meillo@0 79
meillo@10 80 fprintf(stderr, "cannot parse value '%s'\n", rval);
meillo@10 81 exit(EXIT_FAILURE);
meillo@0 82 }
meillo@0 83
meillo@0 84 /* make a list from each line in a file */
meillo@10 85 static GList*
meillo@10 86 parse_list_file(gchar * fname)
meillo@0 87 {
meillo@10 88 GList *list = NULL;
meillo@10 89 FILE *fptr;
meillo@0 90
meillo@28 91 if ((fptr = fopen(fname, "rt")) == NULL) {
meillo@10 92 logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
meillo@10 93 exit(EXIT_FAILURE);
meillo@10 94 }
meillo@0 95
meillo@28 96 gchar buf[256];
meillo@28 97
meillo@28 98 while (!feof(fptr)) {
meillo@28 99 fgets(buf, 255, fptr);
meillo@28 100 if (buf[0] && (buf[0] != '#') && (buf[0] != '\n')) {
meillo@28 101 g_strchomp(buf);
meillo@114 102 DEBUG(6) fprintf(stderr,"parse_list_file: item = %s\n", buf);
meillo@28 103 list = g_list_append(list, g_strdup(buf));
meillo@28 104 }
meillo@28 105 }
meillo@28 106 fclose(fptr);
meillo@28 107
meillo@10 108 return list;
meillo@0 109 }
meillo@0 110
meillo@13 111 /* given a semicolon separated string, this function makes a GList out of it. */
meillo@10 112 GList*
meillo@10 113 parse_list(gchar * line, gboolean read_file)
meillo@0 114 {
meillo@10 115 GList *list = NULL;
meillo@10 116 gchar buf[256];
meillo@10 117 gchar *p, *q;
meillo@0 118
meillo@114 119 DEBUG(6) fprintf(stderr, "parsing list %s, file?:%d\n", line, read_file);
meillo@0 120
meillo@10 121 p = line;
meillo@14 122 while (*p != '\0') {
meillo@10 123 q = buf;
meillo@0 124
meillo@10 125 while (*p && (*p != ';') && (q < buf + 255))
meillo@10 126 *(q++) = *(p++);
meillo@14 127 *q = '\0';
meillo@0 128
meillo@10 129 if ((buf[0] == '/') && (read_file))
meillo@10 130 /* item is a filename, include its contents */
meillo@10 131 list = g_list_concat(list, parse_list_file(buf));
meillo@10 132 else
meillo@10 133 /* just a normal item */
meillo@10 134 list = g_list_append(list, g_strdup(buf));
meillo@0 135
meillo@114 136 DEBUG(6) fprintf(stderr, "item = %s\n", buf);
meillo@0 137
meillo@10 138 if (*p)
meillo@10 139 p++;
meillo@10 140 }
meillo@10 141 return list;
meillo@0 142 }
meillo@0 143
meillo@10 144 static GList*
meillo@10 145 parse_address_list(gchar * line, gboolean read_file)
meillo@0 146 {
meillo@10 147 GList *plain_list = parse_list(line, read_file);
meillo@10 148 GList *node;
meillo@10 149 GList *list = NULL;
meillo@0 150
meillo@10 151 foreach(plain_list, node) {
meillo@10 152 gchar *item = (gchar *) (node->data);
meillo@10 153 address *addr = create_address(item, TRUE);
meillo@10 154 if (addr)
meillo@10 155 list = g_list_append(list, addr);
meillo@10 156 g_free(item);
meillo@10 157 }
meillo@10 158 g_list_free(plain_list);
meillo@0 159
meillo@10 160 return list;
meillo@0 161 }
meillo@0 162
meillo@10 163 static GList*
meillo@10 164 parse_resolve_list(gchar * line)
meillo@0 165 {
meillo@10 166 GList *list;
meillo@10 167 GList *list_node;
meillo@10 168 GList *res_list = NULL;
meillo@0 169
meillo@10 170 list = parse_list(line, FALSE);
meillo@28 171 if (!list) {
meillo@28 172 return NULL;
meillo@28 173 }
meillo@28 174
meillo@28 175 foreach(list, list_node) {
meillo@28 176 gchar *item = (gchar *) (list_node->data);
meillo@28 177 if (strcmp(item, "byname") == 0) {
meillo@28 178 res_list = g_list_append(res_list, resolve_byname);
meillo@0 179 #ifdef ENABLE_RESOLVER
meillo@28 180 } else if (strcmp(item, "dns_a") == 0) {
meillo@28 181 res_list = g_list_append(res_list, resolve_dns_a);
meillo@28 182 } else if (strcmp(item, "dns_mx") == 0) {
meillo@28 183 res_list = g_list_append(res_list, resolve_dns_mx);
meillo@0 184 #endif
meillo@28 185 } else {
meillo@28 186 logwrite(LOG_ALERT, "unknown resolver %s\n", item);
meillo@28 187 exit(EXIT_FAILURE);
meillo@10 188 }
meillo@28 189 g_free(item);
meillo@10 190 }
meillo@28 191 g_list_free(list);
meillo@10 192 return res_list;
meillo@0 193 }
meillo@0 194
meillo@10 195 static interface*
meillo@10 196 parse_interface(gchar * line, gint def_port)
meillo@0 197 {
meillo@10 198 gchar buf[256];
meillo@10 199 gchar *p, *q;
meillo@10 200 interface *iface;
meillo@0 201
meillo@10 202 DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
meillo@0 203
meillo@10 204 p = line;
meillo@10 205 q = buf;
meillo@14 206 while ((*p != '\0') && (*p != ':') && (q < buf + 255))
meillo@10 207 *(q++) = *(p++);
meillo@14 208 *q = '\0';
meillo@0 209
meillo@10 210 iface = g_malloc(sizeof(interface));
meillo@10 211 iface->address = g_strdup(buf);
meillo@0 212
meillo@10 213 if (*p) {
meillo@10 214 p++;
meillo@10 215 iface->port = atoi(p);
meillo@10 216 } else
meillo@10 217 iface->port = def_port;
meillo@114 218 DEBUG(6) fprintf(stderr,"rval=%s, address:port=%s:%i\n",line, iface->address, iface->port);
meillo@0 219
meillo@10 220 return iface;
meillo@0 221 }
meillo@0 222
meillo@10 223 #ifdef ENABLE_IDENT /* so far used for that only */
meillo@10 224 static struct in_addr*
meillo@10 225 parse_network(gchar * line, gint def_port)
meillo@0 226 {
meillo@10 227 gchar buf[256];
meillo@10 228 gchar *p, *q;
meillo@10 229 struct in_addr addr, mask_addr, net_addr, *p_net_addr;
meillo@10 230 guint n;
meillo@0 231
meillo@10 232 DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
meillo@0 233
meillo@10 234 p = line;
meillo@10 235 q = buf;
meillo@14 236 while ((*p != '\0') && (*p != '/') && (q < buf + 255))
meillo@10 237 *(q++) = *(p++);
meillo@14 238 *q = '\0';
meillo@0 239
meillo@28 240 if ((addr.s_addr = inet_addr(buf)) == INADDR_NONE) {
meillo@10 241 fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
meillo@10 242 exit(EXIT_FAILURE);
meillo@10 243 }
meillo@10 244
meillo@28 245 if (*p) {
meillo@28 246 guint i;
meillo@28 247 p++;
meillo@28 248 i = atoi(p);
meillo@28 249 if ((i >= 0) && (i <= 32))
meillo@28 250 n = i ? ~((1 << (32 - i)) - 1) : 0;
meillo@28 251 else {
meillo@28 252 fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
meillo@28 253 exit(EXIT_FAILURE);
meillo@28 254 }
meillo@28 255 } else
meillo@28 256 n = 0;
meillo@28 257
meillo@28 258 mask_addr.s_addr = htonl(n);
meillo@28 259 net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
meillo@28 260
meillo@10 261 p_net_addr = g_malloc(sizeof(struct in_addr));
meillo@10 262 p_net_addr->s_addr = net_addr.s_addr;
meillo@10 263 return p_net_addr;
meillo@0 264 }
meillo@0 265 #endif
meillo@0 266
meillo@10 267 static gboolean
meillo@10 268 eat_comments(FILE * in)
meillo@0 269 {
meillo@10 270 gint c;
meillo@0 271
meillo@10 272 for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
meillo@10 273 c = fgetc(in)) {
meillo@10 274 if (c == '#') {
meillo@10 275 gint c;
meillo@10 276 for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
meillo@10 277 }
meillo@10 278 }
meillo@10 279 if (c == EOF)
meillo@10 280 return FALSE;
meillo@10 281 ungetc(c, in);
meillo@10 282 return TRUE;
meillo@0 283 }
meillo@0 284
meillo@0 285 /* after parsing, eat trailing character until LF */
meillo@10 286 static gboolean
meillo@10 287 eat_line_trailing(FILE * in)
meillo@0 288 {
meillo@10 289 gint c;
meillo@0 290
meillo@10 291 for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
meillo@10 292 if (c == EOF)
meillo@10 293 return FALSE;
meillo@10 294 return TRUE;
meillo@0 295 }
meillo@0 296
meillo@10 297 static gboolean
meillo@10 298 eat_spaces(FILE * in)
meillo@0 299 {
meillo@10 300 gint c;
meillo@10 301
meillo@28 302 for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
meillo@28 303 /* empty */
meillo@28 304 }
meillo@10 305 if (c == EOF)
meillo@10 306 return FALSE;
meillo@10 307 ungetc(c, in);
meillo@10 308 return TRUE;
meillo@0 309 }
meillo@0 310
meillo@10 311 static gboolean
meillo@10 312 read_lval(FILE * in, gchar * buf, gint size)
meillo@0 313 {
meillo@10 314 gint c;
meillo@10 315 gchar *ptr = buf;
meillo@0 316
meillo@10 317 DEBUG(6) fprintf(stderr, "read_lval()\n");
meillo@0 318
meillo@10 319 if (!eat_spaces(in))
meillo@10 320 return FALSE;
meillo@0 321
meillo@10 322 c = fgetc(in);
meillo@10 323 DEBUG(6) fprintf(stderr, "read_lval() 2\n");
meillo@10 324 while ((isalnum(c) || c == '_' || c == '-' || c == '.')
meillo@10 325 && (ptr < buf + size - 1)
meillo@10 326 && (c != EOF)) {
meillo@10 327 *ptr = c;
meillo@10 328 ptr++;
meillo@10 329 c = fgetc(in);
meillo@10 330 }
meillo@14 331 *ptr = '\0';
meillo@10 332 ungetc(c, in);
meillo@0 333
meillo@10 334 if (c == EOF) {
meillo@10 335 fprintf(stderr, "unexpected EOF after %s\n", buf);
meillo@10 336 return FALSE;
meillo@10 337 } else if (ptr >= buf + size - 1) {
meillo@10 338 fprintf(stderr, "lval too long\n");
meillo@10 339 }
meillo@0 340
meillo@10 341 eat_spaces(in);
meillo@0 342
meillo@10 343 DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
meillo@10 344
meillo@14 345 return buf[0] != '\0';
meillo@0 346 }
meillo@0 347
meillo@10 348 static gboolean
meillo@10 349 read_rval(FILE * in, gchar * buf, gint size)
meillo@0 350 {
meillo@10 351 gint c;
meillo@10 352 gchar *ptr = buf;
meillo@0 353
meillo@10 354 DEBUG(6) fprintf(stderr, "read_rval()\n");
meillo@0 355
meillo@10 356 if (!eat_spaces(in))
meillo@10 357 return FALSE;
meillo@10 358
meillo@10 359 c = fgetc(in);
meillo@10 360 if (c != '\"') {
meillo@115 361 while ((isalnum(c) || c == '_' || c == '-' || c == '.'
meillo@115 362 || c == '/' || c == '@' || c == ';' || c == ':')
meillo@10 363 && (ptr < buf + size - 1)
meillo@10 364 && (c != EOF)) {
meillo@10 365 *ptr = c;
meillo@10 366 ptr++;
meillo@10 367 c = fgetc(in);
meillo@10 368 }
meillo@14 369 *ptr = '\0';
meillo@10 370 ungetc(c, in);
meillo@10 371 } else {
meillo@10 372 gboolean escape = FALSE;
meillo@10 373 c = fgetc(in);
meillo@10 374 while (((c != '\"') || escape) && (ptr < buf + size - 1)) {
meillo@13 375 if (c != '\n') { /* ignore line breaks */
meillo@10 376 if ((c == '\\') && (!escape)) {
meillo@10 377 escape = TRUE;
meillo@10 378 } else {
meillo@10 379 *ptr = c;
meillo@10 380 ptr++;
meillo@10 381 escape = FALSE;
meillo@10 382 }
meillo@10 383 }
meillo@10 384 c = fgetc(in);
meillo@10 385 }
meillo@14 386 *ptr = '\0';
meillo@0 387 }
meillo@0 388
meillo@10 389 eat_line_trailing(in);
meillo@0 390
meillo@10 391 DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
meillo@10 392
meillo@10 393 return TRUE;
meillo@0 394 }
meillo@0 395
meillo@10 396 static gboolean
meillo@10 397 read_statement(FILE * in, gchar * lval, gint lsize, gchar * rval, gint rsize)
meillo@0 398 {
meillo@10 399 gint c;
meillo@0 400
meillo@10 401 DEBUG(6) fprintf(stderr, "read_statement()\n");
meillo@0 402
meillo@10 403 /* eat comments and empty lines: */
meillo@10 404 if (!eat_comments(in))
meillo@10 405 return FALSE;
meillo@0 406
meillo@28 407 if (!read_lval(in, lval, lsize)) {
meillo@28 408 return FALSE;
meillo@28 409 }
meillo@28 410
meillo@114 411 DEBUG(6) fprintf(stderr, " lval = %s\n", lval);
meillo@28 412 if ((c = fgetc(in) == '=')) {
meillo@28 413 if (read_rval(in, rval, rsize)) {
meillo@114 414 DEBUG(6) fprintf(stderr, " rval = %s\n", rval);
meillo@28 415 return TRUE;
meillo@10 416 }
meillo@28 417 } else {
meillo@114 418 DEBUG(6) fprintf(stderr," '=' expected after %s, char was '%c'\n", lval, c);
meillo@28 419 fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
meillo@10 420 }
meillo@10 421 return FALSE;
meillo@0 422 }
meillo@0 423
meillo@10 424 gboolean
meillo@10 425 read_conf(gchar * filename)
meillo@0 426 {
meillo@10 427 FILE *in;
meillo@0 428
meillo@10 429 conf.log_max_pri = 7;
meillo@10 430 conf.do_relay = TRUE;
meillo@10 431 conf.alias_local_cmp = strcmp;
meillo@10 432 conf.max_defer_time = 86400 * 4; /* 4 days */
meillo@120 433 conf.max_msg_size = 0; /* no limit on msg size */
meillo@151 434 conf.spool_dir = SPOOL_DIR;
meillo@152 435 conf.mail_dir = "/var/mail";
meillo@206 436 /* we use 127.0.0.1 because `localhost' could be bound to some
meillo@206 437 other IP address. This is unlikely but could be. Using
meillo@206 438 127.0.0.1 is more safe. See mailing list for details */
meillo@206 439 conf.listen_addresses = g_list_append(NULL, parse_interface("127.0.0.1", 25));
meillo@0 440
meillo@28 441 if ((in = fopen(filename, "r")) == NULL) {
meillo@155 442 logwrite(LOG_ALERT, "could not open config file %s: %s\n", filename, strerror(errno));
meillo@28 443 return FALSE;
meillo@28 444 }
meillo@28 445
meillo@28 446 gchar lval[256], rval[2048];
meillo@28 447 while (read_statement(in, lval, 256, rval, 2048)) {
meillo@114 448 DEBUG(6) fprintf(stderr,"read_conf(): lval=%s\n", lval);
meillo@28 449 if (strcmp(lval, "debug_level") == 0)
meillo@28 450 conf.debug_level = atoi(rval);
meillo@28 451 else if (strcmp(lval, "run_as_user") == 0) {
meillo@28 452 if (!conf.run_as_user) /* you should not be able to reset that flag */
meillo@28 453 conf.run_as_user = parse_boolean(rval);
meillo@28 454 } else if (strcmp(lval, "use_syslog") == 0)
meillo@28 455 conf.use_syslog = parse_boolean(rval);
meillo@28 456 else if (strcmp(lval, "mail_dir") == 0)
meillo@28 457 conf.mail_dir = g_strdup(rval);
meillo@28 458 else if (strcmp(lval, "lock_dir") == 0)
meillo@28 459 conf.lock_dir = g_strdup(rval);
meillo@28 460 else if (strcmp(lval, "spool_dir") == 0)
meillo@28 461 conf.spool_dir = g_strdup(rval);
meillo@28 462 else if (strcmp(lval, "log_dir") == 0)
meillo@28 463 conf.log_dir = g_strdup(rval);
meillo@28 464 else if (strcmp(lval, "host_name") == 0) {
meillo@28 465 if (rval[0] != '/')
meillo@28 466 conf.host_name = g_strdup(rval);
meillo@28 467 else {
meillo@28 468 char buf[256];
meillo@28 469 FILE *fptr = fopen(rval, "rt");
meillo@28 470 if (fptr) {
meillo@155 471 logwrite(LOG_ALERT, "could not open %s: %s\n", rval, strerror(errno));
meillo@28 472 return FALSE;
meillo@10 473 }
meillo@28 474 fgets(buf, 255, fptr);
meillo@28 475 g_strchomp(buf);
meillo@28 476 conf.host_name = g_strdup(buf);
meillo@28 477 fclose(fptr);
meillo@28 478 }
meillo@28 479 } else if (strcmp(lval, "local_hosts") == 0)
meillo@28 480 conf.local_hosts = parse_list(rval, FALSE);
meillo@28 481 else if (strcmp(lval, "local_addresses") == 0)
meillo@28 482 conf.local_addresses = parse_list(rval, TRUE);
meillo@28 483 else if (strcmp(lval, "not_local_addresses") == 0)
meillo@28 484 conf.not_local_addresses = parse_list(rval, TRUE);
meillo@28 485 else if (strcmp(lval, "local_nets") == 0)
meillo@28 486 conf.local_nets = parse_list(rval, FALSE);
meillo@28 487 else if (strcmp(lval, "do_save_envelope_to") == 0)
meillo@28 488 conf.do_save_envelope_to = parse_boolean(rval);
meillo@28 489 else if (strcmp(lval, "defer_all") == 0)
meillo@28 490 conf.defer_all = parse_boolean(rval);
meillo@28 491 else if (strcmp(lval, "do_relay") == 0)
meillo@28 492 conf.do_relay = parse_boolean(rval);
meillo@28 493 else if (strcmp(lval, "alias_file") == 0) {
meillo@28 494 conf.alias_file = g_strdup(rval);
meillo@28 495 } else if (strcmp(lval, "alias_local_caseless") == 0) {
meillo@28 496 conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
meillo@28 497 } else if (strcmp(lval, "mbox_default") == 0) {
meillo@28 498 conf.mbox_default = g_strdup(rval);
meillo@28 499 } else if (strcmp(lval, "mbox_users") == 0) {
meillo@28 500 conf.mbox_users = parse_list(rval, TRUE);
meillo@28 501 } else if (strcmp(lval, "mda_users") == 0) {
meillo@28 502 conf.mda_users = parse_list(rval, TRUE);
meillo@28 503 } else if (strcmp(lval, "mda") == 0) {
meillo@28 504 conf.mda = g_strdup(rval);
meillo@28 505 } else if (strcmp(lval, "mda_fromline") == 0) {
meillo@28 506 conf.mda_fromline = parse_boolean(rval);
meillo@28 507 } else if (strcmp(lval, "mda_fromhack") == 0) {
meillo@28 508 conf.mda_fromhack = parse_boolean(rval);
meillo@28 509 } else if (strcmp(lval, "pipe_fromline") == 0) {
meillo@28 510 conf.pipe_fromline = parse_boolean(rval);
meillo@28 511 } else if (strcmp(lval, "pipe_fromhack") == 0) {
meillo@28 512 conf.pipe_fromhack = parse_boolean(rval);
meillo@28 513 } else if (strcmp(lval, "listen_addresses") == 0) {
meillo@28 514 GList *node;
meillo@28 515 GList *tmp_list = parse_list(rval, FALSE);
meillo@0 516
meillo@28 517 conf.listen_addresses = NULL;
meillo@28 518 foreach(tmp_list, node) {
meillo@28 519 conf.listen_addresses = g_list_append(conf.listen_addresses, parse_interface((gchar *) (node-> data), 25));
meillo@28 520 g_free(node->data);
meillo@28 521 }
meillo@28 522 g_list_free(tmp_list);
meillo@28 523 } else if (strcmp(lval, "ident_trusted_nets") == 0) {
meillo@10 524 #ifdef ENABLE_IDENT
meillo@28 525 GList *node;
meillo@28 526 GList *tmp_list = parse_list(rval, FALSE);
meillo@0 527
meillo@28 528 conf.ident_trusted_nets = NULL;
meillo@28 529 foreach(tmp_list, node) {
meillo@28 530 conf.ident_trusted_nets = g_list_append(conf.ident_trusted_nets, parse_network((gchar *) (node->data), 25));
meillo@28 531 g_free(node->data);
meillo@28 532 }
meillo@28 533 g_list_free(tmp_list);
meillo@10 534 #else
meillo@155 535 logwrite(LOG_WARNING, "%s ignored: not compiled with ident support\n", lval);
meillo@10 536 #endif
meillo@28 537 } else if ((strncmp(lval, "connect_route.", 14) == 0)
meillo@28 538 || (strncmp(lval, "online_routes.", 14) == 0)) {
meillo@28 539 GList *file_list = parse_list(rval, FALSE);
meillo@28 540 table_pair *pair = create_pair(&(lval[14]), file_list);
meillo@28 541 conf.connect_routes = g_list_append(conf.connect_routes, pair);
meillo@28 542 } else if (strcmp(lval, "local_net_route") == 0) {
meillo@28 543 conf.local_net_routes = parse_list(rval, FALSE);
meillo@28 544 } else if (strcmp(lval, "online_detect") == 0)
meillo@28 545 conf.online_detect = g_strdup(rval);
meillo@28 546 else if (strcmp(lval, "online_file") == 0)
meillo@28 547 conf.online_file = g_strdup(rval);
meillo@28 548 else if (strcmp(lval, "online_pipe") == 0)
meillo@28 549 conf.online_pipe = g_strdup(rval);
meillo@28 550 else if (strcmp(lval, "do_queue") == 0)
meillo@28 551 conf.do_queue = parse_boolean(rval);
meillo@192 552 else if (strcmp(lval, "errmsg_file") == 0)
meillo@28 553 conf.errmsg_file = g_strdup(rval);
meillo@28 554 else if (strcmp(lval, "warnmsg_file") == 0)
meillo@28 555 conf.warnmsg_file = g_strdup(rval);
meillo@28 556 else if (strcmp(lval, "warn_intervals") == 0)
meillo@28 557 conf.warn_intervals = parse_list(rval, FALSE);
meillo@28 558 else if (strcmp(lval, "max_defer_time") == 0) {
meillo@28 559 gint dummy;
meillo@28 560 gint ival = time_interval(rval, &dummy);
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@28 899 route->name = g_strdup("local_net (default)");
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 }