summaryrefslogtreecommitdiffstats
path: root/maildrop/main.C
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /maildrop/main.C
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'maildrop/main.C')
-rw-r--r--maildrop/main.C1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/maildrop/main.C b/maildrop/main.C
new file mode 100644
index 0000000..9d281eb
--- /dev/null
+++ b/maildrop/main.C
@@ -0,0 +1,1009 @@
+/*
+** Copyright 1998 - 2009 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 AUTHLIB
+#include <courierauth.h>
+#endif
+
+#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;
+const char *quota_warn_message=0;
+
+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;
+#if AUTHLIB_TEMPREJECT
+ authlib_essential=1;
+#else
+ authlib_essential=0;
+#endif
+}
+
+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()
+{
+ merr << "Invalid user specified.\n";
+ exit(EX_NOUSER);
+}
+
+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-2005 Double Precision, Inc."
+
+#if CRLF_TERM
+ "\r\n"
+#else
+ "\n"
+#endif
+#ifdef DbObj
+ "GDBM/DB extensions enabled."
+#if CRLF_TERM
+ "\r\n"
+#else
+ "\n"
+#endif
+#endif
+#if AUTHLIB
+ "Courier Authentication Library extension enabled."
+#if CRLF_TERM
+ "\r\n"
+#else
+ "\n"
+#endif
+#endif
+ "Maildir quota extension are now always enabled."
+#if CRLF_TERM
+ "\r\n"
+#else
+ "\n"
+#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);
+ }
+}
+
+#if AUTHLIB
+// Authlib lookup
+
+static int callback_authlib(struct authinfo *auth,
+ void *void_arg)
+{
+ Maildrop &maildrop=*(Maildrop *)void_arg;
+
+ if (VerboseLevel() > 1)
+ {
+ Buffer b;
+
+ b.set(auth->sysgroupid);
+ b.push(0);
+
+ merr << "maildrop: authlib: groupid="
+ << b << "\n";
+ }
+
+ setgroupid(auth->sysgroupid);
+
+ uid_t u;
+ if (auth->sysusername)
+ {
+ struct passwd *q=getpwnam(auth->sysusername);
+
+ if (q == NULL)
+ {
+ merr << "Cannot find system user "
+ << auth->sysusername
+ << "\n";
+
+ nochangeuidgid();
+ }
+
+ u=q->pw_uid;
+ }
+ else
+ u=*auth->sysuserid;
+
+ if (VerboseLevel() > 1)
+ {
+ Buffer b;
+
+ b.set(u);
+ b.push(0);
+
+ merr << "maildrop: authlib: userid="
+ << b << "\n";
+ }
+
+ setuid(u);
+
+ if ( getuid() != u)
+ nochangeuidgid();
+
+ if (VerboseLevel() > 1)
+ {
+ merr << "maildrop: authlib: logname="
+ << auth->address
+ << ", home="
+ << auth->homedir
+ << ", mail="
+ << (auth->maildir ? auth->maildir:"(default)")
+ << "\n";
+ }
+
+ maildrop.init_home=auth->homedir;
+ maildrop.init_logname=auth->address;
+ maildrop.init_shell="/bin/sh";
+ maildrop.init_default=auth->maildir ? auth->maildir:
+ GetDefaultMailbox(auth->address);
+
+ if ( auth->quota )
+ maildrop.init_quota=auth->quota;
+
+ return 0;
+}
+
+int find_in_authlib(Maildrop *maildrop, const char* user)
+{
+ int rc=auth_getuserinfo("login",
+ user, callback_authlib, maildrop);
+
+ if (rc == 0)
+ return 1;
+
+ if ((rc > 0) && (maildrop->authlib_essential == 1))
+ {
+ errexit=EX_TEMPFAIL;
+ throw "Temporary authentication failure.";
+ }
+
+ return 0;
+}
+#else
+int find_in_authlib(Maildrop *maildrop, const char* user)
+{
+ return 0;
+}
+#endif
+
+static void tempfail(const char *msg)
+{
+ errexit = EX_TEMPFAIL;
+ throw msg;
+}
+
+static int run(int argc, char **argv)
+{
+int argn;
+const char *deliverymode=0;
+char *embedded_filter=0;
+const char *from=0;
+int explicit_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;
+ explicit_from=1;
+ }
+ break;
+ case 'w':
+ if (!*optarg && argn < argc) optarg=argv[argn++];
+ if (*optarg)
+ quota_warn_percent=atoi(optarg);
+ break;
+ case 'W':
+ if (!*optarg && argn < argc) optarg=argv[argn++];
+ if (*optarg)
+ quota_warn_message=optarg;
+ break;
+ case 'a':
+ maildrop.authlib_essential=1;
+ 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_authlib(&maildrop, deliverymode);
+
+ if ( !found )
+ {
+ my_pw=getpwnam(deliverymode);
+ if (!my_pw)
+ nouser();
+#if RESET_GID
+ setgroupid(my_pw->pw_gid);
+#else
+ setgroupid(getegid());
+#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 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);
+ }
+ }
+
+int i;
+Buffer name;
+Buffer value;
+
+ for (i=0; environ[i]; i++)
+ {
+ name=environ[i];
+
+ char *p=strchr(environ[i], '=');
+
+ value= p ? (name.Length(p - environ[i]), p+1):"";
+
+ if (maildrop.isdelivery)
+ {
+ if (name == "LANG" ||
+ name == "LANGUAGE" ||
+ strncmp(name, "LC_", 3) == 0)
+ ;
+ else
+ continue;
+ }
+
+ 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)
+ tempfail("Cannot stat() home directory.");
+ if ( !S_ISDIR(buf.st_mode))
+ tempfail("Home directory is not a directory.");
+ if ( buf.st_mode & S_IWOTH)
+ tempfail("Invalid home directory permissions - world writable.");
+ if ( buf.st_uid != getuid())
+ tempfail("Home directory owned by wrong user.");
+
+ // 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)
+ tempfail("Unable to read $HOME/.mailfilters.");
+ else if ( i >= 0)
+ {
+ if ( !S_ISDIR(buf.st_mode))
+ tempfail("$HOME/.mailfilters should be a directory.");
+ if ( buf.st_mode & (S_IRWXO|S_IRWXG))
+ tempfail("Invalid permissions on $HOME/.mailfilters - remove world and group perms.");
+ if ( buf.st_uid != getuid())
+ tempfail("Invalid user ownership of $HOME/.mailfilters.");
+ }
+ 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;
+ }
+
+ if (explicit_from)
+ maildrop.msginfo.fromname=from;
+
+ 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)
+ tempfail("stat() failed.");
+
+ if (!S_ISREG(stat_buf.st_mode))
+ tempfail("mailfilter file isn't a regular file.");
+ if (stat_buf.st_mode & (S_IRWXO | S_IRWXG))
+ tempfail("Cannot have world/group permissions on the filter file - for your own good.");
+ if (stat_buf.st_uid != getuid())
+ tempfail("mailfilter file is owned by the wrong user.");
+
+ if (r.ParseRecipe(in) < 0)
+ return (EX_TEMPFAIL);
+
+// if (maildrop.msgptr->MessageSize() > 0)
+ r.ExecuteRecipe();
+ }
+//
+// If a message is successfully 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