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

main.C

/*
** Copyright 1998 - 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/

#include    "lexer.h"
#include    "recipe.h"
#include    "varlist.h"
#include    "funcs.h"
#include    "tempfile.h"
#include    "message.h"
#include    "messageinfo.h"
#include    "xconfig.h"
#include    "exittrap.h"
#include    "maildrop.h"
#include    "config.h"
#include    "setgroupid.h"
#include    <sys/types.h>

#if   HAVE_LOCALE_H
#include    <locale.h>
#endif

#if HAVE_SYS_STAT_H
#include    <sys/stat.h>
#endif
#include    <sysexits.h>
#include    <string.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <ctype.h>
#include    <pwd.h>
#include    <grp.h>
#include    "../dbobj.h"
#if   USERDB
#include    "../userdb/userdb.h"
#endif
#if USELDAP
#include        "mdldapconfig.h"
#include        "mdldap.h"
#endif
#if USEMYSQL
#include        "mdmysqlconfig.h"
#include        "mdmysql.h"
#endif

static const char rcsid[]="$Id: main.C,v 1.42 2003/04/10 00:21:57 mrsam Exp $";
#if   HAS_GETHOSTNAME
#else
extern "C" int gethostname(const char *, size_t);
#endif


extern void setprocgroup();

static Message m1, m2;
extern char **environ;
static int errexit=EX_TEMPFAIL;
int quota_warn_percent = -1;
static const char *defaults_vars[]={"LOCKEXT","LOCKSLEEP","LOCKTIMEOUT",
                              "LOCKREFRESH", "PATH", "SENDMAIL",
                              "MAILDIRQUOTA"};
static const char *defaults_vals[]={LOCKEXT_DEF,LOCKSLEEP_DEF,LOCKTIMEOUT_DEF,
                              LOCKREFRESH_DEF, DEFAULT_PATH,
                              SENDMAIL_DEF, ""};

Maildrop maildrop;

Maildrop::Maildrop()
{
      verbose_level=0;
      isdelivery=0;
      sigfpe=0;
      includelevel=0;
      embedded_mode=0;
      msgptr= &m1;
      savemsgptr= &m2;
}

static void help()
{
      mout << "Usage: maildrop [options] [-d user] [arg] [arg] ...\n";
      mout << "       maildrop [options] [filterfile [arg] [arg] ...\n";
}

static void bad()
{
      errexit=EX_TEMPFAIL;
      throw "Bad command line arguments, -h for help.";
}

static void nouser()
{
      errexit=EX_TEMPFAIL;
      throw "Invalid user specified.";
}

static void nochangeuidgid()
{
      errexit=EX_TEMPFAIL;
      throw "Cannot set my user or group id.";
}

static int trusted_user(uid_t uid)
{
static char trusted_users[]=TRUSTED_USERS;
static char buf[ sizeof(trusted_users) ];
char  *p;

      strcpy(buf, trusted_users);
      for (p=buf; (p=strtok(p, " ")) != 0; p=0)
      {
      struct      passwd *q=getpwnam(p);

            if (q && q->pw_uid == uid)
                  return (1);
      }
      return (0);
}

static int trusted_group(gid_t gid)
{
static char trusted_groups[]=TRUSTED_GROUPS;
static char buf[ sizeof(trusted_groups) ];
char  *p;

      strcpy(buf, trusted_groups);
      for (p=buf; (p=strtok(p, " ")) != 0; p=0)
      {
      struct      group *q=getgrnam(p);

            if (q && (gid_t)q->gr_gid == gid)
                  return (1);
      }
      return (0);
}

static int trusted_uidgid(uid_t uid, gid_t gid, gid_t gid2)
{
      if (trusted_user(uid) || trusted_group(gid) ||
            trusted_group(gid2))
            return (1);
      return (0);
}

static void sethostname(Buffer &buf)
{
char    hostname[256];

        hostname[0]=0;
        gethostname(hostname, 256);
        hostname[sizeof(hostname)-1]=0;

      buf=hostname;
}


static void copyright()
{
static const char msg[]="maildrop " VERSION " Copyright 1998-2003 Double Precision, Inc."

#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#ifdef DbObj
      "GDBM extensions enabled."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
#if USE_DB
      "Enabled Berkeley DB instead of GDBM extensions."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
#if MAILDIRQUOTA
      "Maildir quota extension enabled."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
#if USERDB
      "Virtual user database extension enabled."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
#if USELDAP
        "Virtual user database via LDAP extension enabled."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
#if USEMYSQL
        "Virtual user database via MySQL extension enabled."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
#endif
      "This program is distributed under the terms of the GNU General Public"
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
        "License. See COPYING for additional information."
#if CRLF_TERM
      "\r\n"
#else
      "\n"
#endif
 
            ;

      mout << msg;
      mout.flush();
}

void Maildrop::reset_vars()
{
int   i;
Buffer      name, value;

      for (i=0; i<(int)(sizeof(defaults_vars)/sizeof(defaults_vars[0])); i++)
      {
            name=defaults_vars[i];
            value=defaults_vals[i];
            SetVar(name, value);
      }
      name="HOME";
      SetVar(name, maildrop.init_home);
      name="LOGNAME";
      SetVar(name, maildrop.init_logname);
      name="SHELL";
      SetVar(name, maildrop.init_shell);
      name="DEFAULT";
      SetVar(name, maildrop.init_default);

      name="UMASK";
      value="077";
      SetVar(name, value);

      if (maildrop.init_quota.Length() > 0)
      {
            name="MAILDIRQUOTA";
            SetVar(name, maildrop.init_quota);
      }
}

// Finds a user in the userdb
int find_in_userdb(Maildrop *maildrop, const char* user)
{
#if   USERDB
      userdb_init(ETCDIR "/userdb.dat");
      char  *p;
      struct userdbs *udbs;

      p=userdb(user);
      if (!p && errno != ENOENT)
      {
            errexit=EX_TEMPFAIL;
            throw "Error opening userdb.dat";
      }
      udbs=0;
      if (p)
      {
            udbs=userdb_creates(p);
            free(p);
            if (!udbs && errno != ENOENT)
            {
                  errexit=EX_TEMPFAIL;
                  throw "Temp failure in userdb_creates";
            }
      }

      if (udbs)
      {
#if   RESET_GID
            setgroupid(udbs->udb_gid);
#endif
            setuid(udbs->udb_uid);
            if (getuid() != udbs->udb_uid)
                  nochangeuidgid(); // Security violation.

            if (udbs->udb_quota)
                  maildrop->init_quota=udbs->udb_quota;
            maildrop->init_home=udbs->udb_dir;
            maildrop->init_logname=user;
            maildrop->init_shell=udbs->udb_shell &&
                  *udbs->udb_shell ?
                        udbs->udb_shell:"/bin/sh";
            maildrop->init_default=udbs->udb_mailbox &&
                  *udbs->udb_mailbox ?
                        udbs->udb_mailbox:
                              GetDefaultMailbox(user);

            userdb_frees(udbs);

            return 1;
      }
#endif
      return 0;
}

// Finds a user in the mysql database
int find_in_mysql(Maildrop *maildrop, const char* user)
{
#if USEMYSQL
      mdmysqlconfig *mysqlcfg = NULL;
      char *mtmp;

      // Read the config
      mysqlcfg = (mdmysqlconfig*)get_mysql_config(MAILDROPMYSQLCONFIG);
      if ( mysqlcfg )
        if ( !(mysqlcfg->hostname && mysqlcfg->database && mysqlcfg->dbtable) )
            return 0;

      // Find the user
    mdmysqlrec *mrec = NULL;
      mrec = get_user_mysql(mysqlcfg,(char*)user);
      if ( mrec )
      {
          setgroupid(mrec->gidnumber);
          setuid(mrec->uidnumber);
            if ( getuid() != (gid_t)mrec->uidnumber )
                  nochangeuidgid();

            if ( mrec->quota )
                  maildrop->init_quota=mrec->quota;
            else {
                  /* if maildirsize exists, delete it .. or else new quotas may not work
                  if they are now disabled, but once were set... this was a bug I found
                  in v1.2.0 .. if its been fixed then this block can be removed */
                  mtmp = (char*)malloc(strlen(mrec->maildir)+strlen("/maildirsize")+1);
                  strcat(strcpy(mtmp, mrec->maildir), "/maildirsize");
                  unlink(mtmp);
                  free(mtmp);
            }

            maildrop->init_home=mrec->homedir;
            maildrop->init_logname=user;
            maildrop->init_shell="/bin/sh";
            maildrop->init_default=mrec->maildir ? mrec->maildir : 
                  GetDefaultMailbox(user);

            free_mysql_rec(&mrec);
                            
            return 1;
      }
#endif 
      return 0;
}

// Finds a user in ldap
int find_in_ldap(Maildrop* maildrop, const char* user)
{
#if USELDAP
      mdldapconfig *ldapcfg = NULL;
      char *tmp;
      
      // Look for the config
      ldapcfg = (mdldapconfig*)get_ldap_config(MAILDROPLDAPCONFIG);
      if ( ldapcfg )
        if ( !(ldapcfg->hostname && ldapcfg->basedn) )
            return 0;

      // Find the user
      mdldaprec *rec = NULL;
      rec = get_user_ldap(ldapcfg,(char*)user);
      if ( rec )
      {
            setgroupid(rec->gidnumber);
            setuid(rec->uidnumber);
            if ( getuid() != (gid_t)rec->uidnumber )
                  nochangeuidgid();

            if ( rec->quota )
                  maildrop->init_quota=rec->quota;
            else {
                  /* if maildirsize exists, delete it .. or else new quotas may not work
                  if they are now disabled, but once were set... this was a bug I found
                  in v1.2.0 .. if its been fixed then this block can be removed */
                  tmp = (char*)malloc(strlen(rec->maildir)+strlen("/maildirsize")+1);
                  strcat(strcpy(tmp, rec->maildir), "/maildirsize");
                  unlink(tmp);
                  free(tmp);
            }

            maildrop->init_home=rec->homedirectory;
            maildrop->init_logname=user;
            maildrop->init_shell="/bin/sh";
            maildrop->init_default=rec->maildir ? rec->maildir : 
                  GetDefaultMailbox(user);;

            free_ldap_rec(&rec);
                            
            return 1;
      }
#endif 
      return 0;
}

static int run(int argc, char **argv)
{
int   argn;
const char *deliverymode=0;
char *embedded_filter=0;
const char *from=0;
Buffer      recipe;
uid_t orig_uid;
gid_t orig_gid, orig_gid2;
Buffer      extra_headers;
struct passwd *my_pw;
int   found;
#if   HAVE_COURIER
#if   RESTRICT_TRUSTED
const char *numuidgid=0;
#endif
#endif


      umask( 0007 );
      for (argn=1; argn < argc; )
      {
            if (argv[argn][0] != '-')     break;
            if (strcmp(argv[argn], "--") == 0)  { ++argn; break; }

      char  optc=argv[argn][1];
      const char *optarg=argv[argn]+2;

            ++argn;
            switch (optc)     {

#if   HAVE_COURIER
#if   RESTRICT_TRUSTED
            case 'D':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  numuidgid=optarg;
                  break;
#endif
#endif
            case 'd':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  deliverymode=optarg;
                  break;
            case 'V':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  maildrop.verbose_level=atoi(optarg);
                  break;
            case 'v':
                  copyright();
                  return (0);
            case 'm':
                  maildrop.embedded_mode=1;
                  break;
            case 'M':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  maildrop.embedded_mode=1;
                  if (!deliverymode)      deliverymode="";
                  if (!*optarg)
                  {
                        help();
                        return (EX_TEMPFAIL);
                  }
                  embedded_filter=(char *)malloc(strlen(optarg)+1);
                  if (!embedded_filter)   outofmem();
                  strcpy(embedded_filter, optarg);
                  {
                  char *p;

                        for (p=embedded_filter; *p; p++)
                              if (*p == SLASH_CHAR || *p == '.')
                                    *p=':';
                  }
                  break;
            case 'A':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  if (*optarg)
                  {
                        extra_headers += optarg;
                        extra_headers += '\n';
                  }
                  break;
            case 'f':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  if (*optarg)
                        from=optarg;
                  break;
            case 'w':
                  if (!*optarg && argn < argc)  optarg=argv[argn++];
                  if (*optarg)
                        quota_warn_percent=atoi(optarg);
                  break;
            case 'h':
                  help();
                  return (EX_TEMPFAIL);
            default:
                  bad();
            }
      }

      my_pw=0;
      found=0;
      orig_uid=getuid();
      orig_gid=getgid();
      orig_gid2=getegid();
      if (!deliverymode && argn < argc)
            recipe=argv[argn++];
      else
      {
            if (!deliverymode)      deliverymode="";

            if (*deliverymode)
            {
                  found = find_in_userdb(&maildrop, deliverymode);
                  if ( !found ) found = find_in_ldap(&maildrop, deliverymode);
                  // Try to find in mysql
                  if ( !found) found = find_in_mysql(&maildrop, deliverymode);

                  if ( !found )
                  {
                        my_pw=getpwnam(deliverymode);
                        if (!my_pw)
                              nouser();
#if   RESET_GID
                        setgroupid(my_pw->pw_gid);
#endif
                        setuid(my_pw->pw_uid);
                        if (getuid() != my_pw->pw_uid)
                              nochangeuidgid(); // Security violation.

                        maildrop.init_home=my_pw->pw_dir;
                        maildrop.init_logname=my_pw->pw_name;
                        maildrop.init_shell=
                              my_pw->pw_shell && *my_pw->pw_shell
                                    ? my_pw->pw_shell:"/bin/sh";
                        maildrop.init_default=
                              GetDefaultMailbox(my_pw->pw_name);
                        found=1;
                  }
            }
            maildrop.isdelivery=1;
#if   RESTRICT_TRUSTED
            if ( getuid() != orig_uid && !trusted_uidgid(orig_uid,
                  orig_gid, orig_gid2))
            {
                  errexit=EX_TEMPFAIL;
                  throw "You are not a trusted user.";
                              // Security violation
            }
#endif
      }

#if   HAVE_COURIER
#if   RESTRICT_TRUSTED
      if (numuidgid)
      {
      uid_t un=0;
      gid_t gn=getgid();

            if (deliverymode && *deliverymode)
            {
                  errexit=EX_TEMPFAIL;
                  throw "Cannot use both -d and -D options.";
            }

            if ( !trusted_uidgid(orig_uid, orig_gid, orig_gid2))
            {
                  errexit=EX_TEMPFAIL;
                  throw "You are not authorized to use the -D option.";
            }

            if (!isdigit( (int)(unsigned char)*numuidgid))
            {
                  errexit=EX_TEMPFAIL;
                  throw "Invalid -D option.";
            }

            do
            {
                  un=un * 10 + (*numuidgid++ - '0');
            } while (isdigit( (int)(unsigned char)*numuidgid));

            if ( *numuidgid )
            {
                  if ( *numuidgid++ != '/' ||
                        !isdigit( (int)(unsigned char)*numuidgid))
                  {
                        errexit=EX_TEMPFAIL;
                        throw "Invalid -D option.";
                  }
                  gn=0;
                  do
                  {
                        gn=gn * 10 + (*numuidgid++ - '0');
                  } while (isdigit( (int)(unsigned char)*numuidgid));

                  if ( *numuidgid )
                  {
                        errexit=EX_TEMPFAIL;
                        throw "Invalid -D option.";
                  }
            }
            setgroupid(gn);
            setuid(un);
            deliverymode="";
            orig_uid=un;      /* See below for another Courier hook */
      }
#endif
#endif


#if   RESET_GID
      setgroupid(getgid());
#endif

uid_t my_u=getuid();

      setuid(my_u);     // Drop any setuid privileges.

      if (!found)
      {
#if   USERDB
      struct userdbs *udbs;

            udbs=userdb_createsuid(my_u);

            if (!udbs && errno != ENOENT)
            {
                  errexit=EX_TEMPFAIL;
                  throw "Temp failure in userdb_creates";
            }

            if (udbs)
            {
                  if (udbs->udb_quota)
                        maildrop.init_quota=udbs->udb_quota;
                  maildrop.init_home=udbs->udb_dir;
                  maildrop.init_logname=udbs->udb_name;
                  maildrop.init_shell=udbs->udb_shell &&
                              *udbs->udb_shell ?
                              udbs->udb_shell:"/bin/sh";
                  maildrop.init_default=udbs->udb_mailbox &&
                        *udbs->udb_mailbox ?
                              udbs->udb_mailbox:
                        GetDefaultMailbox(udbs->udb_name);
                  userdb_frees(udbs);
            }
            else
#endif
#if HAVE_COURIER
            if (!deliverymode)
#endif
            {
                  my_pw=getpwuid(my_u);
                  if (!my_pw)
                  {
                        errexit=EX_TEMPFAIL;
                        throw "Cannot determine my username.";
                  }

                  maildrop.init_home=my_pw->pw_dir;
                  maildrop.init_logname=my_pw->pw_name;
                  maildrop.init_shell=
                        my_pw->pw_shell && *my_pw->pw_shell
                              ? my_pw->pw_shell:"/bin/sh";
                  maildrop.init_default=
                        GetDefaultMailbox(my_pw->pw_name);
            }
      }

#if   USERDB
      userdb_close();
#endif

int   i;
Buffer      name;
Buffer      value;

      if (!maildrop.isdelivery)
      {
            for (i=0; environ[i]; i++)
            {
                  name=environ[i];

            char  *p=strchr(environ[i], '=');

                  value= p ? (name.Length(p - environ[i]), p+1):"";
                  SetVar(name, value);
            }
      }

      i=1;
      while (argn < argc)
      {
            name="";
            name.append( (unsigned long)i);
            value=argv[argn++];
            SetVar(name, value);
            ++i;
      }

#if   HAVE_COURIER
      if (deliverymode && orig_uid == getuid())
      {
      const char *p;

            if ((p=getenv("HOME")) && *p)
                  maildrop.init_home=p;

            if ((p=getenv("LOGNAME")) && *p)
                  maildrop.init_logname=p;

            if ((p=getenv("SHELL")) && *p)
                  maildrop.init_shell=p;

            p=getenv("MAILDROPDEFAULT");

            if (!p || !*p)
            {
                  p=getenv("LOCAL");

                  if (p && *p)
                        p=GetDefaultMailbox(p);
                  else
                        p="./Maildir";
            }
            maildrop.init_default=p;

            if ((p=getenv("MAILDIRQUOTA")) && *p)
                  maildrop.init_quota=p;
      }
#endif

      if (deliverymode)
      {
      struct      stat  buf;
      Buffer      b;

            b=maildrop.init_home;
            b += '\0';

      const char *h=b;

            if (VerboseLevel() > 1)
                  merr << "maildrop: Changing to " << h << "\n";

            if (chdir(h) < 0)
            {
                  errexit=EX_TEMPFAIL;
                  throw "Unable to change to home directory.";
            }
            recipe=".mailfilter";

            if ( stat(".", &buf) < 0 ||
                  !S_ISDIR(buf.st_mode) ||
                  buf.st_mode & S_IWOTH ||
                  buf.st_uid != getuid())
            {
                  errexit=EX_TEMPFAIL;
                  throw "Invalid home directory permissions - world writable.";
            }

            // Quietly terminate if the sticky bit is set on the homedir

            if ( buf.st_mode & S_ISVTX)
                  return (EX_TEMPFAIL);

            if (embedded_filter)
            {
                  i=stat(".mailfilters", &buf);

                  if ( (i < 0 && errno != ENOENT) || (i >= 0 && (
                        !S_ISDIR(buf.st_mode) ||
                        (buf.st_mode & (S_IRWXO|S_IRWXG)) ||
                        buf.st_uid != getuid())
                                          )
                        )
                  {
                        errexit=EX_TEMPFAIL;
                        throw "Invalid permissions on $HOME/.mailfilters - remove world and group perms.";
                  }
                  recipe = embedded_filter;
            }
      }
#if   SHARED_TEMPDIR

#else
      maildrop.tempdir=maildrop.init_home;
      maildrop.tempdir += "/" TEMPDIR;
      maildrop.tempdir += '\0';
      mkdir( (const char *)maildrop.tempdir, 0700 );
#endif
      maildrop.reset_vars();

Buffer      msg;

      maildrop.global_timer.Set(GLOBAL_TIMEOUT);
      maildrop.msgptr->Init(0);     // Read message from standard input.
      maildrop.msginfo.info( *maildrop.msgptr );
      maildrop.msgptr->ExtraHeaders(extra_headers);
      maildrop.msgptr->setmsgsize();


      if (!from)  from="";
      if (*from)  maildrop.msginfo.fromname=from;

// If invoking user is trusted, trust the From line, else set it to invoking
// user.

      if (
#if KEEP_FROMLINE

// The original From_ line is kept, if necessary

#else

// If invoking user is trusted, trust the From line, else set it to invoking
// user.
            !trusted_uidgid(orig_uid, orig_gid, orig_gid2) ||
#endif

            maildrop.msginfo.fromname.Length() == 0)
      {
            maildrop.msginfo.fromname=maildrop.init_logname;
      }

      name="FROM";
      value=maildrop.msginfo.fromname;
      SetVar(name, value);

      if (VerboseLevel() > 1)
      {
            msg.reset();
            msg.append("Message start at ");
            msg.append((unsigned long)maildrop.msginfo.msgoffset);
            msg.append(" bytes, envelope sender=");
            if (maildrop.msginfo.fromname.Length() > 0)
                  msg += maildrop.msginfo.fromname;
            msg.append("\n");
            msg += '\0';
            merr.write(msg);
      }

      name="HOSTNAME";
      sethostname(value);
      SetVar(name, value);

int   fd;

      //
      //

      if (!embedded_filter && deliverymode)
      {
      Recipe r;
      Lexer in;

            fd=in.Open(ETCDIR "/maildroprc");
            if (fd < 0)
            {
                  if (errno != ENOENT)
                  {
                        errexit=EX_TEMPFAIL;
                        throw "Error opening " ETCDIR "/maildroprc.";
                  }
            }
            else
            {
                  if (r.ParseRecipe(in) < 0)
                        return (EX_TEMPFAIL);
                  r.ExecuteRecipe();
            }
      }

Recipe      r;
Lexer in;

#ifdef      DEFAULTEXT
int   firstdefault=1;
#endif

      name="MAILFILTER";
      value=recipe;
      SetVar(name, value);

      for (;;)
      {
            if (embedded_filter)
            {
                  msg=".mailfilters/";
                  msg += recipe;
                  if (VerboseLevel() > 1)
                        merr << "maildrop: Attempting " << msg << "\n";
                  msg += '\0';
                  fd=in.Open((const char *)msg);
            }
            else
            {
                  msg=recipe;
                  if (VerboseLevel() > 1)
                        merr << "maildrop: Attempting " << msg << "\n";
                  msg += '\0';
                  fd=in.Open((const char *)msg);
                  break;
            }
#ifndef     DEFAULTEXT
            break;
#else
            if (fd >= 0)      break;
            if (errno != ENOENT)    break;

            if (firstdefault)
            {
                  recipe += DEFAULTEXT;
                  firstdefault=0;
                  continue;
            }

            // Pop DEFAULTEXT bytes from end of recipe name

            for (fd=sizeof(DEFAULTEXT)-1; fd; --fd)
                  recipe.pop();

            while (recipe.Length())
            {
                  if (recipe.pop() == '-')
                  {
                        recipe += DEFAULTEXT;
                        break;
                  }
            }
            if (recipe.Length() == 0)
            {
                  msg=".mailfilters/";
                  msg += DEFAULTEXT+1;
                  if (VerboseLevel() > 1)
                        merr << "maildrop: Attempting " << msg << "\n";
                  msg += '\0';
                  fd=in.Open((const char *)msg);
                  break;
            }
#endif
      }

      if (fd < 0)
      {
            //
            //  If we are operating in delivery mode, it's ok if
            //  .mailfilter does not exist.
            //
            if (!deliverymode || errno != ENOENT)
            {
            static char buf[80];

                  sprintf(buf, "Unable to open filter file, errno=%d.",
                        errno);
                  errexit=EX_TEMPFAIL;
                  throw buf;
            }
      }
      else
      {
      struct      stat  stat_buf;

            setprocgroup();

            if (fstat( fd, &stat_buf) != 0)
            {
                  errexit=EX_TEMPFAIL;
                  throw "stat() failed.";
            }

            if (!S_ISREG(stat_buf.st_mode) ||
                  (stat_buf.st_mode & (S_IRWXO | S_IRWXG)) ||
                  stat_buf.st_uid != getuid())
            {
                  errexit=EX_TEMPFAIL;
                  throw "Cannot have world/group permissions on the filter file - for your own good.";
            }

            if (r.ParseRecipe(in) < 0)
                  return (EX_TEMPFAIL);

//          if (maildrop.msgptr->MessageSize() > 0)
                  r.ExecuteRecipe();
      }
//
// If a message is succesfully delivered, an exception is thrown.
// If we're here, we should deliver to the default mailbox.
//

      if (!maildrop.embedded_mode)
      {
            name="DEFAULT";

      const char *v=GetVarStr(name);

            if (!v)
            {
                  errexit=EX_TEMPFAIL;
                  throw "DEFAULT mailbox not defined.";
            }

            value=v;
            value += '\0';
            if (delivery((const char *)value) < 0)
                  return (EX_TEMPFAIL);
      }

      value="EXITCODE";
      return ( GetVar(value)->Int("0") );
}

int main(int argc, char **argv)
{

#if HAVE_SETLOCALE
      setlocale(LC_ALL, "C");
#endif

      _exit(Maildrop::trap(run, argc, argv));
}

const char *GetDefaultMailbox(const char *username)
{
static Buffer buf;
int   isfile=0;

      buf="";

const char *p=DEFAULT_DEF;

      if (*p != SLASH_CHAR)   // Relative to home directory
      {
            buf=maildrop.init_home;
            buf.push(SLASH_CHAR);
            isfile=1;
      }

      while (*p)
      {
            if (*p != '=')
            {
                  buf.push(*p);
                  ++p;
            }

      const char *q=username;

            while (*p == '=')
            {
                  buf.push (*q ? *q:'.');
                  if (*q)     q++;
                  p++;
            }
      }

      if (!isfile)
      {
            buf.push(SLASH_CHAR);
            buf += username;
      }
      buf += '\0';
      return (buf);
}

#if   SHARED_TEMPDIR

#else
const char *TempName()
{
Buffer      t;

      t=(const char *)maildrop.tempdir;
      t += "/tmp.";
      t += '\0';
      return (TempName((const char *)t, 0));
}
#endif

Generated by  Doxygen 1.6.0   Back to index