Logo Search packages:      
Sourcecode: mailagent version File versions  Download package

main.c

/*

 #    #    ##       #    #    #           ####
 ##  ##   #  #      #    ##   #          #    #
 # ## #  #    #     #    # #  #          #
 #    #  ######     #    #  # #   ###    #
 #    #  #    #     #    #   ##   ###    #    #
 #    #  #    #     #    #    #   ###     ####

      The main entry point.
*/

/*
 * $Id: main.c 23 2008-05-30 09:30:12Z rmanfredi $
 *
 *  Copyright (c) 1990-2006, Raphael Manfredi
 *  
 *  You may redistribute only under the terms of the Artistic License,
 *  as specified in the README file that comes with the distribution.
 *  You may reuse parts of this distribution only within the terms of
 *  that same Artistic License; a copy of which may be found at the root
 *  of the source tree for mailagent 3.0.
 *
 * $Log: main.c,v $
 * Revision 3.0.1.6  1997/02/20  11:36:56  ram
 * patch55: now uses getopt() to parse command line switches
 * patch55: new -o switch to redirect output
 *
 * Revision 3.0.1.5  1997/01/31  18:06:43  ram
 * patch54: also trap fatal SIGSEGV and SIGBUS signals
 *
 * Revision 3.0.1.4  1997/01/07  18:26:49  ram
 * patch52: don't use my_exit() when printing version number
 *
 * Revision 3.0.1.3  1996/12/24  13:58:44  ram
 * patch45: use more portable real uid/gid setting
 *
 * Revision 3.0.1.2  1995/08/31  16:19:51  ram
 * patch42: now uses say() to print messages onto stderr
 *
 * Revision 3.0.1.1  1995/01/03  17:55:44  ram
 * patch24: added a -V option to print out the version and patchlevel
 *
 * Revision 3.0  1993/11/29  13:48:15  ram
 * Baseline for mailagent 3.0 netwide release.
 *
 */

#include "config.h"
#include "portable.h"

#ifdef I_STRING
#include <string.h>
#else
#include <strings.h>
#endif

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>

#ifdef I_UNISTD
#include <unistd.h>
#endif

#ifdef I_STDLIB
#include <stdlib.h>
#endif

#include "logfile.h"
#include "io.h"
#include "hash.h"
#include "msg.h"
#include "parser.h"
#include "sysexits.h"
#include "lock.h"
#include "confmagic.h"
#include "patchlevel.h"
#include "revision.h"

#define MAX_STRING      2048  /* Maximum string length */

private Signal_t handler();   /* Signal handler */
private void set_signal();    /* Set up the signal handler */
private int set_real_uid();   /* Reset real uid */
private int set_real_gid();   /* Reset real gid */
private void no_setid();      /* Option not allowed when running set[ug]id */

extern void env_home();       /* Only for tests */
extern void my_exit();

public int main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
      /* This is the main entry point for the mail filter */

      char *value;                                    /* Symbol value */
      int euid, uid;                                  /* Current effective and real uid */
      int egid, gid;                                  /* Effective and real gid */
      int c;                                                /* Current switch value */
      extern char *optarg;                      /* getopt() globals */
      extern int optind;

      /* Compute program name, removing any leading path to keep only the name
       * of the executable file.
       */
      progname = rindex(argv[0], '/');    /* Only last name if '/' found */
      if (progname++ == (char *) 0)       /* There were no '/' */
            progname = argv[0];                       /* This must be the filename then */
      progpid = getpid();                             /* Program's PID */

      /* Security precautions. Look who we are and who we pretend to be */
      uid = getuid();
      gid = getgid();
      euid = geteuid();
      egid = getegid();

      /*
       * The '-o' switch allows redirection of both stderr and stdout to the
       * specified file. This can be used on systems forbiding shell redirection
       * in the .forward. When running set[ug]id, we only append to existing
       * files owned by the real uid, for security reasons.
       *
       * The '-t' option means we are in test mode: set the home directory by
       * using the environment HOME variable, so that we may provide our own
       * configuration file elsewhere. Of course, this cannot be used if the
       * filter is setuid and invoked by an uid different from the owner of the
       * filter program.
       *
       * The '-V' option prints out the version and patchlevel, for sanity
       * checks (to make sure the latest filter is installed, for instance).
       */

      while ((c = getopt(argc, argv, "o:tV")) != EOF) {
            switch (c) {
            case 'o':               /* output redirection */
                  if (!io_redirect(optarg, uid != euid || gid != egid, uid))
                        say("unable to redirect output to %s, continuing...", optarg);
                  break;
            case 't':               /* test mode */
                  no_setid(c, uid, euid, gid, egid);
                  env_home();                         /* Get HOME from environment */
                  break;
            case 'V':               /* version number */
                  printf("filter %.1f-%d\n", VERSION, REVISION);
                  exit(EX_OK);
                  /* NOTRECHED */
            default:
                  say("unknown switch -%c", c);
                  exit(EX_USAGE);
            }
      }

      set_signal();                                   /* Set up signal handler */
      read_conf(argv[0], ".mailagent");   /* Read configuration file */

      add_log(11, "starting processing");

      /* We'll be invoking a perl script with the -S switch, and perl will not
       * allow us to do that if it detects "setuidness". Some sendmail programs
       * are broken and do not reset the uid/gid correctly when they process
       * their queue. This is why it is important to set the setuid and setgid
       * bits on the filter program.
       */

      /* Make sure our gid matches the effective gid */
      if (egid != gid && -1 == set_real_gid(egid)) {
            add_log(1, "SYSERR setgid: %m (%e)");
            add_log(4, "WARNING cannot set GID to %d, continuing as %d", egid, gid);
      } else if (egid != gid)
            add_log(6, "NOTICE reset GID from %d to %d", gid, egid);

      /* Make sure our uid matches the effective uid */
      if (euid != uid && -1 == set_real_uid(euid)) {
            add_log(1, "SYSERR setuid: %m (%e)");
            add_log(4, "WARNING cannot set UID to %d, continuing as %d", euid, uid);
      } else if (euid != uid)
            add_log(6, "NOTICE reset UID from %d to %d", uid, euid);

      value = ht_value(&symtab, "queue");       /* Fetch queue location */
      if (value == (char *) 0)
            fatal("queue directory not defined");

      set_env_vars(envp);                                   /* Set environment variables */
      process();                                            /* Process mail */

      my_exit(EX_OK);         /* We did it */
      return 0;               /* Shut up compielr warnings */
}

private int set_real_uid(ruid)
int ruid;
{
#ifdef HAS_SETRUID
      return setruid(ruid);
#endif
      return setuid(ruid);
}

private int set_real_gid(rgid)
int rgid;
{
#ifdef HAS_SETRGID
      return setrgid(rgid);
#endif
      return setgid(rgid);
}

private void set_signal()
{
      /* Set up the signal handler */

#ifdef SIGHUP
      signal(SIGHUP, handler);
#endif
#ifdef SIGINT
      signal(SIGINT, handler);
#endif
#ifdef SIGQUIT
      signal(SIGQUIT, handler);
#endif
#ifdef SIGTERM
      signal(SIGTERM, handler);
#endif
#ifdef SIGSEGV
      signal(SIGSEGV, handler);
#endif
#ifdef SIGBUS
      signal(SIGBUS, handler);
#endif
}

private void no_setid(opt, uid, euid, gid, egid)
int opt, uid, euid, gid, egid;
{
      /* Don't allow switch '-opt' when running set[ug]id */

      if (uid == euid && gid == egid)
            return;

      say("option -%c not allowed when running set%s",
            opt, uid != euid ? "uid":"gid");
      exit(EX_USAGE);
}

private Signal_t handler(sig)
int sig;
{
      /* A signal was caught */

      release_lock();                           /* Release lock file if necessary */
      fatal("caught signal #%d", sig);
}


Generated by  Doxygen 1.6.0   Back to index