masqmail

annotate src/conf.c @ 209:10da50168dab

replaced the MD5 implementation with the one of Solar Designer Until now, the sample code of RFC 1321 was used. It had an ugly license. Now we use the implementation of Solar Designer, which is in the Public Domain. http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
author meillo@marmaro.de
date Sun, 18 Jul 2010 21:58:15 +0200
parents 4fd237550525
children 8cddc65765bd
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@28 654 else if (strcmp(lval, "do_pipelining") == 0)
meillo@28 655 route->do_pipelining = parse_boolean(rval);
meillo@28 656 else if (strcmp(lval, "allowed_return_paths") == 0)
meillo@28 657 route->allowed_return_paths = parse_address_list(rval, TRUE);
meillo@28 658 else if (strcmp(lval, "allowed_mail_locals") == 0)
meillo@28 659 route->allowed_mail_locals = parse_list(rval, TRUE);
meillo@28 660 else if (strcmp(lval, "not_allowed_return_paths") == 0)
meillo@28 661 route->not_allowed_return_paths = parse_address_list(rval, TRUE);
meillo@28 662 else if (strcmp(lval, "not_allowed_mail_locals") == 0)
meillo@28 663 route->not_allowed_mail_locals = parse_list(rval, TRUE);
meillo@28 664 else if (strcmp(lval, "allowed_rcpt_domains") == 0)
meillo@28 665 route->allowed_rcpt_domains = parse_list(rval, TRUE);
meillo@28 666 else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
meillo@28 667 route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
meillo@28 668 else if (strcmp(lval, "set_h_from_domain") == 0)
meillo@28 669 route->set_h_from_domain = g_strdup(rval);
meillo@28 670 else if (strcmp(lval, "set_h_reply_to_domain") == 0)
meillo@28 671 route->set_h_reply_to_domain = g_strdup(rval);
meillo@28 672 else if (strcmp(lval, "set_return_path_domain") == 0)
meillo@28 673 route->set_return_path_domain = g_strdup(rval);
meillo@28 674 else if (strcmp(lval, "map_return_path_addresses") == 0) {
meillo@28 675 GList *node, *list;
meillo@10 676
meillo@28 677 list = parse_list(rval, TRUE);
meillo@28 678 foreach(list, node) {
meillo@28 679 gchar *item = (gchar *) (node->data);
meillo@28 680 table_pair *pair = parse_table_pair(item, ':');
meillo@28 681 address *addr = create_address((gchar *) (pair->value), TRUE);
meillo@28 682 g_free(pair->value);
meillo@28 683 pair->value = (gpointer *) addr;
meillo@28 684 route->map_return_path_addresses = g_list_append(route->map_return_path_addresses, pair);
meillo@28 685 g_free(item);
meillo@28 686 }
meillo@28 687 g_list_free(list);
meillo@28 688 } else if (strcmp(lval, "map_h_from_addresses") == 0) {
meillo@28 689 GList *list, *node;
meillo@10 690
meillo@28 691 list = parse_list(rval, TRUE);
meillo@28 692 foreach(list, node) {
meillo@28 693 gchar *item = (gchar *) (node->data);
meillo@28 694 table_pair *pair = parse_table_pair(item, ':');
meillo@28 695 route->map_h_from_addresses = g_list_append(route->map_h_from_addresses, pair);
meillo@28 696 g_free(item);
meillo@28 697 }
meillo@28 698 g_list_free(list);
meillo@28 699 } else if (strcmp(lval, "map_h_reply_to_addresses") == 0) {
meillo@28 700 GList *list, *node;
meillo@10 701
meillo@28 702 list = parse_list(rval, TRUE);
meillo@28 703 foreach(list, node) {
meillo@28 704 gchar *item = (gchar *) (node->data);
meillo@28 705 table_pair *pair = parse_table_pair(item, ':');
meillo@28 706 route->map_h_reply_to_addresses = g_list_append(route->map_h_reply_to_addresses, pair);
meillo@28 707 g_free(item);
meillo@10 708 }
meillo@28 709 g_list_free(list);
meillo@28 710 } else if (strcmp(lval, "map_h_mail_followup_to_addresses") == 0) {
meillo@28 711 GList *list, *node;
meillo@28 712
meillo@28 713 list = parse_list(rval, TRUE);
meillo@28 714 foreach(list, node) {
meillo@28 715 gchar *item = (gchar *) (node->data);
meillo@28 716 table_pair *pair = parse_table_pair(item, ':');
meillo@28 717 route->map_h_mail_followup_to_addresses = g_list_append(route->map_h_mail_followup_to_addresses, pair);
meillo@28 718 g_free(item);
meillo@28 719 }
meillo@28 720 g_list_free(list);
meillo@28 721 } else if (strcmp(lval, "expand_h_sender_domain") == 0) {
meillo@28 722 route->expand_h_sender_domain = parse_boolean(rval);
meillo@28 723 } else if (strcmp(lval, "expand_h_sender_address") == 0) {
meillo@28 724 route->expand_h_sender_address = parse_boolean(rval);
meillo@28 725 } else if (strcmp(lval, "resolve_list") == 0)
meillo@28 726 route->resolve_list = parse_resolve_list(rval);
meillo@28 727 else if (strcmp(lval, "do_ssl") == 0) {
meillo@28 728 /* we ignore this. This option is used by sqilconf */
meillo@28 729 ;
meillo@28 730 }
meillo@10 731 #ifdef ENABLE_AUTH
meillo@28 732 else if (strcmp(lval, "auth_name") == 0) {
meillo@28 733 route->auth_name = g_strdup(rval);
meillo@28 734 } else if (strcmp(lval, "auth_login") == 0) {
meillo@28 735 route->auth_login = g_strdup(rval);
meillo@28 736 } else if (strcmp(lval, "auth_secret") == 0) {
meillo@28 737 route->auth_secret = g_strdup(rval);
meillo@28 738 }
meillo@10 739 #else
meillo@28 740 else if ((strcmp(lval, "auth_name") == 0)
meillo@28 741 || (strcmp(lval, "auth_login") == 0)
meillo@28 742 || (strcmp(lval, "auth_secret") == 0)) {
meillo@28 743 logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
meillo@28 744 }
meillo@10 745 #endif
meillo@190 746 else if (strcmp(lval, "pipe") == 0) {
meillo@28 747 route->pipe = g_strdup(rval);
meillo@28 748 } else if (strcmp(lval, "pipe_fromline") == 0) {
meillo@28 749 route->pipe_fromline = parse_boolean(rval);
meillo@28 750 } else if (strcmp(lval, "pipe_fromhack") == 0) {
meillo@28 751 route->pipe_fromhack = parse_boolean(rval);
meillo@28 752 } else if (strcmp(lval, "last_route") == 0) {
meillo@28 753 route->last_route = parse_boolean(rval);
meillo@28 754 } else
meillo@28 755 logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
meillo@28 756 }
meillo@28 757
meillo@28 758 if (route->resolve_list == NULL) {
meillo@28 759 if (is_local_net) {
meillo@28 760 route->resolve_list = g_list_append(NULL, resolve_byname);
meillo@28 761 } else {
meillo@28 762 #ifdef ENABLE_RESOLVER
meillo@28 763 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_mx);
meillo@28 764 route->resolve_list = g_list_append(route->resolve_list, resolve_dns_a);
meillo@28 765 #endif
meillo@28 766 route->resolve_list = g_list_append(route->resolve_list, resolve_byname);
meillo@10 767 }
meillo@28 768 }
meillo@28 769 fclose(in);
meillo@28 770 ok = TRUE;
meillo@10 771
meillo@28 772 /* warn user about misconfigurations: */
meillo@28 773 if ((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)) {
meillo@28 774 logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
meillo@28 775 g_free(route->set_h_from_domain);
meillo@28 776 route->set_h_from_domain = NULL;
meillo@28 777 }
meillo@28 778 if ((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)) {
meillo@28 779 logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
meillo@28 780 g_free(route->set_h_reply_to_domain);
meillo@28 781 route->set_h_reply_to_domain = NULL;
meillo@10 782 }
meillo@10 783
meillo@10 784 if (!ok) {
meillo@10 785 g_free(route);
meillo@10 786 route = NULL;
meillo@10 787 }
meillo@10 788
meillo@10 789 return route;
meillo@10 790 }
meillo@10 791
meillo@10 792 static void
meillo@10 793 _g_list_free_all(GList * list)
meillo@10 794 {
meillo@10 795 GList *node;
meillo@10 796 if (list) {
meillo@10 797 foreach(list, node)
meillo@10 798 g_free(node->data);
meillo@10 799 g_list_free(list);
meillo@10 800 }
meillo@10 801 }
meillo@10 802
meillo@10 803 void
meillo@10 804 destroy_route(connect_route * r)
meillo@10 805 {
meillo@10 806 if (r->filename)
meillo@10 807 g_free(r->filename);
meillo@10 808 if (r->protocol)
meillo@10 809 g_free(r->protocol);
meillo@10 810 if (r->mail_host) {
meillo@10 811 g_free(r->mail_host->address);
meillo@10 812 g_free(r->mail_host);
meillo@10 813 }
meillo@10 814 if (r->wrapper)
meillo@10 815 g_free(r->wrapper);
meillo@10 816 if (r->helo_name)
meillo@10 817 g_free(r->helo_name);
meillo@10 818 _g_list_free_all(r->allowed_mail_locals);
meillo@10 819 _g_list_free_all(r->not_allowed_mail_locals);
meillo@10 820 _g_list_free_all(r->allowed_rcpt_domains);
meillo@10 821 _g_list_free_all(r->not_allowed_rcpt_domains);
meillo@10 822 if (r->set_h_from_domain)
meillo@10 823 g_free(r->set_h_from_domain);
meillo@10 824 if (r->set_h_reply_to_domain)
meillo@10 825 g_free(r->set_h_reply_to_domain);
meillo@10 826 if (r->set_return_path_domain)
meillo@10 827 g_free(r->set_return_path_domain);
meillo@10 828 if (r->map_h_reply_to_addresses)
meillo@10 829 destroy_table(r->map_h_reply_to_addresses);
meillo@10 830 if (r->resolve_list)
meillo@10 831 g_list_free(r->resolve_list);
meillo@10 832 #ifdef ENABLE_AUTH
meillo@10 833 if (r->auth_name)
meillo@10 834 g_free(r->auth_name);
meillo@10 835 if (r->auth_login)
meillo@10 836 g_free(r->auth_login);
meillo@10 837 if (r->auth_secret)
meillo@10 838 g_free(r->auth_secret);
meillo@10 839 #endif
meillo@10 840 if (r->pipe)
meillo@10 841 g_free(r->pipe);
meillo@10 842 g_free(r);
meillo@10 843 }
meillo@10 844
meillo@10 845 GList*
meillo@10 846 read_route_list(GList * rf_list, gboolean is_local_net)
meillo@10 847 {
meillo@10 848 GList *list = NULL;
meillo@10 849 GList *node;
meillo@10 850 uid_t saved_uid, saved_gid;
meillo@10 851
meillo@10 852 if (!conf.run_as_user) {
meillo@10 853 set_euidgid(0, 0, &saved_uid, &saved_gid);
meillo@10 854 }
meillo@10 855
meillo@10 856 foreach(rf_list, node) {
meillo@10 857 gchar *fname = (gchar *) (node->data);
meillo@10 858 connect_route *route = read_route(fname, is_local_net);
meillo@10 859 if (route)
meillo@10 860 list = g_list_append(list, route);
meillo@10 861 else
meillo@10 862 logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
meillo@10 863 }
meillo@10 864
meillo@10 865 /* set uid and gid back */
meillo@10 866 if (!conf.run_as_user) {
meillo@10 867 set_euidgid(saved_uid, saved_gid, NULL, NULL);
meillo@10 868 }
meillo@10 869
meillo@10 870 return list;
meillo@10 871 }
meillo@10 872
meillo@10 873 void
meillo@10 874 destroy_route_list(GList * list)
meillo@10 875 {
meillo@10 876 GList *node;
meillo@10 877
meillo@10 878 foreach(list, node) {
meillo@10 879 connect_route *route = (connect_route *) (node->data);
meillo@10 880 destroy_route(route);
meillo@0 881 }
meillo@0 882 g_list_free(list);
meillo@0 883 }
meillo@0 884
meillo@10 885 connect_route*
meillo@10 886 create_local_route()
meillo@0 887 {
meillo@10 888 connect_route *route;
meillo@0 889
meillo@10 890 route = g_malloc(sizeof(connect_route));
meillo@28 891 if (!route) {
meillo@28 892 return NULL;
meillo@10 893 }
meillo@28 894 memset(route, 0, sizeof(connect_route));
meillo@28 895 route->protocol = g_strdup("smtp");
meillo@28 896 route->is_local_net = TRUE;
meillo@28 897 route->name = g_strdup("local_net (default)");
meillo@28 898 route->expand_h_sender_address = TRUE;
meillo@28 899 route->resolve_list = g_list_append(NULL, resolve_byname);
meillo@28 900 route->connect_error_fail = TRUE;
meillo@10 901 return route;
meillo@0 902 }