masqmail-0.2

diff src/conf.c @ 0:08114f7dcc23

this is masqmail-0.2.21 from oliver kurth
author meillo@marmaro.de
date Fri, 26 Sep 2008 17:05:23 +0200
parents
children 26e34ae9a3e3
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/conf.c	Fri Sep 26 17:05:23 2008 +0200
     1.3 @@ -0,0 +1,995 @@
     1.4 +/*  MasqMail
     1.5 +    Copyright (C) 1999-2001 Oliver Kurth
     1.6 +
     1.7 +    This program is free software; you can redistribute it and/or modify
     1.8 +    it under the terms of the GNU General Public License as published by
     1.9 +    the Free Software Foundation; either version 2 of the License, or
    1.10 +    (at your option) any later version.
    1.11 +
    1.12 +    This program is distributed in the hope that it will be useful,
    1.13 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 +    GNU General Public License for more details.
    1.16 +
    1.17 +    You should have received a copy of the GNU General Public License
    1.18 +    along with this program; if not, write to the Free Software
    1.19 +    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    1.20 +*/
    1.21 +
    1.22 +#include "masqmail.h"
    1.23 +
    1.24 +#include "pwd.h"
    1.25 +#include "grp.h"
    1.26 +
    1.27 +masqmail_conf conf;
    1.28 +
    1.29 +void init_conf()
    1.30 +{
    1.31 +  struct passwd *passwd;
    1.32 +  struct group *group;
    1.33 +
    1.34 +  memset(&conf, 0, sizeof(masqmail_conf));
    1.35 +
    1.36 +  conf.orig_uid = getuid();
    1.37 +  conf.orig_gid = getgid();
    1.38 +
    1.39 +  if((passwd = getpwnam(DEF_MAIL_USER)))
    1.40 +    conf.mail_uid = passwd->pw_uid;
    1.41 +  else{
    1.42 +    fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
    1.43 +    exit(EXIT_FAILURE);
    1.44 +  }
    1.45 +  if((group = getgrnam(DEF_MAIL_GROUP)))
    1.46 +    conf.mail_gid = group->gr_gid;
    1.47 +  else{
    1.48 +    fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
    1.49 +    exit(EXIT_FAILURE);
    1.50 +  }
    1.51 +}
    1.52 +
    1.53 +static gchar *true_strings[] =
    1.54 +{
    1.55 +  "yes", "on", "true", NULL
    1.56 +};
    1.57 +
    1.58 +static gchar *false_strings[] =
    1.59 +{
    1.60 +  "no", "off", "false", NULL
    1.61 +};
    1.62 +
    1.63 +static
    1.64 +gboolean parse_boolean(gchar *rval)
    1.65 +{
    1.66 +  gchar **str;
    1.67 +
    1.68 +  DEBUG(6) fprintf(stderr, "parse_boolean: %s\n", rval);
    1.69 +
    1.70 +  str = true_strings;
    1.71 +  while(*str){
    1.72 +    if(strncasecmp(*str, rval, strlen(*str)) == 0)
    1.73 +      return TRUE;
    1.74 +    str++;
    1.75 +  }
    1.76 +
    1.77 +  str = false_strings;
    1.78 +  while(*str){
    1.79 +    if(strncasecmp(*str, rval, strlen(*str)) == 0)
    1.80 +      return FALSE;
    1.81 +    str++;
    1.82 +  }
    1.83 +
    1.84 +  fprintf(stderr, "cannot parse value '%s'\n", rval);
    1.85 +  exit(EXIT_FAILURE);
    1.86 +}
    1.87 +
    1.88 +/* make a list from each line in a file */
    1.89 +static
    1.90 +GList *parse_list_file(gchar *fname)
    1.91 +{
    1.92 +  GList *list = NULL;
    1.93 +  FILE *fptr;
    1.94 +
    1.95 +  if((fptr = fopen(fname, "rt"))){
    1.96 +    gchar buf[256];
    1.97 +
    1.98 +    while(!feof(fptr)){
    1.99 +      fgets(buf, 255, fptr);
   1.100 +      if(buf[0] && (buf[0] != '#') && (buf[0] != '\n')){
   1.101 +	g_strchomp(buf);
   1.102 +	list = g_list_append(list, g_strdup(buf));
   1.103 +      }
   1.104 +    }
   1.105 +    fclose(fptr);
   1.106 +  }else{
   1.107 +    logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
   1.108 +    exit(EXIT_FAILURE);
   1.109 +  }
   1.110 +
   1.111 +  return list;
   1.112 +}
   1.113 +
   1.114 +/* given a semicolon separated string, this function
   1.115 +   makes a GList out of it.
   1.116 +*/
   1.117 +GList *parse_list(gchar *line, gboolean read_file)
   1.118 +{
   1.119 +  GList *list = NULL;
   1.120 +  gchar buf[256];
   1.121 +  gchar *p, *q;
   1.122 +
   1.123 +  DEBUG(6) fprintf(stderr, "parsing list %s\n", line);
   1.124 +
   1.125 +  p = line;
   1.126 +  while(*p != 0){
   1.127 +    q = buf;
   1.128 +
   1.129 +    while(*p && (*p != ';') && (q < buf+255))
   1.130 +      *(q++) = *(p++);
   1.131 +    *q = 0;
   1.132 +
   1.133 +    if((buf[0] == '/') && (read_file))
   1.134 +      /* item is a filename, include its contents */
   1.135 +      list = g_list_concat(list, parse_list_file(buf));
   1.136 +    else
   1.137 +      /* just a normal item */
   1.138 +      list = g_list_append(list, g_strdup(buf));
   1.139 +
   1.140 +    DEBUG(6) printf("item = %s\n", buf);
   1.141 +
   1.142 +    if(*p) p++;
   1.143 +  }
   1.144 +  return list;
   1.145 +}
   1.146 +
   1.147 +static
   1.148 +GList *parse_address_list(gchar *line, gboolean read_file)
   1.149 +{
   1.150 +  GList *plain_list = parse_list(line, read_file);
   1.151 +  GList *node;
   1.152 +  GList *list = NULL;
   1.153 +
   1.154 +  foreach(plain_list, node){
   1.155 +    gchar *item = (gchar *)(node->data);
   1.156 +    address *addr = create_address(item, TRUE);
   1.157 +    if(addr)
   1.158 +      list = g_list_append(list, addr);
   1.159 +    g_free(item);
   1.160 +  }
   1.161 +  g_list_free(plain_list);
   1.162 +
   1.163 +  return list;
   1.164 +}
   1.165 +
   1.166 +static
   1.167 +GList *parse_resolve_list(gchar *line)
   1.168 +{
   1.169 +  GList *list;
   1.170 +  GList *list_node;
   1.171 +  GList *res_list = NULL;
   1.172 +
   1.173 +  list = parse_list(line, FALSE);
   1.174 +  if(list){
   1.175 +    foreach(list, list_node){
   1.176 +      gchar *item = (gchar *)(list_node->data);
   1.177 +      if(strcmp(item, "byname") == 0){
   1.178 +	res_list = g_list_append(res_list, resolve_byname);
   1.179 +#ifdef ENABLE_RESOLVER
   1.180 +      }else if(strcmp(item, "dns_a") == 0){
   1.181 +	res_list = g_list_append(res_list, resolve_dns_a);
   1.182 +      }else if(strcmp(item, "dns_mx") == 0){
   1.183 +	res_list = g_list_append(res_list, resolve_dns_mx);
   1.184 +#endif
   1.185 +      }else{
   1.186 +	logwrite(LOG_ALERT, "unknown resolver %s\n", item);
   1.187 +	exit(EXIT_FAILURE);
   1.188 +      }
   1.189 +      g_free(item);
   1.190 +    }
   1.191 +    g_list_free(list);
   1.192 +  }
   1.193 +  return res_list;
   1.194 +}
   1.195 +
   1.196 +static
   1.197 +interface *parse_interface(gchar *line, gint def_port)
   1.198 +{
   1.199 +  gchar buf[256];
   1.200 +  gchar *p, *q;
   1.201 +  interface *iface;
   1.202 +
   1.203 +  DEBUG(6) fprintf(stderr, "parse_interface: %s\n", line);
   1.204 +
   1.205 +  p = line;
   1.206 +  q = buf;
   1.207 +  while((*p != 0) && (*p != ':') && (q < buf+255))
   1.208 +    *(q++) = *(p++);
   1.209 +  *q = 0;
   1.210 +
   1.211 +  iface = g_malloc(sizeof(interface));
   1.212 +  iface->address = g_strdup(buf);
   1.213 +
   1.214 +  if(*p){
   1.215 +    p++;
   1.216 +    iface->port = atoi(p);
   1.217 +  }else
   1.218 +    iface->port = def_port;
   1.219 +
   1.220 +  return iface;
   1.221 +}
   1.222 +
   1.223 +#ifdef ENABLE_IDENT /* so far used for that only */
   1.224 +static
   1.225 +struct in_addr *parse_network(gchar *line, gint def_port)
   1.226 +{
   1.227 +  gchar buf[256];
   1.228 +  gchar *p, *q;
   1.229 +  struct in_addr addr, mask_addr, net_addr, *p_net_addr;
   1.230 +  guint n;
   1.231 +
   1.232 +  DEBUG(6) fprintf(stderr, "parse_network: %s\n", line);
   1.233 +
   1.234 +  p = line;
   1.235 +  q = buf;
   1.236 +  while((*p != 0) && (*p != '/') && (q < buf+255))
   1.237 +    *(q++) = *(p++);
   1.238 +  *q = 0;
   1.239 +
   1.240 +  if((addr.s_addr = inet_addr(buf)) != INADDR_NONE){
   1.241 +    if(*p){
   1.242 +      guint i;
   1.243 +      p++;
   1.244 +      i = atoi(p);
   1.245 +      if((i >= 0) && (i <= 32))
   1.246 +	n = i ? ~((1 << (32 - i)) - 1) : 0;
   1.247 +      else{
   1.248 +	fprintf(stderr, "'%d' is not a valid net mask (must be >= 0 and <= 32)\n", i);
   1.249 +	exit(EXIT_FAILURE);
   1.250 +      }
   1.251 +    }else
   1.252 +      n = 0;
   1.253 +    
   1.254 +    mask_addr.s_addr = htonl(n);
   1.255 +    net_addr.s_addr = mask_addr.s_addr & addr.s_addr;
   1.256 +  }else{
   1.257 +    fprintf(stderr, "'%s' is not a valid address (must be ip)\n", buf);
   1.258 +    exit(EXIT_FAILURE);
   1.259 +  }
   1.260 +
   1.261 +  p_net_addr = g_malloc(sizeof(struct in_addr));
   1.262 +  p_net_addr->s_addr = net_addr.s_addr;
   1.263 +  return p_net_addr;
   1.264 +}
   1.265 +#endif
   1.266 +
   1.267 +static
   1.268 +gboolean eat_comments(FILE *in)
   1.269 +{
   1.270 +  gint c;
   1.271 +
   1.272 +  for(c = fgetc(in); (c == '#' || isspace(c)) && c != EOF; c = fgetc(in)){
   1.273 +    if(c == '#'){
   1.274 +      gint c;
   1.275 +      for(c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
   1.276 +    }
   1.277 +  }
   1.278 +  if(c == EOF) return FALSE;
   1.279 +  ungetc(c, in);
   1.280 +  return TRUE;
   1.281 +}
   1.282 +
   1.283 +/* after parsing, eat trailing character until LF */
   1.284 +static
   1.285 +gboolean eat_line_trailing(FILE *in)
   1.286 +{
   1.287 +  gint c;
   1.288 +
   1.289 +  for(c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
   1.290 +  if(c == EOF) return FALSE;
   1.291 +  return TRUE;
   1.292 +}
   1.293 +
   1.294 +static
   1.295 +gboolean eat_spaces(FILE *in)
   1.296 +{
   1.297 +  gint c;
   1.298 +  
   1.299 +  for(c = fgetc(in); c != EOF && isspace(c); c = fgetc(in));
   1.300 +  if(c == EOF) return FALSE;
   1.301 +  ungetc(c, in);
   1.302 +  return TRUE;
   1.303 +}
   1.304 +
   1.305 +static
   1.306 +gboolean read_lval(FILE *in, gchar *buf, gint size)
   1.307 +{
   1.308 +  gint c;
   1.309 +  gchar *ptr = buf;
   1.310 +  
   1.311 +  DEBUG(6) fprintf(stderr, "read_lval()\n");
   1.312 +
   1.313 +  if(!eat_spaces(in)) return FALSE;
   1.314 +
   1.315 +  c = fgetc(in);
   1.316 +  DEBUG(6) fprintf(stderr, "read_lval() 2\n");
   1.317 +  while((isalnum(c) || c == '_' || c == '-' || c == '.')
   1.318 +	&& (ptr < buf+size-1)
   1.319 +	&& (c != EOF)
   1.320 +	){
   1.321 +    *ptr = c; ptr++;
   1.322 +    c = fgetc(in);
   1.323 +  }
   1.324 +  *ptr = 0;
   1.325 +  ungetc(c, in);
   1.326 +
   1.327 +  if(c == EOF){
   1.328 +    fprintf(stderr, "unexpected EOF after %s\n", buf);
   1.329 +    return FALSE;
   1.330 +  }else if(ptr >= buf+size-1){
   1.331 +    fprintf(stderr, "lval too long\n");
   1.332 +  }
   1.333 +
   1.334 +  eat_spaces(in);
   1.335 +
   1.336 +  DEBUG(6) fprintf(stderr, "lval = %s\n", buf);
   1.337 +
   1.338 +  return buf[0] != 0;
   1.339 +}
   1.340 +
   1.341 +static
   1.342 +gboolean read_rval(FILE *in, gchar *buf, gint size)
   1.343 +{
   1.344 +  gint c;
   1.345 +  gchar *ptr = buf;
   1.346 +  
   1.347 +  DEBUG(6) fprintf(stderr, "read_rval()\n");
   1.348 +
   1.349 +  if(!eat_spaces(in)) return FALSE;
   1.350 +
   1.351 +  c = fgetc(in);
   1.352 +  if(c != '\"'){
   1.353 +    while((isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/' || c == '@' || c == ';')
   1.354 +	  && (ptr < buf+size-1)
   1.355 +	  && (c != EOF)
   1.356 +	  ){
   1.357 +      *ptr = c; ptr++;
   1.358 +      c = fgetc(in);
   1.359 +    }
   1.360 +    *ptr = 0;
   1.361 +    ungetc(c, in);
   1.362 +  }else{
   1.363 +    gboolean escape = FALSE;
   1.364 +    c = fgetc(in);
   1.365 +    while(((c != '\"') || escape) && (ptr < buf+size-1)){
   1.366 +      if(c != '\n'){ /* ignore line breaks */
   1.367 +	if((c == '\\') && (!escape)){
   1.368 +	  escape = TRUE;
   1.369 +	}else{
   1.370 +	  *ptr = c; ptr++;
   1.371 +	  escape = FALSE;
   1.372 +	}
   1.373 +      }
   1.374 +      c = fgetc(in);
   1.375 +    }
   1.376 +    *ptr = 0;
   1.377 +  }
   1.378 +  
   1.379 +  eat_line_trailing(in);
   1.380 +
   1.381 +  DEBUG(6) fprintf(stderr, "rval = %s\n", buf);
   1.382 +
   1.383 +  return TRUE;
   1.384 +}
   1.385 +
   1.386 +static
   1.387 +gboolean read_statement(FILE *in,
   1.388 +			gchar *lval, gint lsize,
   1.389 +			gchar *rval, gint rsize)
   1.390 +{
   1.391 +  gint c;
   1.392 +
   1.393 +  DEBUG(6) fprintf(stderr, "read_statement()\n");
   1.394 +
   1.395 +  /* eat comments and empty lines: */
   1.396 +  if(!eat_comments(in)) return FALSE;
   1.397 +
   1.398 +  DEBUG(6) fprintf(stderr, "read_statement() 1\n");
   1.399 +
   1.400 +  if(read_lval(in, lval, lsize)){
   1.401 +    DEBUG(6) fprintf(stderr, "lval = %s\n", lval);
   1.402 +    if((c = fgetc(in) == '=')){
   1.403 +      if(read_rval(in, rval, rsize)){
   1.404 +	DEBUG(6) fprintf(stderr, "rval = %s\n", rval);
   1.405 +	return TRUE;
   1.406 +      }
   1.407 +    }else{
   1.408 +      fprintf(stderr, "'=' expected after %s, char was '%c'\n", lval, c);
   1.409 +    }
   1.410 +  }
   1.411 +  return FALSE;
   1.412 +}
   1.413 +
   1.414 +gboolean read_conf(gchar *filename)
   1.415 +{
   1.416 +  FILE *in;
   1.417 +
   1.418 +  conf.log_max_pri = 7;
   1.419 +
   1.420 +  conf.remote_port = 25;
   1.421 +
   1.422 +  conf.do_relay = TRUE;
   1.423 +
   1.424 +  conf.alias_local_cmp = strcmp;
   1.425 +
   1.426 +  conf.max_defer_time = 86400*4; /* 4 days */
   1.427 +
   1.428 +  if((in = fopen(filename, "r"))){
   1.429 +    gchar lval[256], rval[2048];
   1.430 +    while(read_statement(in, lval, 256, rval, 2048)){
   1.431 +      if(strcmp(lval, "debug_level") == 0)
   1.432 +	conf.debug_level = atoi(rval);
   1.433 +      else if(strcmp(lval, "run_as_user") == 0){
   1.434 +	if(!conf.run_as_user) /* you should not be able
   1.435 +				 to reset that flag */
   1.436 +	  conf.run_as_user = parse_boolean(rval);
   1.437 +      }else if(strcmp(lval, "use_syslog") == 0)
   1.438 +	conf.use_syslog = parse_boolean(rval);
   1.439 +      else if(strcmp(lval, "mail_dir") == 0)
   1.440 +	conf.mail_dir = g_strdup(rval);
   1.441 +      else if(strcmp(lval, "lock_dir") == 0)
   1.442 +	conf.lock_dir = g_strdup(rval);
   1.443 +      else if(strcmp(lval, "spool_dir") == 0)
   1.444 +	conf.spool_dir = g_strdup(rval);
   1.445 +      else if(strcmp(lval, "log_dir") == 0)
   1.446 +	conf.log_dir = g_strdup(rval);
   1.447 +      else if(strcmp(lval, "host_name") == 0){
   1.448 +	if(rval[0] != '/')
   1.449 +	  conf.host_name = g_strdup(rval);
   1.450 +	else{
   1.451 +	  char buf[256];
   1.452 +	  FILE *fptr = fopen(rval, "rt");
   1.453 +	  if(fptr){
   1.454 +	    fgets(buf, 255, fptr);
   1.455 +	    g_strchomp(buf);
   1.456 +	    conf.host_name = g_strdup(buf);
   1.457 +	    fclose(fptr);
   1.458 +	  }else{
   1.459 +	    fprintf(stderr, "could not open %s: %s\n", rval, strerror(errno));
   1.460 +	    return FALSE;
   1.461 +	  }
   1.462 +	}
   1.463 +      }
   1.464 +      else if(strcmp(lval, "remote_port") == 0){
   1.465 +	fprintf(stderr,
   1.466 +		"the remote_port option is now deprecated. Use 'mail_host' in the\n"
   1.467 +		"route configuration instead. See man masqmail.route\n");
   1.468 +	conf.remote_port = atoi(rval);
   1.469 +      }else if(strcmp(lval, "local_hosts") == 0)
   1.470 +	conf.local_hosts = parse_list(rval, FALSE);
   1.471 +      else if(strcmp(lval, "local_addresses") == 0)
   1.472 +	conf.local_addresses = parse_list(rval, TRUE);
   1.473 +      else if(strcmp(lval, "not_local_addresses") == 0)
   1.474 +	conf.not_local_addresses = parse_list(rval, TRUE);
   1.475 +      else if(strcmp(lval, "local_nets") == 0)
   1.476 +	conf.local_nets = parse_list(rval, FALSE);
   1.477 +      else if(strcmp(lval, "do_save_envelope_to") == 0)
   1.478 +	conf.do_save_envelope_to = parse_boolean(rval);
   1.479 +      else if(strcmp(lval, "defer_all") == 0)
   1.480 +	conf.defer_all = parse_boolean(rval);
   1.481 +      else if(strcmp(lval, "do_relay") == 0)
   1.482 +	conf.do_relay = parse_boolean(rval);
   1.483 +      else if(strcmp(lval, "alias_file") == 0){
   1.484 +	conf.alias_file = g_strdup(rval);
   1.485 +      }else if(strcmp(lval, "alias_local_caseless") == 0){
   1.486 +	conf.alias_local_cmp = parse_boolean(rval) ? strcasecmp : strcmp;
   1.487 +      }else if(strcmp(lval, "mbox_default") == 0){
   1.488 +	conf.mbox_default = g_strdup(rval);
   1.489 +      }else if(strcmp(lval, "mbox_users") == 0){
   1.490 +	conf.mbox_users = parse_list(rval, TRUE);
   1.491 +      }else if(strcmp(lval, "mda_users") == 0){
   1.492 +	conf.mda_users = parse_list(rval, TRUE);
   1.493 +      }else if(strcmp(lval, "maildir_users") == 0){
   1.494 +	conf.maildir_users = parse_list(rval, TRUE);
   1.495 +      }else if(strcmp(lval, "mda") == 0){
   1.496 +	conf.mda = g_strdup(rval);
   1.497 +      }else if(strcmp(lval, "mda_fromline") == 0){
   1.498 +	conf.mda_fromline = parse_boolean(rval);
   1.499 +      }else if(strcmp(lval, "mda_fromhack") == 0){
   1.500 +	conf.mda_fromhack = parse_boolean(rval);
   1.501 +      }else if(strcmp(lval, "pipe_fromline") == 0){
   1.502 +	conf.pipe_fromline = parse_boolean(rval);
   1.503 +      }else if(strcmp(lval, "pipe_fromhack") == 0){
   1.504 +	conf.pipe_fromhack = parse_boolean(rval);
   1.505 +      }else if(strcmp(lval, "listen_addresses") == 0){
   1.506 +	GList *node;
   1.507 +	GList *tmp_list = parse_list(rval, FALSE);
   1.508 +	    
   1.509 +	conf.listen_addresses = NULL;
   1.510 +	foreach(tmp_list, node){
   1.511 +	  conf.listen_addresses =
   1.512 +	    g_list_append(conf.listen_addresses,
   1.513 +			  parse_interface((gchar *)(node->data), 25));
   1.514 +	  g_free(node->data);
   1.515 +	}
   1.516 +	g_list_free(tmp_list);
   1.517 +      }
   1.518 +      else if(strcmp(lval, "ident_trusted_nets") == 0){
   1.519 +#ifdef ENABLE_IDENT
   1.520 +	GList *node;
   1.521 +	GList *tmp_list = parse_list(rval, FALSE);
   1.522 +	    
   1.523 +	conf.ident_trusted_nets = NULL;
   1.524 +	foreach(tmp_list, node){
   1.525 +	  conf.ident_trusted_nets =
   1.526 +	    g_list_append(conf.ident_trusted_nets,
   1.527 +			  parse_network((gchar *)(node->data), 25));
   1.528 +	  g_free(node->data);
   1.529 +	}
   1.530 +	g_list_free(tmp_list);
   1.531 +#else
   1.532 +	fprintf(stderr, "%s ignored: not compiled with ident support\n", lval);
   1.533 +#endif
   1.534 +      }
   1.535 +      else if((strncmp(lval, "connect_route.", 14) == 0) ||
   1.536 +	      (strncmp(lval, "online_routes.", 14) == 0)){
   1.537 +	GList *file_list = parse_list(rval, FALSE);
   1.538 +	table_pair *pair = create_pair(&(lval[14]), file_list);
   1.539 +	conf.connect_routes = g_list_append(conf.connect_routes, pair);
   1.540 +      }
   1.541 +      else if(strcmp(lval, "local_net_route") == 0){
   1.542 +	conf.local_net_routes = parse_list(rval, FALSE);
   1.543 +      }
   1.544 +      else if(strcmp(lval, "online_detect") == 0)
   1.545 +	conf.online_detect = g_strdup(rval);
   1.546 +      else if(strcmp(lval, "online_file") == 0)
   1.547 +	conf.online_file = g_strdup(rval);
   1.548 +      else if(strcmp(lval, "online_pipe") == 0)
   1.549 +	conf.online_pipe = g_strdup(rval);
   1.550 +      else if(strcmp(lval, "mserver_iface") == 0)
   1.551 +	conf.mserver_iface = parse_interface(rval, 224);
   1.552 +      else if(strcmp(lval, "do_queue") == 0)
   1.553 +	conf.do_queue = parse_boolean(rval);
   1.554 +      else if(strncmp(lval, "get.", 4) == 0){
   1.555 +#ifdef ENABLE_POP3
   1.556 +	table_pair *pair = create_pair_string(&(lval[4]), rval);
   1.557 +	conf.get_names = g_list_append(conf.get_names, pair);
   1.558 +#else
   1.559 +	fprintf(stderr, "get.<name> ignored: not compiled with pop support\n");
   1.560 +#endif
   1.561 +      }
   1.562 +      else if(strncmp(lval, "online_gets.", 12) == 0){
   1.563 +#ifdef ENABLE_POP3
   1.564 +	GList *file_list = parse_list(rval, FALSE);
   1.565 +	table_pair *pair = create_pair(&(lval[12]), file_list);
   1.566 +	conf.online_gets = g_list_append(conf.online_gets, pair);
   1.567 +#else
   1.568 +	fprintf(stderr, "online_gets.<name> ignored: not compiled with pop support\n");
   1.569 +#endif
   1.570 +      }
   1.571 +      else if(strcmp(lval, "errmsg_file") == 0)
   1.572 +	conf.errmsg_file = g_strdup(rval);
   1.573 +      else if(strcmp(lval, "warnmsg_file") == 0)
   1.574 +	conf.warnmsg_file = g_strdup(rval);
   1.575 +      else if(strcmp(lval, "warn_intervals") == 0)
   1.576 +	conf.warn_intervals = parse_list(rval, FALSE);
   1.577 +      else if(strcmp(lval, "max_defer_time") == 0){
   1.578 +	gint dummy;
   1.579 +	gint ival = time_interval(rval, &dummy);
   1.580 +	if(ival < 0)
   1.581 +	  fprintf(stderr, "invalid time interval for 'max_defer_time': %s\n", rval);
   1.582 +	else
   1.583 +	  conf.max_defer_time = ival;
   1.584 +      }else if(strcmp(lval, "log_user") == 0)
   1.585 +	conf.log_user = g_strdup(rval);
   1.586 +
   1.587 +      else
   1.588 +	fprintf(stderr, "var '%s' not (yet) known, ignored\n", lval);
   1.589 +    }
   1.590 +    fclose(in);
   1.591 +
   1.592 +    if(conf.errmsg_file == NULL)
   1.593 +      conf.errmsg_file = g_strdup(DATA_DIR"/tpl/failmsg.tpl");
   1.594 +    if(conf.warnmsg_file == NULL)
   1.595 +      conf.warnmsg_file = g_strdup(DATA_DIR"/tpl/warnmsg.tpl");
   1.596 +
   1.597 +    if(conf.lock_dir == NULL)
   1.598 +      conf.lock_dir = g_strdup_printf("%s/lock/", conf.spool_dir);
   1.599 +
   1.600 +    if(conf.mbox_default == NULL)
   1.601 +      conf.mbox_default = g_strdup("mbox");
   1.602 +
   1.603 +    if(conf.warn_intervals == NULL)
   1.604 +      conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
   1.605 +
   1.606 +    return TRUE;
   1.607 +  }else
   1.608 +    fprintf(stderr, "could not open config file %s: %s\n", filename, strerror(errno));
   1.609 +  return FALSE;
   1.610 +}
   1.611 +
   1.612 +connect_route *read_route(gchar *filename, gboolean is_local_net)
   1.613 +{
   1.614 +  gboolean ok = FALSE;
   1.615 +  FILE *in;
   1.616 +
   1.617 +  connect_route *route = g_malloc(sizeof(connect_route));
   1.618 +  memset(route, 0, sizeof(connect_route));
   1.619 +
   1.620 +  DEBUG(5) debugf("read_route, filename = %s\n", filename);
   1.621 +
   1.622 +  route->filename = g_strdup(filename);
   1.623 +  route->name = g_strdup(filename); /* quick hack */
   1.624 +
   1.625 +  route->protocol = g_strdup("smtp");
   1.626 +  route->expand_h_sender_address = TRUE;
   1.627 +
   1.628 +  route->is_local_net = is_local_net;
   1.629 +
   1.630 +  route->do_pipelining = TRUE;
   1.631 +
   1.632 +  if((in = fopen(route->filename, "r"))){
   1.633 +    gchar lval[256], rval[2048];
   1.634 +    while(read_statement(in, lval, 256, rval, 2048)){
   1.635 +      if(strcmp(lval, "protocol") == 0)
   1.636 +	route->protocol = g_strdup(rval);
   1.637 +      else if(strcmp(lval, "mail_host") == 0)
   1.638 +	route->mail_host = parse_interface(rval, conf.remote_port);
   1.639 +      else if(strcmp(lval, "helo_name") == 0)
   1.640 +	route->helo_name = g_strdup(rval);
   1.641 +      else if(strcmp(lval, "wrapper") == 0)
   1.642 +	route->wrapper = g_strdup(rval);
   1.643 +      else if(strcmp(lval, "connect_error_fail") == 0)
   1.644 +	route->connect_error_fail = parse_boolean(rval);
   1.645 +      else if(strcmp(lval, "do_correct_helo") == 0)
   1.646 +	route->do_correct_helo = parse_boolean(rval);
   1.647 +      else if(strcmp(lval, "do_pipelining") == 0)
   1.648 +	route->do_pipelining = parse_boolean(rval);
   1.649 +      else if(strcmp(lval, "allowed_return_paths") == 0)
   1.650 +	route->allowed_return_paths = parse_address_list(rval, TRUE);
   1.651 +      else if(strcmp(lval, "allowed_mail_locals") == 0)
   1.652 +	route->allowed_mail_locals = parse_list(rval, TRUE);
   1.653 +      else if(strcmp(lval, "not_allowed_return_paths") == 0)
   1.654 +	route->not_allowed_return_paths = parse_address_list(rval, TRUE);
   1.655 +      else if(strcmp(lval, "not_allowed_mail_locals") == 0)
   1.656 +	route->not_allowed_mail_locals = parse_list(rval, TRUE);
   1.657 +      else if(strcmp(lval, "allowed_rcpt_domains") == 0)
   1.658 +	route->allowed_rcpt_domains = parse_list(rval, TRUE);
   1.659 +      else if(strcmp(lval, "not_allowed_rcpt_domains") == 0)
   1.660 +	route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
   1.661 +      else if(strcmp(lval, "set_h_from_domain") == 0)
   1.662 +	route->set_h_from_domain = g_strdup(rval);
   1.663 +      else if(strcmp(lval, "set_h_reply_to_domain") == 0)
   1.664 +	route->set_h_reply_to_domain = g_strdup(rval);
   1.665 +      else if(strcmp(lval, "set_return_path_domain") == 0)
   1.666 +	route->set_return_path_domain = g_strdup(rval);
   1.667 +      else if(strcmp(lval, "map_return_path_addresses") == 0){
   1.668 +	GList *node, *list;
   1.669 +
   1.670 +	list = parse_list(rval, TRUE);
   1.671 +	foreach(list, node){
   1.672 +	  gchar *item = (gchar *)(node->data);
   1.673 +	  table_pair *pair = parse_table_pair(item, ':');
   1.674 +	  address *addr = create_address((gchar *)(pair->value), TRUE);
   1.675 +	  g_free(pair->value);
   1.676 +	  pair->value = (gpointer *)addr;
   1.677 +	  route->map_return_path_addresses =
   1.678 +	    g_list_append(route->map_return_path_addresses, pair);
   1.679 +	  g_free(item);
   1.680 +	}
   1.681 +	g_list_free(list);
   1.682 +      }
   1.683 +      else if(strcmp(lval, "map_h_from_addresses") == 0){
   1.684 +	GList *list, *node;
   1.685 +
   1.686 +	list = parse_list(rval, TRUE);
   1.687 +	foreach(list, node){
   1.688 +	  gchar *item = (gchar *)(node->data);
   1.689 +	  table_pair *pair = parse_table_pair(item, ':');
   1.690 +	  route->map_h_from_addresses = 
   1.691 +	    g_list_append(route->map_h_from_addresses, pair);
   1.692 +	  g_free(item);
   1.693 +	}
   1.694 +	g_list_free(list);
   1.695 +      }
   1.696 +      else if(strcmp(lval, "map_h_reply_to_addresses") == 0){
   1.697 +	GList *list, *node;
   1.698 +
   1.699 +	list = parse_list(rval, TRUE);
   1.700 +	foreach(list, node){
   1.701 +	  gchar *item = (gchar *)(node->data);
   1.702 +	  table_pair *pair = parse_table_pair(item, ':');
   1.703 +	  route->map_h_reply_to_addresses = 
   1.704 +	    g_list_append(route->map_h_reply_to_addresses, pair);
   1.705 +	  g_free(item);
   1.706 +	}
   1.707 +	g_list_free(list);
   1.708 +      }
   1.709 +      else if(strcmp(lval, "map_h_mail_followup_to_addresses") == 0){
   1.710 +	GList *list, *node;
   1.711 +
   1.712 +	list = parse_list(rval, TRUE);
   1.713 +	foreach(list, node){
   1.714 +	  gchar *item = (gchar *)(node->data);
   1.715 +	  table_pair *pair = parse_table_pair(item, ':');
   1.716 +	  route->map_h_mail_followup_to_addresses = 
   1.717 +	    g_list_append(route->map_h_mail_followup_to_addresses, pair);
   1.718 +	  g_free(item);
   1.719 +	}
   1.720 +	g_list_free(list);
   1.721 +      }
   1.722 +      else if(strcmp(lval, "expand_h_sender_domain") == 0){
   1.723 +	route->expand_h_sender_domain = parse_boolean(rval);	    
   1.724 +      }
   1.725 +      else if(strcmp(lval, "expand_h_sender_address") == 0){
   1.726 +	route->expand_h_sender_address = parse_boolean(rval);	    
   1.727 +      }
   1.728 +      else if(strcmp(lval, "resolve_list") == 0)
   1.729 +	route->resolve_list = parse_resolve_list(rval);
   1.730 +      else if(strcmp(lval, "do_ssl") == 0){
   1.731 +	/* we ignore this. This option is used by sqilconf */
   1.732 +	;
   1.733 +      }
   1.734 +#ifdef ENABLE_AUTH
   1.735 +      else if(strcmp(lval, "auth_name") == 0){
   1.736 +	route->auth_name = g_strdup(rval);
   1.737 +      }
   1.738 +      else if(strcmp(lval, "auth_login") == 0){
   1.739 +	route->auth_login = g_strdup(rval);
   1.740 +      }
   1.741 +      else if(strcmp(lval, "auth_secret") == 0){
   1.742 +	route->auth_secret = g_strdup(rval);
   1.743 +      }
   1.744 +#else
   1.745 +      else if((strcmp(lval, "auth_name") == 0) ||
   1.746 +	      (strcmp(lval, "auth_login") == 0) ||
   1.747 +	      (strcmp(lval, "auth_secret") == 0)){
   1.748 +	logwrite(LOG_WARNING, "%s ignored: not compiled with auth support.\n", lval);
   1.749 +      }
   1.750 +#endif
   1.751 +      else if(strcmp(lval, "pop3_login") == 0){
   1.752 +#ifdef ENABLE_POP3
   1.753 +	route->pop3_login = g_strdup(rval);
   1.754 +#else
   1.755 +	logwrite(LOG_WARNING, "pop3_login ignored: not compiled with pop support.\n");
   1.756 +#endif
   1.757 +      }
   1.758 +      else if(strcmp(lval, "pipe") == 0){
   1.759 +	route->pipe = g_strdup(rval);
   1.760 +      }
   1.761 +      else if(strcmp(lval, "pipe_fromline") == 0){
   1.762 +	route->pipe_fromline = parse_boolean(rval);
   1.763 +      }
   1.764 +      else if(strcmp(lval, "pipe_fromhack") == 0){
   1.765 +	route->pipe_fromhack = parse_boolean(rval);
   1.766 +      }
   1.767 +      else if(strcmp(lval, "last_route") == 0){
   1.768 +	route->last_route = parse_boolean(rval);
   1.769 +      }
   1.770 +      else
   1.771 +	logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
   1.772 +    }
   1.773 +
   1.774 +    if(route->resolve_list == NULL){
   1.775 +      if(is_local_net){
   1.776 +	route->resolve_list =
   1.777 +	  g_list_append(NULL, resolve_byname);
   1.778 +      }else{
   1.779 +#ifdef ENABLE_RESOLVER
   1.780 +	route->resolve_list =
   1.781 +	  g_list_append(route->resolve_list, resolve_dns_mx);
   1.782 +	route->resolve_list =
   1.783 +	  g_list_append(route->resolve_list, resolve_dns_a);
   1.784 +#endif
   1.785 +	route->resolve_list =
   1.786 +	  g_list_append(route->resolve_list, resolve_byname);
   1.787 +      }
   1.788 +    }
   1.789 +    fclose(in);
   1.790 +    ok = TRUE;
   1.791 +
   1.792 +    /* warn user about misconfigurations: */
   1.793 +    if((route->map_h_from_addresses != NULL) && (route->set_h_from_domain != NULL)){
   1.794 +      logwrite(LOG_WARNING, "'map_h_from_addresses' overrides 'set_h_from_domain'\n");
   1.795 +      g_free(route->set_h_from_domain);
   1.796 +      route->set_h_from_domain = NULL;
   1.797 +    }
   1.798 +    if((route->map_h_reply_to_addresses != NULL) && (route->set_h_reply_to_domain != NULL)){
   1.799 +      logwrite(LOG_WARNING, "'map_h_reply_to_addresses' overrides 'set_h_reply_to_domain'\n");
   1.800 +      g_free(route->set_h_reply_to_domain);
   1.801 +      route->set_h_reply_to_domain = NULL;
   1.802 +    }
   1.803 +  }else{
   1.804 +    logwrite(LOG_ALERT, "could not open route file %s: %s\n",
   1.805 +	     route->filename, strerror(errno));
   1.806 +  }
   1.807 +
   1.808 +  if(!ok){
   1.809 +    g_free(route);
   1.810 +    route = NULL;
   1.811 +  }
   1.812 +
   1.813 +  return route;
   1.814 +}
   1.815 +
   1.816 +static
   1.817 +void _g_list_free_all(GList *list)
   1.818 +{
   1.819 +  GList *node;
   1.820 +  if(list){
   1.821 +    foreach(list, node)
   1.822 +      g_free(node->data);
   1.823 +    g_list_free(list);
   1.824 +  }
   1.825 +}
   1.826 +
   1.827 +void destroy_route(connect_route *r)
   1.828 +{
   1.829 +  if(r->filename) g_free(r->filename);
   1.830 +  if(r->protocol) g_free(r->protocol);
   1.831 +  if(r->mail_host){
   1.832 +    g_free(r->mail_host->address);
   1.833 +    g_free(r->mail_host);
   1.834 +  }
   1.835 +  if(r->wrapper) g_free(r->wrapper);
   1.836 +  if(r->helo_name) g_free(r->helo_name);
   1.837 +  _g_list_free_all(r->allowed_mail_locals);
   1.838 +  _g_list_free_all(r->not_allowed_mail_locals);
   1.839 +  _g_list_free_all(r->allowed_rcpt_domains);
   1.840 +  _g_list_free_all(r->not_allowed_rcpt_domains);
   1.841 +  if(r->set_h_from_domain) g_free(r->set_h_from_domain);
   1.842 +  if(r->set_h_reply_to_domain) g_free(r->set_h_reply_to_domain);
   1.843 +  if(r->set_return_path_domain) g_free(r->set_return_path_domain);
   1.844 +  if(r->map_h_reply_to_addresses) destroy_table(r->map_h_reply_to_addresses);
   1.845 +  if(r->resolve_list) g_list_free(r->resolve_list);
   1.846 +#ifdef ENABLE_AUTH
   1.847 +  if(r->auth_name) g_free(r->auth_name);
   1.848 +  if(r->auth_login) g_free(r->auth_login);
   1.849 +  if(r->auth_secret) g_free(r->auth_secret);
   1.850 +#endif
   1.851 +#ifdef ENABLE_POP3
   1.852 +  if(r->pop3_login) g_free(r->pop3_login);
   1.853 +#endif
   1.854 +  if(r->pipe) g_free(r->pipe);
   1.855 +  g_free(r);
   1.856 +}
   1.857 +
   1.858 +GList *read_route_list(GList *rf_list, gboolean is_local_net)
   1.859 +{
   1.860 +  GList *list = NULL;
   1.861 +  GList *node;
   1.862 +  uid_t saved_uid, saved_gid;
   1.863 +
   1.864 +  if(!conf.run_as_user){
   1.865 +    set_euidgid(0, 0, &saved_uid, &saved_gid);
   1.866 +  }
   1.867 +
   1.868 +  foreach(rf_list, node){
   1.869 +    gchar *fname = (gchar *)(node->data);
   1.870 +    connect_route *route = read_route(fname, is_local_net);
   1.871 +    if(route)
   1.872 +      list = g_list_append(list, route);
   1.873 +    else
   1.874 +      logwrite(LOG_ALERT, "could not read route configuration %s\n", fname);
   1.875 +  }
   1.876 +
   1.877 +  /* set uid and gid back */
   1.878 +  if(!conf.run_as_user){
   1.879 +    set_euidgid(saved_uid, saved_gid, NULL, NULL);
   1.880 +  }
   1.881 +
   1.882 +  return list;
   1.883 +}
   1.884 +
   1.885 +void destroy_route_list(GList *list)
   1.886 +{
   1.887 +  GList *node;
   1.888 +
   1.889 +  foreach(list, node){
   1.890 +    connect_route *route = (connect_route *)(node->data);
   1.891 +    destroy_route(route);
   1.892 +  }
   1.893 +  g_list_free(list);
   1.894 +}
   1.895 +
   1.896 +#ifdef ENABLE_POP3
   1.897 +
   1.898 +get_conf *read_get_conf(gchar *filename)
   1.899 +{
   1.900 +  FILE *in;
   1.901 +
   1.902 +  get_conf *gc = g_malloc(sizeof(get_conf));
   1.903 +  memset(gc, 0, sizeof(get_conf));
   1.904 +
   1.905 +  gc->server_port = 110;
   1.906 +
   1.907 +  if((in = fopen(filename, "r"))){
   1.908 +    gchar lval[256], rval[2048];
   1.909 +    while(read_statement(in, lval, 256, rval, 2048)){
   1.910 +      if(strcmp(lval, "protocol") == 0)
   1.911 +	gc->protocol = g_strdup(rval);
   1.912 +      else if(strcmp(lval, "server") == 0)
   1.913 +	gc->server_name = g_strdup(rval);
   1.914 +      else if(strcmp(lval, "port") == 0)
   1.915 +	gc->server_port = atoi(rval);
   1.916 +      else if(strcmp(lval, "wrapper") == 0)
   1.917 +	gc->wrapper = g_strdup(rval);
   1.918 +      else if(strcmp(lval, "user") == 0)
   1.919 +	gc->login_user = g_strdup(rval);
   1.920 +      else if(strcmp(lval, "pass") == 0)
   1.921 +	gc->login_pass = g_strdup(rval);
   1.922 +      else if(strcmp(lval, "address") == 0)
   1.923 +	gc->address = create_address_qualified(rval, TRUE, conf.host_name);
   1.924 +      else if(strcmp(lval, "return_path") == 0)
   1.925 +	gc->return_path = create_address_qualified(rval, TRUE, conf.host_name);
   1.926 +      else if(strcmp(lval, "do_ssl") == 0)
   1.927 +	/* we ignore this. This option is used by sqilconf */
   1.928 +	;
   1.929 +      else if(strcmp(lval, "do_keep") == 0)
   1.930 +	gc->do_keep = parse_boolean(rval);
   1.931 +      else if(strcmp(lval, "do_uidl") == 0)
   1.932 +	gc->do_uidl = parse_boolean(rval);
   1.933 +      else if(strcmp(lval, "do_uidl_dele") == 0)
   1.934 +	gc->do_uidl_dele = parse_boolean(rval);
   1.935 +      else if(strcmp(lval, "max_size") == 0)
   1.936 +	gc->max_size = atoi(rval);
   1.937 +      else if(strcmp(lval, "max_size_delete") == 0)
   1.938 +	gc->max_size = parse_boolean(rval);
   1.939 +      else if(strcmp(lval, "max_count") == 0)
   1.940 +	gc->max_count = atoi(rval);
   1.941 +      else if(strcmp(lval, "resolve_list") == 0)
   1.942 +	gc->resolve_list = parse_resolve_list(rval);
   1.943 +      else
   1.944 +	logwrite(LOG_WARNING, "var '%s' not (yet) known, ignored\n", lval);
   1.945 +    }
   1.946 +    fclose(in);
   1.947 +
   1.948 +    if(gc->resolve_list == NULL){
   1.949 +#ifdef ENABLE_RESOLVER
   1.950 +      gc->resolve_list =
   1.951 +	g_list_append(NULL, resolve_dns_a);
   1.952 +#endif
   1.953 +      gc->resolve_list =
   1.954 +	g_list_append(NULL, resolve_byname);
   1.955 +    }
   1.956 +    
   1.957 +    if(gc->protocol == NULL)
   1.958 +      gc->protocol = g_strdup("pop3");
   1.959 +    return gc;
   1.960 +  }
   1.961 +  logwrite(LOG_ALERT, "could not open get file %s: %s\n", filename, strerror(errno));
   1.962 +
   1.963 +  g_free(gc);
   1.964 +  return NULL;
   1.965 +}
   1.966 +
   1.967 +void destroy_get_conf(get_conf *gc)
   1.968 +{
   1.969 +  if(gc->protocol) g_free(gc->protocol);
   1.970 +  if(gc->server_name) g_free(gc->server_name);
   1.971 +  if(gc->login_user) g_free(gc->login_user);
   1.972 +  if(gc->login_pass) g_free(gc->login_pass);
   1.973 +  if(gc->wrapper) g_free(gc->wrapper);
   1.974 +  if(gc->address) destroy_address(gc->address);
   1.975 +  if(gc->return_path) destroy_address(gc->return_path);
   1.976 +  if(gc->resolve_list) g_list_free(gc->resolve_list);
   1.977 +  g_free(gc);
   1.978 +}
   1.979 +
   1.980 +#endif
   1.981 +
   1.982 +connect_route *create_local_route()
   1.983 +{
   1.984 +  connect_route *route;
   1.985 +
   1.986 +  route = g_malloc(sizeof(connect_route));
   1.987 +  if(route){
   1.988 +    memset(route, 0, sizeof(connect_route));
   1.989 +    route->protocol = g_strdup("smtp");
   1.990 +    route->is_local_net = TRUE;
   1.991 +    route->name = g_strdup("local_net (default)");
   1.992 +    route->expand_h_sender_address = TRUE;
   1.993 +    route->resolve_list =
   1.994 +      g_list_append(NULL, resolve_byname);
   1.995 +    route->connect_error_fail = TRUE;
   1.996 +  }
   1.997 +  return route;
   1.998 +}