main.c revision 98121
138032Speter/* 294334Sgshapiro * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1490792Sgshapiro#define _DEFINE 1590792Sgshapiro#include <sendmail.h> 1690792Sgshapiro#include <sm/xtrap.h> 1790792Sgshapiro#include <sm/signal.h> 1890792Sgshapiro 1938032Speter#ifndef lint 2090792SgshapiroSM_UNUSED(static char copyright[]) = 2173188Sgshapiro"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ 2264562Sgshapiro All rights reserved.\n\ 2338032Speter Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 2438032Speter Copyright (c) 1988, 1993\n\ 2538032Speter The Regents of the University of California. All rights reserved.\n"; 2664562Sgshapiro#endif /* ! lint */ 2738032Speter 2898121SgshapiroSM_RCSID("@(#)$Id: main.c,v 8.882 2002/05/10 16:20:55 ca Exp $") 2938032Speter 3038032Speter 3164562Sgshapiro#if NETINET || NETINET6 3264562Sgshapiro# include <arpa/inet.h> 3364562Sgshapiro#endif /* NETINET || NETINET6 */ 3464562Sgshapiro 3590792Sgshapiro/* for getcfname() */ 3690792Sgshapiro#include <sendmail/pathnames.h> 3790792Sgshapiro 3890792Sgshapirostatic SM_DEBUG_T 3990792SgshapiroDebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart", 4090792Sgshapiro "@(#)$Debug: no_persistent_restart - don't restart, log only $"); 4190792Sgshapiro 4290792Sgshapirostatic void dump_class __P((STAB *, int)); 4390792Sgshapirostatic void obsolete __P((char **)); 4490792Sgshapirostatic void testmodeline __P((char *, ENVELOPE *)); 4590792Sgshapirostatic char *getextenv __P((const char *)); 4690792Sgshapirostatic void sm_printoptions __P((char **)); 4777349Sgshapirostatic SIGFUNC_DECL intindebug __P((int)); 4890792Sgshapirostatic SIGFUNC_DECL sighup __P((int)); 4990792Sgshapirostatic SIGFUNC_DECL sigpipe __P((int)); 5090792Sgshapirostatic SIGFUNC_DECL sigterm __P((int)); 5180785Sgshapiro#ifdef SIGUSR1 5277349Sgshapirostatic SIGFUNC_DECL sigusr1 __P((int)); 5390792Sgshapiro#endif /* SIGUSR1 */ 5464562Sgshapiro 5538032Speter/* 5638032Speter** SENDMAIL -- Post mail to a set of destinations. 5738032Speter** 5838032Speter** This is the basic mail router. All user mail programs should 5938032Speter** call this routine to actually deliver mail. Sendmail in 6038032Speter** turn calls a bunch of mail servers that do the real work of 6138032Speter** delivering the mail. 6238032Speter** 6364562Sgshapiro** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 6438032Speter** (read by readcf.c). 6538032Speter** 6638032Speter** Usage: 6738032Speter** /usr/lib/sendmail [flags] addr ... 6838032Speter** 6938032Speter** See the associated documentation for details. 7038032Speter** 7190792Sgshapiro** Authors: 7238032Speter** Eric Allman, UCB/INGRES (until 10/81). 7338032Speter** Britton-Lee, Inc., purveyors of fine 7438032Speter** database computers (11/81 - 10/88). 7538032Speter** International Computer Science Institute 7638032Speter** (11/88 - 9/89). 7738032Speter** UCB/Mammoth Project (10/89 - 7/95). 7838032Speter** InReference, Inc. (8/95 - 1/97). 7938032Speter** Sendmail, Inc. (1/98 - present). 8038032Speter** The support of the my employers is gratefully acknowledged. 8138032Speter** Few of them (Britton-Lee in particular) have had 8238032Speter** anything to gain from my involvement in this project. 8390792Sgshapiro** 8490792Sgshapiro** Gregory Neil Shapiro, 8590792Sgshapiro** Worcester Polytechnic Institute (until 3/98). 8690792Sgshapiro** Sendmail, Inc. (3/98 - present). 8790792Sgshapiro** 8890792Sgshapiro** Claus Assmann, 8990792Sgshapiro** Sendmail, Inc. (12/98 - present). 9038032Speter*/ 9138032Speter 9238032Speterchar *FullName; /* sender's full name */ 9338032SpeterENVELOPE BlankEnvelope; /* a "blank" envelope */ 9464562Sgshapirostatic ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 9538032SpeterADDRESS NullAddress = /* a null address */ 9638032Speter { "", "", NULL, "" }; 9738032Speterchar *CommandLineArgs; /* command line args for pid file */ 9890792Sgshapirobool Warn_Q_option = false; /* warn about Q option use */ 9964562Sgshapirostatic int MissingFds = 0; /* bit map of fds missing on startup */ 10090792Sgshapirochar *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */ 10138032Speter 10238032Speter#ifdef NGROUPS_MAX 10338032SpeterGIDSET_T InitialGidSet[NGROUPS_MAX]; 10464562Sgshapiro#endif /* NGROUPS_MAX */ 10538032Speter 10690792Sgshapiro#define MAXCONFIGLEVEL 10 /* highest config version level known */ 10738032Speter 10864562Sgshapiro#if SASL 10964562Sgshapirostatic sasl_callback_t srvcallbacks[] = 11064562Sgshapiro{ 11164562Sgshapiro { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, 11264562Sgshapiro { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, 11364562Sgshapiro { SASL_CB_LIST_END, NULL, NULL } 11464562Sgshapiro}; 11564562Sgshapiro#endif /* SASL */ 11664562Sgshapiro 11790792Sgshapirounsigned int SubmitMode; 11890792Sgshapiroint SyslogPrefixLen; /* estimated length of syslog prefix */ 11990792Sgshapiro#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 12090792Sgshapiro#ifndef SL_FUDGE 12190792Sgshapiro# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 12290792Sgshapiro#endif /* ! SL_FUDGE */ 12390792Sgshapiro#define SLDLL 8 /* est. length of default syslog label */ 12464562Sgshapiro 12590792Sgshapiro 12690792Sgshapiro/* Some options are dangerous to allow users to use in non-submit mode */ 12790792Sgshapiro#define CHECK_AGAINST_OPMODE(cmd) \ 12890792Sgshapiro{ \ 12990792Sgshapiro if (extraprivs && \ 13090792Sgshapiro OpMode != MD_DELIVER && OpMode != MD_SMTP && \ 13190792Sgshapiro OpMode != MD_VERIFY && OpMode != MD_TEST) \ 13290792Sgshapiro { \ 13390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 13490792Sgshapiro "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \ 13590792Sgshapiro (cmd)); \ 13690792Sgshapiro break; \ 13790792Sgshapiro } \ 13890792Sgshapiro if (extraprivs && queuerun) \ 13990792Sgshapiro { \ 14090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 14190792Sgshapiro "WARNING: Ignoring submission mode -%c option with -q\n", \ 14290792Sgshapiro (cmd)); \ 14390792Sgshapiro break; \ 14490792Sgshapiro } \ 14590792Sgshapiro} 14690792Sgshapiro 14738032Speterint 14838032Spetermain(argc, argv, envp) 14938032Speter int argc; 15038032Speter char **argv; 15138032Speter char **envp; 15238032Speter{ 15338032Speter register char *p; 15438032Speter char **av; 15538032Speter extern char Version[]; 15638032Speter char *ep, *from; 15738032Speter STAB *st; 15838032Speter register int i; 15938032Speter int j; 16064562Sgshapiro int dp; 16190792Sgshapiro int fill_errno; 16290792Sgshapiro int qgrp = NOQGRP; /* queue group to process */ 16390792Sgshapiro bool safecf = true; 16464562Sgshapiro BITMAP256 *p_flags = NULL; /* daemon flags */ 16590792Sgshapiro bool warn_C_flag = false; 16690792Sgshapiro bool auth = true; /* whether to set e_auth_param */ 16738032Speter char warn_f_flag = '\0'; 16890792Sgshapiro bool run_in_foreground = false; /* -bD mode */ 16990792Sgshapiro bool queuerun = false, debug = false; 17038032Speter struct passwd *pw; 17138032Speter struct hostent *hp; 17238032Speter char *nullserver = NULL; 17364562Sgshapiro char *authinfo = NULL; 17464562Sgshapiro char *sysloglabel = NULL; /* label for syslog */ 17590792Sgshapiro char *conffile = NULL; /* name of .cf file */ 17690792Sgshapiro char *queuegroup = NULL; /* queue group to process */ 17790792Sgshapiro#if _FFR_QUARANTINE 17890792Sgshapiro char *quarantining = NULL; /* quarantine queue items? */ 17990792Sgshapiro#endif /* _FFR_QUARANTINE */ 18090792Sgshapiro bool extraprivs; 18190792Sgshapiro bool forged, negate; 18290792Sgshapiro bool queuepersistent = false; /* queue runner process runs forever */ 18390792Sgshapiro bool foregroundqueue = false; /* queue run in foreground */ 18490792Sgshapiro bool save_val; /* to save some bool var. */ 18590792Sgshapiro int cftype; /* which cf file to use? */ 18690792Sgshapiro static time_t starttime = 0; /* when was process started */ 18764562Sgshapiro struct stat traf_st; /* for TrafficLog FIFO check */ 18890792Sgshapiro char buf[MAXLINE]; 18938032Speter char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 19038032Speter static char rnamebuf[MAXNAME]; /* holds RealUserName */ 19138032Speter char *emptyenviron[1]; 19290792Sgshapiro#if STARTTLS 19366494Sgshapiro bool tls_ok; 19490792Sgshapiro#endif /* STARTTLS */ 19538032Speter QUEUE_CHAR *new; 19690792Sgshapiro ENVELOPE *e; 19738032Speter extern int DtableSize; 19838032Speter extern int optind; 19938032Speter extern int opterr; 20038032Speter extern char *optarg; 20138032Speter extern char **environ; 20290792Sgshapiro#if SASL 20390792Sgshapiro extern void sm_sasl_init __P((void)); 20490792Sgshapiro#endif /* SASL */ 20538032Speter 20690792Sgshapiro#if USE_ENVIRON 20790792Sgshapiro envp = environ; 20890792Sgshapiro#endif /* USE_ENVIRON */ 20990792Sgshapiro 21090792Sgshapiro /* turn off profiling */ 21190792Sgshapiro SM_PROF(0); 21290792Sgshapiro 21390792Sgshapiro /* install default exception handler */ 21490792Sgshapiro sm_exc_newthread(fatal_error); 21590792Sgshapiro 21638032Speter /* 21738032Speter ** Check to see if we reentered. 21838032Speter ** This would normally happen if e_putheader or e_putbody 21938032Speter ** were NULL when invoked. 22038032Speter */ 22138032Speter 22290792Sgshapiro if (starttime != 0) 22338032Speter { 22438032Speter syserr("main: reentered!"); 22538032Speter abort(); 22638032Speter } 22790792Sgshapiro starttime = curtime(); 22838032Speter 22938032Speter /* avoid null pointer dereferences */ 23038032Speter TermEscape.te_rv_on = TermEscape.te_rv_off = ""; 23138032Speter 23290792Sgshapiro RealUid = getuid(); 23390792Sgshapiro RealGid = getgid(); 23477349Sgshapiro 23590792Sgshapiro /* Check if sendmail is running with extra privs */ 23690792Sgshapiro extraprivs = (RealUid != 0 && 23790792Sgshapiro (geteuid() != getuid() || getegid() != getgid())); 23877349Sgshapiro 23990792Sgshapiro CurrentPid = getpid(); 24038032Speter 24190792Sgshapiro /* get whatever .cf file is right for the opmode */ 24290792Sgshapiro cftype = SM_GET_RIGHT_CF; 24364562Sgshapiro 24438032Speter /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 24538032Speter DtableSize = getdtsize(); 24638032Speter if (DtableSize > 256) 24738032Speter DtableSize = 256; 24838032Speter 24938032Speter /* 25038032Speter ** Be sure we have enough file descriptors. 25138032Speter ** But also be sure that 0, 1, & 2 are open. 25238032Speter */ 25338032Speter 25490792Sgshapiro /* reset errno and fill_errno; the latter is used way down below */ 25590792Sgshapiro errno = fill_errno = 0; 25638032Speter fill_fd(STDIN_FILENO, NULL); 25790792Sgshapiro if (errno != 0) 25890792Sgshapiro fill_errno = errno; 25938032Speter fill_fd(STDOUT_FILENO, NULL); 26090792Sgshapiro if (errno != 0) 26190792Sgshapiro fill_errno = errno; 26238032Speter fill_fd(STDERR_FILENO, NULL); 26390792Sgshapiro if (errno != 0) 26490792Sgshapiro fill_errno = errno; 26538032Speter 26638032Speter i = DtableSize; 26738032Speter while (--i > 0) 26838032Speter { 26990792Sgshapiro if (i != STDIN_FILENO && i != STDOUT_FILENO && 27090792Sgshapiro i != STDERR_FILENO) 27138032Speter (void) close(i); 27238032Speter } 27338032Speter errno = 0; 27438032Speter 27538032Speter#if LOG 27690792Sgshapiro# ifndef SM_LOG_STR 27790792Sgshapiro# define SM_LOG_STR "sendmail" 27890792Sgshapiro# endif /* ! SM_LOG_STR */ 27964562Sgshapiro# ifdef LOG_MAIL 28090792Sgshapiro openlog(SM_LOG_STR, LOG_PID, LOG_MAIL); 28164562Sgshapiro# else /* LOG_MAIL */ 28290792Sgshapiro openlog(SM_LOG_STR, LOG_PID); 28364562Sgshapiro# endif /* LOG_MAIL */ 28464562Sgshapiro#endif /* LOG */ 28538032Speter 28690792Sgshapiro /* 28790792Sgshapiro ** Seed the random number generator. 28890792Sgshapiro ** Used for queue file names, picking a queue directory, and 28990792Sgshapiro ** MX randomization. 29090792Sgshapiro */ 29138032Speter 29290792Sgshapiro seed_random(); 29338032Speter 29490792Sgshapiro /* do machine-dependent initializations */ 29590792Sgshapiro init_md(argc, argv); 29690792Sgshapiro 29790792Sgshapiro 29890792Sgshapiro SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL; 29990792Sgshapiro 30038032Speter /* reset status from syserr() calls for missing file descriptors */ 30138032Speter Errors = 0; 30238032Speter ExitStat = EX_OK; 30338032Speter 30464562Sgshapiro SubmitMode = SUBMIT_UNKNOWN; 30538032Speter#if XDEBUG 30638032Speter checkfd012("after openlog"); 30764562Sgshapiro#endif /* XDEBUG */ 30838032Speter 30990792Sgshapiro tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1"); 31038032Speter 31138032Speter#ifdef NGROUPS_MAX 31238032Speter /* save initial group set for future checks */ 31338032Speter i = getgroups(NGROUPS_MAX, InitialGidSet); 31490792Sgshapiro if (i <= 0) 31590792Sgshapiro { 31638032Speter InitialGidSet[0] = (GID_T) -1; 31790792Sgshapiro i = 0; 31890792Sgshapiro } 31938032Speter while (i < NGROUPS_MAX) 32038032Speter InitialGidSet[i++] = InitialGidSet[0]; 32164562Sgshapiro#endif /* NGROUPS_MAX */ 32238032Speter 32338032Speter /* drop group id privileges (RunAsUser not yet set) */ 32490792Sgshapiro dp = drop_privileges(false); 32564562Sgshapiro setstat(dp); 32638032Speter 32790792Sgshapiro#ifdef SIGUSR1 32877349Sgshapiro /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 32994334Sgshapiro if (!extraprivs) 33077349Sgshapiro { 33177349Sgshapiro /* arrange to dump state on user-1 signal */ 33290792Sgshapiro (void) sm_signal(SIGUSR1, sigusr1); 33377349Sgshapiro } 33494334Sgshapiro else 33594334Sgshapiro { 33694334Sgshapiro /* ignore user-1 signal */ 33794334Sgshapiro (void) sm_signal(SIGUSR1, SIG_IGN); 33894334Sgshapiro } 33990792Sgshapiro#endif /* SIGUSR1 */ 34038032Speter 34138032Speter /* initialize for setproctitle */ 34238032Speter initsetproctitle(argc, argv, envp); 34338032Speter 34438032Speter /* Handle any non-getoptable constructions. */ 34538032Speter obsolete(argv); 34638032Speter 34738032Speter /* 34838032Speter ** Do a quick prescan of the argument list. 34938032Speter */ 35038032Speter 35164562Sgshapiro 35290792Sgshapiro /* find initial opMode */ 35390792Sgshapiro OpMode = MD_DELIVER; 35490792Sgshapiro av = argv; 35590792Sgshapiro p = strrchr(*av, '/'); 35690792Sgshapiro if (p++ == NULL) 35790792Sgshapiro p = *av; 35890792Sgshapiro if (strcmp(p, "newaliases") == 0) 35990792Sgshapiro OpMode = MD_INITALIAS; 36090792Sgshapiro else if (strcmp(p, "mailq") == 0) 36190792Sgshapiro OpMode = MD_PRINT; 36290792Sgshapiro else if (strcmp(p, "smtpd") == 0) 36390792Sgshapiro OpMode = MD_DAEMON; 36490792Sgshapiro else if (strcmp(p, "hoststat") == 0) 36590792Sgshapiro OpMode = MD_HOSTSTAT; 36690792Sgshapiro else if (strcmp(p, "purgestat") == 0) 36790792Sgshapiro OpMode = MD_PURGESTAT; 36890792Sgshapiro 36990792Sgshapiro#if _FFR_QUARANTINE 37090792Sgshapiro# if defined(__osf__) || defined(_AIX3) 37190792Sgshapiro# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:xQ:" 37290792Sgshapiro# endif /* defined(__osf__) || defined(_AIX3) */ 37390792Sgshapiro# if defined(sony_news) 37490792Sgshapiro# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:" 37590792Sgshapiro# endif /* defined(sony_news) */ 37690792Sgshapiro# ifndef OPTIONS 37790792Sgshapiro# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:Q:" 37890792Sgshapiro# endif /* ! OPTIONS */ 37990792Sgshapiro#else /* _FFR_QUARANTINE */ 38090792Sgshapiro# if defined(__osf__) || defined(_AIX3) 38190792Sgshapiro# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:x" 38290792Sgshapiro# endif /* defined(__osf__) || defined(_AIX3) */ 38390792Sgshapiro# if defined(sony_news) 38490792Sgshapiro# define OPTIONS "A:B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtV:vX:" 38590792Sgshapiro# endif /* defined(sony_news) */ 38690792Sgshapiro# ifndef OPTIONS 38790792Sgshapiro# define OPTIONS "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:" 38890792Sgshapiro# endif /* ! OPTIONS */ 38990792Sgshapiro#endif /* _FFR_QUARANTINE */ 39090792Sgshapiro 39138032Speter opterr = 0; 39238032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 39338032Speter { 39438032Speter switch (j) 39538032Speter { 39690792Sgshapiro case 'b': /* operations mode */ 39794334Sgshapiro j = (optarg == NULL) ? ' ' : *optarg; 39894334Sgshapiro switch (j) 39938032Speter { 40090792Sgshapiro case MD_DAEMON: 40190792Sgshapiro case MD_FGDAEMON: 40290792Sgshapiro case MD_SMTP: 40390792Sgshapiro case MD_INITALIAS: 40490792Sgshapiro case MD_DELIVER: 40590792Sgshapiro case MD_VERIFY: 40690792Sgshapiro case MD_TEST: 40790792Sgshapiro case MD_PRINT: 40890792Sgshapiro case MD_PRINTNQE: 40990792Sgshapiro case MD_HOSTSTAT: 41090792Sgshapiro case MD_PURGESTAT: 41190792Sgshapiro case MD_ARPAFTP: 41290792Sgshapiro OpMode = j; 41338032Speter break; 41490792Sgshapiro 41590792Sgshapiro case MD_FREEZE: 41690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41790792Sgshapiro "Frozen configurations unsupported\n"); 41890792Sgshapiro return EX_USAGE; 41990792Sgshapiro 42090792Sgshapiro default: 42190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42290792Sgshapiro "Invalid operation mode %c\n", 42390792Sgshapiro j); 42490792Sgshapiro return EX_USAGE; 42538032Speter } 42690792Sgshapiro break; 42790792Sgshapiro 42890792Sgshapiro case 'd': 42990792Sgshapiro debug = true; 43038032Speter tTflag(optarg); 43190792Sgshapiro (void) sm_io_setvbuf(smioout, SM_TIME_DEFAULT, 43290792Sgshapiro (char *) NULL, SM_IO_NBF, 43390792Sgshapiro SM_IO_BUFSIZ); 43438032Speter break; 43564562Sgshapiro 43664562Sgshapiro case 'G': /* relay (gateway) submission */ 43790792Sgshapiro SubmitMode = SUBMIT_MTA; 43864562Sgshapiro break; 43964562Sgshapiro 44064562Sgshapiro case 'L': 44190792Sgshapiro j = SM_MIN(strlen(optarg), 24) + 1; 44264562Sgshapiro sysloglabel = xalloc(j); 44390792Sgshapiro (void) sm_strlcpy(sysloglabel, optarg, j); 44490792Sgshapiro SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + 44590792Sgshapiro SL_FUDGE + j; 44664562Sgshapiro break; 44764562Sgshapiro 44890792Sgshapiro#if _FFR_QUARANTINE 44990792Sgshapiro case 'Q': 45090792Sgshapiro#endif /* _FFR_QUARANTINE */ 45190792Sgshapiro case 'q': 45290792Sgshapiro /* just check if it is there */ 45390792Sgshapiro queuerun = true; 45464562Sgshapiro break; 45538032Speter } 45638032Speter } 45738032Speter opterr = 1; 45838032Speter 45990792Sgshapiro /* Don't leak queue information via debug flags */ 46090792Sgshapiro if (extraprivs && queuerun && debug) 46190792Sgshapiro { 46290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 46390792Sgshapiro "WARNING: Can not use -d with -q. Disabling debugging.\n"); 46490792Sgshapiro sm_debug_setfile(NULL); 46590792Sgshapiro (void) memset(tTdvect, '\0', sizeof tTdvect); 46690792Sgshapiro } 46790792Sgshapiro 46877349Sgshapiro#if LOG 46964562Sgshapiro if (sysloglabel != NULL) 47064562Sgshapiro { 47177349Sgshapiro /* Sanitize the string */ 47277349Sgshapiro for (p = sysloglabel; *p != '\0'; p++) 47377349Sgshapiro { 47477349Sgshapiro if (!isascii(*p) || !isprint(*p) || *p == '%') 47577349Sgshapiro *p = '*'; 47677349Sgshapiro } 47764562Sgshapiro closelog(); 47864562Sgshapiro# ifdef LOG_MAIL 47964562Sgshapiro openlog(sysloglabel, LOG_PID, LOG_MAIL); 48064562Sgshapiro# else /* LOG_MAIL */ 48164562Sgshapiro openlog(sysloglabel, LOG_PID); 48264562Sgshapiro# endif /* LOG_MAIL */ 48377349Sgshapiro } 48464562Sgshapiro#endif /* LOG */ 48564562Sgshapiro 48638032Speter /* set up the blank envelope */ 48738032Speter BlankEnvelope.e_puthdr = putheader; 48838032Speter BlankEnvelope.e_putbody = putbody; 48938032Speter BlankEnvelope.e_xfp = NULL; 49038032Speter STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 49138032Speter CurEnv = &BlankEnvelope; 49238032Speter STRUCTCOPY(NullAddress, MainEnvelope.e_from); 49338032Speter 49438032Speter /* 49538032Speter ** Set default values for variables. 49638032Speter ** These cannot be in initialized data space. 49738032Speter */ 49838032Speter 49938032Speter setdefaults(&BlankEnvelope); 50090792Sgshapiro initmacros(&BlankEnvelope); 50138032Speter 50290792Sgshapiro /* reset macro */ 50390792Sgshapiro set_op_mode(OpMode); 50438032Speter 50538032Speter pw = sm_getpwuid(RealUid); 50638032Speter if (pw != NULL) 50790792Sgshapiro (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 50838032Speter else 50990792Sgshapiro (void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 51090792Sgshapiro (int) RealUid); 51164562Sgshapiro 51238032Speter RealUserName = rnamebuf; 51338032Speter 51438032Speter if (tTd(0, 101)) 51538032Speter { 51690792Sgshapiro sm_dprintf("Version %s\n", Version); 51790792Sgshapiro finis(false, true, EX_OK); 51890792Sgshapiro /* NOTREACHED */ 51938032Speter } 52038032Speter 52138032Speter /* 52290792Sgshapiro ** if running non-set-user-ID binary as non-root, pretend 52338032Speter ** we are the RunAsUid 52438032Speter */ 52577349Sgshapiro 52638032Speter if (RealUid != 0 && geteuid() == RealUid) 52738032Speter { 52838032Speter if (tTd(47, 1)) 52990792Sgshapiro sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n", 53090792Sgshapiro (int) RealUid); 53138032Speter RunAsUid = RealUid; 53238032Speter } 53338032Speter else if (geteuid() != 0) 53438032Speter RunAsUid = geteuid(); 53538032Speter 53690792Sgshapiro EffGid = getegid(); 53790792Sgshapiro if (RealUid != 0 && EffGid == RealGid) 53838032Speter RunAsGid = RealGid; 53938032Speter 54038032Speter if (tTd(47, 5)) 54138032Speter { 54290792Sgshapiro sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 54390792Sgshapiro (int) geteuid(), (int) getuid(), 54490792Sgshapiro (int) getegid(), (int) getgid()); 54590792Sgshapiro sm_dprintf("main: RunAsUser = %d:%d\n", 54690792Sgshapiro (int) RunAsUid, (int) RunAsGid); 54738032Speter } 54838032Speter 54938032Speter /* save command line arguments */ 55064562Sgshapiro j = 0; 55138032Speter for (av = argv; *av != NULL; ) 55264562Sgshapiro j += strlen(*av++) + 1; 55338032Speter SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); 55464562Sgshapiro CommandLineArgs = xalloc(j); 55538032Speter p = CommandLineArgs; 55638032Speter for (av = argv, i = 0; *av != NULL; ) 55738032Speter { 55864562Sgshapiro int h; 55964562Sgshapiro 56038032Speter SaveArgv[i++] = newstr(*av); 56138032Speter if (av != argv) 56238032Speter *p++ = ' '; 56390792Sgshapiro (void) sm_strlcpy(p, *av++, j); 56464562Sgshapiro h = strlen(p); 56564562Sgshapiro p += h; 56664562Sgshapiro j -= h + 1; 56738032Speter } 56838032Speter SaveArgv[i] = NULL; 56938032Speter 57038032Speter if (tTd(0, 1)) 57138032Speter { 57238032Speter extern char *CompileOptions[]; 57338032Speter 57490792Sgshapiro sm_dprintf("Version %s\n Compiled with:", Version); 57590792Sgshapiro sm_printoptions(CompileOptions); 57638032Speter } 57738032Speter if (tTd(0, 10)) 57838032Speter { 57938032Speter extern char *OsCompileOptions[]; 58038032Speter 58190792Sgshapiro sm_dprintf(" OS Defines:"); 58290792Sgshapiro sm_printoptions(OsCompileOptions); 58338032Speter#ifdef _PATH_UNIX 58490792Sgshapiro sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 58564562Sgshapiro#endif /* _PATH_UNIX */ 58690792Sgshapiro 58790792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MSP)\n", 58890792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF, 58990792Sgshapiro conffile)); 59090792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MTA)\n", 59190792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF, 59290792Sgshapiro conffile)); 59390792Sgshapiro sm_dprintf(" Pid file:\t%s (default)\n", PidFile); 59438032Speter } 59538032Speter 59690792Sgshapiro if (tTd(0, 12)) 59790792Sgshapiro { 59890792Sgshapiro extern char *SmCompileOptions[]; 59938032Speter 60090792Sgshapiro sm_dprintf(" libsm Defines:"); 60190792Sgshapiro sm_printoptions(SmCompileOptions); 60290792Sgshapiro } 60390792Sgshapiro 60490792Sgshapiro if (tTd(0, 13)) 60590792Sgshapiro { 60690792Sgshapiro extern char *FFRCompileOptions[]; 60790792Sgshapiro 60890792Sgshapiro sm_dprintf(" FFR Defines:"); 60990792Sgshapiro sm_printoptions(FFRCompileOptions); 61090792Sgshapiro } 61190792Sgshapiro 61290792Sgshapiro InChannel = smioin; 61390792Sgshapiro OutChannel = smioout; 61490792Sgshapiro 61538032Speter /* clear sendmail's environment */ 61638032Speter ExternalEnviron = environ; 61738032Speter emptyenviron[0] = NULL; 61838032Speter environ = emptyenviron; 61938032Speter 62038032Speter /* 62142575Speter ** restore any original TZ setting until TimeZoneSpec has been 62242575Speter ** determined - or early log messages may get bogus time stamps 62338032Speter */ 62490792Sgshapiro 62538032Speter if ((p = getextenv("TZ")) != NULL) 62638032Speter { 62738032Speter char *tz; 62838032Speter int tzlen; 62938032Speter 63090792Sgshapiro /* XXX check for reasonable length? */ 63138032Speter tzlen = strlen(p) + 4; 63238032Speter tz = xalloc(tzlen); 63390792Sgshapiro (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p); 63490792Sgshapiro 63590792Sgshapiro /* XXX check return code? */ 63664562Sgshapiro (void) putenv(tz); 63738032Speter } 63838032Speter 63938032Speter /* prime the child environment */ 64038032Speter setuserenv("AGENT", "sendmail"); 64138032Speter 64290792Sgshapiro (void) sm_signal(SIGPIPE, SIG_IGN); 64338032Speter OldUmask = umask(022); 64438032Speter FullName = getextenv("NAME"); 64595154Sgshapiro if (FullName != NULL) 64695154Sgshapiro FullName = newstr(FullName); 64738032Speter 64838032Speter /* 64938032Speter ** Initialize name server if it is going to be used. 65038032Speter */ 65138032Speter 65238032Speter#if NAMED_BIND 65338032Speter if (!bitset(RES_INIT, _res.options)) 65464562Sgshapiro (void) res_init(); 65538032Speter if (tTd(8, 8)) 65638032Speter _res.options |= RES_DEBUG; 65738032Speter else 65838032Speter _res.options &= ~RES_DEBUG; 65938032Speter# ifdef RES_NOALIASES 66090792Sgshapiro if (bitset(RES_NOALIASES, _res.options)) 66190792Sgshapiro ResNoAliases = true; 66238032Speter _res.options |= RES_NOALIASES; 66364562Sgshapiro# endif /* RES_NOALIASES */ 66464562Sgshapiro TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 66564562Sgshapiro TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 66664562Sgshapiro TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 66764562Sgshapiro TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 66864562Sgshapiro TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 66964562Sgshapiro TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 67064562Sgshapiro#endif /* NAMED_BIND */ 67138032Speter 67238032Speter errno = 0; 67338032Speter from = NULL; 67438032Speter 67538032Speter /* initialize some macros, etc. */ 67690792Sgshapiro init_vendor_macros(&BlankEnvelope); 67738032Speter 67838032Speter /* version */ 67990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version); 68038032Speter 68138032Speter /* hostname */ 68238032Speter hp = myhostname(jbuf, sizeof jbuf); 68338032Speter if (jbuf[0] != '\0') 68438032Speter { 68590792Sgshapiro struct utsname utsname; 68638032Speter 68738032Speter if (tTd(0, 4)) 68890792Sgshapiro sm_dprintf("Canonical name: %s\n", jbuf); 68990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf); 69090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf); 69138032Speter setclass('w', jbuf); 69238032Speter 69338032Speter p = strchr(jbuf, '.'); 69438032Speter if (p != NULL) 69538032Speter { 69638032Speter if (p[1] != '\0') 69738032Speter { 69890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', 69990792Sgshapiro &p[1]); 70038032Speter } 70138032Speter while (p != NULL && strchr(&p[1], '.') != NULL) 70238032Speter { 70338032Speter *p = '\0'; 70438032Speter if (tTd(0, 4)) 70590792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", jbuf); 70638032Speter setclass('w', jbuf); 70738032Speter *p++ = '.'; 70838032Speter p = strchr(p, '.'); 70938032Speter } 71038032Speter } 71138032Speter 71238032Speter if (uname(&utsname) >= 0) 71338032Speter p = utsname.nodename; 71438032Speter else 71538032Speter { 71638032Speter if (tTd(0, 22)) 71790792Sgshapiro sm_dprintf("uname failed (%s)\n", 71890792Sgshapiro sm_errstring(errno)); 71938032Speter makelower(jbuf); 72038032Speter p = jbuf; 72138032Speter } 72238032Speter if (tTd(0, 4)) 72390792Sgshapiro sm_dprintf(" UUCP nodename: %s\n", p); 72490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p); 72538032Speter setclass('k', p); 72638032Speter setclass('w', p); 72738032Speter } 72838032Speter if (hp != NULL) 72938032Speter { 73038032Speter for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 73138032Speter { 73238032Speter if (tTd(0, 4)) 73390792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", *av); 73438032Speter setclass('w', *av); 73538032Speter } 73664562Sgshapiro#if NETINET || NETINET6 73790792Sgshapiro for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++) 73838032Speter { 73964562Sgshapiro# if NETINET6 74064562Sgshapiro char *addr; 74164562Sgshapiro char buf6[INET6_ADDRSTRLEN]; 74264562Sgshapiro struct in6_addr ia6; 74364562Sgshapiro# endif /* NETINET6 */ 74464562Sgshapiro# if NETINET 74564562Sgshapiro struct in_addr ia; 74664562Sgshapiro# endif /* NETINET */ 74764562Sgshapiro char ipbuf[103]; 74864562Sgshapiro 74964562Sgshapiro ipbuf[0] = '\0'; 75064562Sgshapiro switch (hp->h_addrtype) 75138032Speter { 75264562Sgshapiro# if NETINET 75364562Sgshapiro case AF_INET: 75464562Sgshapiro if (hp->h_length != INADDRSZ) 75564562Sgshapiro break; 75638032Speter 75764562Sgshapiro memmove(&ia, hp->h_addr_list[i], INADDRSZ); 75890792Sgshapiro (void) sm_snprintf(ipbuf, sizeof ipbuf, 75990792Sgshapiro "[%.100s]", inet_ntoa(ia)); 76064562Sgshapiro break; 76164562Sgshapiro# endif /* NETINET */ 76264562Sgshapiro 76364562Sgshapiro# if NETINET6 76464562Sgshapiro case AF_INET6: 76564562Sgshapiro if (hp->h_length != IN6ADDRSZ) 76664562Sgshapiro break; 76764562Sgshapiro 76864562Sgshapiro memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 76964562Sgshapiro addr = anynet_ntop(&ia6, buf6, sizeof buf6); 77064562Sgshapiro if (addr != NULL) 77190792Sgshapiro (void) sm_snprintf(ipbuf, sizeof ipbuf, 77290792Sgshapiro "[%.100s]", addr); 77364562Sgshapiro break; 77464562Sgshapiro# endif /* NETINET6 */ 77538032Speter } 77664562Sgshapiro if (ipbuf[0] == '\0') 77764562Sgshapiro break; 77864562Sgshapiro 77964562Sgshapiro if (tTd(0, 4)) 78090792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", ipbuf); 78164562Sgshapiro setclass('w', ipbuf); 78238032Speter } 78364562Sgshapiro#endif /* NETINET || NETINET6 */ 78490792Sgshapiro#if NETINET6 78571345Sgshapiro freehostent(hp); 78671345Sgshapiro hp = NULL; 78790792Sgshapiro#endif /* NETINET6 */ 78838032Speter } 78938032Speter 79038032Speter /* current time */ 79190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL)); 79290792Sgshapiro 79364562Sgshapiro /* current load average */ 79490792Sgshapiro sm_getla(); 79538032Speter 79638032Speter QueueLimitRecipient = (QUEUE_CHAR *) NULL; 79738032Speter QueueLimitSender = (QUEUE_CHAR *) NULL; 79838032Speter QueueLimitId = (QUEUE_CHAR *) NULL; 79990792Sgshapiro#if _FFR_QUARANTINE 80090792Sgshapiro QueueLimitQuarantine = (QUEUE_CHAR *) NULL; 80190792Sgshapiro#endif /* _FFR_QUARANTINE */ 80238032Speter 80338032Speter /* 80442575Speter ** Crack argv. 80538032Speter */ 80638032Speter 80738032Speter optind = 1; 80838032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 80938032Speter { 81038032Speter switch (j) 81138032Speter { 81238032Speter case 'b': /* operations mode */ 81390792Sgshapiro /* already done */ 81490792Sgshapiro break; 81538032Speter 81690792Sgshapiro case 'A': /* use Alternate sendmail/submit.cf */ 81790792Sgshapiro cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF 81890792Sgshapiro : SM_GET_SENDMAIL_CF; 81938032Speter break; 82038032Speter 82138032Speter case 'B': /* body type */ 82290792Sgshapiro CHECK_AGAINST_OPMODE(j); 82390792Sgshapiro BlankEnvelope.e_bodytype = newstr(optarg); 82438032Speter break; 82538032Speter 82638032Speter case 'C': /* select configuration file (already done) */ 82738032Speter if (RealUid != 0) 82890792Sgshapiro warn_C_flag = true; 82990792Sgshapiro conffile = newstr(optarg); 83090792Sgshapiro dp = drop_privileges(true); 83164562Sgshapiro setstat(dp); 83290792Sgshapiro safecf = false; 83338032Speter break; 83438032Speter 83590792Sgshapiro case 'd': /* debugging */ 83690792Sgshapiro /* already done */ 83738032Speter break; 83838032Speter 83938032Speter case 'f': /* from address */ 84038032Speter case 'r': /* obsolete -f flag */ 84190792Sgshapiro CHECK_AGAINST_OPMODE(j); 84238032Speter if (from != NULL) 84338032Speter { 84438032Speter usrerr("More than one \"from\" person"); 84538032Speter ExitStat = EX_USAGE; 84638032Speter break; 84738032Speter } 84890792Sgshapiro from = newstr(denlstring(optarg, true, true)); 84938032Speter if (strcmp(RealUserName, from) != 0) 85038032Speter warn_f_flag = j; 85138032Speter break; 85238032Speter 85338032Speter case 'F': /* set full name */ 85490792Sgshapiro CHECK_AGAINST_OPMODE(j); 85538032Speter FullName = newstr(optarg); 85638032Speter break; 85738032Speter 85864562Sgshapiro case 'G': /* relay (gateway) submission */ 85964562Sgshapiro /* already set */ 86090792Sgshapiro CHECK_AGAINST_OPMODE(j); 86164562Sgshapiro break; 86264562Sgshapiro 86338032Speter case 'h': /* hop count */ 86490792Sgshapiro CHECK_AGAINST_OPMODE(j); 86590792Sgshapiro BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep, 86690792Sgshapiro 10); 86790792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "%d", 86890792Sgshapiro BlankEnvelope.e_hopcount); 86990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf); 87090792Sgshapiro 87138032Speter if (*ep) 87238032Speter { 87338032Speter usrerr("Bad hop count (%s)", optarg); 87438032Speter ExitStat = EX_USAGE; 87538032Speter } 87638032Speter break; 87764562Sgshapiro 87864562Sgshapiro case 'L': /* program label */ 87964562Sgshapiro /* already set */ 88064562Sgshapiro break; 88164562Sgshapiro 88238032Speter case 'n': /* don't alias */ 88390792Sgshapiro CHECK_AGAINST_OPMODE(j); 88490792Sgshapiro NoAlias = true; 88538032Speter break; 88638032Speter 88738032Speter case 'N': /* delivery status notifications */ 88890792Sgshapiro CHECK_AGAINST_OPMODE(j); 88938032Speter DefaultNotify |= QHASNOTIFY; 89090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 89190792Sgshapiro macid("{dsn_notify}"), optarg); 89290792Sgshapiro if (sm_strcasecmp(optarg, "never") == 0) 89338032Speter break; 89438032Speter for (p = optarg; p != NULL; optarg = p) 89538032Speter { 89638032Speter p = strchr(p, ','); 89738032Speter if (p != NULL) 89838032Speter *p++ = '\0'; 89990792Sgshapiro if (sm_strcasecmp(optarg, "success") == 0) 90038032Speter DefaultNotify |= QPINGONSUCCESS; 90190792Sgshapiro else if (sm_strcasecmp(optarg, "failure") == 0) 90238032Speter DefaultNotify |= QPINGONFAILURE; 90390792Sgshapiro else if (sm_strcasecmp(optarg, "delay") == 0) 90438032Speter DefaultNotify |= QPINGONDELAY; 90538032Speter else 90638032Speter { 90738032Speter usrerr("Invalid -N argument"); 90838032Speter ExitStat = EX_USAGE; 90938032Speter } 91038032Speter } 91138032Speter break; 91238032Speter 91338032Speter case 'o': /* set option */ 91490792Sgshapiro setoption(*optarg, optarg + 1, false, true, 91590792Sgshapiro &BlankEnvelope); 91638032Speter break; 91738032Speter 91838032Speter case 'O': /* set option (long form) */ 91990792Sgshapiro setoption(' ', optarg, false, true, &BlankEnvelope); 92038032Speter break; 92138032Speter 92238032Speter case 'p': /* set protocol */ 92390792Sgshapiro CHECK_AGAINST_OPMODE(j); 92438032Speter p = strchr(optarg, ':'); 92538032Speter if (p != NULL) 92638032Speter { 92738032Speter *p++ = '\0'; 92838032Speter if (*p != '\0') 92938032Speter { 93090792Sgshapiro ep = sm_malloc_x(strlen(p) + 1); 93138032Speter cleanstrcpy(ep, p, MAXNAME); 93290792Sgshapiro macdefine(&BlankEnvelope.e_macro, 93390792Sgshapiro A_HEAP, 's', ep); 93438032Speter } 93538032Speter } 93638032Speter if (*optarg != '\0') 93738032Speter { 93890792Sgshapiro ep = sm_malloc_x(strlen(optarg) + 1); 93938032Speter cleanstrcpy(ep, optarg, MAXNAME); 94090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_HEAP, 94190792Sgshapiro 'r', ep); 94238032Speter } 94338032Speter break; 94438032Speter 94590792Sgshapiro#if _FFR_QUARANTINE 94690792Sgshapiro case 'Q': /* change quarantining on queued items */ 94790792Sgshapiro /* sanity check */ 94890792Sgshapiro if (OpMode != MD_DELIVER && 94990792Sgshapiro OpMode != MD_QUEUERUN) 95090792Sgshapiro { 95190792Sgshapiro usrerr("Can not use -Q with -b%c", OpMode); 95290792Sgshapiro ExitStat = EX_USAGE; 95390792Sgshapiro break; 95490792Sgshapiro } 95590792Sgshapiro 95690792Sgshapiro if (OpMode == MD_DELIVER) 95790792Sgshapiro set_op_mode(MD_QUEUERUN); 95890792Sgshapiro 95990792Sgshapiro FullName = NULL; 96090792Sgshapiro 96190792Sgshapiro quarantining = newstr(optarg); 96290792Sgshapiro break; 96390792Sgshapiro#endif /* _FFR_QUARANTINE */ 96490792Sgshapiro 96538032Speter case 'q': /* run queue files at intervals */ 96664562Sgshapiro /* sanity check */ 96764562Sgshapiro if (OpMode != MD_DELIVER && 96864562Sgshapiro OpMode != MD_DAEMON && 96964562Sgshapiro OpMode != MD_FGDAEMON && 97064562Sgshapiro OpMode != MD_PRINT && 97190792Sgshapiro OpMode != MD_PRINTNQE && 97264562Sgshapiro OpMode != MD_QUEUERUN) 97364562Sgshapiro { 97464562Sgshapiro usrerr("Can not use -q with -b%c", OpMode); 97564562Sgshapiro ExitStat = EX_USAGE; 97664562Sgshapiro break; 97764562Sgshapiro } 97864562Sgshapiro 97964562Sgshapiro /* don't override -bd, -bD or -bp */ 98064562Sgshapiro if (OpMode == MD_DELIVER) 98190792Sgshapiro set_op_mode(MD_QUEUERUN); 98264562Sgshapiro 98338032Speter FullName = NULL; 98490792Sgshapiro negate = optarg[0] == '!'; 98590792Sgshapiro if (negate) 98690792Sgshapiro { 98790792Sgshapiro /* negate meaning of pattern match */ 98890792Sgshapiro optarg++; /* skip '!' for next switch */ 98990792Sgshapiro } 99064562Sgshapiro 99138032Speter switch (optarg[0]) 99238032Speter { 99390792Sgshapiro case 'G': /* Limit by queue group name */ 99490792Sgshapiro if (negate) 99590792Sgshapiro { 99690792Sgshapiro usrerr("Can not use -q!G"); 99790792Sgshapiro ExitStat = EX_USAGE; 99890792Sgshapiro break; 99990792Sgshapiro } 100090792Sgshapiro if (queuegroup != NULL) 100190792Sgshapiro { 100290792Sgshapiro usrerr("Can not use multiple -qG options"); 100390792Sgshapiro ExitStat = EX_USAGE; 100490792Sgshapiro break; 100590792Sgshapiro } 100690792Sgshapiro queuegroup = newstr(&optarg[1]); 100790792Sgshapiro break; 100890792Sgshapiro 100990792Sgshapiro case 'I': /* Limit by ID */ 101064562Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof *new); 101138032Speter new->queue_match = newstr(&optarg[1]); 101290792Sgshapiro new->queue_negate = negate; 101338032Speter new->queue_next = QueueLimitId; 101438032Speter QueueLimitId = new; 101538032Speter break; 101638032Speter 101790792Sgshapiro case 'R': /* Limit by recipient */ 101864562Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof *new); 101938032Speter new->queue_match = newstr(&optarg[1]); 102090792Sgshapiro new->queue_negate = negate; 102138032Speter new->queue_next = QueueLimitRecipient; 102238032Speter QueueLimitRecipient = new; 102338032Speter break; 102438032Speter 102590792Sgshapiro case 'S': /* Limit by sender */ 102664562Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof *new); 102738032Speter new->queue_match = newstr(&optarg[1]); 102890792Sgshapiro new->queue_negate = negate; 102938032Speter new->queue_next = QueueLimitSender; 103038032Speter QueueLimitSender = new; 103138032Speter break; 103238032Speter 103390792Sgshapiro case 'f': /* foreground queue run */ 103490792Sgshapiro foregroundqueue = true; 103590792Sgshapiro break; 103690792Sgshapiro 103790792Sgshapiro#if _FFR_QUARANTINE 103890792Sgshapiro case 'Q': /* Limit by quarantine message */ 103990792Sgshapiro if (optarg[1] != '\0') 104090792Sgshapiro { 104190792Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof *new); 104290792Sgshapiro new->queue_match = newstr(&optarg[1]); 104390792Sgshapiro new->queue_negate = negate; 104490792Sgshapiro new->queue_next = QueueLimitQuarantine; 104590792Sgshapiro QueueLimitQuarantine = new; 104690792Sgshapiro } 104790792Sgshapiro QueueMode = QM_QUARANTINE; 104890792Sgshapiro break; 104990792Sgshapiro 105090792Sgshapiro case 'L': /* act on lost items */ 105190792Sgshapiro QueueMode = QM_LOST; 105290792Sgshapiro break; 105390792Sgshapiro#endif /* _FFR_QUARANTINE */ 105490792Sgshapiro 105590792Sgshapiro case 'p': /* Persistent queue */ 105690792Sgshapiro queuepersistent = true; 105790792Sgshapiro if (QueueIntvl == 0) 105890792Sgshapiro QueueIntvl = 1; 105990792Sgshapiro if (optarg[1] == '\0') 106090792Sgshapiro break; 106190792Sgshapiro ++optarg; 106290792Sgshapiro /* FALLTHROUGH */ 106390792Sgshapiro 106438032Speter default: 106564562Sgshapiro i = Errors; 106638032Speter QueueIntvl = convtime(optarg, 'm'); 106764562Sgshapiro 106864562Sgshapiro /* check for bad conversion */ 106964562Sgshapiro if (i < Errors) 107064562Sgshapiro ExitStat = EX_USAGE; 107138032Speter break; 107238032Speter } 107338032Speter break; 107438032Speter 107538032Speter case 'R': /* DSN RET: what to return */ 107690792Sgshapiro CHECK_AGAINST_OPMODE(j); 107790792Sgshapiro if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags)) 107838032Speter { 107938032Speter usrerr("Duplicate -R flag"); 108038032Speter ExitStat = EX_USAGE; 108138032Speter break; 108238032Speter } 108390792Sgshapiro BlankEnvelope.e_flags |= EF_RET_PARAM; 108490792Sgshapiro if (sm_strcasecmp(optarg, "hdrs") == 0) 108590792Sgshapiro BlankEnvelope.e_flags |= EF_NO_BODY_RETN; 108690792Sgshapiro else if (sm_strcasecmp(optarg, "full") != 0) 108738032Speter { 108838032Speter usrerr("Invalid -R value"); 108938032Speter ExitStat = EX_USAGE; 109038032Speter } 109190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 109290792Sgshapiro macid("{dsn_ret}"), optarg); 109338032Speter break; 109438032Speter 109538032Speter case 't': /* read recipients from message */ 109690792Sgshapiro CHECK_AGAINST_OPMODE(j); 109790792Sgshapiro GrabTo = true; 109838032Speter break; 109938032Speter 110038032Speter case 'V': /* DSN ENVID: set "original" envelope id */ 110190792Sgshapiro CHECK_AGAINST_OPMODE(j); 110238032Speter if (!xtextok(optarg)) 110338032Speter { 110438032Speter usrerr("Invalid syntax in -V flag"); 110538032Speter ExitStat = EX_USAGE; 110638032Speter } 110738032Speter else 110864562Sgshapiro { 110990792Sgshapiro BlankEnvelope.e_envid = newstr(optarg); 111090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 111190792Sgshapiro macid("{dsn_envid}"), optarg); 111264562Sgshapiro } 111338032Speter break; 111438032Speter 111538032Speter case 'X': /* traffic log file */ 111690792Sgshapiro dp = drop_privileges(true); 111764562Sgshapiro setstat(dp); 111864562Sgshapiro if (stat(optarg, &traf_st) == 0 && 111964562Sgshapiro S_ISFIFO(traf_st.st_mode)) 112090792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 112190792Sgshapiro SM_TIME_DEFAULT, 112290792Sgshapiro optarg, 112390792Sgshapiro SM_IO_WRONLY, NULL); 112464562Sgshapiro else 112590792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 112690792Sgshapiro SM_TIME_DEFAULT, 112790792Sgshapiro optarg, 112890792Sgshapiro SM_IO_APPEND, NULL); 112938032Speter if (TrafficLogFile == NULL) 113038032Speter { 113138032Speter syserr("cannot open %s", optarg); 113238032Speter ExitStat = EX_CANTCREAT; 113338032Speter break; 113438032Speter } 113590792Sgshapiro (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT, 113690792Sgshapiro NULL, SM_IO_LBF, 0); 113738032Speter break; 113838032Speter 113938032Speter /* compatibility flags */ 114038032Speter case 'c': /* connect to non-local mailers */ 114138032Speter case 'i': /* don't let dot stop me */ 114238032Speter case 'm': /* send to me too */ 114338032Speter case 'T': /* set timeout interval */ 114438032Speter case 'v': /* give blow-by-blow description */ 114590792Sgshapiro setoption(j, "T", false, true, &BlankEnvelope); 114638032Speter break; 114738032Speter 114838032Speter case 'e': /* error message disposition */ 114938032Speter case 'M': /* define macro */ 115090792Sgshapiro setoption(j, optarg, false, true, &BlankEnvelope); 115138032Speter break; 115238032Speter 115338032Speter case 's': /* save From lines in headers */ 115490792Sgshapiro setoption('f', "T", false, true, &BlankEnvelope); 115538032Speter break; 115638032Speter 115764562Sgshapiro#ifdef DBM 115838032Speter case 'I': /* initialize alias DBM file */ 115990792Sgshapiro set_op_mode(MD_INITALIAS); 116038032Speter break; 116164562Sgshapiro#endif /* DBM */ 116238032Speter 116364562Sgshapiro#if defined(__osf__) || defined(_AIX3) 116438032Speter case 'x': /* random flag that OSF/1 & AIX mailx passes */ 116538032Speter break; 116664562Sgshapiro#endif /* defined(__osf__) || defined(_AIX3) */ 116764562Sgshapiro#if defined(sony_news) 116838032Speter case 'E': 116938032Speter case 'J': /* ignore flags for Japanese code conversion 117064562Sgshapiro implemented on Sony NEWS */ 117138032Speter break; 117264562Sgshapiro#endif /* defined(sony_news) */ 117338032Speter 117438032Speter default: 117590792Sgshapiro finis(true, true, EX_USAGE); 117690792Sgshapiro /* NOTREACHED */ 117738032Speter break; 117838032Speter } 117938032Speter } 118038032Speter 118190792Sgshapiro /* if we've had errors so far, exit now */ 118290792Sgshapiro if ((ExitStat != EX_OK && OpMode != MD_TEST) || 118390792Sgshapiro ExitStat == EX_OSERR) 118464562Sgshapiro { 118590792Sgshapiro finis(false, true, ExitStat); 118690792Sgshapiro /* NOTREACHED */ 118764562Sgshapiro } 118890792Sgshapiro 118990792Sgshapiro if (bitset(SUBMIT_MTA, SubmitMode)) 119064562Sgshapiro { 119190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 119290792Sgshapiro macid("{daemon_flags}"), "CC f"); 119364562Sgshapiro } 119490792Sgshapiro else if (OpMode == MD_DELIVER || OpMode == MD_SMTP) 119564562Sgshapiro { 119690792Sgshapiro SubmitMode = SUBMIT_MSA; 119790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 119890792Sgshapiro macid("{daemon_flags}"), "c u"); 119964562Sgshapiro } 120064562Sgshapiro 120138032Speter /* 120238032Speter ** Do basic initialization. 120338032Speter ** Read system control file. 120438032Speter ** Extract special fields for local use. 120538032Speter */ 120638032Speter 120738032Speter#if XDEBUG 120838032Speter checkfd012("before readcf"); 120964562Sgshapiro#endif /* XDEBUG */ 121090792Sgshapiro vendor_pre_defaults(&BlankEnvelope); 121164562Sgshapiro 121290792Sgshapiro readcf(getcfname(OpMode, SubmitMode, cftype, conffile), 121390792Sgshapiro safecf, &BlankEnvelope); 121490792Sgshapiro#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 121590792Sgshapiro ConfigFileRead = true; 121690792Sgshapiro#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 121790792Sgshapiro vendor_post_defaults(&BlankEnvelope); 121838032Speter 121990792Sgshapiro /* now we can complain about missing fds */ 122090792Sgshapiro if (MissingFds != 0 && LogLevel > 8) 122190792Sgshapiro { 122290792Sgshapiro char mbuf[MAXLINE]; 122390792Sgshapiro 122490792Sgshapiro mbuf[0] = '\0'; 122590792Sgshapiro if (bitset(1 << STDIN_FILENO, MissingFds)) 122690792Sgshapiro (void) sm_strlcat(mbuf, ", stdin", sizeof mbuf); 122790792Sgshapiro if (bitset(1 << STDOUT_FILENO, MissingFds)) 122890792Sgshapiro (void) sm_strlcat(mbuf, ", stdout", sizeof mbuf); 122990792Sgshapiro if (bitset(1 << STDERR_FILENO, MissingFds)) 123090792Sgshapiro (void) sm_strlcat(mbuf, ", stderr", sizeof mbuf); 123190792Sgshapiro 123290792Sgshapiro /* Notice: fill_errno is from high above: fill_fd() */ 123390792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 123490792Sgshapiro "File descriptors missing on startup: %s; %s", 123590792Sgshapiro &mbuf[2], sm_errstring(fill_errno)); 123690792Sgshapiro } 123790792Sgshapiro 123877349Sgshapiro /* Remove the ability for a normal user to send signals */ 123990792Sgshapiro if (RealUid != 0 && RealUid != geteuid()) 124077349Sgshapiro { 124177349Sgshapiro uid_t new_uid = geteuid(); 124277349Sgshapiro 124377349Sgshapiro#if HASSETREUID 124477349Sgshapiro /* 124577349Sgshapiro ** Since we can differentiate between uid and euid, 124677349Sgshapiro ** make the uid a different user so the real user 124777349Sgshapiro ** can't send signals. However, it doesn't need to be 124877349Sgshapiro ** root (euid has root). 124977349Sgshapiro */ 125077349Sgshapiro 125177349Sgshapiro if (new_uid == 0) 125277349Sgshapiro new_uid = DefUid; 125377349Sgshapiro if (tTd(47, 5)) 125490792Sgshapiro sm_dprintf("Changing real uid to %d\n", (int) new_uid); 125577349Sgshapiro if (setreuid(new_uid, geteuid()) < 0) 125677349Sgshapiro { 125777349Sgshapiro syserr("main: setreuid(%d, %d) failed", 125877349Sgshapiro (int) new_uid, (int) geteuid()); 125990792Sgshapiro finis(false, true, EX_OSERR); 126077349Sgshapiro /* NOTREACHED */ 126177349Sgshapiro } 126277349Sgshapiro if (tTd(47, 10)) 126390792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 126490792Sgshapiro (int) geteuid(), (int) getuid()); 126577349Sgshapiro#else /* HASSETREUID */ 126677349Sgshapiro /* 126777349Sgshapiro ** Have to change both effective and real so need to 126877349Sgshapiro ** change them both to effective to keep privs. 126977349Sgshapiro */ 127077349Sgshapiro 127177349Sgshapiro if (tTd(47, 5)) 127290792Sgshapiro sm_dprintf("Changing uid to %d\n", (int) new_uid); 127377349Sgshapiro if (setuid(new_uid) < 0) 127477349Sgshapiro { 127577349Sgshapiro syserr("main: setuid(%d) failed", (int) new_uid); 127690792Sgshapiro finis(false, true, EX_OSERR); 127777349Sgshapiro /* NOTREACHED */ 127877349Sgshapiro } 127977349Sgshapiro if (tTd(47, 10)) 128090792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 128190792Sgshapiro (int) geteuid(), (int) getuid()); 128277349Sgshapiro#endif /* HASSETREUID */ 128377349Sgshapiro } 128477349Sgshapiro 128590792Sgshapiro#if NAMED_BIND 128690792Sgshapiro if (FallBackMX != NULL) 128790792Sgshapiro (void) getfallbackmxrr(FallBackMX); 128890792Sgshapiro#endif /* NAMED_BIND */ 128990792Sgshapiro 129090792Sgshapiro if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER) 129190792Sgshapiro { 129290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 129390792Sgshapiro "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n"); 129490792Sgshapiro } 129590792Sgshapiro 129690792Sgshapiro if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)) 129790792Sgshapiro { 129890792Sgshapiro usrerr("Mail submission program cannot be used as daemon"); 129990792Sgshapiro finis(false, true, EX_USAGE); 130090792Sgshapiro } 130190792Sgshapiro 130290792Sgshapiro if (OpMode == MD_DELIVER || OpMode == MD_SMTP || 130390792Sgshapiro OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP || 130490792Sgshapiro OpMode == MD_DAEMON || OpMode == MD_FGDAEMON) 130590792Sgshapiro makeworkgroups(); 130690792Sgshapiro 130777349Sgshapiro /* set up the basic signal handlers */ 130890792Sgshapiro if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN) 130990792Sgshapiro (void) sm_signal(SIGINT, intsig); 131090792Sgshapiro (void) sm_signal(SIGTERM, intsig); 131177349Sgshapiro 131238032Speter /* Enforce use of local time (null string overrides this) */ 131338032Speter if (TimeZoneSpec == NULL) 131438032Speter unsetenv("TZ"); 131538032Speter else if (TimeZoneSpec[0] != '\0') 131638032Speter setuserenv("TZ", TimeZoneSpec); 131738032Speter else 131838032Speter setuserenv("TZ", NULL); 131938032Speter tzset(); 132038032Speter 132190792Sgshapiro /* initialize mailbox database */ 132290792Sgshapiro i = sm_mbdb_initialize(Mbdb); 132390792Sgshapiro if (i != EX_OK) 132490792Sgshapiro { 132590792Sgshapiro usrerr("Can't initialize mailbox database \"%s\": %s", 132690792Sgshapiro Mbdb, sm_strexit(i)); 132790792Sgshapiro ExitStat = i; 132890792Sgshapiro } 132990792Sgshapiro 133038032Speter /* avoid denial-of-service attacks */ 133138032Speter resetlimits(); 133238032Speter 133390792Sgshapiro if (OpMode == MD_TEST) 133438032Speter { 133590792Sgshapiro /* can't be done after readcf if RunAs* is used */ 133690792Sgshapiro dp = drop_privileges(true); 133790792Sgshapiro if (dp != EX_OK) 133890792Sgshapiro { 133990792Sgshapiro finis(false, true, dp); 134090792Sgshapiro /* NOTREACHED */ 134190792Sgshapiro } 134290792Sgshapiro } 134390792Sgshapiro else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 134490792Sgshapiro { 134538032Speter /* drop privileges -- daemon mode done after socket/bind */ 134690792Sgshapiro dp = drop_privileges(false); 134764562Sgshapiro setstat(dp); 134890792Sgshapiro if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0)) 134990792Sgshapiro { 135090792Sgshapiro usrerr("Mail submission program must have RunAsUser set to non root user"); 135190792Sgshapiro finis(false, true, EX_CONFIG); 135290792Sgshapiro /* NOTREACHED */ 135390792Sgshapiro } 135438032Speter } 135538032Speter 135664562Sgshapiro#if NAMED_BIND 135764562Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 135864562Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 135964562Sgshapiro#endif /* NAMED_BIND */ 136064562Sgshapiro 136138032Speter /* 136238032Speter ** Find our real host name for future logging. 136338032Speter */ 136438032Speter 136564562Sgshapiro authinfo = getauthinfo(STDIN_FILENO, &forged); 136690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 136738032Speter 136838032Speter /* suppress error printing if errors mailed back or whatever */ 136990792Sgshapiro if (BlankEnvelope.e_errormode != EM_PRINT) 137090792Sgshapiro HoldErrs = true; 137138032Speter 137238032Speter /* set up the $=m class now, after .cf has a chance to redefine $m */ 137390792Sgshapiro expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope); 137473188Sgshapiro if (jbuf[0] != '\0') 137573188Sgshapiro setclass('m', jbuf); 137638032Speter 137738032Speter /* probe interfaces and locate any additional names */ 137890792Sgshapiro if (DontProbeInterfaces != DPI_PROBENONE) 137938032Speter load_if_names(); 138038032Speter 138190792Sgshapiro if (tTd(0, 10)) 138290792Sgshapiro { 138390792Sgshapiro /* Now we know which .cf file we use */ 138490792Sgshapiro sm_dprintf(" Conf file:\t%s (selected)\n", 138590792Sgshapiro getcfname(OpMode, SubmitMode, cftype, conffile)); 138690792Sgshapiro sm_dprintf(" Pid file:\t%s (selected)\n", PidFile); 138790792Sgshapiro } 138890792Sgshapiro 138938032Speter if (tTd(0, 1)) 139038032Speter { 139190792Sgshapiro sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 139290792Sgshapiro sm_dprintf("\n (short domain name) $w = "); 139390792Sgshapiro xputs(macvalue('w', &BlankEnvelope)); 139490792Sgshapiro sm_dprintf("\n (canonical domain name) $j = "); 139590792Sgshapiro xputs(macvalue('j', &BlankEnvelope)); 139690792Sgshapiro sm_dprintf("\n (subdomain name) $m = "); 139790792Sgshapiro xputs(macvalue('m', &BlankEnvelope)); 139890792Sgshapiro sm_dprintf("\n (node name) $k = "); 139990792Sgshapiro xputs(macvalue('k', &BlankEnvelope)); 140090792Sgshapiro sm_dprintf("\n========================================================\n\n"); 140138032Speter } 140238032Speter 140338032Speter /* 140438032Speter ** Do more command line checking -- these are things that 140538032Speter ** have to modify the results of reading the config file. 140638032Speter */ 140738032Speter 140838032Speter /* process authorization warnings from command line */ 140938032Speter if (warn_C_flag) 141090792Sgshapiro auth_warning(&BlankEnvelope, "Processed by %s with -C %s", 141190792Sgshapiro RealUserName, conffile); 141264562Sgshapiro if (Warn_Q_option && !wordinclass(RealUserName, 't')) 141390792Sgshapiro auth_warning(&BlankEnvelope, "Processed from queue %s", 141490792Sgshapiro QueueDir); 141590792Sgshapiro if (sysloglabel != NULL && !wordinclass(RealUserName, 't') && 141690792Sgshapiro RealUid != 0 && RealUid != TrustedUid && LogLevel > 1) 141790792Sgshapiro sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label", 141890792Sgshapiro (int) RealUid); 141938032Speter 142038032Speter /* check body type for legality */ 142190792Sgshapiro i = check_bodytype(BlankEnvelope.e_bodytype); 142290792Sgshapiro if (i == BODYTYPE_ILLEGAL) 142338032Speter { 142490792Sgshapiro usrerr("Illegal body type %s", BlankEnvelope.e_bodytype); 142590792Sgshapiro BlankEnvelope.e_bodytype = NULL; 142638032Speter } 142790792Sgshapiro else if (i != BODYTYPE_NONE) 142890792Sgshapiro SevenBitInput = (i == BODYTYPE_7BIT); 142938032Speter 143038032Speter /* tweak default DSN notifications */ 143138032Speter if (DefaultNotify == 0) 143238032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 143338032Speter 143438032Speter /* be sure we don't pick up bogus HOSTALIASES environment variable */ 143564562Sgshapiro if (OpMode == MD_QUEUERUN && RealUid != 0) 143638032Speter (void) unsetenv("HOSTALIASES"); 143738032Speter 143838032Speter /* check for sane configuration level */ 143938032Speter if (ConfigLevel > MAXCONFIGLEVEL) 144038032Speter { 144138032Speter syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 144290792Sgshapiro ConfigLevel, Version, MAXCONFIGLEVEL); 144338032Speter } 144438032Speter 144538032Speter /* need MCI cache to have persistence */ 144638032Speter if (HostStatDir != NULL && MaxMciCache == 0) 144738032Speter { 144838032Speter HostStatDir = NULL; 144990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 145090792Sgshapiro "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 145138032Speter } 145238032Speter 145338032Speter /* need HostStatusDir in order to have SingleThreadDelivery */ 145438032Speter if (SingleThreadDelivery && HostStatDir == NULL) 145538032Speter { 145690792Sgshapiro SingleThreadDelivery = false; 145790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 145890792Sgshapiro "Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 145938032Speter } 146038032Speter 146138032Speter /* check for permissions */ 146290792Sgshapiro if (RealUid != 0 && 146342575Speter RealUid != TrustedUid) 146438032Speter { 146590792Sgshapiro char *action = NULL; 146690792Sgshapiro 146790792Sgshapiro switch (OpMode) 146890792Sgshapiro { 146990792Sgshapiro case MD_QUEUERUN: 147090792Sgshapiro#if _FFR_QUARANTINE 147190792Sgshapiro if (quarantining != NULL) 147290792Sgshapiro action = "quarantine jobs"; 147390792Sgshapiro else 147490792Sgshapiro#endif /* _FFR_QUARANTINE */ 147590792Sgshapiro /* Normal users can do a single queue run */ 147690792Sgshapiro if (QueueIntvl == 0) 147790792Sgshapiro break; 147890792Sgshapiro 147990792Sgshapiro /* but not persistent queue runners */ 148090792Sgshapiro if (action == NULL) 148190792Sgshapiro action = "start a queue runner daemon"; 148290792Sgshapiro /* FALLTHROUGH */ 148390792Sgshapiro 148490792Sgshapiro case MD_PURGESTAT: 148590792Sgshapiro if (action == NULL) 148690792Sgshapiro action = "purge host status"; 148790792Sgshapiro /* FALLTHROUGH */ 148890792Sgshapiro 148990792Sgshapiro case MD_DAEMON: 149090792Sgshapiro case MD_FGDAEMON: 149190792Sgshapiro if (action == NULL) 149290792Sgshapiro action = "run daemon"; 149390792Sgshapiro 149490792Sgshapiro if (tTd(65, 1)) 149590792Sgshapiro sm_dprintf("Deny user %d attempt to %s\n", 149690792Sgshapiro (int) RealUid, action); 149790792Sgshapiro 149890792Sgshapiro if (LogLevel > 1) 149990792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 150090792Sgshapiro "user %d attempted to %s", 150190792Sgshapiro (int) RealUid, action); 150290792Sgshapiro HoldErrs = false; 150390792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 150490792Sgshapiro finis(false, true, EX_USAGE); 150590792Sgshapiro /* NOTREACHED */ 150690792Sgshapiro break; 150790792Sgshapiro 150890792Sgshapiro case MD_VERIFY: 150990792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags)) 151090792Sgshapiro { 151190792Sgshapiro /* 151290792Sgshapiro ** If -bv and RestrictExpand, 151390792Sgshapiro ** drop privs to prevent normal 151490792Sgshapiro ** users from reading private 151590792Sgshapiro ** aliases/forwards/:include:s 151690792Sgshapiro */ 151790792Sgshapiro 151890792Sgshapiro if (tTd(65, 1)) 151990792Sgshapiro sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n", 152090792Sgshapiro (int) RealUid); 152190792Sgshapiro 152290792Sgshapiro dp = drop_privileges(true); 152390792Sgshapiro 152490792Sgshapiro /* Fake address safety */ 152590792Sgshapiro if (tTd(65, 1)) 152690792Sgshapiro sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n"); 152790792Sgshapiro setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail); 152890792Sgshapiro 152990792Sgshapiro if (dp != EX_OK) 153090792Sgshapiro { 153190792Sgshapiro if (tTd(65, 1)) 153290792Sgshapiro sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n", 153390792Sgshapiro (int) RealUid); 153490792Sgshapiro CurEnv->e_id = NULL; 153590792Sgshapiro finis(true, true, dp); 153690792Sgshapiro /* NOTREACHED */ 153790792Sgshapiro } 153890792Sgshapiro } 153990792Sgshapiro break; 154090792Sgshapiro 154190792Sgshapiro case MD_TEST: 154290792Sgshapiro case MD_PRINT: 154390792Sgshapiro case MD_PRINTNQE: 154490792Sgshapiro case MD_FREEZE: 154590792Sgshapiro case MD_HOSTSTAT: 154690792Sgshapiro /* Nothing special to check */ 154790792Sgshapiro break; 154890792Sgshapiro 154990792Sgshapiro case MD_INITALIAS: 155090792Sgshapiro if (!wordinclass(RealUserName, 't')) 155190792Sgshapiro { 155290792Sgshapiro if (tTd(65, 1)) 155390792Sgshapiro sm_dprintf("Deny user %d attempt to rebuild the alias map\n", 155490792Sgshapiro (int) RealUid); 155590792Sgshapiro if (LogLevel > 1) 155690792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 155790792Sgshapiro "user %d attempted to rebuild the alias map", 155890792Sgshapiro (int) RealUid); 155990792Sgshapiro HoldErrs = false; 156090792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 156190792Sgshapiro finis(false, true, EX_USAGE); 156290792Sgshapiro /* NOTREACHED */ 156390792Sgshapiro } 156490792Sgshapiro if (UseMSP) 156590792Sgshapiro { 156690792Sgshapiro HoldErrs = false; 156790792Sgshapiro usrerr("User %d cannot rebuild aliases in mail submission program", 156890792Sgshapiro (int) RealUid); 156990792Sgshapiro finis(false, true, EX_USAGE); 157090792Sgshapiro /* NOTREACHED */ 157190792Sgshapiro } 157290792Sgshapiro /* FALLTHROUGH */ 157390792Sgshapiro 157490792Sgshapiro default: 157590792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) && 157690792Sgshapiro Verbose != 0) 157790792Sgshapiro { 157890792Sgshapiro /* 157990792Sgshapiro ** If -v and RestrictExpand, reset 158090792Sgshapiro ** Verbose to prevent normal users 158190792Sgshapiro ** from seeing the expansion of 158290792Sgshapiro ** aliases/forwards/:include:s 158390792Sgshapiro */ 158490792Sgshapiro 158590792Sgshapiro if (tTd(65, 1)) 158690792Sgshapiro sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n", 158790792Sgshapiro (int) RealUid); 158890792Sgshapiro Verbose = 0; 158990792Sgshapiro } 159090792Sgshapiro break; 159190792Sgshapiro } 159238032Speter } 159338032Speter 159438032Speter if (MeToo) 159538032Speter BlankEnvelope.e_flags |= EF_METOO; 159638032Speter 159738032Speter switch (OpMode) 159838032Speter { 159938032Speter case MD_TEST: 160038032Speter /* don't have persistent host status in test mode */ 160138032Speter HostStatDir = NULL; 160238032Speter if (Verbose == 0) 160338032Speter Verbose = 2; 160490792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 160590792Sgshapiro HoldErrs = false; 160638032Speter break; 160738032Speter 160838032Speter case MD_VERIFY: 160990792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 161090792Sgshapiro HoldErrs = false; 161138032Speter /* arrange to exit cleanly on hangup signal */ 161290792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 161390792Sgshapiro (void) sm_signal(SIGHUP, intsig); 161490792Sgshapiro if (geteuid() != 0) 161590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 161690792Sgshapiro "Notice: -bv may give misleading output for non-privileged user\n"); 161738032Speter break; 161838032Speter 161938032Speter case MD_FGDAEMON: 162090792Sgshapiro run_in_foreground = true; 162190792Sgshapiro set_op_mode(MD_DAEMON); 162264562Sgshapiro /* FALLTHROUGH */ 162338032Speter 162438032Speter case MD_DAEMON: 162590792Sgshapiro vendor_daemon_setup(&BlankEnvelope); 162638032Speter 162738032Speter /* remove things that don't make sense in daemon mode */ 162838032Speter FullName = NULL; 162990792Sgshapiro GrabTo = false; 163038032Speter 163138032Speter /* arrange to restart on hangup signal */ 163238032Speter if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 163338032Speter sm_syslog(LOG_WARNING, NOQID, 163464562Sgshapiro "daemon invoked without full pathname; kill -1 won't work"); 163538032Speter break; 163638032Speter 163738032Speter case MD_INITALIAS: 163838032Speter Verbose = 2; 163990792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 164090792Sgshapiro HoldErrs = false; 164164562Sgshapiro /* FALLTHROUGH */ 164238032Speter 164338032Speter default: 164438032Speter /* arrange to exit cleanly on hangup signal */ 164590792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 164690792Sgshapiro (void) sm_signal(SIGHUP, intsig); 164738032Speter break; 164838032Speter } 164938032Speter 165038032Speter /* special considerations for FullName */ 165138032Speter if (FullName != NULL) 165238032Speter { 165338032Speter char *full = NULL; 165438032Speter 165538032Speter /* full names can't have newlines */ 165664562Sgshapiro if (strchr(FullName, '\n') != NULL) 165738032Speter { 165890792Sgshapiro full = newstr(denlstring(FullName, true, true)); 165973188Sgshapiro FullName = full; 166038032Speter } 166173188Sgshapiro 166238032Speter /* check for characters that may have to be quoted */ 166338032Speter if (!rfc822_string(FullName)) 166438032Speter { 166538032Speter /* 166638032Speter ** Quote a full name with special characters 166738032Speter ** as a comment so crackaddr() doesn't destroy 166838032Speter ** the name portion of the address. 166938032Speter */ 167073188Sgshapiro 167190792Sgshapiro FullName = addquotes(FullName, NULL); 167238032Speter if (full != NULL) 167390792Sgshapiro sm_free(full); /* XXX */ 167438032Speter } 167538032Speter } 167638032Speter 167738032Speter /* do heuristic mode adjustment */ 167838032Speter if (Verbose) 167938032Speter { 168038032Speter /* turn off noconnect option */ 168190792Sgshapiro setoption('c', "F", true, false, &BlankEnvelope); 168238032Speter 168338032Speter /* turn on interactive delivery */ 168490792Sgshapiro setoption('d', "", true, false, &BlankEnvelope); 168538032Speter } 168638032Speter 168742575Speter#ifdef VENDOR_CODE 168842575Speter /* check for vendor mismatch */ 168942575Speter if (VendorCode != VENDOR_CODE) 169042575Speter { 169142575Speter message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 169242575Speter getvendor(VENDOR_CODE), getvendor(VendorCode)); 169342575Speter } 169464562Sgshapiro#endif /* VENDOR_CODE */ 169564562Sgshapiro 169638032Speter /* check for out of date configuration level */ 169738032Speter if (ConfigLevel < MAXCONFIGLEVEL) 169838032Speter { 169938032Speter message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 170038032Speter Version, MAXCONFIGLEVEL, ConfigLevel); 170138032Speter } 170238032Speter 170338032Speter if (ConfigLevel < 3) 170490792Sgshapiro UseErrorsTo = true; 170538032Speter 170638032Speter /* set options that were previous macros */ 170738032Speter if (SmtpGreeting == NULL) 170838032Speter { 170990792Sgshapiro if (ConfigLevel < 7 && 171090792Sgshapiro (p = macvalue('e', &BlankEnvelope)) != NULL) 171138032Speter SmtpGreeting = newstr(p); 171238032Speter else 171338032Speter SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 171438032Speter } 171538032Speter if (UnixFromLine == NULL) 171638032Speter { 171790792Sgshapiro if (ConfigLevel < 7 && 171890792Sgshapiro (p = macvalue('l', &BlankEnvelope)) != NULL) 171938032Speter UnixFromLine = newstr(p); 172038032Speter else 172138032Speter UnixFromLine = "From \201g \201d"; 172238032Speter } 172364562Sgshapiro SmtpError[0] = '\0'; 172438032Speter 172538032Speter /* our name for SMTP codes */ 172690792Sgshapiro expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope); 172773188Sgshapiro if (jbuf[0] == '\0') 172890792Sgshapiro PSTRSET(MyHostName, "localhost"); 172973188Sgshapiro else 173090792Sgshapiro PSTRSET(MyHostName, jbuf); 173173188Sgshapiro if (strchr(MyHostName, '.') == NULL) 173238032Speter message("WARNING: local host name (%s) is not qualified; fix $j in config file", 173373188Sgshapiro MyHostName); 173438032Speter 173538032Speter /* make certain that this name is part of the $=w class */ 173638032Speter setclass('w', MyHostName); 173738032Speter 173890792Sgshapiro /* fill in the structure of the *default* queue */ 173990792Sgshapiro st = stab("mqueue", ST_QUEUE, ST_FIND); 174090792Sgshapiro if (st == NULL) 174190792Sgshapiro syserr("No default queue (mqueue) defined"); 174290792Sgshapiro else 174390792Sgshapiro set_def_queueval(st->s_quegrp, true); 174490792Sgshapiro 174538032Speter /* the indices of built-in mailers */ 174638032Speter st = stab("local", ST_MAILER, ST_FIND); 174738032Speter if (st != NULL) 174838032Speter LocalMailer = st->s_mailer; 174938032Speter else if (OpMode != MD_TEST || !warn_C_flag) 175038032Speter syserr("No local mailer defined"); 175138032Speter 175238032Speter st = stab("prog", ST_MAILER, ST_FIND); 175338032Speter if (st == NULL) 175438032Speter syserr("No prog mailer defined"); 175538032Speter else 175638032Speter { 175738032Speter ProgMailer = st->s_mailer; 175838032Speter clrbitn(M_MUSER, ProgMailer->m_flags); 175938032Speter } 176038032Speter 176138032Speter st = stab("*file*", ST_MAILER, ST_FIND); 176238032Speter if (st == NULL) 176338032Speter syserr("No *file* mailer defined"); 176438032Speter else 176538032Speter { 176638032Speter FileMailer = st->s_mailer; 176738032Speter clrbitn(M_MUSER, FileMailer->m_flags); 176838032Speter } 176938032Speter 177038032Speter st = stab("*include*", ST_MAILER, ST_FIND); 177138032Speter if (st == NULL) 177238032Speter syserr("No *include* mailer defined"); 177338032Speter else 177438032Speter InclMailer = st->s_mailer; 177538032Speter 177638032Speter if (ConfigLevel < 6) 177738032Speter { 177838032Speter /* heuristic tweaking of local mailer for back compat */ 177938032Speter if (LocalMailer != NULL) 178038032Speter { 178138032Speter setbitn(M_ALIASABLE, LocalMailer->m_flags); 178238032Speter setbitn(M_HASPWENT, LocalMailer->m_flags); 178338032Speter setbitn(M_TRYRULESET5, LocalMailer->m_flags); 178438032Speter setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 178538032Speter setbitn(M_CHECKPROG, LocalMailer->m_flags); 178638032Speter setbitn(M_CHECKFILE, LocalMailer->m_flags); 178738032Speter setbitn(M_CHECKUDB, LocalMailer->m_flags); 178838032Speter } 178938032Speter if (ProgMailer != NULL) 179038032Speter setbitn(M_RUNASRCPT, ProgMailer->m_flags); 179138032Speter if (FileMailer != NULL) 179238032Speter setbitn(M_RUNASRCPT, FileMailer->m_flags); 179338032Speter } 179438032Speter if (ConfigLevel < 7) 179538032Speter { 179638032Speter if (LocalMailer != NULL) 179738032Speter setbitn(M_VRFY250, LocalMailer->m_flags); 179838032Speter if (ProgMailer != NULL) 179938032Speter setbitn(M_VRFY250, ProgMailer->m_flags); 180038032Speter if (FileMailer != NULL) 180138032Speter setbitn(M_VRFY250, FileMailer->m_flags); 180238032Speter } 180338032Speter 180438032Speter /* MIME Content-Types that cannot be transfer encoded */ 180538032Speter setclass('n', "multipart/signed"); 180638032Speter 180738032Speter /* MIME message/xxx subtypes that can be treated as messages */ 180838032Speter setclass('s', "rfc822"); 180938032Speter 181038032Speter /* MIME Content-Transfer-Encodings that can be encoded */ 181138032Speter setclass('e', "7bit"); 181238032Speter setclass('e', "8bit"); 181338032Speter setclass('e', "binary"); 181438032Speter 181538032Speter#ifdef USE_B_CLASS 181638032Speter /* MIME Content-Types that should be treated as binary */ 181738032Speter setclass('b', "image"); 181838032Speter setclass('b', "audio"); 181938032Speter setclass('b', "video"); 182038032Speter setclass('b', "application/octet-stream"); 182164562Sgshapiro#endif /* USE_B_CLASS */ 182238032Speter 182342575Speter /* MIME headers which have fields to check for overflow */ 182490792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition"); 182590792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-type"); 182642575Speter 182742575Speter /* MIME headers to check for length overflow */ 182890792Sgshapiro setclass(macid("{checkMIMETextHeaders}"), "content-description"); 182942575Speter 183042575Speter /* MIME headers to check for overflow and rebalance */ 183190792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-disposition"); 183290792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-id"); 183390792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding"); 183490792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-type"); 183590792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "mime-version"); 183642575Speter 183790792Sgshapiro /* Macros to save in the queue file -- don't remove any */ 183890792Sgshapiro setclass(macid("{persistentMacros}"), "r"); 183990792Sgshapiro setclass(macid("{persistentMacros}"), "s"); 184090792Sgshapiro setclass(macid("{persistentMacros}"), "_"); 184190792Sgshapiro setclass(macid("{persistentMacros}"), "{if_addr}"); 184290792Sgshapiro setclass(macid("{persistentMacros}"), "{daemon_flags}"); 184364562Sgshapiro 184438032Speter /* operate in queue directory */ 184590792Sgshapiro if (QueueDir == NULL || *QueueDir == '\0') 184638032Speter { 184738032Speter if (OpMode != MD_TEST) 184838032Speter { 184938032Speter syserr("QueueDirectory (Q) option must be set"); 185038032Speter ExitStat = EX_CONFIG; 185138032Speter } 185238032Speter } 185338032Speter else 185438032Speter { 185564562Sgshapiro if (OpMode != MD_TEST) 185690792Sgshapiro setup_queues(OpMode == MD_DAEMON); 185738032Speter } 185838032Speter 185938032Speter /* check host status directory for validity */ 186090792Sgshapiro if (HostStatDir != NULL && !path_is_dir(HostStatDir, false)) 186138032Speter { 186238032Speter /* cannot use this value */ 186390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 186490792Sgshapiro "Warning: Cannot use HostStatusDirectory = %s: %s\n", 186590792Sgshapiro HostStatDir, sm_errstring(errno)); 186638032Speter HostStatDir = NULL; 186738032Speter } 186838032Speter 186990792Sgshapiro if (OpMode == MD_QUEUERUN && 187090792Sgshapiro RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 187138032Speter { 187238032Speter struct stat stbuf; 187338032Speter 187438032Speter /* check to see if we own the queue directory */ 187538032Speter if (stat(".", &stbuf) < 0) 187638032Speter syserr("main: cannot stat %s", QueueDir); 187738032Speter if (stbuf.st_uid != RealUid) 187838032Speter { 187938032Speter /* nope, really a botch */ 188090792Sgshapiro HoldErrs = false; 188138032Speter usrerr("You do not have permission to process the queue"); 188290792Sgshapiro finis(false, true, EX_NOPERM); 188390792Sgshapiro /* NOTREACHED */ 188438032Speter } 188538032Speter } 188638032Speter 188790792Sgshapiro#if MILTER 188864562Sgshapiro /* sanity checks on milter filters */ 188964562Sgshapiro if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 189090792Sgshapiro { 189190792Sgshapiro milter_config(InputFilterList, InputFilters, MAXFILTERS); 189290792Sgshapiro# if _FFR_MILTER_PERDAEMON 189390792Sgshapiro setup_daemon_milters(); 189490792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 189590792Sgshapiro } 189690792Sgshapiro#endif /* MILTER */ 189764562Sgshapiro 189890792Sgshapiro /* Convert queuegroup string to qgrp number */ 189990792Sgshapiro if (queuegroup != NULL) 190090792Sgshapiro { 190190792Sgshapiro qgrp = name2qid(queuegroup); 190290792Sgshapiro if (qgrp == NOQGRP) 190390792Sgshapiro { 190490792Sgshapiro HoldErrs = false; 190590792Sgshapiro usrerr("Queue group %s unknown", queuegroup); 190690792Sgshapiro finis(false, true, ExitStat); 190790792Sgshapiro /* NOTREACHED */ 190890792Sgshapiro } 190990792Sgshapiro } 191066494Sgshapiro 191138032Speter /* if we've had errors so far, exit now */ 191238032Speter if (ExitStat != EX_OK && OpMode != MD_TEST) 191390792Sgshapiro { 191490792Sgshapiro finis(false, true, ExitStat); 191590792Sgshapiro /* NOTREACHED */ 191690792Sgshapiro } 191738032Speter 191890792Sgshapiro#if SASL 191990792Sgshapiro /* sendmail specific SASL initialization */ 192090792Sgshapiro sm_sasl_init(); 192190792Sgshapiro#endif /* SASL */ 192290792Sgshapiro 192338032Speter#if XDEBUG 192438032Speter checkfd012("before main() initmaps"); 192564562Sgshapiro#endif /* XDEBUG */ 192638032Speter 192738032Speter /* 192838032Speter ** Do operation-mode-dependent initialization. 192938032Speter */ 193038032Speter 193138032Speter switch (OpMode) 193238032Speter { 193338032Speter case MD_PRINT: 193438032Speter /* print the queue */ 193590792Sgshapiro HoldErrs = false; 193690792Sgshapiro dropenvelope(&BlankEnvelope, true, false); 193790792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 193890792Sgshapiro if (qgrp != NOQGRP) 193990792Sgshapiro { 194090792Sgshapiro int j; 194190792Sgshapiro 194290792Sgshapiro /* Selecting a particular queue group to run */ 194390792Sgshapiro for (j = 0; j < Queue[qgrp]->qg_numqueues; j++) 194490792Sgshapiro { 194590792Sgshapiro if (StopRequest) 194690792Sgshapiro stop_sendmail(); 194790792Sgshapiro (void) print_single_queue(qgrp, j); 194890792Sgshapiro } 194990792Sgshapiro finis(false, true, EX_OK); 195090792Sgshapiro /* NOTREACHED */ 195190792Sgshapiro } 195238032Speter printqueue(); 195390792Sgshapiro finis(false, true, EX_OK); 195490792Sgshapiro /* NOTREACHED */ 195542575Speter break; 195638032Speter 195790792Sgshapiro case MD_PRINTNQE: 195890792Sgshapiro /* print number of entries in queue */ 195990792Sgshapiro dropenvelope(&BlankEnvelope, true, false); 196090792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 196190792Sgshapiro printnqe(smioout, NULL); 196290792Sgshapiro finis(false, true, EX_OK); 196390792Sgshapiro /* NOTREACHED */ 196490792Sgshapiro break; 196590792Sgshapiro 196690792Sgshapiro#if _FFR_QUARANTINE 196790792Sgshapiro case MD_QUEUERUN: 196890792Sgshapiro /* only handle quarantining here */ 196990792Sgshapiro if (quarantining == NULL) 197090792Sgshapiro break; 197190792Sgshapiro 197290792Sgshapiro if (QueueMode != QM_QUARANTINE && 197390792Sgshapiro QueueMode != QM_NORMAL) 197490792Sgshapiro { 197590792Sgshapiro HoldErrs = false; 197690792Sgshapiro usrerr("Can not use -Q with -q%c", QueueMode); 197790792Sgshapiro ExitStat = EX_USAGE; 197890792Sgshapiro finis(false, true, ExitStat); 197990792Sgshapiro /* NOTREACHED */ 198090792Sgshapiro } 198190792Sgshapiro quarantine_queue(quarantining, qgrp); 198290792Sgshapiro finis(false, true, EX_OK); 198390792Sgshapiro break; 198490792Sgshapiro#endif /* _FFR_QUARANTINE */ 198590792Sgshapiro 198638032Speter case MD_HOSTSTAT: 198790792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 198864562Sgshapiro (void) mci_traverse_persistent(mci_print_persistent, NULL); 198990792Sgshapiro finis(false, true, EX_OK); 199090792Sgshapiro /* NOTREACHED */ 199164562Sgshapiro break; 199238032Speter 199338032Speter case MD_PURGESTAT: 199464562Sgshapiro (void) mci_traverse_persistent(mci_purge_persistent, NULL); 199590792Sgshapiro finis(false, true, EX_OK); 199690792Sgshapiro /* NOTREACHED */ 199764562Sgshapiro break; 199838032Speter 199938032Speter case MD_INITALIAS: 200042575Speter /* initialize maps */ 200164562Sgshapiro initmaps(); 200290792Sgshapiro finis(false, true, ExitStat); 200390792Sgshapiro /* NOTREACHED */ 200442575Speter break; 200538032Speter 200638032Speter case MD_SMTP: 200738032Speter case MD_DAEMON: 200838032Speter /* reset DSN parameters */ 200938032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 201090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 201190792Sgshapiro macid("{dsn_notify}"), NULL); 201290792Sgshapiro BlankEnvelope.e_envid = NULL; 201390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 201490792Sgshapiro macid("{dsn_envid}"), NULL); 201590792Sgshapiro BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 201690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 201790792Sgshapiro macid("{dsn_ret}"), NULL); 201838032Speter 201942575Speter /* don't open maps for daemon -- done below in child */ 202038032Speter break; 202138032Speter } 202238032Speter 202338032Speter if (tTd(0, 15)) 202438032Speter { 202538032Speter /* print configuration table (or at least part of it) */ 202638032Speter if (tTd(0, 90)) 202738032Speter printrules(); 202838032Speter for (i = 0; i < MAXMAILERS; i++) 202938032Speter { 203038032Speter if (Mailer[i] != NULL) 203138032Speter printmailer(Mailer[i]); 203238032Speter } 203338032Speter } 203438032Speter 203538032Speter /* 203638032Speter ** Switch to the main envelope. 203738032Speter */ 203838032Speter 203990792Sgshapiro CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope, 204090792Sgshapiro sm_rpool_new_x(NULL)); 204138032Speter MainEnvelope.e_flags = BlankEnvelope.e_flags; 204238032Speter 204338032Speter /* 204438032Speter ** If test mode, read addresses from stdin and process. 204538032Speter */ 204638032Speter 204738032Speter if (OpMode == MD_TEST) 204838032Speter { 204990792Sgshapiro if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL))) 205038032Speter Verbose = 2; 205138032Speter 205238032Speter if (Verbose) 205338032Speter { 205490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 205590792Sgshapiro "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 205690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 205790792Sgshapiro "Enter <ruleset> <address>\n"); 205838032Speter } 205990792Sgshapiro macdefine(&(MainEnvelope.e_macro), A_PERM, 206090792Sgshapiro macid("{addr_type}"), "e r"); 206138032Speter for (;;) 206238032Speter { 206390792Sgshapiro SM_TRY 206490792Sgshapiro { 206590792Sgshapiro (void) sm_signal(SIGINT, intindebug); 206690792Sgshapiro (void) sm_releasesignal(SIGINT); 206790792Sgshapiro if (Verbose == 2) 206890792Sgshapiro (void) sm_io_fprintf(smioout, 206990792Sgshapiro SM_TIME_DEFAULT, 207090792Sgshapiro "> "); 207190792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 207290792Sgshapiro if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, 207390792Sgshapiro sizeof buf) == NULL) 207490792Sgshapiro testmodeline("/quit", &MainEnvelope); 207590792Sgshapiro p = strchr(buf, '\n'); 207690792Sgshapiro if (p != NULL) 207790792Sgshapiro *p = '\0'; 207890792Sgshapiro if (Verbose < 2) 207990792Sgshapiro (void) sm_io_fprintf(smioout, 208090792Sgshapiro SM_TIME_DEFAULT, 208190792Sgshapiro "> %s\n", buf); 208290792Sgshapiro testmodeline(buf, &MainEnvelope); 208390792Sgshapiro } 208490792Sgshapiro SM_EXCEPT(exc, "[!F]*") 208590792Sgshapiro { 208690792Sgshapiro /* 208790792Sgshapiro ** 8.10 just prints \n on interrupt. 208890792Sgshapiro ** I'm printing the exception here in case 208990792Sgshapiro ** sendmail is extended to raise additional 209090792Sgshapiro ** exceptions in this context. 209190792Sgshapiro */ 209290792Sgshapiro 209390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 209490792Sgshapiro "\n"); 209590792Sgshapiro sm_exc_print(exc, smioout); 209690792Sgshapiro } 209790792Sgshapiro SM_END_TRY 209838032Speter } 209938032Speter } 210038032Speter 210190792Sgshapiro#if STARTTLS 210290792Sgshapiro tls_ok = true; 210390792Sgshapiro if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER) 210490792Sgshapiro { 210590792Sgshapiro /* check whether STARTTLS is turned off for the client */ 210690792Sgshapiro if (chkclientmodifiers(D_NOTLS)) 210790792Sgshapiro tls_ok = false; 210890792Sgshapiro } 210990792Sgshapiro else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON || 211090792Sgshapiro OpMode == MD_SMTP) 211190792Sgshapiro { 211290792Sgshapiro /* check whether STARTTLS is turned off for the server */ 211390792Sgshapiro if (chkdaemonmodifiers(D_NOTLS)) 211490792Sgshapiro tls_ok = false; 211590792Sgshapiro } 211690792Sgshapiro else /* other modes don't need STARTTLS */ 211790792Sgshapiro tls_ok = false; 211864562Sgshapiro 211990792Sgshapiro if (tls_ok) 212090792Sgshapiro { 212190792Sgshapiro /* basic TLS initialization */ 212290792Sgshapiro tls_ok = init_tls_library(); 212390792Sgshapiro } 212490792Sgshapiro 212590792Sgshapiro if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)) 212690792Sgshapiro { 212790792Sgshapiro /* disable TLS for client */ 212890792Sgshapiro setclttls(false); 212990792Sgshapiro } 213090792Sgshapiro#endif /* STARTTLS */ 213190792Sgshapiro 213264562Sgshapiro /* 213338032Speter ** If collecting stuff from the queue, go start doing that. 213438032Speter */ 213538032Speter 213664562Sgshapiro if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 213738032Speter { 213890792Sgshapiro pid_t pid = -1; 213990792Sgshapiro 214090792Sgshapiro#if STARTTLS 214190792Sgshapiro /* init TLS for client, ignore result for now */ 214290792Sgshapiro (void) initclttls(tls_ok); 214390792Sgshapiro#endif /* STARTTLS */ 214490792Sgshapiro 214590792Sgshapiro /* 214690792Sgshapiro ** The parent process of the caller of runqueue() needs 214790792Sgshapiro ** to stay around for a possible SIGTERM. The SIGTERM will 214890792Sgshapiro ** tell this process that all of the queue runners children 214990792Sgshapiro ** need to be sent SIGTERM as well. At the same time, we 215090792Sgshapiro ** want to return control to the command line. So we do an 215190792Sgshapiro ** extra fork(). 215290792Sgshapiro */ 215390792Sgshapiro 215490792Sgshapiro if (Verbose || foregroundqueue || (pid = fork()) <= 0) 215564562Sgshapiro { 215690792Sgshapiro /* 215790792Sgshapiro ** If the fork() failed we should still try to do 215890792Sgshapiro ** the queue run. If it succeeded then the child 215990792Sgshapiro ** is going to start the run and wait for all 216090792Sgshapiro ** of the children to finish. 216190792Sgshapiro */ 216290792Sgshapiro 216390792Sgshapiro if (pid == 0) 216490792Sgshapiro { 216590792Sgshapiro /* Reset global flags */ 216690792Sgshapiro RestartRequest = NULL; 216790792Sgshapiro ShutdownRequest = NULL; 216890792Sgshapiro PendingSignal = 0; 216990792Sgshapiro 217090792Sgshapiro /* disconnect from terminal */ 217190792Sgshapiro disconnect(2, CurEnv); 217290792Sgshapiro } 217390792Sgshapiro 217490792Sgshapiro CurrentPid = getpid(); 217590792Sgshapiro if (qgrp != NOQGRP) 217690792Sgshapiro { 217790792Sgshapiro /* 217890792Sgshapiro ** To run a specific queue group mark it to 217990792Sgshapiro ** be run, select the work group it's in and 218090792Sgshapiro ** increment the work counter. 218190792Sgshapiro */ 218290792Sgshapiro 218394334Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 218494334Sgshapiro i++) 218594334Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 218694334Sgshapiro Queue[qgrp]->qg_nextrun = 0; 218790792Sgshapiro (void) run_work_group(Queue[qgrp]->qg_wgrp, 218890792Sgshapiro false, Verbose, 218990792Sgshapiro queuepersistent, false); 219090792Sgshapiro } 219190792Sgshapiro else 219290792Sgshapiro (void) runqueue(false, Verbose, 219390792Sgshapiro queuepersistent, true); 219490792Sgshapiro 219590792Sgshapiro /* set the title to make it easier to find */ 219690792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 219790792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 219890792Sgshapiro while (CurChildren > 0) 219990792Sgshapiro { 220090792Sgshapiro int status; 220190792Sgshapiro pid_t ret; 220290792Sgshapiro 220390792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 220490792Sgshapiro continue; 220590792Sgshapiro 220690792Sgshapiro /* Only drop when a child gives status */ 220790792Sgshapiro if (WIFSTOPPED(status)) 220890792Sgshapiro continue; 220990792Sgshapiro 221090792Sgshapiro proc_list_drop(ret, status, NULL); 221190792Sgshapiro } 221264562Sgshapiro } 221390792Sgshapiro finis(true, true, ExitStat); 221490792Sgshapiro /* NOTREACHED */ 221538032Speter } 221638032Speter 221771345Sgshapiro# if SASL 221871345Sgshapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 221971345Sgshapiro { 222090792Sgshapiro /* check whether AUTH is turned off for the server */ 222190792Sgshapiro if (!chkdaemonmodifiers(D_NOAUTH) && 222290792Sgshapiro (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 222371345Sgshapiro syserr("!sasl_server_init failed! [%s]", 222490792Sgshapiro sasl_errstring(i, NULL, NULL)); 222571345Sgshapiro } 222671345Sgshapiro# endif /* SASL */ 222771345Sgshapiro 222890792Sgshapiro if (OpMode == MD_SMTP) 222990792Sgshapiro { 223090792Sgshapiro proc_list_add(CurrentPid, "Sendmail SMTP Agent", 223190792Sgshapiro PROC_DAEMON, 0, -1); 223290792Sgshapiro 223390792Sgshapiro /* clean up background delivery children */ 223490792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 223590792Sgshapiro } 223690792Sgshapiro 223738032Speter /* 223838032Speter ** If a daemon, wait for a request. 223938032Speter ** getrequests will always return in a child. 224038032Speter ** If we should also be processing the queue, start 224138032Speter ** doing it in background. 224238032Speter ** We check for any errors that might have happened 224338032Speter ** during startup. 224438032Speter */ 224538032Speter 224638032Speter if (OpMode == MD_DAEMON || QueueIntvl != 0) 224738032Speter { 224838032Speter char dtype[200]; 224938032Speter 225038032Speter if (!run_in_foreground && !tTd(99, 100)) 225138032Speter { 225238032Speter /* put us in background */ 225338032Speter i = fork(); 225438032Speter if (i < 0) 225538032Speter syserr("daemon: cannot fork"); 225638032Speter if (i != 0) 225790792Sgshapiro { 225890792Sgshapiro finis(false, true, EX_OK); 225990792Sgshapiro /* NOTREACHED */ 226090792Sgshapiro } 226138032Speter 226290792Sgshapiro /* 226390792Sgshapiro ** Initialize exception stack and default exception 226490792Sgshapiro ** handler for child process. 226590792Sgshapiro */ 226690792Sgshapiro 226790792Sgshapiro /* Reset global flags */ 226890792Sgshapiro RestartRequest = NULL; 226990792Sgshapiro RestartWorkGroup = false; 227090792Sgshapiro ShutdownRequest = NULL; 227190792Sgshapiro PendingSignal = 0; 227290792Sgshapiro CurrentPid = getpid(); 227390792Sgshapiro 227490792Sgshapiro sm_exc_newthread(fatal_error); 227590792Sgshapiro 227638032Speter /* disconnect from our controlling tty */ 227790792Sgshapiro disconnect(2, &MainEnvelope); 227838032Speter } 227938032Speter 228038032Speter dtype[0] = '\0'; 228138032Speter if (OpMode == MD_DAEMON) 228290792Sgshapiro { 228390792Sgshapiro (void) sm_strlcat(dtype, "+SMTP", sizeof dtype); 228490792Sgshapiro DaemonPid = CurrentPid; 228590792Sgshapiro } 228638032Speter if (QueueIntvl != 0) 228738032Speter { 228890792Sgshapiro (void) sm_strlcat2(dtype, 228990792Sgshapiro queuepersistent 229090792Sgshapiro ? "+persistent-queueing@" 229190792Sgshapiro : "+queueing@", 229290792Sgshapiro pintvl(QueueIntvl, true), 229390792Sgshapiro sizeof dtype); 229438032Speter } 229538032Speter if (tTd(0, 1)) 229690792Sgshapiro (void) sm_strlcat(dtype, "+debugging", sizeof dtype); 229738032Speter 229838032Speter sm_syslog(LOG_INFO, NOQID, 229964562Sgshapiro "starting daemon (%s): %s", Version, dtype + 1); 230090792Sgshapiro#if XLA 230138032Speter xla_create_file(); 230264562Sgshapiro#endif /* XLA */ 230338032Speter 230464562Sgshapiro /* save daemon type in a macro for possible PidFile use */ 230590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 230690792Sgshapiro macid("{daemon_info}"), dtype + 1); 230764562Sgshapiro 230864562Sgshapiro /* save queue interval in a macro for possible PidFile use */ 230990792Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 231090792Sgshapiro macid("{queue_interval}"), pintvl(QueueIntvl, true)); 231164562Sgshapiro 231290792Sgshapiro /* workaround: can't seem to release the signal in the parent */ 231390792Sgshapiro (void) sm_signal(SIGHUP, sighup); 231490792Sgshapiro (void) sm_releasesignal(SIGHUP); 231590792Sgshapiro (void) sm_signal(SIGTERM, sigterm); 231690792Sgshapiro 231764562Sgshapiro if (QueueIntvl != 0) 231838032Speter { 231990792Sgshapiro (void) runqueue(true, false, queuepersistent, true); 232090792Sgshapiro 232190792Sgshapiro /* 232290792Sgshapiro ** If queuepersistent but not in daemon mode then 232390792Sgshapiro ** we're going to do the queue runner monitoring here. 232490792Sgshapiro ** If in daemon mode then the monitoring will happen 232590792Sgshapiro ** elsewhere. 232690792Sgshapiro */ 232790792Sgshapiro 232890792Sgshapiro if (OpMode != MD_DAEMON && queuepersistent) 232990792Sgshapiro { 233090792Sgshapiro /* set the title to make it easier to find */ 233190792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 233290792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 233390792Sgshapiro while (CurChildren > 0) 233490792Sgshapiro { 233590792Sgshapiro int status; 233690792Sgshapiro pid_t ret; 233790792Sgshapiro int group; 233890792Sgshapiro 233990792Sgshapiro if (ShutdownRequest != NULL) 234090792Sgshapiro shutdown_daemon(); 234190792Sgshapiro else if (RestartRequest != NULL) 234290792Sgshapiro restart_daemon(); 234390792Sgshapiro else if (RestartWorkGroup) 234490792Sgshapiro restart_marked_work_groups(); 234590792Sgshapiro 234690792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 234790792Sgshapiro continue; 234890792Sgshapiro 234990792Sgshapiro if (WIFSTOPPED(status)) 235090792Sgshapiro continue; 235190792Sgshapiro 235290792Sgshapiro /* Probe only on a child status */ 235390792Sgshapiro proc_list_drop(ret, status, &group); 235490792Sgshapiro 235590792Sgshapiro if (WIFSIGNALED(status)) 235690792Sgshapiro { 235790792Sgshapiro if (WCOREDUMP(status)) 235890792Sgshapiro { 235990792Sgshapiro sm_syslog(LOG_ERR, NOQID, 236090792Sgshapiro "persistent queue runner=%d core dumped, signal=%d", 236190792Sgshapiro group, WTERMSIG(status)); 236290792Sgshapiro 236390792Sgshapiro /* don't restart this one */ 236490792Sgshapiro mark_work_group_restart(group, -1); 236590792Sgshapiro continue; 236690792Sgshapiro } 236790792Sgshapiro 236890792Sgshapiro sm_syslog(LOG_ERR, NOQID, 236990792Sgshapiro "persistent queue runner=%d died, signal=%d", 237090792Sgshapiro group, WTERMSIG(status)); 237190792Sgshapiro } 237290792Sgshapiro 237390792Sgshapiro /* 237490792Sgshapiro ** When debugging active, don't 237590792Sgshapiro ** restart the persistent queues. 237690792Sgshapiro ** But do log this as info. 237790792Sgshapiro */ 237890792Sgshapiro 237990792Sgshapiro if (sm_debug_active(&DebugNoPRestart, 238090792Sgshapiro 1)) 238190792Sgshapiro { 238290792Sgshapiro sm_syslog(LOG_DEBUG, NOQID, 238390792Sgshapiro "persistent queue runner=%d, exited", 238490792Sgshapiro group); 238590792Sgshapiro mark_work_group_restart(group, -1); 238690792Sgshapiro } 238790792Sgshapiro } 238890792Sgshapiro finis(true, true, ExitStat); 238990792Sgshapiro /* NOTREACHED */ 239090792Sgshapiro } 239190792Sgshapiro 239238032Speter if (OpMode != MD_DAEMON) 239338032Speter { 239490792Sgshapiro char qtype[200]; 239590792Sgshapiro 239690792Sgshapiro /* 239790792Sgshapiro ** Write the pid to file 239890792Sgshapiro ** XXX Overwrites sendmail.pid 239990792Sgshapiro */ 240090792Sgshapiro 240190792Sgshapiro log_sendmail_pid(&MainEnvelope); 240290792Sgshapiro 240390792Sgshapiro /* set the title to make it easier to find */ 240490792Sgshapiro qtype[0] = '\0'; 240590792Sgshapiro (void) sm_strlcpyn(qtype, sizeof qtype, 4, 240690792Sgshapiro "Queue runner@", 240790792Sgshapiro pintvl(QueueIntvl, true), 240890792Sgshapiro " for ", 240990792Sgshapiro QueueDir); 241090792Sgshapiro sm_setproctitle(true, CurEnv, qtype); 241138032Speter for (;;) 241238032Speter { 241364562Sgshapiro (void) pause(); 241477349Sgshapiro if (ShutdownRequest != NULL) 241577349Sgshapiro shutdown_daemon(); 241690792Sgshapiro else if (RestartRequest != NULL) 241790792Sgshapiro restart_daemon(); 241890792Sgshapiro else if (RestartWorkGroup) 241990792Sgshapiro restart_marked_work_groups(); 242090792Sgshapiro 242190792Sgshapiro if (doqueuerun()) 242290792Sgshapiro (void) runqueue(true, false, 242390792Sgshapiro false, false); 242438032Speter } 242538032Speter } 242638032Speter } 242790792Sgshapiro dropenvelope(&MainEnvelope, true, false); 242838032Speter 242990792Sgshapiro#if STARTTLS 243064562Sgshapiro /* init TLS for server, ignore result for now */ 243190792Sgshapiro (void) initsrvtls(tls_ok); 243290792Sgshapiro#endif /* STARTTLS */ 243390792Sgshapiro#if PROFILING 243490792Sgshapiro nextreq: 243590792Sgshapiro#endif /* PROFILING */ 243690792Sgshapiro p_flags = getrequests(&MainEnvelope); 243738032Speter 243838032Speter /* drop privileges */ 243990792Sgshapiro (void) drop_privileges(false); 244038032Speter 244138032Speter /* 244238032Speter ** Get authentication data 244390792Sgshapiro ** Set _ macro in BlankEnvelope before calling newenvelope(). 244438032Speter */ 244538032Speter 244690792Sgshapiro authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 244790792Sgshapiro NULL), &forged); 244890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 244990792Sgshapiro 245090792Sgshapiro /* at this point we are in a child: reset state */ 245190792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 245290792Sgshapiro (void) newenvelope(&MainEnvelope, &MainEnvelope, 245390792Sgshapiro sm_rpool_new_x(NULL)); 245438032Speter } 245538032Speter 245664562Sgshapiro if (LogLevel > 9) 245764562Sgshapiro { 245864562Sgshapiro /* log connection information */ 245964562Sgshapiro sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo); 246064562Sgshapiro } 246164562Sgshapiro 246238032Speter /* 246338032Speter ** If running SMTP protocol, start collecting and executing 246438032Speter ** commands. This will never return. 246538032Speter */ 246638032Speter 246738032Speter if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 246838032Speter { 246938032Speter char pbuf[20]; 247038032Speter 247138032Speter /* 247238032Speter ** Save some macros for check_* rulesets. 247338032Speter */ 247438032Speter 247538032Speter if (forged) 247638032Speter { 247738032Speter char ipbuf[103]; 247838032Speter 247990792Sgshapiro (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 248090792Sgshapiro anynet_ntoa(&RealHostAddr)); 248190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 248290792Sgshapiro macid("{client_name}"), ipbuf); 248338032Speter } 248438032Speter else 248590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 248690792Sgshapiro macid("{client_name}"), RealHostName); 248790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 248890792Sgshapiro macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 248990792Sgshapiro sm_getla(); 249038032Speter 249190792Sgshapiro switch (RealHostAddr.sa.sa_family) 249264562Sgshapiro { 249390792Sgshapiro#if NETINET 249464562Sgshapiro case AF_INET: 249590792Sgshapiro (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 249690792Sgshapiro RealHostAddr.sin.sin_port); 249764562Sgshapiro break; 249890792Sgshapiro#endif /* NETINET */ 249990792Sgshapiro#if NETINET6 250064562Sgshapiro case AF_INET6: 250190792Sgshapiro (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 250290792Sgshapiro RealHostAddr.sin6.sin6_port); 250364562Sgshapiro break; 250490792Sgshapiro#endif /* NETINET6 */ 250564562Sgshapiro default: 250690792Sgshapiro (void) sm_snprintf(pbuf, sizeof pbuf, "0"); 250764562Sgshapiro break; 250864562Sgshapiro } 250990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 251090792Sgshapiro macid("{client_port}"), pbuf); 251142575Speter 251238032Speter if (OpMode == MD_DAEMON) 251338032Speter { 251438032Speter /* validate the connection */ 251590792Sgshapiro HoldErrs = true; 251638032Speter nullserver = validate_connection(&RealHostAddr, 251790792Sgshapiro RealHostName, 251890792Sgshapiro &MainEnvelope); 251990792Sgshapiro HoldErrs = false; 252038032Speter } 252164562Sgshapiro else if (p_flags == NULL) 252264562Sgshapiro { 252364562Sgshapiro p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); 252464562Sgshapiro clrbitmap(p_flags); 252564562Sgshapiro } 252690792Sgshapiro#if STARTTLS 252764562Sgshapiro if (OpMode == MD_SMTP) 252890792Sgshapiro (void) initsrvtls(tls_ok); 252990792Sgshapiro#endif /* STARTTLS */ 253071345Sgshapiro 253190792Sgshapiro /* turn off profiling */ 253290792Sgshapiro SM_PROF(1); 253390792Sgshapiro smtp(nullserver, *p_flags, &MainEnvelope); 253490792Sgshapiro#if PROFILING 253590792Sgshapiro /* turn off profiling */ 253690792Sgshapiro SM_PROF(0); 253790792Sgshapiro if (OpMode == MD_DAEMON) 253890792Sgshapiro goto nextreq; 253990792Sgshapiro#endif /* PROFILING */ 254038032Speter } 254138032Speter 254290792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 254390792Sgshapiro clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 254438032Speter if (OpMode == MD_VERIFY) 254538032Speter { 254690792Sgshapiro set_delivery_mode(SM_VERIFY, &MainEnvelope); 254738032Speter PostMasterCopy = NULL; 254838032Speter } 254938032Speter else 255038032Speter { 255138032Speter /* interactive -- all errors are global */ 255290792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 255338032Speter } 255438032Speter 255538032Speter /* 255638032Speter ** Do basic system initialization and set the sender 255738032Speter */ 255838032Speter 255990792Sgshapiro initsys(&MainEnvelope); 256090792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 256190792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 256290792Sgshapiro setsender(from, &MainEnvelope, NULL, '\0', false); 256364562Sgshapiro if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 256490792Sgshapiro (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 256590792Sgshapiro strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 256664562Sgshapiro { 256790792Sgshapiro auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 256890792Sgshapiro RealUserName, from, warn_f_flag); 256964562Sgshapiro#if SASL 257090792Sgshapiro auth = false; 257164562Sgshapiro#endif /* SASL */ 257264562Sgshapiro } 257364562Sgshapiro if (auth) 257464562Sgshapiro { 257564562Sgshapiro char *fv; 257664562Sgshapiro 257764562Sgshapiro /* set the initial sender for AUTH= to $f@$j */ 257890792Sgshapiro fv = macvalue('f', &MainEnvelope); 257964562Sgshapiro if (fv == NULL || *fv == '\0') 258090792Sgshapiro MainEnvelope.e_auth_param = NULL; 258164562Sgshapiro else 258264562Sgshapiro { 258364562Sgshapiro if (strchr(fv, '@') == NULL) 258464562Sgshapiro { 258590792Sgshapiro i = strlen(fv) + strlen(macvalue('j', 258690792Sgshapiro &MainEnvelope)) + 2; 258790792Sgshapiro p = sm_malloc_x(i); 258890792Sgshapiro (void) sm_strlcpyn(p, i, 3, fv, "@", 258990792Sgshapiro macvalue('j', 259090792Sgshapiro &MainEnvelope)); 259164562Sgshapiro } 259264562Sgshapiro else 259390792Sgshapiro p = sm_strdup_x(fv); 259490792Sgshapiro MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 259590792Sgshapiro xtextify(p, "=")); 259690792Sgshapiro sm_free(p); /* XXX */ 259764562Sgshapiro } 259864562Sgshapiro } 259990792Sgshapiro if (macvalue('s', &MainEnvelope) == NULL) 260090792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 260138032Speter 260290792Sgshapiro av = argv + optind; 260338032Speter if (*av == NULL && !GrabTo) 260438032Speter { 260590792Sgshapiro MainEnvelope.e_to = NULL; 260690792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 260790792Sgshapiro HoldErrs = false; 260890792Sgshapiro SuperSafe = SAFE_NO; 260938032Speter usrerr("Recipient names must be specified"); 261038032Speter 261138032Speter /* collect body for UUCP return */ 261238032Speter if (OpMode != MD_VERIFY) 261390792Sgshapiro collect(InChannel, false, NULL, &MainEnvelope); 261490792Sgshapiro finis(true, true, EX_USAGE); 261590792Sgshapiro /* NOTREACHED */ 261638032Speter } 261738032Speter 261838032Speter /* 261938032Speter ** Scan argv and deliver the message to everyone. 262038032Speter */ 262138032Speter 262290792Sgshapiro save_val = LogUsrErrs; 262390792Sgshapiro LogUsrErrs = true; 262490792Sgshapiro sendtoargv(av, &MainEnvelope); 262590792Sgshapiro LogUsrErrs = save_val; 262638032Speter 262738032Speter /* if we have had errors sofar, arrange a meaningful exit stat */ 262838032Speter if (Errors > 0 && ExitStat == EX_OK) 262938032Speter ExitStat = EX_USAGE; 263038032Speter 263138032Speter#if _FFR_FIX_DASHT 263238032Speter /* 263338032Speter ** If using -t, force not sending to argv recipients, even 263438032Speter ** if they are mentioned in the headers. 263538032Speter */ 263638032Speter 263738032Speter if (GrabTo) 263838032Speter { 263938032Speter ADDRESS *q; 264064562Sgshapiro 264190792Sgshapiro for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 264264562Sgshapiro q->q_state = QS_REMOVED; 264338032Speter } 264464562Sgshapiro#endif /* _FFR_FIX_DASHT */ 264538032Speter 264638032Speter /* 264738032Speter ** Read the input mail. 264838032Speter */ 264938032Speter 265090792Sgshapiro MainEnvelope.e_to = NULL; 265138032Speter if (OpMode != MD_VERIFY || GrabTo) 265238032Speter { 265390792Sgshapiro int savederrors; 265490792Sgshapiro unsigned long savedflags; 265538032Speter 265690792Sgshapiro /* 265790792Sgshapiro ** workaround for compiler warning on Irix: 265890792Sgshapiro ** do not initialize variable in the definition, but 265990792Sgshapiro ** later on: 266090792Sgshapiro ** warning(1548): transfer of control bypasses 266190792Sgshapiro ** initialization of: 266290792Sgshapiro ** variable "savederrors" (declared at line 2570) 266390792Sgshapiro ** variable "savedflags" (declared at line 2571) 266490792Sgshapiro ** goto giveup; 266590792Sgshapiro */ 266690792Sgshapiro 266790792Sgshapiro savederrors = Errors; 266890792Sgshapiro savedflags = MainEnvelope.e_flags & EF_FATALERRS; 266990792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 267090792Sgshapiro MainEnvelope.e_flags &= ~EF_FATALERRS; 267164562Sgshapiro Errors = 0; 267264562Sgshapiro buffer_errors(); 267390792Sgshapiro collect(InChannel, false, NULL, &MainEnvelope); 267438032Speter 267564562Sgshapiro /* header checks failed */ 267664562Sgshapiro if (Errors > 0) 267764562Sgshapiro { 267890792Sgshapiro giveup: 267990792Sgshapiro if (!GrabTo) 268064562Sgshapiro { 268190792Sgshapiro /* Log who the mail would have gone to */ 268290792Sgshapiro logundelrcpts(&MainEnvelope, 268390792Sgshapiro MainEnvelope.e_message, 268490792Sgshapiro 8, false); 268564562Sgshapiro } 268690792Sgshapiro flush_errors(true); 268790792Sgshapiro finis(true, true, ExitStat); 268864562Sgshapiro /* NOTREACHED */ 268964562Sgshapiro return -1; 269064562Sgshapiro } 269164562Sgshapiro 269238032Speter /* bail out if message too large */ 269390792Sgshapiro if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 269438032Speter { 269590792Sgshapiro finis(true, true, ExitStat != EX_OK ? ExitStat 269690792Sgshapiro : EX_DATAERR); 269764562Sgshapiro /* NOTREACHED */ 269838032Speter return -1; 269938032Speter } 270098121Sgshapiro 270198121Sgshapiro /* set message size */ 270298121Sgshapiro (void) sm_snprintf(buf, sizeof buf, "%ld", 270398121Sgshapiro MainEnvelope.e_msgsize); 270498121Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 270598121Sgshapiro macid("{msg_size}"), buf); 270698121Sgshapiro 270764562Sgshapiro Errors = savederrors; 270890792Sgshapiro MainEnvelope.e_flags |= savedflags; 270938032Speter } 271038032Speter errno = 0; 271138032Speter 271238032Speter if (tTd(1, 1)) 271390792Sgshapiro sm_dprintf("From person = \"%s\"\n", 271490792Sgshapiro MainEnvelope.e_from.q_paddr); 271538032Speter 271690792Sgshapiro#if _FFR_QUARANTINE 271790792Sgshapiro /* Check if quarantining stats should be updated */ 271890792Sgshapiro if (MainEnvelope.e_quarmsg != NULL) 271990792Sgshapiro markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 272090792Sgshapiro#endif /* _FFR_QUARANTINE */ 272190792Sgshapiro 272238032Speter /* 272338032Speter ** Actually send everything. 272438032Speter ** If verifying, just ack. 272538032Speter */ 272638032Speter 272790792Sgshapiro if (Errors == 0) 272838032Speter { 272990792Sgshapiro if (!split_by_recipient(&MainEnvelope) && 273090792Sgshapiro bitset(EF_FATALERRS, MainEnvelope.e_flags)) 273190792Sgshapiro goto giveup; 273238032Speter } 273390792Sgshapiro 273490792Sgshapiro /* make sure we deliver at least the first envelope */ 273590792Sgshapiro i = FastSplit > 0 ? 0 : -1; 273690792Sgshapiro for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 273790792Sgshapiro { 273890792Sgshapiro ENVELOPE *next; 273990792Sgshapiro 274090792Sgshapiro e->e_from.q_state = QS_SENDER; 274190792Sgshapiro if (tTd(1, 5)) 274290792Sgshapiro { 274390792Sgshapiro sm_dprintf("main[%d]: QS_SENDER ", i); 274490792Sgshapiro printaddr(&e->e_from, false); 274590792Sgshapiro } 274690792Sgshapiro e->e_to = NULL; 274790792Sgshapiro sm_getla(); 274890792Sgshapiro GrabTo = false; 274964562Sgshapiro#if NAMED_BIND 275090792Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 275190792Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 275264562Sgshapiro#endif /* NAMED_BIND */ 275390792Sgshapiro next = e->e_sibling; 275490792Sgshapiro e->e_sibling = NULL; 275538032Speter 275690792Sgshapiro /* after FastSplit envelopes: queue up */ 275790792Sgshapiro sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 275890792Sgshapiro e->e_sibling = next; 275990792Sgshapiro } 276090792Sgshapiro 276138032Speter /* 276238032Speter ** All done. 276338032Speter ** Don't send return error message if in VERIFY mode. 276438032Speter */ 276538032Speter 276690792Sgshapiro finis(true, true, ExitStat); 276764562Sgshapiro /* NOTREACHED */ 276864562Sgshapiro return ExitStat; 276938032Speter} 277090792Sgshapiro/* 277177349Sgshapiro** STOP_SENDMAIL -- Stop the running program 277277349Sgshapiro** 277377349Sgshapiro** Parameters: 277477349Sgshapiro** none. 277577349Sgshapiro** 277677349Sgshapiro** Returns: 277777349Sgshapiro** none. 277877349Sgshapiro** 277977349Sgshapiro** Side Effects: 278077349Sgshapiro** exits. 278177349Sgshapiro*/ 278238032Speter 278377349Sgshapirovoid 278477349Sgshapirostop_sendmail() 278577349Sgshapiro{ 278677349Sgshapiro /* reset uid for process accounting */ 278777349Sgshapiro endpwent(); 278877349Sgshapiro (void) setuid(RealUid); 278977349Sgshapiro exit(EX_OK); 279077349Sgshapiro} 279190792Sgshapiro/* 279238032Speter** FINIS -- Clean up and exit. 279338032Speter** 279438032Speter** Parameters: 279542575Speter** drop -- whether or not to drop CurEnv envelope 279690792Sgshapiro** cleanup -- call exit() or _exit()? 279742575Speter** exitstat -- exit status to use for exit() call 279838032Speter** 279938032Speter** Returns: 280038032Speter** never 280138032Speter** 280238032Speter** Side Effects: 280338032Speter** exits sendmail 280438032Speter*/ 280538032Speter 280638032Spetervoid 280790792Sgshapirofinis(drop, cleanup, exitstat) 280842575Speter bool drop; 280990792Sgshapiro bool cleanup; 281042575Speter volatile int exitstat; 281138032Speter{ 281298121Sgshapiro 281377349Sgshapiro /* Still want to process new timeouts added below */ 281490792Sgshapiro sm_clear_events(); 281590792Sgshapiro (void) sm_releasesignal(SIGALRM); 281642575Speter 281738032Speter if (tTd(2, 1)) 281838032Speter { 281990792Sgshapiro sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 282090792Sgshapiro exitstat, 282190792Sgshapiro CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 282238032Speter printenvflags(CurEnv); 282338032Speter } 282438032Speter if (tTd(2, 9)) 282590792Sgshapiro printopenfds(false); 282638032Speter 282790792Sgshapiro SM_TRY 282890792Sgshapiro /* 282990792Sgshapiro ** Clean up. This might raise E:mta.quickabort 283090792Sgshapiro */ 283138032Speter 283290792Sgshapiro /* clean up temp files */ 283390792Sgshapiro CurEnv->e_to = NULL; 283490792Sgshapiro if (drop) 283590792Sgshapiro { 283690792Sgshapiro if (CurEnv->e_id != NULL) 283790792Sgshapiro { 283890792Sgshapiro dropenvelope(CurEnv, true, false); 283990792Sgshapiro sm_rpool_free(CurEnv->e_rpool); 284090792Sgshapiro CurEnv->e_rpool = NULL; 284190792Sgshapiro } 284290792Sgshapiro else 284390792Sgshapiro poststats(StatFile); 284490792Sgshapiro } 284538032Speter 284690792Sgshapiro /* flush any cached connections */ 284790792Sgshapiro mci_flush(true, NULL); 284838032Speter 284990792Sgshapiro /* close maps belonging to this pid */ 285090792Sgshapiro closemaps(false); 285142575Speter 285264562Sgshapiro#if USERDB 285390792Sgshapiro /* close UserDatabase */ 285490792Sgshapiro _udbx_close(); 285564562Sgshapiro#endif /* USERDB */ 285642575Speter 285790792Sgshapiro#if SASL 285890792Sgshapiro stop_sasl_client(); 285990792Sgshapiro#endif /* SASL */ 286090792Sgshapiro 286190792Sgshapiro#if XLA 286290792Sgshapiro /* clean up extended load average stuff */ 286390792Sgshapiro xla_all_end(); 286464562Sgshapiro#endif /* XLA */ 286538032Speter 286690792Sgshapiro SM_FINALLY 286790792Sgshapiro /* 286890792Sgshapiro ** And exit. 286990792Sgshapiro */ 287038032Speter 287190792Sgshapiro if (LogLevel > 78) 287290792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 287390792Sgshapiro (int) CurrentPid); 287490792Sgshapiro if (exitstat == EX_TEMPFAIL || 287590792Sgshapiro CurEnv->e_errormode == EM_BERKNET) 287690792Sgshapiro exitstat = EX_OK; 287764562Sgshapiro 287890792Sgshapiro /* XXX clean up queues and related data structures */ 287990792Sgshapiro cleanup_queues(); 288090792Sgshapiro#if SM_CONF_SHM 288190792Sgshapiro cleanup_shm(DaemonPid == getpid()); 288290792Sgshapiro#endif /* SM_CONF_SHM */ 288390792Sgshapiro 288490792Sgshapiro /* reset uid for process accounting */ 288590792Sgshapiro endpwent(); 288690792Sgshapiro sm_mbdb_terminate(); 288790792Sgshapiro (void) setuid(RealUid); 288890792Sgshapiro#if SM_HEAP_CHECK 288990792Sgshapiro /* dump the heap, if we are checking for memory leaks */ 289090792Sgshapiro if (sm_debug_active(&SmHeapCheck, 2)) 289190792Sgshapiro sm_heap_report(smioout, 289290792Sgshapiro sm_debug_level(&SmHeapCheck) - 1); 289390792Sgshapiro#endif /* SM_HEAP_CHECK */ 289490792Sgshapiro if (sm_debug_active(&SmXtrapReport, 1)) 289590792Sgshapiro sm_dprintf("xtrap count = %d\n", SmXtrapCount); 289690792Sgshapiro if (cleanup) 289790792Sgshapiro exit(exitstat); 289890792Sgshapiro else 289990792Sgshapiro _exit(exitstat); 290090792Sgshapiro SM_END_TRY 290138032Speter} 290290792Sgshapiro/* 290390792Sgshapiro** INTINDEBUG -- signal handler for SIGINT in -bt mode 290477349Sgshapiro** 290577349Sgshapiro** Parameters: 290690792Sgshapiro** sig -- incoming signal. 290790792Sgshapiro** 290890792Sgshapiro** Returns: 290990792Sgshapiro** none. 291090792Sgshapiro** 291190792Sgshapiro** Side Effects: 291290792Sgshapiro** longjmps back to test mode loop. 291390792Sgshapiro** 291490792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 291590792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 291690792Sgshapiro** DOING. 291790792Sgshapiro*/ 291890792Sgshapiro 291990792Sgshapiro/* Type of an exception generated on SIGINT during address test mode. */ 292090792Sgshapirostatic const SM_EXC_TYPE_T EtypeInterrupt = 292190792Sgshapiro{ 292290792Sgshapiro SmExcTypeMagic, 292390792Sgshapiro "S:mta.interrupt", 292490792Sgshapiro "", 292590792Sgshapiro sm_etype_printf, 292690792Sgshapiro "interrupt", 292790792Sgshapiro}; 292890792Sgshapiro 292990792Sgshapiro/* ARGSUSED */ 293090792Sgshapirostatic SIGFUNC_DECL 293190792Sgshapirointindebug(sig) 293290792Sgshapiro int sig; 293390792Sgshapiro{ 293490792Sgshapiro int save_errno = errno; 293590792Sgshapiro 293690792Sgshapiro FIX_SYSV_SIGNAL(sig, intindebug); 293790792Sgshapiro errno = save_errno; 293890792Sgshapiro CHECK_CRITICAL(sig); 293990792Sgshapiro errno = save_errno; 294090792Sgshapiro sm_exc_raisenew_x(&EtypeInterrupt); 294190792Sgshapiro errno = save_errno; 294290792Sgshapiro return SIGFUNC_RETURN; 294390792Sgshapiro} 294490792Sgshapiro/* 294590792Sgshapiro** SIGTERM -- SIGTERM handler for the daemon 294690792Sgshapiro** 294790792Sgshapiro** Parameters: 294877349Sgshapiro** sig -- signal number. 294977349Sgshapiro** 295077349Sgshapiro** Returns: 295177349Sgshapiro** none. 295277349Sgshapiro** 295377349Sgshapiro** Side Effects: 295477349Sgshapiro** Sets ShutdownRequest which will hopefully trigger 295577349Sgshapiro** the daemon to exit. 295677349Sgshapiro** 295777349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 295877349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 295977349Sgshapiro** DOING. 296077349Sgshapiro*/ 296177349Sgshapiro 296277349Sgshapiro/* ARGSUSED */ 296377349Sgshapirostatic SIGFUNC_DECL 296490792Sgshapirosigterm(sig) 296577349Sgshapiro int sig; 296677349Sgshapiro{ 296777349Sgshapiro int save_errno = errno; 296877349Sgshapiro 296990792Sgshapiro FIX_SYSV_SIGNAL(sig, sigterm); 297077349Sgshapiro ShutdownRequest = "signal"; 297177349Sgshapiro errno = save_errno; 297277349Sgshapiro return SIGFUNC_RETURN; 297377349Sgshapiro} 297490792Sgshapiro/* 297590792Sgshapiro** SIGHUP -- handle a SIGHUP signal 297677349Sgshapiro** 297777349Sgshapiro** Parameters: 297890792Sgshapiro** sig -- incoming signal. 297977349Sgshapiro** 298077349Sgshapiro** Returns: 298177349Sgshapiro** none. 298277349Sgshapiro** 298377349Sgshapiro** Side Effects: 298490792Sgshapiro** Sets RestartRequest which should cause the daemon 298590792Sgshapiro** to restart. 298690792Sgshapiro** 298790792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 298890792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 298990792Sgshapiro** DOING. 299077349Sgshapiro*/ 299177349Sgshapiro 299290792Sgshapiro/* ARGSUSED */ 299390792Sgshapirostatic SIGFUNC_DECL 299490792Sgshapirosighup(sig) 299590792Sgshapiro int sig; 299677349Sgshapiro{ 299790792Sgshapiro int save_errno = errno; 299877349Sgshapiro 299990792Sgshapiro FIX_SYSV_SIGNAL(sig, sighup); 300090792Sgshapiro RestartRequest = "signal"; 300190792Sgshapiro errno = save_errno; 300290792Sgshapiro return SIGFUNC_RETURN; 300390792Sgshapiro} 300490792Sgshapiro/* 300590792Sgshapiro** SIGPIPE -- signal handler for SIGPIPE 300690792Sgshapiro** 300790792Sgshapiro** Parameters: 300890792Sgshapiro** sig -- incoming signal. 300990792Sgshapiro** 301090792Sgshapiro** Returns: 301190792Sgshapiro** none. 301290792Sgshapiro** 301390792Sgshapiro** Side Effects: 301490792Sgshapiro** Sets StopRequest which should cause the mailq/hoststatus 301590792Sgshapiro** display to stop. 301690792Sgshapiro** 301790792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 301890792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 301990792Sgshapiro** DOING. 302090792Sgshapiro*/ 302177349Sgshapiro 302290792Sgshapiro/* ARGSUSED */ 302390792Sgshapirostatic SIGFUNC_DECL 302490792Sgshapirosigpipe(sig) 302590792Sgshapiro int sig; 302690792Sgshapiro{ 302790792Sgshapiro int save_errno = errno; 302877349Sgshapiro 302990792Sgshapiro FIX_SYSV_SIGNAL(sig, sigpipe); 303090792Sgshapiro StopRequest = true; 303190792Sgshapiro errno = save_errno; 303290792Sgshapiro return SIGFUNC_RETURN; 303377349Sgshapiro} 303490792Sgshapiro/* 303538032Speter** INTSIG -- clean up on interrupt 303638032Speter** 303764562Sgshapiro** This just arranges to exit. It pessimizes in that it 303838032Speter** may resend a message. 303938032Speter** 304038032Speter** Parameters: 304138032Speter** none. 304238032Speter** 304338032Speter** Returns: 304438032Speter** none. 304538032Speter** 304638032Speter** Side Effects: 304738032Speter** Unlocks the current job. 304877349Sgshapiro** 304977349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 305077349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 305177349Sgshapiro** DOING. 305277349Sgshapiro** 305377349Sgshapiro** XXX: More work is needed for this signal handler. 305438032Speter*/ 305538032Speter 305638032Speter/* ARGSUSED */ 305738032SpeterSIGFUNC_DECL 305838032Speterintsig(sig) 305938032Speter int sig; 306038032Speter{ 306190792Sgshapiro bool drop = false; 306277349Sgshapiro int save_errno = errno; 306364562Sgshapiro 306477349Sgshapiro FIX_SYSV_SIGNAL(sig, intsig); 306577349Sgshapiro errno = save_errno; 306677349Sgshapiro CHECK_CRITICAL(sig); 306790792Sgshapiro sm_allsignals(true); 306890792Sgshapiro 306964562Sgshapiro if (sig != 0 && LogLevel > 79) 307038032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 307138032Speter FileName = NULL; 307264562Sgshapiro 307364562Sgshapiro /* Clean-up on aborted stdin message submission */ 307464562Sgshapiro if (CurEnv->e_id != NULL && 307564562Sgshapiro (OpMode == MD_SMTP || 307664562Sgshapiro OpMode == MD_DELIVER || 307764562Sgshapiro OpMode == MD_ARPAFTP)) 307864562Sgshapiro { 307964562Sgshapiro register ADDRESS *q; 308064562Sgshapiro 308164562Sgshapiro /* don't return an error indication */ 308264562Sgshapiro CurEnv->e_to = NULL; 308364562Sgshapiro CurEnv->e_flags &= ~EF_FATALERRS; 308464562Sgshapiro CurEnv->e_flags |= EF_CLRQUEUE; 308564562Sgshapiro 308664562Sgshapiro /* 308764562Sgshapiro ** Spin through the addresses and 308864562Sgshapiro ** mark them dead to prevent bounces 308964562Sgshapiro */ 309064562Sgshapiro 309164562Sgshapiro for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 309264562Sgshapiro q->q_state = QS_DONTSEND; 309364562Sgshapiro 309490792Sgshapiro drop = true; 309564562Sgshapiro } 309680785Sgshapiro else if (OpMode != MD_TEST) 309790792Sgshapiro { 309864562Sgshapiro unlockqueue(CurEnv); 309938032Speter } 310038032Speter 310190792Sgshapiro finis(drop, false, EX_OK); 310290792Sgshapiro /* NOTREACHED */ 310338032Speter} 310490792Sgshapiro/* 310538032Speter** DISCONNECT -- remove our connection with any foreground process 310638032Speter** 310738032Speter** Parameters: 310838032Speter** droplev -- how "deeply" we should drop the line. 310938032Speter** 0 -- ignore signals, mail back errors, make sure 311038032Speter** output goes to stdout. 311164562Sgshapiro** 1 -- also, make stdout go to /dev/null. 311238032Speter** 2 -- also, disconnect from controlling terminal 311338032Speter** (only for daemon mode). 311438032Speter** e -- the current envelope. 311538032Speter** 311638032Speter** Returns: 311738032Speter** none 311838032Speter** 311938032Speter** Side Effects: 312038032Speter** Trys to insure that we are immune to vagaries of 312138032Speter** the controlling tty. 312238032Speter*/ 312338032Speter 312438032Spetervoid 312538032Speterdisconnect(droplev, e) 312638032Speter int droplev; 312738032Speter register ENVELOPE *e; 312838032Speter{ 312938032Speter int fd; 313038032Speter 313138032Speter if (tTd(52, 1)) 313290792Sgshapiro sm_dprintf("disconnect: In %d Out %d, e=%p\n", 313390792Sgshapiro sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 313490792Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e); 313538032Speter if (tTd(52, 100)) 313638032Speter { 313790792Sgshapiro sm_dprintf("don't\n"); 313838032Speter return; 313938032Speter } 314038032Speter if (LogLevel > 93) 314138032Speter sm_syslog(LOG_DEBUG, e->e_id, 314264562Sgshapiro "disconnect level %d", 314364562Sgshapiro droplev); 314438032Speter 314538032Speter /* be sure we don't get nasty signals */ 314690792Sgshapiro (void) sm_signal(SIGINT, SIG_IGN); 314790792Sgshapiro (void) sm_signal(SIGQUIT, SIG_IGN); 314838032Speter 314938032Speter /* we can't communicate with our caller, so.... */ 315090792Sgshapiro HoldErrs = true; 315138032Speter CurEnv->e_errormode = EM_MAIL; 315238032Speter Verbose = 0; 315390792Sgshapiro DisConnected = true; 315438032Speter 315538032Speter /* all input from /dev/null */ 315690792Sgshapiro if (InChannel != smioin) 315738032Speter { 315890792Sgshapiro (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 315990792Sgshapiro InChannel = smioin; 316038032Speter } 316190792Sgshapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 316290792Sgshapiro SM_IO_RDONLY, NULL, smioin) == NULL) 316338032Speter sm_syslog(LOG_ERR, e->e_id, 316490792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 316590792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 316638032Speter 316790792Sgshapiro /* 316890792Sgshapiro ** output to the transcript 316990792Sgshapiro ** We also compare the fd numbers here since OutChannel 317090792Sgshapiro ** might be a layer on top of smioout due to encryption 317190792Sgshapiro ** (see sfsasl.c). 317290792Sgshapiro */ 317390792Sgshapiro 317490792Sgshapiro if (OutChannel != smioout && 317590792Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 317690792Sgshapiro sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 317738032Speter { 317890792Sgshapiro (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 317990792Sgshapiro OutChannel = smioout; 318090792Sgshapiro 318190792Sgshapiro#if 0 318290792Sgshapiro /* 318390792Sgshapiro ** Has smioout been closed? Reopen it. 318490792Sgshapiro ** This shouldn't happen anymore, the code is here 318590792Sgshapiro ** just as a reminder. 318690792Sgshapiro */ 318790792Sgshapiro 318890792Sgshapiro if (smioout->sm_magic == NULL && 318990792Sgshapiro sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 319090792Sgshapiro SM_IO_WRONLY, NULL, smioout) == NULL) 319190792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 319290792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 319390792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 319490792Sgshapiro#endif /* 0 */ 319538032Speter } 319638032Speter if (droplev > 0) 319738032Speter { 319890792Sgshapiro fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 319964562Sgshapiro if (fd == -1) 320064562Sgshapiro sm_syslog(LOG_ERR, e->e_id, 320190792Sgshapiro "disconnect: open(\"%s\") failed: %s", 320290792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 320390792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 320464562Sgshapiro (void) dup2(fd, STDOUT_FILENO); 320564562Sgshapiro (void) dup2(fd, STDERR_FILENO); 320664562Sgshapiro (void) close(fd); 320738032Speter } 320838032Speter 320938032Speter /* drop our controlling TTY completely if possible */ 321038032Speter if (droplev > 1) 321138032Speter { 321238032Speter (void) setsid(); 321338032Speter errno = 0; 321438032Speter } 321538032Speter 321638032Speter#if XDEBUG 321738032Speter checkfd012("disconnect"); 321864562Sgshapiro#endif /* XDEBUG */ 321938032Speter 322038032Speter if (LogLevel > 71) 322190792Sgshapiro sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 322290792Sgshapiro (int) CurrentPid); 322338032Speter 322438032Speter errno = 0; 322538032Speter} 322638032Speter 322738032Speterstatic void 322838032Speterobsolete(argv) 322938032Speter char *argv[]; 323038032Speter{ 323138032Speter register char *ap; 323238032Speter register char *op; 323338032Speter 323438032Speter while ((ap = *++argv) != NULL) 323538032Speter { 323638032Speter /* Return if "--" or not an option of any form. */ 323738032Speter if (ap[0] != '-' || ap[1] == '-') 323838032Speter return; 323938032Speter 324090792Sgshapiro#if _FFR_QUARANTINE 324190792Sgshapiro /* Don't allow users to use "-Q." or "-Q ." */ 324290792Sgshapiro if ((ap[1] == 'Q' && ap[2] == '.') || 324390792Sgshapiro (ap[1] == 'Q' && argv[1] != NULL && 324490792Sgshapiro argv[1][0] == '.' && argv[1][1] == '\0')) 324590792Sgshapiro { 324690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 324790792Sgshapiro "Can not use -Q.\n"); 324890792Sgshapiro exit(EX_USAGE); 324990792Sgshapiro } 325090792Sgshapiro#endif /* _FFR_QUARANTINE */ 325190792Sgshapiro 325238032Speter /* skip over options that do have a value */ 325338032Speter op = strchr(OPTIONS, ap[1]); 325438032Speter if (op != NULL && *++op == ':' && ap[2] == '\0' && 325538032Speter ap[1] != 'd' && 325638032Speter#if defined(sony_news) 325738032Speter ap[1] != 'E' && ap[1] != 'J' && 325864562Sgshapiro#endif /* defined(sony_news) */ 325938032Speter argv[1] != NULL && argv[1][0] != '-') 326038032Speter { 326138032Speter argv++; 326238032Speter continue; 326338032Speter } 326438032Speter 326538032Speter /* If -C doesn't have an argument, use sendmail.cf. */ 326690792Sgshapiro#define __DEFPATH "sendmail.cf" 326738032Speter if (ap[1] == 'C' && ap[2] == '\0') 326838032Speter { 326938032Speter *argv = xalloc(sizeof(__DEFPATH) + 2); 327090792Sgshapiro (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 327190792Sgshapiro "-C", __DEFPATH); 327238032Speter } 327338032Speter 327438032Speter /* If -q doesn't have an argument, run it once. */ 327538032Speter if (ap[1] == 'q' && ap[2] == '\0') 327638032Speter *argv = "-q0"; 327738032Speter 327890792Sgshapiro#if _FFR_QUARANTINE 327990792Sgshapiro /* If -Q doesn't have an argument, disable quarantining */ 328090792Sgshapiro if (ap[1] == 'Q' && ap[2] == '\0') 328190792Sgshapiro *argv = "-Q."; 328290792Sgshapiro#endif /* _FFR_QUARANTINE */ 328390792Sgshapiro 328438032Speter /* if -d doesn't have an argument, use 0-99.1 */ 328538032Speter if (ap[1] == 'd' && ap[2] == '\0') 328638032Speter *argv = "-d0-99.1"; 328738032Speter 328864562Sgshapiro#if defined(sony_news) 328938032Speter /* if -E doesn't have an argument, use -EC */ 329038032Speter if (ap[1] == 'E' && ap[2] == '\0') 329138032Speter *argv = "-EC"; 329238032Speter 329338032Speter /* if -J doesn't have an argument, use -JJ */ 329438032Speter if (ap[1] == 'J' && ap[2] == '\0') 329538032Speter *argv = "-JJ"; 329664562Sgshapiro#endif /* defined(sony_news) */ 329738032Speter } 329838032Speter} 329990792Sgshapiro/* 330038032Speter** AUTH_WARNING -- specify authorization warning 330138032Speter** 330238032Speter** Parameters: 330338032Speter** e -- the current envelope. 330438032Speter** msg -- the text of the message. 330538032Speter** args -- arguments to the message. 330638032Speter** 330738032Speter** Returns: 330838032Speter** none. 330938032Speter*/ 331038032Speter 331138032Spetervoid 331238032Speter#ifdef __STDC__ 331338032Speterauth_warning(register ENVELOPE *e, const char *msg, ...) 331464562Sgshapiro#else /* __STDC__ */ 331538032Speterauth_warning(e, msg, va_alist) 331638032Speter register ENVELOPE *e; 331738032Speter const char *msg; 331838032Speter va_dcl 331964562Sgshapiro#endif /* __STDC__ */ 332038032Speter{ 332138032Speter char buf[MAXLINE]; 332290792Sgshapiro SM_VA_LOCAL_DECL 332338032Speter 332438032Speter if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 332538032Speter { 332638032Speter register char *p; 332738032Speter static char hostbuf[48]; 332838032Speter 332938032Speter if (hostbuf[0] == '\0') 333071345Sgshapiro { 333171345Sgshapiro struct hostent *hp; 333238032Speter 333371345Sgshapiro hp = myhostname(hostbuf, sizeof hostbuf); 333490792Sgshapiro#if NETINET6 333571345Sgshapiro if (hp != NULL) 333671345Sgshapiro { 333771345Sgshapiro freehostent(hp); 333871345Sgshapiro hp = NULL; 333971345Sgshapiro } 334090792Sgshapiro#endif /* NETINET6 */ 334171345Sgshapiro } 334271345Sgshapiro 334390792Sgshapiro (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": "); 334438032Speter p = &buf[strlen(buf)]; 334590792Sgshapiro SM_VA_START(ap, msg); 334690792Sgshapiro (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 334790792Sgshapiro SM_VA_END(ap); 334890792Sgshapiro addheader("X-Authentication-Warning", buf, 0, e); 334938032Speter if (LogLevel > 3) 335038032Speter sm_syslog(LOG_INFO, e->e_id, 335164562Sgshapiro "Authentication-Warning: %.400s", 335264562Sgshapiro buf); 335338032Speter } 335438032Speter} 335590792Sgshapiro/* 335638032Speter** GETEXTENV -- get from external environment 335738032Speter** 335838032Speter** Parameters: 335938032Speter** envar -- the name of the variable to retrieve 336038032Speter** 336138032Speter** Returns: 336238032Speter** The value, if any. 336338032Speter*/ 336438032Speter 336590792Sgshapirostatic char * 336638032Spetergetextenv(envar) 336738032Speter const char *envar; 336838032Speter{ 336938032Speter char **envp; 337038032Speter int l; 337138032Speter 337238032Speter l = strlen(envar); 337338032Speter for (envp = ExternalEnviron; *envp != NULL; envp++) 337438032Speter { 337538032Speter if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 337638032Speter return &(*envp)[l + 1]; 337738032Speter } 337838032Speter return NULL; 337938032Speter} 338090792Sgshapiro/* 338190792Sgshapiro** SETUSERENV -- set an environment in the propagated environment 338238032Speter** 338338032Speter** Parameters: 338438032Speter** envar -- the name of the environment variable. 338538032Speter** value -- the value to which it should be set. If 338638032Speter** null, this is extracted from the incoming 338738032Speter** environment. If that is not set, the call 338838032Speter** to setuserenv is ignored. 338938032Speter** 339038032Speter** Returns: 339138032Speter** none. 339238032Speter*/ 339338032Speter 339438032Spetervoid 339538032Spetersetuserenv(envar, value) 339638032Speter const char *envar; 339738032Speter const char *value; 339838032Speter{ 339964562Sgshapiro int i, l; 340038032Speter char **evp = UserEnviron; 340138032Speter char *p; 340238032Speter 340338032Speter if (value == NULL) 340438032Speter { 340538032Speter value = getextenv(envar); 340638032Speter if (value == NULL) 340738032Speter return; 340838032Speter } 340938032Speter 341090792Sgshapiro /* XXX enforce reasonable size? */ 341164562Sgshapiro i = strlen(envar) + 1; 341264562Sgshapiro l = strlen(value) + i + 1; 341364562Sgshapiro p = (char *) xalloc(l); 341490792Sgshapiro (void) sm_strlcpyn(p, l, 3, envar, "=", value); 341538032Speter 341638032Speter while (*evp != NULL && strncmp(*evp, p, i) != 0) 341738032Speter evp++; 341838032Speter if (*evp != NULL) 341938032Speter { 342038032Speter *evp++ = p; 342138032Speter } 342238032Speter else if (evp < &UserEnviron[MAXUSERENVIRON]) 342338032Speter { 342438032Speter *evp++ = p; 342538032Speter *evp = NULL; 342638032Speter } 342738032Speter 342838032Speter /* make sure it is in our environment as well */ 342938032Speter if (putenv(p) < 0) 343038032Speter syserr("setuserenv: putenv(%s) failed", p); 343138032Speter} 343290792Sgshapiro/* 343338032Speter** DUMPSTATE -- dump state 343438032Speter** 343538032Speter** For debugging. 343638032Speter*/ 343738032Speter 343838032Spetervoid 343938032Speterdumpstate(when) 344038032Speter char *when; 344138032Speter{ 344238032Speter register char *j = macvalue('j', CurEnv); 344338032Speter int rs; 344464562Sgshapiro extern int NextMacroId; 344538032Speter 344638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 344764562Sgshapiro "--- dumping state on %s: $j = %s ---", 344864562Sgshapiro when, 344964562Sgshapiro j == NULL ? "<NULL>" : j); 345038032Speter if (j != NULL) 345138032Speter { 345238032Speter if (!wordinclass(j, 'w')) 345338032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 345464562Sgshapiro "*** $j not in $=w ***"); 345538032Speter } 345638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 345790792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 345864562Sgshapiro NextMacroId, MAXMACROID); 345938032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 346090792Sgshapiro printopenfds(true); 346138032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 346290792Sgshapiro mci_dump_all(true); 346338032Speter rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 346438032Speter if (rs > 0) 346538032Speter { 346664562Sgshapiro int status; 346738032Speter register char **pvp; 346838032Speter char *pv[MAXATOM + 1]; 346938032Speter 347038032Speter pv[0] = NULL; 347190792Sgshapiro status = REWRITE(pv, rs, CurEnv); 347238032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 347364562Sgshapiro "--- ruleset debug_dumpstate returns stat %d, pv: ---", 347464562Sgshapiro status); 347538032Speter for (pvp = pv; *pvp != NULL; pvp++) 347638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 347738032Speter } 347838032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 347938032Speter} 348090792Sgshapiro 348180785Sgshapiro#ifdef SIGUSR1 348290792Sgshapiro/* 348377349Sgshapiro** SIGUSR1 -- Signal a request to dump state. 348477349Sgshapiro** 348577349Sgshapiro** Parameters: 348677349Sgshapiro** sig -- calling signal. 348777349Sgshapiro** 348877349Sgshapiro** Returns: 348977349Sgshapiro** none. 349077349Sgshapiro** 349177349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 349277349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 349377349Sgshapiro** DOING. 349477349Sgshapiro** 349577349Sgshapiro** XXX: More work is needed for this signal handler. 349677349Sgshapiro*/ 349738032Speter 349838032Speter/* ARGSUSED */ 349977349Sgshapirostatic SIGFUNC_DECL 350038032Spetersigusr1(sig) 350138032Speter int sig; 350238032Speter{ 350377349Sgshapiro int save_errno = errno; 350490792Sgshapiro# if SM_HEAP_CHECK 350590792Sgshapiro extern void dumpstab __P((void)); 350690792Sgshapiro# endif /* SM_HEAP_CHECK */ 350777349Sgshapiro 350877349Sgshapiro FIX_SYSV_SIGNAL(sig, sigusr1); 350977349Sgshapiro errno = save_errno; 351077349Sgshapiro CHECK_CRITICAL(sig); 351138032Speter dumpstate("user signal"); 351290792Sgshapiro# if SM_HEAP_CHECK 351390792Sgshapiro dumpstab(); 351490792Sgshapiro# endif /* SM_HEAP_CHECK */ 351577349Sgshapiro errno = save_errno; 351638032Speter return SIGFUNC_RETURN; 351738032Speter} 351890792Sgshapiro#endif /* SIGUSR1 */ 351990792Sgshapiro 352090792Sgshapiro/* 352138032Speter** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 352238032Speter** 352338032Speter** Parameters: 352438032Speter** to_real_uid -- if set, drop to the real uid instead 352538032Speter** of the RunAsUser. 352638032Speter** 352738032Speter** Returns: 352838032Speter** EX_OSERR if the setuid failed. 352938032Speter** EX_OK otherwise. 353038032Speter*/ 353138032Speter 353238032Speterint 353338032Speterdrop_privileges(to_real_uid) 353438032Speter bool to_real_uid; 353538032Speter{ 353638032Speter int rval = EX_OK; 353738032Speter GIDSET_T emptygidset[1]; 353838032Speter 353938032Speter if (tTd(47, 1)) 354090792Sgshapiro sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n", 354190792Sgshapiro (int) to_real_uid, 354290792Sgshapiro (int) RealUid, (int) RealGid, 354390792Sgshapiro (int) getuid(), (int) getgid(), 354490792Sgshapiro (int) geteuid(), (int) getegid(), 354590792Sgshapiro (int) RunAsUid, (int) RunAsGid); 354638032Speter 354738032Speter if (to_real_uid) 354838032Speter { 354938032Speter RunAsUserName = RealUserName; 355038032Speter RunAsUid = RealUid; 355138032Speter RunAsGid = RealGid; 355294334Sgshapiro EffGid = RunAsGid; 355338032Speter } 355438032Speter 355538032Speter /* make sure no one can grab open descriptors for secret files */ 355638032Speter endpwent(); 355790792Sgshapiro sm_mbdb_terminate(); 355838032Speter 355938032Speter /* reset group permissions; these can be set later */ 356038032Speter emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 356190792Sgshapiro 356290792Sgshapiro /* 356390792Sgshapiro ** Notice: on some OS (Linux...) the setgroups() call causes 356490792Sgshapiro ** a logfile entry if sendmail is not run by root. 356590792Sgshapiro ** However, it is unclear (no POSIX standard) whether 356690792Sgshapiro ** setgroups() can only succeed if executed by root. 356790792Sgshapiro ** So for now we keep it as it is; if you want to change it, use 356890792Sgshapiro ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 356990792Sgshapiro */ 357090792Sgshapiro 357138032Speter if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 357264562Sgshapiro { 357364562Sgshapiro syserr("drop_privileges: setgroups(1, %d) failed", 357490792Sgshapiro (int) emptygidset[0]); 357538032Speter rval = EX_OSERR; 357664562Sgshapiro } 357738032Speter 357890792Sgshapiro /* reset primary group id */ 357990792Sgshapiro if (to_real_uid) 358064562Sgshapiro { 358190792Sgshapiro /* 358290792Sgshapiro ** Drop gid to real gid. 358390792Sgshapiro ** On some OS we must reset the effective[/real[/saved]] gid, 358490792Sgshapiro ** and then use setgid() to finally drop all group privileges. 358590792Sgshapiro ** Later on we check whether we can get back the 358690792Sgshapiro ** effective gid. 358790792Sgshapiro */ 358890792Sgshapiro 358990792Sgshapiro#if HASSETEGID 359090792Sgshapiro if (setegid(RunAsGid) < 0) 359190792Sgshapiro { 359290792Sgshapiro syserr("drop_privileges: setegid(%d) failed", 359390792Sgshapiro (int) RunAsGid); 359490792Sgshapiro rval = EX_OSERR; 359590792Sgshapiro } 359690792Sgshapiro#else /* HASSETEGID */ 359790792Sgshapiro# if HASSETREGID 359890792Sgshapiro if (setregid(RunAsGid, RunAsGid) < 0) 359990792Sgshapiro { 360090792Sgshapiro syserr("drop_privileges: setregid(%d, %d) failed", 360190792Sgshapiro (int) RunAsGid, (int) RunAsGid); 360290792Sgshapiro rval = EX_OSERR; 360390792Sgshapiro } 360490792Sgshapiro# else /* HASSETREGID */ 360590792Sgshapiro# if HASSETRESGID 360690792Sgshapiro if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 360790792Sgshapiro { 360890792Sgshapiro syserr("drop_privileges: setresgid(%d, %d, %d) failed", 360990792Sgshapiro (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 361090792Sgshapiro rval = EX_OSERR; 361190792Sgshapiro } 361290792Sgshapiro# endif /* HASSETRESGID */ 361390792Sgshapiro# endif /* HASSETREGID */ 361490792Sgshapiro#endif /* HASSETEGID */ 361564562Sgshapiro } 361690792Sgshapiro if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 361790792Sgshapiro { 361890792Sgshapiro if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 361990792Sgshapiro { 362090792Sgshapiro syserr("drop_privileges: setgid(%d) failed", 362190792Sgshapiro (int) RunAsGid); 362290792Sgshapiro rval = EX_OSERR; 362390792Sgshapiro } 362490792Sgshapiro errno = 0; 362590792Sgshapiro if (rval == EX_OK && getegid() != RunAsGid) 362690792Sgshapiro { 362790792Sgshapiro syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", 362890792Sgshapiro (int) getegid(), (int) RunAsGid); 362990792Sgshapiro rval = EX_OSERR; 363090792Sgshapiro } 363190792Sgshapiro } 363290792Sgshapiro 363390792Sgshapiro /* fiddle with uid */ 363464562Sgshapiro if (to_real_uid || RunAsUid != 0) 363564562Sgshapiro { 363694334Sgshapiro uid_t euid; 363764562Sgshapiro 363890792Sgshapiro /* 363990792Sgshapiro ** Try to setuid(RunAsUid). 364090792Sgshapiro ** euid must be RunAsUid, 364194334Sgshapiro ** ruid must be RunAsUid unless (e|r)uid wasn't 0 364294334Sgshapiro ** and we didn't have to drop privileges to the real uid. 364390792Sgshapiro */ 364490792Sgshapiro 364590792Sgshapiro if (setuid(RunAsUid) < 0 || 364694334Sgshapiro geteuid() != RunAsUid || 364794334Sgshapiro (getuid() != RunAsUid && 364894334Sgshapiro (to_real_uid || geteuid() == 0 || getuid() == 0))) 364964562Sgshapiro { 365090792Sgshapiro#if HASSETREUID 365190792Sgshapiro /* 365290792Sgshapiro ** if ruid != RunAsUid, euid == RunAsUid, then 365390792Sgshapiro ** try resetting just the real uid, then using 365490792Sgshapiro ** setuid() to drop the saved-uid as well. 365590792Sgshapiro */ 365690792Sgshapiro 365794334Sgshapiro if (geteuid() == RunAsUid) 365890792Sgshapiro { 365990792Sgshapiro if (setreuid(RunAsUid, -1) < 0) 366090792Sgshapiro { 366190792Sgshapiro syserr("drop_privileges: setreuid(%d, -1) failed", 366290792Sgshapiro (int) RunAsUid); 366390792Sgshapiro rval = EX_OSERR; 366490792Sgshapiro } 366590792Sgshapiro if (setuid(RunAsUid) < 0) 366690792Sgshapiro { 366790792Sgshapiro syserr("drop_privileges: second setuid(%d) attempt failed", 366890792Sgshapiro (int) RunAsUid); 366990792Sgshapiro rval = EX_OSERR; 367090792Sgshapiro } 367190792Sgshapiro } 367290792Sgshapiro else 367390792Sgshapiro#endif /* HASSETREUID */ 367490792Sgshapiro { 367590792Sgshapiro syserr("drop_privileges: setuid(%d) failed", 367690792Sgshapiro (int) RunAsUid); 367790792Sgshapiro rval = EX_OSERR; 367890792Sgshapiro } 367964562Sgshapiro } 368094334Sgshapiro euid = geteuid(); 368190792Sgshapiro if (RunAsUid != 0 && setuid(0) == 0) 368264562Sgshapiro { 368364562Sgshapiro /* 368464562Sgshapiro ** Believe it or not, the Linux capability model 368564562Sgshapiro ** allows a non-root process to override setuid() 368664562Sgshapiro ** on a process running as root and prevent that 368764562Sgshapiro ** process from dropping privileges. 368864562Sgshapiro */ 368964562Sgshapiro 369064562Sgshapiro syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 369164562Sgshapiro rval = EX_OSERR; 369264562Sgshapiro } 369364562Sgshapiro else if (RunAsUid != euid && setuid(euid) == 0) 369464562Sgshapiro { 369564562Sgshapiro /* 369664562Sgshapiro ** Some operating systems will keep the saved-uid 369764562Sgshapiro ** if a non-root effective-uid calls setuid(real-uid) 369864562Sgshapiro ** making it possible to set it back again later. 369964562Sgshapiro */ 370064562Sgshapiro 370190792Sgshapiro syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 370264562Sgshapiro rval = EX_OSERR; 370364562Sgshapiro } 370464562Sgshapiro } 370590792Sgshapiro 370690792Sgshapiro if ((to_real_uid || RunAsGid != 0) && 370790792Sgshapiro rval == EX_OK && RunAsGid != EffGid && 370890792Sgshapiro getuid() != 0 && geteuid() != 0) 370990792Sgshapiro { 371090792Sgshapiro errno = 0; 371190792Sgshapiro if (setgid(EffGid) == 0) 371290792Sgshapiro { 371390792Sgshapiro syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 371490792Sgshapiro (int) EffGid); 371590792Sgshapiro rval = EX_OSERR; 371690792Sgshapiro } 371790792Sgshapiro } 371890792Sgshapiro 371938032Speter if (tTd(47, 5)) 372038032Speter { 372190792Sgshapiro sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 372290792Sgshapiro (int) geteuid(), (int) getuid(), 372390792Sgshapiro (int) getegid(), (int) getgid()); 372490792Sgshapiro sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 372590792Sgshapiro (int) RunAsUid, (int) RunAsGid); 372664562Sgshapiro if (tTd(47, 10)) 372790792Sgshapiro sm_dprintf("drop_privileges: rval = %d\n", rval); 372838032Speter } 372938032Speter return rval; 373038032Speter} 373190792Sgshapiro/* 373238032Speter** FILL_FD -- make sure a file descriptor has been properly allocated 373338032Speter** 373438032Speter** Used to make sure that stdin/out/err are allocated on startup 373538032Speter** 373638032Speter** Parameters: 373738032Speter** fd -- the file descriptor to be filled. 373838032Speter** where -- a string used for logging. If NULL, this is 373938032Speter** being called on startup, and logging should 374038032Speter** not be done. 374138032Speter** 374238032Speter** Returns: 374338032Speter** none 374490792Sgshapiro** 374590792Sgshapiro** Side Effects: 374690792Sgshapiro** possibly changes MissingFds 374738032Speter*/ 374838032Speter 374938032Spetervoid 375038032Speterfill_fd(fd, where) 375138032Speter int fd; 375238032Speter char *where; 375338032Speter{ 375438032Speter int i; 375538032Speter struct stat stbuf; 375638032Speter 375738032Speter if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 375838032Speter return; 375938032Speter 376038032Speter if (where != NULL) 376138032Speter syserr("fill_fd: %s: fd %d not open", where, fd); 376238032Speter else 376338032Speter MissingFds |= 1 << fd; 376490792Sgshapiro i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 376538032Speter if (i < 0) 376638032Speter { 376790792Sgshapiro syserr("!fill_fd: %s: cannot open %s", 376890792Sgshapiro where == NULL ? "startup" : where, SM_PATH_DEVNULL); 376938032Speter } 377038032Speter if (fd != i) 377138032Speter { 377238032Speter (void) dup2(i, fd); 377338032Speter (void) close(i); 377438032Speter } 377538032Speter} 377690792Sgshapiro/* 377790792Sgshapiro** SM_PRINTOPTIONS -- print options 377890792Sgshapiro** 377990792Sgshapiro** Parameters: 378090792Sgshapiro** options -- array of options. 378190792Sgshapiro** 378290792Sgshapiro** Returns: 378390792Sgshapiro** none. 378490792Sgshapiro*/ 378590792Sgshapiro 378690792Sgshapirostatic void 378790792Sgshapirosm_printoptions(options) 378890792Sgshapiro char **options; 378990792Sgshapiro{ 379090792Sgshapiro int ll; 379190792Sgshapiro char **av; 379290792Sgshapiro 379390792Sgshapiro av = options; 379490792Sgshapiro ll = 7; 379590792Sgshapiro while (*av != NULL) 379690792Sgshapiro { 379790792Sgshapiro if (ll + strlen(*av) > 63) 379890792Sgshapiro { 379990792Sgshapiro sm_dprintf("\n"); 380090792Sgshapiro ll = 0; 380190792Sgshapiro } 380290792Sgshapiro if (ll == 0) 380390792Sgshapiro sm_dprintf("\t\t"); 380490792Sgshapiro else 380590792Sgshapiro sm_dprintf(" "); 380690792Sgshapiro sm_dprintf("%s", *av); 380790792Sgshapiro ll += strlen(*av++) + 1; 380890792Sgshapiro } 380990792Sgshapiro sm_dprintf("\n"); 381090792Sgshapiro} 381190792Sgshapiro/* 381238032Speter** TESTMODELINE -- process a test mode input line 381338032Speter** 381438032Speter** Parameters: 381538032Speter** line -- the input line. 381638032Speter** e -- the current environment. 381738032Speter** Syntax: 381838032Speter** # a comment 381938032Speter** .X process X as a configuration line 382038032Speter** =X dump a configuration item (such as mailers) 382138032Speter** $X dump a macro or class 382238032Speter** /X try an activity 382338032Speter** X normal process through rule set X 382438032Speter*/ 382538032Speter 382664562Sgshapirostatic void 382738032Spetertestmodeline(line, e) 382838032Speter char *line; 382938032Speter ENVELOPE *e; 383038032Speter{ 383138032Speter register char *p; 383238032Speter char *q; 383338032Speter auto char *delimptr; 383438032Speter int mid; 383538032Speter int i, rs; 383638032Speter STAB *map; 383738032Speter char **s; 383838032Speter struct rewrite *rw; 383938032Speter ADDRESS a; 384038032Speter static int tryflags = RF_COPYNONE; 384138032Speter char exbuf[MAXLINE]; 384290792Sgshapiro extern unsigned char TokTypeNoC[]; 384338032Speter 384466494Sgshapiro /* skip leading spaces */ 384566494Sgshapiro while (*line == ' ') 384666494Sgshapiro line++; 384766494Sgshapiro 384838032Speter switch (line[0]) 384938032Speter { 385038032Speter case '#': 385164562Sgshapiro case '\0': 385238032Speter return; 385338032Speter 385438032Speter case '?': 385564562Sgshapiro help("-bt", e); 385638032Speter return; 385738032Speter 385838032Speter case '.': /* config-style settings */ 385938032Speter switch (line[1]) 386038032Speter { 386138032Speter case 'D': 386290792Sgshapiro mid = macid_parse(&line[2], &delimptr); 386371345Sgshapiro if (mid == 0) 386438032Speter return; 386538032Speter translate_dollars(delimptr); 386690792Sgshapiro macdefine(&e->e_macro, A_TEMP, mid, delimptr); 386738032Speter break; 386838032Speter 386938032Speter case 'C': 387038032Speter if (line[2] == '\0') /* not to call syserr() */ 387138032Speter return; 387238032Speter 387390792Sgshapiro mid = macid_parse(&line[2], &delimptr); 387471345Sgshapiro if (mid == 0) 387538032Speter return; 387638032Speter translate_dollars(delimptr); 387738032Speter expand(delimptr, exbuf, sizeof exbuf, e); 387838032Speter p = exbuf; 387938032Speter while (*p != '\0') 388038032Speter { 388138032Speter register char *wd; 388238032Speter char delim; 388338032Speter 388438032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 388538032Speter p++; 388638032Speter wd = p; 388738032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 388838032Speter p++; 388938032Speter delim = *p; 389038032Speter *p = '\0'; 389138032Speter if (wd[0] != '\0') 389238032Speter setclass(mid, wd); 389338032Speter *p = delim; 389438032Speter } 389538032Speter break; 389638032Speter 389738032Speter case '\0': 389890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 389990792Sgshapiro "Usage: .[DC]macro value(s)\n"); 390038032Speter break; 390138032Speter 390238032Speter default: 390390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 390490792Sgshapiro "Unknown \".\" command %s\n", line); 390538032Speter break; 390638032Speter } 390738032Speter return; 390838032Speter 390938032Speter case '=': /* config-style settings */ 391038032Speter switch (line[1]) 391138032Speter { 391238032Speter case 'S': /* dump rule set */ 391338032Speter rs = strtorwset(&line[2], NULL, ST_FIND); 391438032Speter if (rs < 0) 391538032Speter { 391690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 391790792Sgshapiro "Undefined ruleset %s\n", &line[2]); 391838032Speter return; 391938032Speter } 392038032Speter rw = RewriteRules[rs]; 392138032Speter if (rw == NULL) 392238032Speter return; 392338032Speter do 392438032Speter { 392590792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 392690792Sgshapiro 'R'); 392738032Speter s = rw->r_lhs; 392838032Speter while (*s != NULL) 392938032Speter { 393038032Speter xputs(*s++); 393190792Sgshapiro (void) sm_io_putc(smioout, 393290792Sgshapiro SM_TIME_DEFAULT, ' '); 393338032Speter } 393490792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 393590792Sgshapiro '\t'); 393690792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 393790792Sgshapiro '\t'); 393838032Speter s = rw->r_rhs; 393938032Speter while (*s != NULL) 394038032Speter { 394138032Speter xputs(*s++); 394290792Sgshapiro (void) sm_io_putc(smioout, 394390792Sgshapiro SM_TIME_DEFAULT, ' '); 394438032Speter } 394590792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 394690792Sgshapiro '\n'); 394738032Speter } while ((rw = rw->r_next) != NULL); 394838032Speter break; 394938032Speter 395038032Speter case 'M': 395138032Speter for (i = 0; i < MAXMAILERS; i++) 395238032Speter { 395338032Speter if (Mailer[i] != NULL) 395438032Speter printmailer(Mailer[i]); 395538032Speter } 395638032Speter break; 395738032Speter 395838032Speter case '\0': 395990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 396090792Sgshapiro "Usage: =Sruleset or =M\n"); 396138032Speter break; 396238032Speter 396338032Speter default: 396490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 396590792Sgshapiro "Unknown \"=\" command %s\n", line); 396638032Speter break; 396738032Speter } 396838032Speter return; 396938032Speter 397038032Speter case '-': /* set command-line-like opts */ 397138032Speter switch (line[1]) 397238032Speter { 397338032Speter case 'd': 397438032Speter tTflag(&line[2]); 397538032Speter break; 397638032Speter 397738032Speter case '\0': 397890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 397990792Sgshapiro "Usage: -d{debug arguments}\n"); 398038032Speter break; 398138032Speter 398238032Speter default: 398390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 398490792Sgshapiro "Unknown \"-\" command %s\n", line); 398538032Speter break; 398638032Speter } 398738032Speter return; 398838032Speter 398938032Speter case '$': 399038032Speter if (line[1] == '=') 399138032Speter { 399290792Sgshapiro mid = macid(&line[2]); 399371345Sgshapiro if (mid != 0) 399438032Speter stabapply(dump_class, mid); 399538032Speter return; 399638032Speter } 399790792Sgshapiro mid = macid(&line[1]); 399871345Sgshapiro if (mid == 0) 399938032Speter return; 400038032Speter p = macvalue(mid, e); 400138032Speter if (p == NULL) 400290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 400390792Sgshapiro "Undefined\n"); 400438032Speter else 400538032Speter { 400638032Speter xputs(p); 400790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 400890792Sgshapiro "\n"); 400938032Speter } 401038032Speter return; 401138032Speter 401238032Speter case '/': /* miscellaneous commands */ 401338032Speter p = &line[strlen(line)]; 401438032Speter while (--p >= line && isascii(*p) && isspace(*p)) 401538032Speter *p = '\0'; 401638032Speter p = strpbrk(line, " \t"); 401738032Speter if (p != NULL) 401838032Speter { 401938032Speter while (isascii(*p) && isspace(*p)) 402038032Speter *p++ = '\0'; 402138032Speter } 402238032Speter else 402338032Speter p = ""; 402438032Speter if (line[1] == '\0') 402538032Speter { 402690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 402790792Sgshapiro "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 402838032Speter return; 402938032Speter } 403090792Sgshapiro if (sm_strcasecmp(&line[1], "quit") == 0) 403164562Sgshapiro { 403264562Sgshapiro CurEnv->e_id = NULL; 403390792Sgshapiro finis(true, true, ExitStat); 403490792Sgshapiro /* NOTREACHED */ 403564562Sgshapiro } 403690792Sgshapiro if (sm_strcasecmp(&line[1], "mx") == 0) 403738032Speter { 403838032Speter#if NAMED_BIND 403938032Speter /* look up MX records */ 404038032Speter int nmx; 404138032Speter auto int rcode; 404238032Speter char *mxhosts[MAXMXHOSTS + 1]; 404338032Speter 404438032Speter if (*p == '\0') 404538032Speter { 404690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 404790792Sgshapiro "Usage: /mx address\n"); 404838032Speter return; 404938032Speter } 405090792Sgshapiro nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true, 405190792Sgshapiro NULL); 405290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 405390792Sgshapiro "getmxrr(%s) returns %d value(s):\n", 405490792Sgshapiro p, nmx); 405538032Speter for (i = 0; i < nmx; i++) 405690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 405790792Sgshapiro "\t%s\n", mxhosts[i]); 405864562Sgshapiro#else /* NAMED_BIND */ 405990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 406090792Sgshapiro "No MX code compiled in\n"); 406164562Sgshapiro#endif /* NAMED_BIND */ 406238032Speter } 406390792Sgshapiro else if (sm_strcasecmp(&line[1], "canon") == 0) 406438032Speter { 406538032Speter char host[MAXHOSTNAMELEN]; 406638032Speter 406738032Speter if (*p == '\0') 406838032Speter { 406990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 407090792Sgshapiro "Usage: /canon address\n"); 407138032Speter return; 407238032Speter } 407390792Sgshapiro else if (sm_strlcpy(host, p, sizeof host) >= sizeof host) 407438032Speter { 407590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 407690792Sgshapiro "Name too long\n"); 407738032Speter return; 407838032Speter } 407990792Sgshapiro (void) getcanonname(host, sizeof host, HasWildcardMX, 408090792Sgshapiro NULL); 408190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 408290792Sgshapiro "getcanonname(%s) returns %s\n", 408390792Sgshapiro p, host); 408438032Speter } 408590792Sgshapiro else if (sm_strcasecmp(&line[1], "map") == 0) 408638032Speter { 408738032Speter auto int rcode = EX_OK; 408838032Speter char *av[2]; 408938032Speter 409038032Speter if (*p == '\0') 409138032Speter { 409290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 409390792Sgshapiro "Usage: /map mapname key\n"); 409438032Speter return; 409538032Speter } 409690792Sgshapiro for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 409738032Speter continue; 409838032Speter if (*q == '\0') 409938032Speter { 410090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 410190792Sgshapiro "No key specified\n"); 410238032Speter return; 410338032Speter } 410438032Speter *q++ = '\0'; 410538032Speter map = stab(p, ST_MAP, ST_FIND); 410638032Speter if (map == NULL) 410738032Speter { 410890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 410990792Sgshapiro "Map named \"%s\" not found\n", p); 411038032Speter return; 411138032Speter } 411264562Sgshapiro if (!bitset(MF_OPEN, map->s_map.map_mflags) && 411364562Sgshapiro !openmap(&(map->s_map))) 411438032Speter { 411590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 411690792Sgshapiro "Map named \"%s\" not open\n", p); 411738032Speter return; 411838032Speter } 411990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 412090792Sgshapiro "map_lookup: %s (%s) ", p, q); 412138032Speter av[0] = q; 412238032Speter av[1] = NULL; 412338032Speter p = (*map->s_map.map_class->map_lookup) 412438032Speter (&map->s_map, q, av, &rcode); 412538032Speter if (p == NULL) 412690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 412790792Sgshapiro "no match (%d)\n", 412890792Sgshapiro rcode); 412938032Speter else 413090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 413190792Sgshapiro "returns %s (%d)\n", p, 413290792Sgshapiro rcode); 413338032Speter } 413490792Sgshapiro else if (sm_strcasecmp(&line[1], "try") == 0) 413538032Speter { 413638032Speter MAILER *m; 413764562Sgshapiro STAB *st; 413838032Speter auto int rcode = EX_OK; 413938032Speter 414038032Speter q = strpbrk(p, " \t"); 414138032Speter if (q != NULL) 414238032Speter { 414338032Speter while (isascii(*q) && isspace(*q)) 414438032Speter *q++ = '\0'; 414538032Speter } 414638032Speter if (q == NULL || *q == '\0') 414738032Speter { 414890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 414990792Sgshapiro "Usage: /try mailer address\n"); 415038032Speter return; 415138032Speter } 415264562Sgshapiro st = stab(p, ST_MAILER, ST_FIND); 415364562Sgshapiro if (st == NULL) 415438032Speter { 415590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 415690792Sgshapiro "Unknown mailer %s\n", p); 415738032Speter return; 415838032Speter } 415964562Sgshapiro m = st->s_mailer; 416090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 416190792Sgshapiro "Trying %s %s address %s for mailer %s\n", 416290792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? "header" 416390792Sgshapiro : "envelope", 416490792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? "sender" 416590792Sgshapiro : "recipient", q, p); 416638032Speter p = remotename(q, m, tryflags, &rcode, CurEnv); 416790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 416890792Sgshapiro "Rcode = %d, addr = %s\n", 416990792Sgshapiro rcode, p == NULL ? "<NULL>" : p); 417038032Speter e->e_to = NULL; 417138032Speter } 417290792Sgshapiro else if (sm_strcasecmp(&line[1], "tryflags") == 0) 417338032Speter { 417438032Speter if (*p == '\0') 417538032Speter { 417690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 417790792Sgshapiro "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 417838032Speter return; 417938032Speter } 418038032Speter for (; *p != '\0'; p++) 418138032Speter { 418238032Speter switch (*p) 418338032Speter { 418438032Speter case 'H': 418538032Speter case 'h': 418638032Speter tryflags |= RF_HEADERADDR; 418738032Speter break; 418838032Speter 418938032Speter case 'E': 419038032Speter case 'e': 419138032Speter tryflags &= ~RF_HEADERADDR; 419238032Speter break; 419338032Speter 419438032Speter case 'S': 419538032Speter case 's': 419638032Speter tryflags |= RF_SENDERADDR; 419738032Speter break; 419838032Speter 419938032Speter case 'R': 420038032Speter case 'r': 420138032Speter tryflags &= ~RF_SENDERADDR; 420238032Speter break; 420338032Speter } 420438032Speter } 420564562Sgshapiro exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 420664562Sgshapiro exbuf[1] = ' '; 420764562Sgshapiro exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 420864562Sgshapiro exbuf[3] = '\0'; 420990792Sgshapiro macdefine(&e->e_macro, A_TEMP, 421090792Sgshapiro macid("{addr_type}"), exbuf); 421138032Speter } 421290792Sgshapiro else if (sm_strcasecmp(&line[1], "parse") == 0) 421338032Speter { 421438032Speter if (*p == '\0') 421538032Speter { 421690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 421790792Sgshapiro "Usage: /parse address\n"); 421838032Speter return; 421938032Speter } 422038032Speter q = crackaddr(p); 422190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 422290792Sgshapiro "Cracked address = "); 422338032Speter xputs(q); 422490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 422590792Sgshapiro "\nParsing %s %s address\n", 422690792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? 422790792Sgshapiro "header" : "envelope", 422890792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? 422990792Sgshapiro "sender" : "recipient"); 423090792Sgshapiro if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 423190792Sgshapiro == NULL) 423290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 423390792Sgshapiro "Cannot parse\n"); 423438032Speter else if (a.q_host != NULL && a.q_host[0] != '\0') 423590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 423690792Sgshapiro "mailer %s, host %s, user %s\n", 423790792Sgshapiro a.q_mailer->m_name, 423890792Sgshapiro a.q_host, 423990792Sgshapiro a.q_user); 424038032Speter else 424190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 424290792Sgshapiro "mailer %s, user %s\n", 424390792Sgshapiro a.q_mailer->m_name, 424490792Sgshapiro a.q_user); 424538032Speter e->e_to = NULL; 424638032Speter } 424738032Speter else 424838032Speter { 424990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 425090792Sgshapiro "Unknown \"/\" command %s\n", 425190792Sgshapiro line); 425238032Speter } 425338032Speter return; 425438032Speter } 425538032Speter 425638032Speter for (p = line; isascii(*p) && isspace(*p); p++) 425738032Speter continue; 425838032Speter q = p; 425938032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 426038032Speter p++; 426138032Speter if (*p == '\0') 426238032Speter { 426390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 426490792Sgshapiro "No address!\n"); 426538032Speter return; 426638032Speter } 426738032Speter *p = '\0'; 426890792Sgshapiro if (invalidaddr(p + 1, NULL, true)) 426938032Speter return; 427038032Speter do 427138032Speter { 427238032Speter register char **pvp; 427338032Speter char pvpbuf[PSBUFSIZE]; 427438032Speter 427538032Speter pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, 427664562Sgshapiro &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL); 427738032Speter if (pvp == NULL) 427838032Speter continue; 427938032Speter p = q; 428038032Speter while (*p != '\0') 428138032Speter { 428264562Sgshapiro int status; 428338032Speter 428438032Speter rs = strtorwset(p, NULL, ST_FIND); 428538032Speter if (rs < 0) 428638032Speter { 428790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 428890792Sgshapiro "Undefined ruleset %s\n", 428990792Sgshapiro p); 429038032Speter break; 429138032Speter } 429290792Sgshapiro status = REWRITE(pvp, rs, e); 429364562Sgshapiro if (status != EX_OK) 429490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 429590792Sgshapiro "== Ruleset %s (%d) status %d\n", 429690792Sgshapiro p, rs, status); 429738032Speter while (*p != '\0' && *p++ != ',') 429838032Speter continue; 429938032Speter } 430038032Speter } while (*(p = delimptr) != '\0'); 430138032Speter} 430238032Speter 430364562Sgshapirostatic void 430438032Speterdump_class(s, id) 430538032Speter register STAB *s; 430638032Speter int id; 430738032Speter{ 430890792Sgshapiro if (s->s_symtype != ST_CLASS) 430938032Speter return; 431071345Sgshapiro if (bitnset(bitidx(id), s->s_class)) 431190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 431290792Sgshapiro "%s\n", s->s_name); 431338032Speter} 431490792Sgshapiro 431590792Sgshapiro/* 431690792Sgshapiro** An exception type used to create QuickAbort exceptions. 431790792Sgshapiro** This is my first cut at converting QuickAbort from longjmp to exceptions. 431890792Sgshapiro** These exceptions have a single integer argument, which is the argument 431990792Sgshapiro** to longjmp in the original code (either 1 or 2). I don't know the 432090792Sgshapiro** significance of 1 vs 2: the calls to setjmp don't care. 432190792Sgshapiro*/ 432290792Sgshapiro 432390792Sgshapiroconst SM_EXC_TYPE_T EtypeQuickAbort = 432490792Sgshapiro{ 432590792Sgshapiro SmExcTypeMagic, 432690792Sgshapiro "E:mta.quickabort", 432790792Sgshapiro "i", 432890792Sgshapiro sm_etype_printf, 432990792Sgshapiro "quick abort %0", 433090792Sgshapiro}; 4331