masqmail

diff src/masqmail.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/masqmail.c	Fri Sep 26 17:05:23 2008 +0200
     1.3 @@ -0,0 +1,828 @@
     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 <stdio.h>
    1.23 +#include <errno.h>
    1.24 +#include <stdlib.h>
    1.25 +#include <string.h>
    1.26 +#include <unistd.h>
    1.27 +#include <sys/types.h>
    1.28 +#include <sys/socket.h>
    1.29 +#include <sys/time.h>
    1.30 +#include <netinet/in.h>
    1.31 +#include <netdb.h>
    1.32 +#include <syslog.h>
    1.33 +#include <signal.h>
    1.34 +
    1.35 +#include <glib.h>
    1.36 +
    1.37 +#include "masqmail.h"
    1.38 +
    1.39 +/* mutually exclusive modes. Note that there is neither a 'get' mode
    1.40 +   nor a 'queue daemon' mode. These, as well as the distinction beween
    1.41 +   the two (non exclusive) daemon (queue and listen) modes are handled
    1.42 +   by flags.*/
    1.43 +typedef enum _mta_mode
    1.44 +{
    1.45 +  MODE_ACCEPT = 0, /* accept message on stdin */
    1.46 +  MODE_DAEMON,     /* run as daemon */
    1.47 +  MODE_RUNQUEUE,   /* single queue run, online or offline */
    1.48 +  MODE_GET_DAEMON, /* run as get (retrieve) daemon */
    1.49 +  MODE_SMTP,       /* accept SMTP on stdin */
    1.50 +  MODE_LIST,       /* list queue */
    1.51 +  MODE_MCMD,       /* do queue manipulation */
    1.52 +  MODE_VERSION,    /* show version */
    1.53 +  MODE_BI,         /* fake ;-) */
    1.54 +  MODE_NONE        /* to prevent default MODE_ACCEPT */    
    1.55 +}mta_mode;
    1.56 +
    1.57 +char *pidfile = NULL;
    1.58 +volatile int sigterm_in_progress = 0;
    1.59 +
    1.60 +static
    1.61 +void sigterm_handler(int sig)
    1.62 +{
    1.63 +  if(sigterm_in_progress)
    1.64 +    raise(sig);
    1.65 +  sigterm_in_progress = 1;
    1.66 +
    1.67 +  if(pidfile){
    1.68 +    uid_t uid;
    1.69 +    uid = seteuid(0);
    1.70 +    if(unlink(pidfile) != 0)
    1.71 +      logwrite(LOG_WARNING, "could not delete pid file %s: %s\n",
    1.72 +	       pidfile, strerror(errno));
    1.73 +    seteuid(uid); /* we exit anyway after this, just to be sure */
    1.74 +  }
    1.75 +
    1.76 +  signal(sig, SIG_DFL);
    1.77 +  raise(sig);
    1.78 +}
    1.79 +
    1.80 +#ifdef ENABLE_IDENT /* so far used for that only */
    1.81 +static
    1.82 +gboolean is_in_netlist(gchar *host, GList *netlist)
    1.83 +{
    1.84 +  guint hostip = inet_addr(host);
    1.85 +  struct in_addr addr;
    1.86 +
    1.87 +  addr.s_addr = hostip;
    1.88 +  if(addr.s_addr != INADDR_NONE){
    1.89 +    GList *node;
    1.90 +    foreach(netlist, node){
    1.91 +      struct in_addr *net = (struct in_addr *)(node->data);
    1.92 +      if((addr.s_addr & net->s_addr) == net->s_addr)
    1.93 +	return TRUE;
    1.94 +    }
    1.95 +  }
    1.96 +  return FALSE;
    1.97 +}
    1.98 +#endif
    1.99 +
   1.100 +gchar *get_optarg(char *argv[], gint argc, gint *argp, gint *pos)
   1.101 +{
   1.102 +  if(argv[*argp][*pos])
   1.103 +    return &(argv[*argp][*pos]);
   1.104 +  else{
   1.105 +    if(*argp+1 < argc){
   1.106 +      if(argv[(*argp)+1][0] != '-'){
   1.107 +	(*argp)++;
   1.108 +	*pos = 0;
   1.109 +	return &(argv[*argp][*pos]);
   1.110 +      }
   1.111 +    }
   1.112 +  }
   1.113 +  return NULL;
   1.114 +}  
   1.115 +
   1.116 +gchar *get_progname(gchar *arg0)
   1.117 +{
   1.118 +  gchar *p = arg0 + strlen(arg0) - 1;
   1.119 +  while(p > arg0){
   1.120 +    if(*p == '/')
   1.121 +      return p+1;
   1.122 +    p--;
   1.123 +  }
   1.124 +  return p;
   1.125 +}
   1.126 +
   1.127 +gboolean write_pidfile(gchar *name)
   1.128 +{
   1.129 +  FILE *fptr;
   1.130 +
   1.131 +  if((fptr = fopen(name, "wt"))){
   1.132 +    fprintf(fptr, "%d\n", getpid());
   1.133 +    fclose(fptr);
   1.134 +    pidfile = strdup(name);
   1.135 +    return TRUE;
   1.136 +  }
   1.137 +  logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno));
   1.138 +  return FALSE;
   1.139 +}
   1.140 +
   1.141 +static
   1.142 +void mode_daemon(gboolean do_listen, gint queue_interval, char *argv[])
   1.143 +{
   1.144 +  guint pid;
   1.145 +
   1.146 +  /* daemon */
   1.147 +  if(!conf.run_as_user){
   1.148 +    if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
   1.149 +      fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
   1.150 +      exit(EXIT_FAILURE);
   1.151 +    }
   1.152 +  }
   1.153 +
   1.154 +  if((pid = fork()) > 0){
   1.155 +    exit(EXIT_SUCCESS);
   1.156 +  }else if(pid < 0){
   1.157 +    logwrite(LOG_ALERT, "could not fork!");
   1.158 +    exit(EXIT_FAILURE);
   1.159 +  }
   1.160 +
   1.161 +  signal(SIGTERM, sigterm_handler);
   1.162 +  write_pidfile(PIDFILEDIR"/masqmail.pid");
   1.163 +
   1.164 +  conf.do_verbose = FALSE;
   1.165 +
   1.166 +  fclose(stdin);
   1.167 +  fclose(stdout);
   1.168 +  fclose(stderr);
   1.169 +
   1.170 +  listen_port(do_listen ? conf.listen_addresses : NULL,
   1.171 +	      queue_interval, argv);
   1.172 +}
   1.173 +
   1.174 +#ifdef ENABLE_POP3
   1.175 +static
   1.176 +void mode_get_daemon(gint get_interval, char *argv[])
   1.177 +{
   1.178 +  guint pid;
   1.179 +
   1.180 +  /* daemon */
   1.181 +  if(!conf.run_as_user){
   1.182 +    if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
   1.183 +      fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
   1.184 +      exit(EXIT_FAILURE);
   1.185 +    }
   1.186 +  }
   1.187 +
   1.188 +  if((pid = fork()) > 0){
   1.189 +    exit(EXIT_SUCCESS);
   1.190 +  }else if(pid < 0){
   1.191 +    logwrite(LOG_ALERT, "could not fork!");
   1.192 +    exit(EXIT_FAILURE);
   1.193 +  }
   1.194 +
   1.195 +  signal(SIGTERM, sigterm_handler);
   1.196 +  write_pidfile(PIDFILEDIR"/masqmail-get.pid");
   1.197 +
   1.198 +  conf.do_verbose = FALSE;
   1.199 +
   1.200 +  fclose(stdin);
   1.201 +  fclose(stdout);
   1.202 +  fclose(stderr);
   1.203 +
   1.204 +  get_daemon(get_interval, argv);
   1.205 +}
   1.206 +#endif
   1.207 +
   1.208 +#ifdef ENABLE_SMTP_SERVER
   1.209 +static void mode_smtp()
   1.210 +{
   1.211 +  /* accept smtp message on stdin */
   1.212 +  /* write responses to stderr. */
   1.213 +
   1.214 +  struct sockaddr_in saddr;
   1.215 +  gchar *peername = NULL;
   1.216 +  int dummy = sizeof(saddr);
   1.217 +#ifdef ENABLE_IDENT
   1.218 +  gchar *ident = NULL;
   1.219 +#endif
   1.220 +
   1.221 +  conf.do_verbose = FALSE;
   1.222 +
   1.223 +  if(!conf.run_as_user){
   1.224 +    seteuid(conf.orig_uid);
   1.225 +    setegid(conf.orig_gid);
   1.226 +  }
   1.227 +
   1.228 +  DEBUG(5) debugf("accepting smtp message on stdin\n");
   1.229 +
   1.230 +  if(getpeername(0, (struct sockaddr *)(&saddr), &dummy) == 0){
   1.231 +    peername = g_strdup(inet_ntoa(saddr.sin_addr));
   1.232 +#ifdef ENABLE_IDENT
   1.233 +    {
   1.234 +      gchar *id = NULL;
   1.235 +      if((id = (gchar *)ident_id(0, 60))){
   1.236 +	ident = g_strdup(id);
   1.237 +      }
   1.238 +    }
   1.239 +#endif
   1.240 +  }else if(errno != ENOTSOCK)
   1.241 +    exit(EXIT_FAILURE);
   1.242 +
   1.243 +  //smtp_in(stdin, stdout, peername);
   1.244 +  smtp_in(stdin, stderr, peername, NULL);
   1.245 +
   1.246 +#ifdef ENABLE_IDENT
   1.247 +  if(ident) g_free(ident);
   1.248 +#endif
   1.249 +}
   1.250 +#endif
   1.251 +
   1.252 +static void mode_accept(address *return_path, gchar *full_sender_name,
   1.253 +			guint accept_flags, char **addresses, int addr_cnt)
   1.254 +{
   1.255 +  /* accept message on stdin */
   1.256 +  accept_error err;
   1.257 +  message *msg = create_message();
   1.258 +  gint i;
   1.259 +
   1.260 +  if(return_path != NULL){
   1.261 +    if((conf.orig_uid != 0) &&
   1.262 +       (conf.orig_uid != conf.mail_uid) &&
   1.263 +       (!is_ingroup(conf.orig_uid, conf.mail_gid))){
   1.264 +      fprintf(stderr,
   1.265 +	      "must be in root, %s or in group %s for setting return path.\n",
   1.266 +	      DEF_MAIL_USER, DEF_MAIL_GROUP);
   1.267 +      exit(EXIT_FAILURE);
   1.268 +    }
   1.269 +  }
   1.270 +
   1.271 +  if(!conf.run_as_user){
   1.272 +    seteuid(conf.orig_uid);
   1.273 +    setegid(conf.orig_gid);
   1.274 +  }
   1.275 +
   1.276 +  DEBUG(5) debugf("accepting message on stdin\n");
   1.277 +
   1.278 +  msg->received_prot = PROT_LOCAL;
   1.279 +  for(i = 0; i < addr_cnt; i++){
   1.280 +    if(addresses[i][0] != '|')
   1.281 +      msg->rcpt_list =
   1.282 +	g_list_append(msg->rcpt_list,
   1.283 +		      create_address_qualified(addresses[i], TRUE, conf.host_name));
   1.284 +    else{
   1.285 +      logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]);
   1.286 +      exit(EXIT_FAILURE);
   1.287 +    }
   1.288 +  }
   1.289 +
   1.290 +  /* -f option */
   1.291 +  msg->return_path = return_path;
   1.292 +
   1.293 +  /* -F option */
   1.294 +  msg->full_sender_name = full_sender_name;
   1.295 +    
   1.296 +  if((err = accept_message(stdin, msg, accept_flags)) == AERR_OK){
   1.297 +    if(spool_write(msg, TRUE)){
   1.298 +      pid_t pid;
   1.299 +      logwrite(LOG_NOTICE, "%s <= %s with %s\n",
   1.300 +	       msg->uid, addr_string(msg->return_path),
   1.301 +	       prot_names[PROT_LOCAL]);
   1.302 +
   1.303 +      if(!conf.do_queue){
   1.304 +
   1.305 +	if((pid = fork()) == 0){
   1.306 +
   1.307 +	  conf.do_verbose = FALSE;
   1.308 +
   1.309 +	  fclose(stdin);
   1.310 +	  fclose(stdout);
   1.311 +	  fclose(stderr);
   1.312 +
   1.313 +	  if(deliver(msg)){
   1.314 +	    exit(EXIT_SUCCESS);
   1.315 +	  }else
   1.316 +	    exit(EXIT_FAILURE);
   1.317 +	}else if(pid < 0){
   1.318 +	  logwrite(LOG_ALERT, "could not fork for delivery, id = %s",
   1.319 +		   msg->uid);
   1.320 +	}
   1.321 +      }
   1.322 +    }else{
   1.323 +      fprintf(stderr, "Could not write spool file\n");
   1.324 +      exit(EXIT_FAILURE);
   1.325 +    }
   1.326 +  }else{
   1.327 +    switch(err){
   1.328 +    case AERR_EOF:
   1.329 +      fprintf(stderr, "unexpected EOF.\n");
   1.330 +      exit(EXIT_FAILURE);
   1.331 +    case AERR_NORCPT:
   1.332 +      fprintf(stderr, "no recipients.\n");
   1.333 +      exit(EXIT_FAILURE);
   1.334 +    default:
   1.335 +      /* should never happen: */
   1.336 +      fprintf(stderr, "Unknown error (%d)\r\n", err);
   1.337 +      exit(EXIT_FAILURE);
   1.338 +    }
   1.339 +    exit(EXIT_FAILURE);
   1.340 +  }
   1.341 +}
   1.342 +
   1.343 +int
   1.344 +main(int argc, char *argv[])
   1.345 +{
   1.346 +  /* cmd line flags */
   1.347 +  gchar *conf_file = CONF_FILE;
   1.348 +  gint arg = 1;
   1.349 +  gboolean do_get = FALSE;
   1.350 +  gboolean do_get_online = FALSE;
   1.351 +
   1.352 +  gboolean do_listen = FALSE;
   1.353 +  gboolean do_runq = FALSE;
   1.354 +  gboolean do_runq_online = FALSE;
   1.355 +
   1.356 +  gboolean do_queue = FALSE;
   1.357 +
   1.358 +  gboolean do_verbose = FALSE;
   1.359 +  gint debug_level = -1;
   1.360 +
   1.361 +  mta_mode mta_mode = MODE_ACCEPT;
   1.362 +
   1.363 +  gint queue_interval = 0;
   1.364 +  gint get_interval = 0;
   1.365 +  gboolean opt_t = FALSE;
   1.366 +  gboolean opt_i = FALSE;
   1.367 +  gboolean opt_odb = FALSE;
   1.368 +  gboolean opt_oem = FALSE;
   1.369 +  gboolean exit_failure = FALSE;
   1.370 +
   1.371 +  gchar *M_cmd = NULL;
   1.372 +
   1.373 +  gint exit_code = EXIT_SUCCESS;
   1.374 +  gchar *route_name = NULL;
   1.375 +  gchar *get_name = NULL;
   1.376 +  gchar *progname;
   1.377 +  gchar *f_address = NULL;
   1.378 +  gchar *full_sender_name = NULL;
   1.379 +  address *return_path = NULL; /* may be changed by -f option */
   1.380 +
   1.381 +  progname = get_progname(argv[0]);
   1.382 +
   1.383 +  if(strcmp(progname, "mailq") == 0)
   1.384 +    { mta_mode = MODE_LIST; }
   1.385 +  else if(strcmp(progname, "mailrm") == 0)
   1.386 +    { mta_mode = MODE_MCMD; M_cmd = "rm"; }
   1.387 +  else if(strcmp(progname, "runq") == 0)
   1.388 +    { mta_mode = MODE_RUNQUEUE; do_runq = TRUE; }
   1.389 +  else if(strcmp(progname, "rmail") == 0)
   1.390 +    { mta_mode = MODE_ACCEPT; opt_i = TRUE; }
   1.391 +  else if(strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0)
   1.392 +    { mta_mode = MODE_SMTP; }
   1.393 +
   1.394 +  /* parse cmd line */
   1.395 +  while(arg < argc){
   1.396 +    gint pos = 0;
   1.397 +    if((argv[arg][pos] == '-') && (argv[arg][pos+1] != '-')){
   1.398 +      pos++;
   1.399 +      switch(argv[arg][pos++]){
   1.400 +      case 'b':
   1.401 +	switch(argv[arg][pos++]){
   1.402 +	case 'd':
   1.403 +	  do_listen = TRUE;
   1.404 +	  mta_mode = MODE_DAEMON;
   1.405 +	  break;
   1.406 +	case 'i':
   1.407 +	  /* ignored */
   1.408 +	  mta_mode = MODE_BI;
   1.409 +	  break;
   1.410 +	case 's':
   1.411 +	  mta_mode = MODE_SMTP;
   1.412 +	  break;
   1.413 +	case 'p':
   1.414 +	  mta_mode = MODE_LIST;
   1.415 +	  break;
   1.416 +	case 'V':
   1.417 +	  mta_mode = MODE_VERSION;
   1.418 +	  break;
   1.419 +	default:
   1.420 +	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
   1.421 +	  exit(EXIT_FAILURE);
   1.422 +	}
   1.423 +	break;
   1.424 +      case 'B':
   1.425 +	/* we ignore this and throw the argument away */
   1.426 +	get_optarg(argv, argc, &arg, &pos);
   1.427 +	break;
   1.428 +      case 'C':
   1.429 +	if(!(conf_file = get_optarg(argv, argc, &arg, &pos))){
   1.430 +	  fprintf(stderr, "-C requires a filename as argument.\n");
   1.431 +	  exit(EXIT_FAILURE);
   1.432 +	}
   1.433 +	break;
   1.434 +      case 'F':
   1.435 +	{
   1.436 +	  full_sender_name = get_optarg(argv, argc, &arg, &pos);
   1.437 +	  if(!full_sender_name){
   1.438 +	    fprintf(stderr, "-F requires a name as an argument\n");
   1.439 +	    exit(EXIT_FAILURE);
   1.440 +	  }
   1.441 +	}
   1.442 +	break;
   1.443 +      case 'd':
   1.444 +	if(getuid() == 0){
   1.445 +	  char *lvl = get_optarg(argv, argc, &arg, &pos);
   1.446 +	  if(lvl)
   1.447 +	    debug_level = atoi(lvl);
   1.448 +	  else{
   1.449 +	    fprintf(stderr, "-d requires a number as an argument.\n");
   1.450 +	    exit(EXIT_FAILURE);
   1.451 +	  }
   1.452 +	}else{
   1.453 +	  fprintf(stderr, "only root may set the debug level.\n");
   1.454 +	  exit(EXIT_FAILURE);
   1.455 +	}
   1.456 +	break;
   1.457 +      case 'f':
   1.458 +	/* set return path */
   1.459 +	{
   1.460 +	  gchar *address;
   1.461 +	  address = get_optarg(argv, argc, &arg, &pos);
   1.462 +	  if(address){
   1.463 +	    f_address = g_strdup(address);
   1.464 +	  }else{
   1.465 +	    fprintf(stderr, "-f requires an address as an argument\n");
   1.466 +	    exit(EXIT_FAILURE);
   1.467 +	  }
   1.468 +	}
   1.469 +	break;
   1.470 +      case 'g':
   1.471 +	do_get = TRUE;
   1.472 +	if(!mta_mode) mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */
   1.473 +	if(argv[arg][pos] == 'o'){
   1.474 +	  pos++;
   1.475 +	  do_get_online = TRUE;
   1.476 +	  /* can be NULL, then we use online detection method */
   1.477 +	  route_name = get_optarg(argv, argc, &arg, &pos);
   1.478 +
   1.479 +	  if(route_name != NULL){
   1.480 +	    if(isdigit(route_name[0])){
   1.481 +	      get_interval = time_interval(route_name, &pos);
   1.482 +	      route_name = get_optarg(argv, argc, &arg, &pos);
   1.483 +	      mta_mode = MODE_GET_DAEMON;
   1.484 +	      do_get = FALSE;
   1.485 +	    }
   1.486 +	  }
   1.487 +	}else{
   1.488 +	  if((optarg = get_optarg(argv, argc, &arg, &pos))){
   1.489 +	    get_name = get_optarg(argv, argc, &arg, &pos);
   1.490 +	  }
   1.491 +	}
   1.492 +	break;
   1.493 +      case 'i':
   1.494 +	if(argv[arg][pos] == 0){
   1.495 +	  opt_i = TRUE;
   1.496 +	  exit_failure = FALSE; /* may override -oem */
   1.497 +	}else{
   1.498 +	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
   1.499 +	  exit(EXIT_FAILURE);
   1.500 +	}
   1.501 +	break;
   1.502 +      case 'M':
   1.503 +	{
   1.504 +	  mta_mode = MODE_MCMD;
   1.505 +	  M_cmd = g_strdup(&(argv[arg][pos]));
   1.506 +	}
   1.507 +	break;
   1.508 +      case 'o':
   1.509 +	switch(argv[arg][pos++]){
   1.510 +	case 'e':
   1.511 +	  if(argv[arg][pos++] == 'm') /* -oem */
   1.512 +	    if(!opt_i) exit_failure = TRUE;
   1.513 +	    opt_oem = TRUE;
   1.514 +	  break;
   1.515 +	case 'd':
   1.516 +	  if(argv[arg][pos] == 'b') /* -odb */
   1.517 +	    opt_odb = TRUE;
   1.518 +	  else if(argv[arg][pos] == 'q') /* -odq */
   1.519 +	    do_queue = TRUE;
   1.520 +	  break;
   1.521 +	case 'i':
   1.522 +	  opt_i = TRUE;
   1.523 +	  exit_failure = FALSE; /* may override -oem */
   1.524 +	  break;
   1.525 +	}
   1.526 +	break;
   1.527 +
   1.528 +      case 'q':
   1.529 +	{
   1.530 +	  gchar *optarg;
   1.531 +
   1.532 +	  do_runq = TRUE;
   1.533 +	  mta_mode = MODE_RUNQUEUE;
   1.534 +	  if(argv[arg][pos] == 'o'){
   1.535 +	    pos++;
   1.536 +	    do_runq = FALSE;
   1.537 +	    do_runq_online = TRUE;
   1.538 +	    /* can be NULL, then we use online detection method */
   1.539 +	    route_name = get_optarg(argv, argc, &arg, &pos);
   1.540 +	  }else if((optarg = get_optarg(argv, argc, &arg, &pos))){
   1.541 +	    mta_mode = MODE_DAEMON;
   1.542 +	    queue_interval = time_interval(optarg, &pos);
   1.543 +	  }
   1.544 +	}
   1.545 +	break;
   1.546 +      case 't':
   1.547 +	if(argv[arg][pos] == 0){
   1.548 +	  opt_t = TRUE;
   1.549 +	}else{
   1.550 +	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
   1.551 +	  exit(EXIT_FAILURE);
   1.552 +	}
   1.553 +	break;
   1.554 +      case 'v':
   1.555 +	do_verbose = TRUE;
   1.556 +	break;
   1.557 +      default:
   1.558 +	fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
   1.559 +	exit(EXIT_FAILURE);
   1.560 +      }
   1.561 +    }else{
   1.562 +      if(argv[arg][pos+1] == '-'){
   1.563 +        if(argv[arg][pos+2] != '\0'){
   1.564 +	  fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
   1.565 +	  exit(EXIT_FAILURE);
   1.566 +        }
   1.567 +	arg++;
   1.568 +      }
   1.569 +      break;
   1.570 +    }
   1.571 +    arg++;
   1.572 +  }
   1.573 +
   1.574 +  if(mta_mode == MODE_VERSION){
   1.575 +    gchar *with_resolver = "", *with_smtp_server = "", *with_pop3 = "", *with_auth = "", 
   1.576 +      *with_maildir = "", *with_ident = "", *with_mserver = "";
   1.577 +    
   1.578 +#ifdef ENABLE_RESOLVER
   1.579 +    with_resolver = " +resolver";
   1.580 +#endif
   1.581 +#ifdef ENABLE_SMTP_SERVER
   1.582 +    with_smtp_server = " +smtp-server";
   1.583 +#endif
   1.584 +#ifdef ENABLE_POP3
   1.585 +    with_pop3 = " +pop3";
   1.586 +#endif
   1.587 +#ifdef ENABLE_AUTH
   1.588 +    with_auth = " +auth";
   1.589 +#endif
   1.590 +#ifdef ENABLE_MAILDIR
   1.591 +    with_maildir = " +maildir";
   1.592 +#endif
   1.593 +#ifdef ENABLE_IDENT
   1.594 +    with_ident = " +ident";
   1.595 +#endif
   1.596 +#ifdef ENABLE_MSERVER
   1.597 +    with_mserver = " +mserver";
   1.598 +#endif
   1.599 +
   1.600 +    printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION,
   1.601 +	   with_resolver, with_smtp_server, with_pop3, with_auth,
   1.602 +	   with_maildir, with_ident, with_mserver);
   1.603 +      
   1.604 +    exit(EXIT_SUCCESS);
   1.605 +  }
   1.606 +
   1.607 +  /* initialize random generator */
   1.608 +  srand(time(NULL));
   1.609 +  /* ignore SIGPIPE signal */
   1.610 +  signal(SIGPIPE, SIG_IGN);
   1.611 +
   1.612 +  /* close all possibly open file descriptors */
   1.613 +  {
   1.614 +    int i, max_fd = sysconf(_SC_OPEN_MAX);
   1.615 +
   1.616 +    if(max_fd <= 0) max_fd = 64;
   1.617 +    for(i = 3; i < max_fd; i++)
   1.618 +      close(i);
   1.619 +  }
   1.620 +
   1.621 +  init_conf();
   1.622 +
   1.623 +  /* if we are not privileged, and the config file was changed we
   1.624 +     implicetely set the the run_as_user flag and give up all
   1.625 +     privileges.
   1.626 +
   1.627 +     So it is possible for a user to run his own daemon without
   1.628 +     breaking security.
   1.629 +  */
   1.630 +  if(strcmp(conf_file, CONF_FILE) != 0){
   1.631 +    if(conf.orig_uid != 0){
   1.632 +      conf.run_as_user = TRUE;
   1.633 +      seteuid(conf.orig_uid);
   1.634 +      setegid(conf.orig_gid);
   1.635 +      setuid(conf.orig_uid);
   1.636 +      setgid(conf.orig_gid);
   1.637 +    }
   1.638 +  }
   1.639 +
   1.640 +  read_conf(conf_file);
   1.641 +
   1.642 +  if(do_queue) conf.do_queue = TRUE;
   1.643 +  if(do_verbose) conf.do_verbose = TRUE;
   1.644 +  if(debug_level >= 0) /* if >= 0, it was given by argument */
   1.645 +    conf.debug_level = debug_level;
   1.646 +
   1.647 +  chdir("/");
   1.648 +
   1.649 +  if(!conf.run_as_user){
   1.650 +    if(setgid(0) != 0){
   1.651 +      fprintf(stderr,
   1.652 +	      "could not set gid to 0. Is the setuid bit set? : %s\n",
   1.653 +	      strerror(errno));
   1.654 +      exit(EXIT_FAILURE);
   1.655 +    }
   1.656 +    if(setuid(0) != 0){
   1.657 +      fprintf(stderr,
   1.658 +	      "could not gain root privileges. Is the setuid bit set? : %s\n",
   1.659 +	      strerror(errno));
   1.660 +      exit(EXIT_FAILURE);
   1.661 +    }
   1.662 +  }
   1.663 +
   1.664 +  if(!logopen()){
   1.665 +    fprintf(stderr, "could not open log file\n");
   1.666 +    exit(EXIT_FAILURE);
   1.667 +  }
   1.668 +
   1.669 +  DEBUG(1) debugf("masqmail %s starting\n", VERSION);
   1.670 +
   1.671 +  DEBUG(5){
   1.672 +    gchar **str = argv;
   1.673 +    debugf("args: \n");
   1.674 +    while(*str){
   1.675 +      debugf("%s \n", *str);
   1.676 +      str++;
   1.677 +    }
   1.678 +  }
   1.679 +  DEBUG(5) debugf("queue_interval = %d\n", queue_interval);
   1.680 +
   1.681 +  if(f_address){
   1.682 +    return_path = create_address_qualified(f_address, TRUE, conf.host_name);
   1.683 +    g_free(f_address);
   1.684 +    if(!return_path){
   1.685 +      fprintf(stderr, "invalid RFC821 address: %s\n", f_address);
   1.686 +      exit(EXIT_FAILURE);
   1.687 +    }
   1.688 +  }
   1.689 +
   1.690 +  if(do_get){
   1.691 +#ifdef ENABLE_POP3
   1.692 +    if((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)){
   1.693 +
   1.694 +      set_identity(conf.orig_uid, "getting mail");
   1.695 +
   1.696 +      if(do_get_online){
   1.697 +	if(route_name != NULL){
   1.698 +	  conf.online_detect = g_strdup("argument");
   1.699 +	  set_online_name(route_name);
   1.700 +	}
   1.701 +	get_online();
   1.702 +      }else{
   1.703 +	if(get_name)
   1.704 +	  get_from_name(get_name);
   1.705 +	else
   1.706 +	  get_all();
   1.707 +      }
   1.708 +    }else{
   1.709 +      logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n");
   1.710 +    }
   1.711 +#else
   1.712 +    fprintf(stderr, "get (pop) support not compiled in\n");
   1.713 +#endif
   1.714 +  }
   1.715 +
   1.716 +  switch(mta_mode){
   1.717 +  case MODE_DAEMON:
   1.718 +    mode_daemon(do_listen, queue_interval, argv);
   1.719 +    break;
   1.720 +  case MODE_RUNQUEUE:
   1.721 +    {
   1.722 +      /* queue runs */
   1.723 +      set_identity(conf.orig_uid, "queue run");
   1.724 +
   1.725 +      if(do_runq)
   1.726 +	exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE;
   1.727 +
   1.728 +      if(do_runq_online){
   1.729 +	if(route_name != NULL){
   1.730 +	  conf.online_detect = g_strdup("argument");
   1.731 +	  set_online_name(route_name);
   1.732 +	}
   1.733 +	exit_code = queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE;
   1.734 +      }
   1.735 +    }
   1.736 +    break;
   1.737 +  case MODE_GET_DAEMON:
   1.738 +#ifdef ENABLE_POP3
   1.739 +    if(route_name != NULL){
   1.740 +      conf.online_detect = g_strdup("argument");
   1.741 +      set_online_name(route_name);
   1.742 +    }
   1.743 +    mode_get_daemon(get_interval, argv);
   1.744 +#endif
   1.745 +    break;
   1.746 +
   1.747 +  case MODE_SMTP:
   1.748 +#ifdef ENABLE_SMTP_SERVER
   1.749 +    mode_smtp();
   1.750 +#else
   1.751 +    fprintf(stderr, "smtp server support not compiled in\n");
   1.752 +#endif
   1.753 +    break;
   1.754 +  case MODE_LIST:
   1.755 +
   1.756 +    queue_list();
   1.757 +    break;
   1.758 +
   1.759 +  case MODE_BI:
   1.760 +    
   1.761 +    exit(EXIT_SUCCESS);
   1.762 +    break; /* well... */
   1.763 +    
   1.764 +  case MODE_MCMD:
   1.765 +    if(strcmp(M_cmd, "rm") == 0){
   1.766 +      gboolean ok = FALSE;
   1.767 +
   1.768 +      set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
   1.769 +
   1.770 +      if(is_privileged_user(conf.orig_uid)){
   1.771 +	for(; arg < argc; arg++){
   1.772 +	  if(queue_delete(argv[arg]))
   1.773 +	    ok = TRUE;
   1.774 +	}
   1.775 +      }else{
   1.776 +	struct passwd *pw = getpwuid(conf.orig_uid);
   1.777 +	if(pw){
   1.778 +	  for(; arg < argc; arg++){
   1.779 +	    message *msg = msg_spool_read(argv[arg], FALSE);
   1.780 +#ifdef ENABLE_IDENT
   1.781 +	    if(((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) ||
   1.782 +	       is_in_netlist(msg->received_host, conf.ident_trusted_nets)){
   1.783 +#else
   1.784 +	      if((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)){
   1.785 +#endif
   1.786 +	      if(msg->ident){
   1.787 +		if(strcmp(pw->pw_name, msg->ident) == 0){
   1.788 +		  if(queue_delete(argv[arg]))
   1.789 +		    ok = TRUE;
   1.790 +		}else{
   1.791 +		  fprintf(stderr, "you do not own message id %s\n", argv[arg]);
   1.792 +		}
   1.793 +	      }else
   1.794 +		fprintf(stderr, "message %s does not have an ident.\n", argv[arg]);
   1.795 +	    }else{
   1.796 +	      fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]);
   1.797 +	    }
   1.798 +	  }
   1.799 +	}else{
   1.800 +	  fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno));
   1.801 +	}
   1.802 +      }
   1.803 +      exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
   1.804 +    }else{
   1.805 +      fprintf(stderr, "unknown command %s\n", M_cmd);
   1.806 +      exit(EXIT_FAILURE);
   1.807 +    }
   1.808 +    break;
   1.809 +
   1.810 +    case MODE_ACCEPT:
   1.811 +    {
   1.812 +      guint accept_flags =
   1.813 +	(opt_t ? ACC_DEL_RCPTS|ACC_DEL_BCC|ACC_RCPT_FROM_HEAD : ACC_HEAD_FROM_RCPT) |
   1.814 +	(opt_i ? ACC_NODOT_TERM : ACC_NODOT_RELAX);
   1.815 +    
   1.816 +      mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg);
   1.817 +
   1.818 +      exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS);
   1.819 +    }
   1.820 +    break;
   1.821 +  case MODE_NONE:
   1.822 +      break;
   1.823 +  default:
   1.824 +      fprintf(stderr, "unknown mode: %d\n", mta_mode);
   1.825 +      break;
   1.826 +    }
   1.827 +    
   1.828 +  logclose();
   1.829 +
   1.830 +  exit(exit_code);
   1.831 +}