main.c revision 249729
138032Speter/* 2223067Sgshapiro * Copyright (c) 1998-2006, 2008, 2009, 2011 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> 16168515Sgshapiro#include <sm/sendmail.h> 1790792Sgshapiro#include <sm/xtrap.h> 1890792Sgshapiro#include <sm/signal.h> 1990792Sgshapiro 2038032Speter#ifndef lint 2190792SgshapiroSM_UNUSED(static char copyright[]) = 22132943Sgshapiro"@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\ 2364562Sgshapiro All rights reserved.\n\ 2438032Speter Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 2538032Speter Copyright (c) 1988, 1993\n\ 2638032Speter The Regents of the University of California. All rights reserved.\n"; 2764562Sgshapiro#endif /* ! lint */ 2838032Speter 29249729SgshapiroSM_RCSID("@(#)$Id: main.c,v 8.983 2013/03/12 15:24:52 ca Exp $") 3038032Speter 3138032Speter 3264562Sgshapiro#if NETINET || NETINET6 3364562Sgshapiro# include <arpa/inet.h> 3464562Sgshapiro#endif /* NETINET || NETINET6 */ 3564562Sgshapiro 3690792Sgshapiro/* for getcfname() */ 3790792Sgshapiro#include <sendmail/pathnames.h> 3890792Sgshapiro 3990792Sgshapirostatic SM_DEBUG_T 4090792SgshapiroDebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart", 4190792Sgshapiro "@(#)$Debug: no_persistent_restart - don't restart, log only $"); 4290792Sgshapiro 4390792Sgshapirostatic void dump_class __P((STAB *, int)); 4490792Sgshapirostatic void obsolete __P((char **)); 4590792Sgshapirostatic void testmodeline __P((char *, ENVELOPE *)); 4690792Sgshapirostatic char *getextenv __P((const char *)); 4790792Sgshapirostatic void sm_printoptions __P((char **)); 4877349Sgshapirostatic SIGFUNC_DECL intindebug __P((int)); 4990792Sgshapirostatic SIGFUNC_DECL sighup __P((int)); 5090792Sgshapirostatic SIGFUNC_DECL sigpipe __P((int)); 5190792Sgshapirostatic SIGFUNC_DECL sigterm __P((int)); 5280785Sgshapiro#ifdef SIGUSR1 5377349Sgshapirostatic SIGFUNC_DECL sigusr1 __P((int)); 5490792Sgshapiro#endif /* SIGUSR1 */ 5564562Sgshapiro 5638032Speter/* 5738032Speter** SENDMAIL -- Post mail to a set of destinations. 5838032Speter** 5938032Speter** This is the basic mail router. All user mail programs should 6038032Speter** call this routine to actually deliver mail. Sendmail in 6138032Speter** turn calls a bunch of mail servers that do the real work of 6238032Speter** delivering the mail. 6338032Speter** 6464562Sgshapiro** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 6538032Speter** (read by readcf.c). 6638032Speter** 6738032Speter** Usage: 6838032Speter** /usr/lib/sendmail [flags] addr ... 6938032Speter** 7038032Speter** See the associated documentation for details. 7138032Speter** 7290792Sgshapiro** Authors: 7338032Speter** Eric Allman, UCB/INGRES (until 10/81). 7438032Speter** Britton-Lee, Inc., purveyors of fine 7538032Speter** database computers (11/81 - 10/88). 7638032Speter** International Computer Science Institute 7738032Speter** (11/88 - 9/89). 7838032Speter** UCB/Mammoth Project (10/89 - 7/95). 7938032Speter** InReference, Inc. (8/95 - 1/97). 8038032Speter** Sendmail, Inc. (1/98 - present). 81111823Sgshapiro** The support of my employers is gratefully acknowledged. 8238032Speter** Few of them (Britton-Lee in particular) have had 8338032Speter** anything to gain from my involvement in this project. 8490792Sgshapiro** 8590792Sgshapiro** Gregory Neil Shapiro, 8690792Sgshapiro** Worcester Polytechnic Institute (until 3/98). 8790792Sgshapiro** Sendmail, Inc. (3/98 - present). 8890792Sgshapiro** 8990792Sgshapiro** Claus Assmann, 9090792Sgshapiro** Sendmail, Inc. (12/98 - present). 9138032Speter*/ 9238032Speter 9338032Speterchar *FullName; /* sender's full name */ 9438032SpeterENVELOPE BlankEnvelope; /* a "blank" envelope */ 9564562Sgshapirostatic ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 9638032SpeterADDRESS NullAddress = /* a null address */ 9738032Speter { "", "", NULL, "" }; 9838032Speterchar *CommandLineArgs; /* command line args for pid file */ 9990792Sgshapirobool Warn_Q_option = false; /* warn about Q option use */ 10064562Sgshapirostatic int MissingFds = 0; /* bit map of fds missing on startup */ 10190792Sgshapirochar *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */ 10238032Speter 10338032Speter#ifdef NGROUPS_MAX 10438032SpeterGIDSET_T InitialGidSet[NGROUPS_MAX]; 10564562Sgshapiro#endif /* NGROUPS_MAX */ 10638032Speter 10790792Sgshapiro#define MAXCONFIGLEVEL 10 /* highest config version level known */ 10838032Speter 10964562Sgshapiro#if SASL 11064562Sgshapirostatic sasl_callback_t srvcallbacks[] = 11164562Sgshapiro{ 112225906Sume { SASL_CB_VERIFYFILE, (sasl_callback_ft)&safesaslfile, NULL }, 113225906Sume { SASL_CB_PROXY_POLICY, (sasl_callback_ft)&proxy_policy, NULL }, 11464562Sgshapiro { SASL_CB_LIST_END, NULL, NULL } 11564562Sgshapiro}; 11664562Sgshapiro#endif /* SASL */ 11764562Sgshapiro 11890792Sgshapirounsigned int SubmitMode; 11990792Sgshapiroint SyslogPrefixLen; /* estimated length of syslog prefix */ 12090792Sgshapiro#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 12190792Sgshapiro#ifndef SL_FUDGE 12290792Sgshapiro# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 12390792Sgshapiro#endif /* ! SL_FUDGE */ 12490792Sgshapiro#define SLDLL 8 /* est. length of default syslog label */ 12564562Sgshapiro 12690792Sgshapiro 12790792Sgshapiro/* Some options are dangerous to allow users to use in non-submit mode */ 12890792Sgshapiro#define CHECK_AGAINST_OPMODE(cmd) \ 12990792Sgshapiro{ \ 13090792Sgshapiro if (extraprivs && \ 13190792Sgshapiro OpMode != MD_DELIVER && OpMode != MD_SMTP && \ 132203004Sgshapiro OpMode != MD_ARPAFTP && OpMode != MD_CHECKCONFIG && \ 13390792Sgshapiro OpMode != MD_VERIFY && OpMode != MD_TEST) \ 13490792Sgshapiro { \ 13590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 13690792Sgshapiro "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \ 13790792Sgshapiro (cmd)); \ 13890792Sgshapiro break; \ 13990792Sgshapiro } \ 14090792Sgshapiro if (extraprivs && queuerun) \ 14190792Sgshapiro { \ 14290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 14390792Sgshapiro "WARNING: Ignoring submission mode -%c option with -q\n", \ 14490792Sgshapiro (cmd)); \ 14590792Sgshapiro break; \ 14690792Sgshapiro } \ 14790792Sgshapiro} 14890792Sgshapiro 14938032Speterint 15038032Spetermain(argc, argv, envp) 15138032Speter int argc; 15238032Speter char **argv; 15338032Speter char **envp; 15438032Speter{ 15538032Speter register char *p; 15638032Speter char **av; 15738032Speter extern char Version[]; 15838032Speter char *ep, *from; 15938032Speter STAB *st; 16038032Speter register int i; 16138032Speter int j; 16264562Sgshapiro int dp; 16390792Sgshapiro int fill_errno; 16490792Sgshapiro int qgrp = NOQGRP; /* queue group to process */ 16590792Sgshapiro bool safecf = true; 16664562Sgshapiro BITMAP256 *p_flags = NULL; /* daemon flags */ 16790792Sgshapiro bool warn_C_flag = false; 16890792Sgshapiro bool auth = true; /* whether to set e_auth_param */ 16938032Speter char warn_f_flag = '\0'; 17090792Sgshapiro bool run_in_foreground = false; /* -bD mode */ 17190792Sgshapiro bool queuerun = false, debug = false; 17238032Speter struct passwd *pw; 17338032Speter struct hostent *hp; 17438032Speter char *nullserver = NULL; 17564562Sgshapiro char *authinfo = NULL; 17664562Sgshapiro char *sysloglabel = NULL; /* label for syslog */ 17790792Sgshapiro char *conffile = NULL; /* name of .cf file */ 17890792Sgshapiro char *queuegroup = NULL; /* queue group to process */ 17990792Sgshapiro char *quarantining = NULL; /* quarantine queue items? */ 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? */ 186132943Sgshapiro SM_FILE_T *smdebug; 18790792Sgshapiro static time_t starttime = 0; /* when was process started */ 18864562Sgshapiro struct stat traf_st; /* for TrafficLog FIFO check */ 18990792Sgshapiro char buf[MAXLINE]; 19038032Speter char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 19138032Speter static char rnamebuf[MAXNAME]; /* holds RealUserName */ 19238032Speter char *emptyenviron[1]; 19390792Sgshapiro#if STARTTLS 19466494Sgshapiro bool tls_ok; 19590792Sgshapiro#endif /* STARTTLS */ 19638032Speter QUEUE_CHAR *new; 19790792Sgshapiro ENVELOPE *e; 19838032Speter extern int DtableSize; 19938032Speter extern int optind; 20038032Speter extern int opterr; 20138032Speter extern char *optarg; 20238032Speter extern char **environ; 20390792Sgshapiro#if SASL 20490792Sgshapiro extern void sm_sasl_init __P((void)); 20590792Sgshapiro#endif /* SASL */ 20638032Speter 20790792Sgshapiro#if USE_ENVIRON 20890792Sgshapiro envp = environ; 20990792Sgshapiro#endif /* USE_ENVIRON */ 21090792Sgshapiro 21190792Sgshapiro /* turn off profiling */ 21290792Sgshapiro SM_PROF(0); 21390792Sgshapiro 21490792Sgshapiro /* install default exception handler */ 21590792Sgshapiro sm_exc_newthread(fatal_error); 21690792Sgshapiro 217110560Sgshapiro /* set the default in/out channel so errors reported to screen */ 218110560Sgshapiro InChannel = smioin; 219110560Sgshapiro OutChannel = smioout; 220110560Sgshapiro 22138032Speter /* 22238032Speter ** Check to see if we reentered. 22338032Speter ** This would normally happen if e_putheader or e_putbody 22438032Speter ** were NULL when invoked. 22538032Speter */ 22638032Speter 22790792Sgshapiro if (starttime != 0) 22838032Speter { 22938032Speter syserr("main: reentered!"); 23038032Speter abort(); 23138032Speter } 23290792Sgshapiro starttime = curtime(); 23338032Speter 23438032Speter /* avoid null pointer dereferences */ 235168515Sgshapiro TermEscape.te_rv_on = TermEscape.te_under_on = TermEscape.te_normal = ""; 23638032Speter 23790792Sgshapiro RealUid = getuid(); 23890792Sgshapiro RealGid = getgid(); 23977349Sgshapiro 24090792Sgshapiro /* Check if sendmail is running with extra privs */ 24190792Sgshapiro extraprivs = (RealUid != 0 && 24290792Sgshapiro (geteuid() != getuid() || getegid() != getgid())); 24377349Sgshapiro 24490792Sgshapiro CurrentPid = getpid(); 24538032Speter 24690792Sgshapiro /* get whatever .cf file is right for the opmode */ 24790792Sgshapiro cftype = SM_GET_RIGHT_CF; 24864562Sgshapiro 24938032Speter /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 25038032Speter DtableSize = getdtsize(); 25138032Speter if (DtableSize > 256) 25238032Speter DtableSize = 256; 25338032Speter 25438032Speter /* 25538032Speter ** Be sure we have enough file descriptors. 25638032Speter ** But also be sure that 0, 1, & 2 are open. 25738032Speter */ 25838032Speter 25990792Sgshapiro /* reset errno and fill_errno; the latter is used way down below */ 26090792Sgshapiro errno = fill_errno = 0; 26138032Speter fill_fd(STDIN_FILENO, NULL); 26290792Sgshapiro if (errno != 0) 26390792Sgshapiro fill_errno = errno; 26438032Speter fill_fd(STDOUT_FILENO, NULL); 26590792Sgshapiro if (errno != 0) 26690792Sgshapiro fill_errno = errno; 26738032Speter fill_fd(STDERR_FILENO, NULL); 26890792Sgshapiro if (errno != 0) 26990792Sgshapiro fill_errno = errno; 27038032Speter 271132943Sgshapiro sm_closefrom(STDERR_FILENO + 1, DtableSize); 27238032Speter errno = 0; 273132943Sgshapiro smdebug = NULL; 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; 305182352Sgshapiro#if _FFR_LOCAL_DAEMON 306182352Sgshapiro LocalDaemon = false; 307223067Sgshapiro# if NETINET6 308223067Sgshapiro V6LoopbackAddrFound = false; 309223067Sgshapiro# endif /* NETINET6 */ 310182352Sgshapiro#endif /* _FFR_LOCAL_DAEMON */ 31138032Speter#if XDEBUG 31238032Speter checkfd012("after openlog"); 31364562Sgshapiro#endif /* XDEBUG */ 31438032Speter 315168515Sgshapiro tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1"); 31638032Speter 31738032Speter#ifdef NGROUPS_MAX 31838032Speter /* save initial group set for future checks */ 31938032Speter i = getgroups(NGROUPS_MAX, InitialGidSet); 32090792Sgshapiro if (i <= 0) 32190792Sgshapiro { 32238032Speter InitialGidSet[0] = (GID_T) -1; 32390792Sgshapiro i = 0; 32490792Sgshapiro } 32538032Speter while (i < NGROUPS_MAX) 32638032Speter InitialGidSet[i++] = InitialGidSet[0]; 32764562Sgshapiro#endif /* NGROUPS_MAX */ 32838032Speter 32938032Speter /* drop group id privileges (RunAsUser not yet set) */ 33090792Sgshapiro dp = drop_privileges(false); 33164562Sgshapiro setstat(dp); 33238032Speter 33390792Sgshapiro#ifdef SIGUSR1 33477349Sgshapiro /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 33594334Sgshapiro if (!extraprivs) 33677349Sgshapiro { 33777349Sgshapiro /* arrange to dump state on user-1 signal */ 33890792Sgshapiro (void) sm_signal(SIGUSR1, sigusr1); 33977349Sgshapiro } 34094334Sgshapiro else 34194334Sgshapiro { 34294334Sgshapiro /* ignore user-1 signal */ 34394334Sgshapiro (void) sm_signal(SIGUSR1, SIG_IGN); 34494334Sgshapiro } 34590792Sgshapiro#endif /* SIGUSR1 */ 34638032Speter 34738032Speter /* initialize for setproctitle */ 34838032Speter initsetproctitle(argc, argv, envp); 34938032Speter 35038032Speter /* Handle any non-getoptable constructions. */ 35138032Speter obsolete(argv); 35238032Speter 35338032Speter /* 35438032Speter ** Do a quick prescan of the argument list. 35538032Speter */ 35638032Speter 35764562Sgshapiro 35890792Sgshapiro /* find initial opMode */ 35990792Sgshapiro OpMode = MD_DELIVER; 36090792Sgshapiro av = argv; 36190792Sgshapiro p = strrchr(*av, '/'); 36290792Sgshapiro if (p++ == NULL) 36390792Sgshapiro p = *av; 36490792Sgshapiro if (strcmp(p, "newaliases") == 0) 36590792Sgshapiro OpMode = MD_INITALIAS; 36690792Sgshapiro else if (strcmp(p, "mailq") == 0) 36790792Sgshapiro OpMode = MD_PRINT; 36890792Sgshapiro else if (strcmp(p, "smtpd") == 0) 36990792Sgshapiro OpMode = MD_DAEMON; 37090792Sgshapiro else if (strcmp(p, "hoststat") == 0) 37190792Sgshapiro OpMode = MD_HOSTSTAT; 37290792Sgshapiro else if (strcmp(p, "purgestat") == 0) 37390792Sgshapiro OpMode = MD_PURGESTAT; 37490792Sgshapiro 375132943Sgshapiro#if defined(__osf__) || defined(_AIX3) 376132943Sgshapiro# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:x" 377132943Sgshapiro#endif /* defined(__osf__) || defined(_AIX3) */ 378132943Sgshapiro#if defined(sony_news) 379132943Sgshapiro# define OPTIONS "A:B:b:C:cD:d:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" 380132943Sgshapiro#endif /* defined(sony_news) */ 381132943Sgshapiro#ifndef OPTIONS 382132943Sgshapiro# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" 383132943Sgshapiro#endif /* ! OPTIONS */ 38490792Sgshapiro 385112810Sgshapiro /* Set to 0 to allow -b; need to check optarg before using it! */ 38638032Speter opterr = 0; 38738032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 38838032Speter { 38938032Speter switch (j) 39038032Speter { 39190792Sgshapiro case 'b': /* operations mode */ 39294334Sgshapiro j = (optarg == NULL) ? ' ' : *optarg; 39394334Sgshapiro switch (j) 39438032Speter { 39590792Sgshapiro case MD_DAEMON: 39690792Sgshapiro case MD_FGDAEMON: 39790792Sgshapiro case MD_SMTP: 39890792Sgshapiro case MD_INITALIAS: 39990792Sgshapiro case MD_DELIVER: 40090792Sgshapiro case MD_VERIFY: 40190792Sgshapiro case MD_TEST: 40290792Sgshapiro case MD_PRINT: 40390792Sgshapiro case MD_PRINTNQE: 40490792Sgshapiro case MD_HOSTSTAT: 40590792Sgshapiro case MD_PURGESTAT: 40690792Sgshapiro case MD_ARPAFTP: 407203004Sgshapiro#if _FFR_CHECKCONFIG 408203004Sgshapiro case MD_CHECKCONFIG: 409203004Sgshapiro#endif /* _FFR_CHECKCONFIG */ 41090792Sgshapiro OpMode = j; 41138032Speter break; 41290792Sgshapiro 413182352Sgshapiro#if _FFR_LOCAL_DAEMON 414182352Sgshapiro case MD_LOCAL: 415182352Sgshapiro OpMode = MD_DAEMON; 416182352Sgshapiro LocalDaemon = true; 417182352Sgshapiro break; 418182352Sgshapiro#endif /* _FFR_LOCAL_DAEMON */ 419182352Sgshapiro 42090792Sgshapiro case MD_FREEZE: 42190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42290792Sgshapiro "Frozen configurations unsupported\n"); 42390792Sgshapiro return EX_USAGE; 42490792Sgshapiro 42590792Sgshapiro default: 42690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42790792Sgshapiro "Invalid operation mode %c\n", 42890792Sgshapiro j); 42990792Sgshapiro return EX_USAGE; 43038032Speter } 43190792Sgshapiro break; 43290792Sgshapiro 433132943Sgshapiro case 'D': 434132943Sgshapiro if (debug) 435132943Sgshapiro { 436132943Sgshapiro errno = 0; 437132943Sgshapiro syserr("-D file must be before -d"); 438132943Sgshapiro ExitStat = EX_USAGE; 439132943Sgshapiro break; 440132943Sgshapiro } 441132943Sgshapiro dp = drop_privileges(true); 442132943Sgshapiro setstat(dp); 443132943Sgshapiro smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 444132943Sgshapiro optarg, SM_IO_APPEND, NULL); 445132943Sgshapiro if (smdebug == NULL) 446132943Sgshapiro { 447132943Sgshapiro syserr("cannot open %s", optarg); 448132943Sgshapiro ExitStat = EX_CANTCREAT; 449132943Sgshapiro break; 450132943Sgshapiro } 451132943Sgshapiro sm_debug_setfile(smdebug); 452132943Sgshapiro break; 453132943Sgshapiro 45490792Sgshapiro case 'd': 45590792Sgshapiro debug = true; 45638032Speter tTflag(optarg); 457132943Sgshapiro (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT, 45890792Sgshapiro (char *) NULL, SM_IO_NBF, 45990792Sgshapiro SM_IO_BUFSIZ); 46038032Speter break; 46164562Sgshapiro 46264562Sgshapiro case 'G': /* relay (gateway) submission */ 46390792Sgshapiro SubmitMode = SUBMIT_MTA; 46464562Sgshapiro break; 46564562Sgshapiro 46664562Sgshapiro case 'L': 467112810Sgshapiro if (optarg == NULL) 468112810Sgshapiro { 469112810Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 470112810Sgshapiro "option requires an argument -- '%c'", 471112810Sgshapiro (char) j); 472112810Sgshapiro return EX_USAGE; 473112810Sgshapiro } 474132943Sgshapiro j = SM_MIN(strlen(optarg), 32) + 1; 47564562Sgshapiro sysloglabel = xalloc(j); 47690792Sgshapiro (void) sm_strlcpy(sysloglabel, optarg, j); 47790792Sgshapiro SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + 47890792Sgshapiro SL_FUDGE + j; 47964562Sgshapiro break; 48064562Sgshapiro 48190792Sgshapiro case 'Q': 48290792Sgshapiro case 'q': 48390792Sgshapiro /* just check if it is there */ 48490792Sgshapiro queuerun = true; 48564562Sgshapiro break; 48638032Speter } 48738032Speter } 48838032Speter opterr = 1; 48938032Speter 49090792Sgshapiro /* Don't leak queue information via debug flags */ 49190792Sgshapiro if (extraprivs && queuerun && debug) 49290792Sgshapiro { 49390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 49490792Sgshapiro "WARNING: Can not use -d with -q. Disabling debugging.\n"); 495132943Sgshapiro sm_debug_close(); 49690792Sgshapiro sm_debug_setfile(NULL); 497168515Sgshapiro (void) memset(tTdvect, '\0', sizeof(tTdvect)); 49890792Sgshapiro } 49990792Sgshapiro 50077349Sgshapiro#if LOG 50164562Sgshapiro if (sysloglabel != NULL) 50264562Sgshapiro { 50377349Sgshapiro /* Sanitize the string */ 50477349Sgshapiro for (p = sysloglabel; *p != '\0'; p++) 50577349Sgshapiro { 50677349Sgshapiro if (!isascii(*p) || !isprint(*p) || *p == '%') 50777349Sgshapiro *p = '*'; 50877349Sgshapiro } 50964562Sgshapiro closelog(); 51064562Sgshapiro# ifdef LOG_MAIL 51164562Sgshapiro openlog(sysloglabel, LOG_PID, LOG_MAIL); 51264562Sgshapiro# else /* LOG_MAIL */ 51364562Sgshapiro openlog(sysloglabel, LOG_PID); 51464562Sgshapiro# endif /* LOG_MAIL */ 51577349Sgshapiro } 51664562Sgshapiro#endif /* LOG */ 51764562Sgshapiro 51838032Speter /* set up the blank envelope */ 51938032Speter BlankEnvelope.e_puthdr = putheader; 52038032Speter BlankEnvelope.e_putbody = putbody; 52138032Speter BlankEnvelope.e_xfp = NULL; 52238032Speter STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 52338032Speter CurEnv = &BlankEnvelope; 52438032Speter STRUCTCOPY(NullAddress, MainEnvelope.e_from); 52538032Speter 52638032Speter /* 52738032Speter ** Set default values for variables. 52838032Speter ** These cannot be in initialized data space. 52938032Speter */ 53038032Speter 53138032Speter setdefaults(&BlankEnvelope); 53290792Sgshapiro initmacros(&BlankEnvelope); 53338032Speter 53490792Sgshapiro /* reset macro */ 53590792Sgshapiro set_op_mode(OpMode); 536159609Sgshapiro if (OpMode == MD_DAEMON) 537159609Sgshapiro DaemonPid = CurrentPid; /* needed for finis() to work */ 53838032Speter 53938032Speter pw = sm_getpwuid(RealUid); 54038032Speter if (pw != NULL) 541168515Sgshapiro (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof(rnamebuf)); 54238032Speter else 543168515Sgshapiro (void) sm_snprintf(rnamebuf, sizeof(rnamebuf), "Unknown UID %d", 54490792Sgshapiro (int) RealUid); 54564562Sgshapiro 54638032Speter RealUserName = rnamebuf; 54738032Speter 54838032Speter if (tTd(0, 101)) 54938032Speter { 55090792Sgshapiro sm_dprintf("Version %s\n", Version); 55190792Sgshapiro finis(false, true, EX_OK); 55290792Sgshapiro /* NOTREACHED */ 55338032Speter } 55438032Speter 55538032Speter /* 55690792Sgshapiro ** if running non-set-user-ID binary as non-root, pretend 55738032Speter ** we are the RunAsUid 55838032Speter */ 55977349Sgshapiro 56038032Speter if (RealUid != 0 && geteuid() == RealUid) 56138032Speter { 56238032Speter if (tTd(47, 1)) 56390792Sgshapiro sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n", 56490792Sgshapiro (int) RealUid); 56538032Speter RunAsUid = RealUid; 56638032Speter } 56738032Speter else if (geteuid() != 0) 56838032Speter RunAsUid = geteuid(); 56938032Speter 57090792Sgshapiro EffGid = getegid(); 57190792Sgshapiro if (RealUid != 0 && EffGid == RealGid) 57238032Speter RunAsGid = RealGid; 57338032Speter 57438032Speter if (tTd(47, 5)) 57538032Speter { 57690792Sgshapiro sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 57790792Sgshapiro (int) geteuid(), (int) getuid(), 57890792Sgshapiro (int) getegid(), (int) getgid()); 57990792Sgshapiro sm_dprintf("main: RunAsUser = %d:%d\n", 58090792Sgshapiro (int) RunAsUid, (int) RunAsGid); 58138032Speter } 58238032Speter 58338032Speter /* save command line arguments */ 58464562Sgshapiro j = 0; 58538032Speter for (av = argv; *av != NULL; ) 58664562Sgshapiro j += strlen(*av++) + 1; 587168515Sgshapiro SaveArgv = (char **) xalloc(sizeof(char *) * (argc + 1)); 58864562Sgshapiro CommandLineArgs = xalloc(j); 58938032Speter p = CommandLineArgs; 59038032Speter for (av = argv, i = 0; *av != NULL; ) 59138032Speter { 59264562Sgshapiro int h; 59364562Sgshapiro 59438032Speter SaveArgv[i++] = newstr(*av); 59538032Speter if (av != argv) 59638032Speter *p++ = ' '; 59790792Sgshapiro (void) sm_strlcpy(p, *av++, j); 59864562Sgshapiro h = strlen(p); 59964562Sgshapiro p += h; 60064562Sgshapiro j -= h + 1; 60138032Speter } 60238032Speter SaveArgv[i] = NULL; 60338032Speter 60438032Speter if (tTd(0, 1)) 60538032Speter { 60638032Speter extern char *CompileOptions[]; 60738032Speter 60890792Sgshapiro sm_dprintf("Version %s\n Compiled with:", Version); 60990792Sgshapiro sm_printoptions(CompileOptions); 61038032Speter } 61138032Speter if (tTd(0, 10)) 61238032Speter { 61338032Speter extern char *OsCompileOptions[]; 61438032Speter 61590792Sgshapiro sm_dprintf(" OS Defines:"); 61690792Sgshapiro sm_printoptions(OsCompileOptions); 61738032Speter#ifdef _PATH_UNIX 61890792Sgshapiro sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 61964562Sgshapiro#endif /* _PATH_UNIX */ 62090792Sgshapiro 62190792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MSP)\n", 62290792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF, 62390792Sgshapiro conffile)); 62490792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MTA)\n", 62590792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF, 62690792Sgshapiro conffile)); 62790792Sgshapiro sm_dprintf(" Pid file:\t%s (default)\n", PidFile); 62838032Speter } 62938032Speter 63090792Sgshapiro if (tTd(0, 12)) 63190792Sgshapiro { 63290792Sgshapiro extern char *SmCompileOptions[]; 63338032Speter 63490792Sgshapiro sm_dprintf(" libsm Defines:"); 63590792Sgshapiro sm_printoptions(SmCompileOptions); 63690792Sgshapiro } 63790792Sgshapiro 63890792Sgshapiro if (tTd(0, 13)) 63990792Sgshapiro { 64090792Sgshapiro extern char *FFRCompileOptions[]; 64190792Sgshapiro 64290792Sgshapiro sm_dprintf(" FFR Defines:"); 64390792Sgshapiro sm_printoptions(FFRCompileOptions); 64490792Sgshapiro } 64590792Sgshapiro 64638032Speter /* clear sendmail's environment */ 64738032Speter ExternalEnviron = environ; 64838032Speter emptyenviron[0] = NULL; 64938032Speter environ = emptyenviron; 65038032Speter 65138032Speter /* 65242575Speter ** restore any original TZ setting until TimeZoneSpec has been 65342575Speter ** determined - or early log messages may get bogus time stamps 65438032Speter */ 65590792Sgshapiro 65638032Speter if ((p = getextenv("TZ")) != NULL) 65738032Speter { 65838032Speter char *tz; 65938032Speter int tzlen; 66038032Speter 66190792Sgshapiro /* XXX check for reasonable length? */ 66238032Speter tzlen = strlen(p) + 4; 66338032Speter tz = xalloc(tzlen); 66490792Sgshapiro (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p); 66590792Sgshapiro 66690792Sgshapiro /* XXX check return code? */ 66764562Sgshapiro (void) putenv(tz); 66838032Speter } 66938032Speter 67038032Speter /* prime the child environment */ 671157001Sgshapiro sm_setuserenv("AGENT", "sendmail"); 67238032Speter 67390792Sgshapiro (void) sm_signal(SIGPIPE, SIG_IGN); 67438032Speter OldUmask = umask(022); 67538032Speter FullName = getextenv("NAME"); 67695154Sgshapiro if (FullName != NULL) 67795154Sgshapiro FullName = newstr(FullName); 67838032Speter 67938032Speter /* 68038032Speter ** Initialize name server if it is going to be used. 68138032Speter */ 68238032Speter 68338032Speter#if NAMED_BIND 68438032Speter if (!bitset(RES_INIT, _res.options)) 68564562Sgshapiro (void) res_init(); 68638032Speter if (tTd(8, 8)) 68738032Speter _res.options |= RES_DEBUG; 68838032Speter else 68938032Speter _res.options &= ~RES_DEBUG; 69038032Speter# ifdef RES_NOALIASES 69138032Speter _res.options |= RES_NOALIASES; 69264562Sgshapiro# endif /* RES_NOALIASES */ 69364562Sgshapiro TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 69464562Sgshapiro TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 69564562Sgshapiro TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 69664562Sgshapiro TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 69764562Sgshapiro TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 69864562Sgshapiro TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 69964562Sgshapiro#endif /* NAMED_BIND */ 70038032Speter 70138032Speter errno = 0; 70238032Speter from = NULL; 70338032Speter 70438032Speter /* initialize some macros, etc. */ 70590792Sgshapiro init_vendor_macros(&BlankEnvelope); 70638032Speter 70738032Speter /* version */ 70890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version); 70938032Speter 71038032Speter /* hostname */ 711168515Sgshapiro hp = myhostname(jbuf, sizeof(jbuf)); 71238032Speter if (jbuf[0] != '\0') 71338032Speter { 71490792Sgshapiro struct utsname utsname; 71538032Speter 71638032Speter if (tTd(0, 4)) 71790792Sgshapiro sm_dprintf("Canonical name: %s\n", jbuf); 71890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf); 71990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf); 72038032Speter setclass('w', jbuf); 72138032Speter 72238032Speter p = strchr(jbuf, '.'); 723132943Sgshapiro if (p != NULL && p[1] != '\0') 724132943Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]); 72538032Speter 72638032Speter if (uname(&utsname) >= 0) 72738032Speter p = utsname.nodename; 72838032Speter else 72938032Speter { 73038032Speter if (tTd(0, 22)) 73190792Sgshapiro sm_dprintf("uname failed (%s)\n", 73290792Sgshapiro sm_errstring(errno)); 73338032Speter makelower(jbuf); 73438032Speter p = jbuf; 73538032Speter } 73638032Speter if (tTd(0, 4)) 73790792Sgshapiro sm_dprintf(" UUCP nodename: %s\n", p); 73890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p); 73938032Speter setclass('k', p); 74038032Speter setclass('w', p); 74138032Speter } 74238032Speter if (hp != NULL) 74338032Speter { 74438032Speter for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 74538032Speter { 74638032Speter if (tTd(0, 4)) 74790792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", *av); 74838032Speter setclass('w', *av); 74938032Speter } 75064562Sgshapiro#if NETINET || NETINET6 75190792Sgshapiro for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++) 75238032Speter { 75364562Sgshapiro# if NETINET6 75464562Sgshapiro char *addr; 75564562Sgshapiro char buf6[INET6_ADDRSTRLEN]; 75664562Sgshapiro struct in6_addr ia6; 75764562Sgshapiro# endif /* NETINET6 */ 75864562Sgshapiro# if NETINET 75964562Sgshapiro struct in_addr ia; 76064562Sgshapiro# endif /* NETINET */ 76164562Sgshapiro char ipbuf[103]; 76264562Sgshapiro 76364562Sgshapiro ipbuf[0] = '\0'; 76464562Sgshapiro switch (hp->h_addrtype) 76538032Speter { 76664562Sgshapiro# if NETINET 76764562Sgshapiro case AF_INET: 76864562Sgshapiro if (hp->h_length != INADDRSZ) 76964562Sgshapiro break; 77038032Speter 77164562Sgshapiro memmove(&ia, hp->h_addr_list[i], INADDRSZ); 772168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), 77390792Sgshapiro "[%.100s]", inet_ntoa(ia)); 77464562Sgshapiro break; 77564562Sgshapiro# endif /* NETINET */ 77664562Sgshapiro 77764562Sgshapiro# if NETINET6 77864562Sgshapiro case AF_INET6: 77964562Sgshapiro if (hp->h_length != IN6ADDRSZ) 78064562Sgshapiro break; 78164562Sgshapiro 78264562Sgshapiro memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 783168515Sgshapiro addr = anynet_ntop(&ia6, buf6, sizeof(buf6)); 78464562Sgshapiro if (addr != NULL) 785168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), 78690792Sgshapiro "[%.100s]", addr); 78764562Sgshapiro break; 78864562Sgshapiro# endif /* NETINET6 */ 78938032Speter } 79064562Sgshapiro if (ipbuf[0] == '\0') 79164562Sgshapiro break; 79264562Sgshapiro 79364562Sgshapiro if (tTd(0, 4)) 79490792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", ipbuf); 79564562Sgshapiro setclass('w', ipbuf); 79638032Speter } 79764562Sgshapiro#endif /* NETINET || NETINET6 */ 79890792Sgshapiro#if NETINET6 79971345Sgshapiro freehostent(hp); 80071345Sgshapiro hp = NULL; 80190792Sgshapiro#endif /* NETINET6 */ 80238032Speter } 80338032Speter 80438032Speter /* current time */ 80590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL)); 80690792Sgshapiro 80764562Sgshapiro /* current load average */ 80890792Sgshapiro sm_getla(); 80938032Speter 81038032Speter QueueLimitRecipient = (QUEUE_CHAR *) NULL; 81138032Speter QueueLimitSender = (QUEUE_CHAR *) NULL; 81238032Speter QueueLimitId = (QUEUE_CHAR *) NULL; 81390792Sgshapiro QueueLimitQuarantine = (QUEUE_CHAR *) NULL; 81438032Speter 81538032Speter /* 81642575Speter ** Crack argv. 81738032Speter */ 81838032Speter 81938032Speter optind = 1; 82038032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 82138032Speter { 82238032Speter switch (j) 82338032Speter { 82438032Speter case 'b': /* operations mode */ 82590792Sgshapiro /* already done */ 82690792Sgshapiro break; 82738032Speter 82890792Sgshapiro case 'A': /* use Alternate sendmail/submit.cf */ 82990792Sgshapiro cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF 83090792Sgshapiro : SM_GET_SENDMAIL_CF; 83138032Speter break; 83238032Speter 83338032Speter case 'B': /* body type */ 83490792Sgshapiro CHECK_AGAINST_OPMODE(j); 83590792Sgshapiro BlankEnvelope.e_bodytype = newstr(optarg); 83638032Speter break; 83738032Speter 83838032Speter case 'C': /* select configuration file (already done) */ 83938032Speter if (RealUid != 0) 84090792Sgshapiro warn_C_flag = true; 84190792Sgshapiro conffile = newstr(optarg); 84290792Sgshapiro dp = drop_privileges(true); 84364562Sgshapiro setstat(dp); 84490792Sgshapiro safecf = false; 84538032Speter break; 84638032Speter 847132943Sgshapiro case 'D': 84890792Sgshapiro case 'd': /* debugging */ 84990792Sgshapiro /* already done */ 85038032Speter break; 85138032Speter 85238032Speter case 'f': /* from address */ 85338032Speter case 'r': /* obsolete -f flag */ 85490792Sgshapiro CHECK_AGAINST_OPMODE(j); 85538032Speter if (from != NULL) 85638032Speter { 85738032Speter usrerr("More than one \"from\" person"); 85838032Speter ExitStat = EX_USAGE; 85938032Speter break; 86038032Speter } 861110560Sgshapiro if (optarg[0] == '\0') 862110560Sgshapiro from = newstr("<>"); 863110560Sgshapiro else 864110560Sgshapiro from = newstr(denlstring(optarg, true, true)); 86538032Speter if (strcmp(RealUserName, from) != 0) 86638032Speter warn_f_flag = j; 86738032Speter break; 86838032Speter 86938032Speter case 'F': /* set full name */ 87090792Sgshapiro CHECK_AGAINST_OPMODE(j); 87138032Speter FullName = newstr(optarg); 87238032Speter break; 87338032Speter 87464562Sgshapiro case 'G': /* relay (gateway) submission */ 87564562Sgshapiro /* already set */ 87690792Sgshapiro CHECK_AGAINST_OPMODE(j); 87764562Sgshapiro break; 87864562Sgshapiro 87938032Speter case 'h': /* hop count */ 88090792Sgshapiro CHECK_AGAINST_OPMODE(j); 88190792Sgshapiro BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep, 88290792Sgshapiro 10); 883168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", 88490792Sgshapiro BlankEnvelope.e_hopcount); 88590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf); 88690792Sgshapiro 88738032Speter if (*ep) 88838032Speter { 88938032Speter usrerr("Bad hop count (%s)", optarg); 89038032Speter ExitStat = EX_USAGE; 89138032Speter } 89238032Speter break; 89364562Sgshapiro 89464562Sgshapiro case 'L': /* program label */ 89564562Sgshapiro /* already set */ 89664562Sgshapiro break; 89764562Sgshapiro 89838032Speter case 'n': /* don't alias */ 89990792Sgshapiro CHECK_AGAINST_OPMODE(j); 90090792Sgshapiro NoAlias = true; 90138032Speter break; 90238032Speter 90338032Speter case 'N': /* delivery status notifications */ 90490792Sgshapiro CHECK_AGAINST_OPMODE(j); 90538032Speter DefaultNotify |= QHASNOTIFY; 90690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 90790792Sgshapiro macid("{dsn_notify}"), optarg); 90890792Sgshapiro if (sm_strcasecmp(optarg, "never") == 0) 90938032Speter break; 91038032Speter for (p = optarg; p != NULL; optarg = p) 91138032Speter { 91238032Speter p = strchr(p, ','); 91338032Speter if (p != NULL) 91438032Speter *p++ = '\0'; 91590792Sgshapiro if (sm_strcasecmp(optarg, "success") == 0) 91638032Speter DefaultNotify |= QPINGONSUCCESS; 91790792Sgshapiro else if (sm_strcasecmp(optarg, "failure") == 0) 91838032Speter DefaultNotify |= QPINGONFAILURE; 91990792Sgshapiro else if (sm_strcasecmp(optarg, "delay") == 0) 92038032Speter DefaultNotify |= QPINGONDELAY; 92138032Speter else 92238032Speter { 92338032Speter usrerr("Invalid -N argument"); 92438032Speter ExitStat = EX_USAGE; 92538032Speter } 92638032Speter } 92738032Speter break; 92838032Speter 92938032Speter case 'o': /* set option */ 93090792Sgshapiro setoption(*optarg, optarg + 1, false, true, 93190792Sgshapiro &BlankEnvelope); 93238032Speter break; 93338032Speter 93438032Speter case 'O': /* set option (long form) */ 93590792Sgshapiro setoption(' ', optarg, false, true, &BlankEnvelope); 93638032Speter break; 93738032Speter 93838032Speter case 'p': /* set protocol */ 93990792Sgshapiro CHECK_AGAINST_OPMODE(j); 94038032Speter p = strchr(optarg, ':'); 94138032Speter if (p != NULL) 94238032Speter { 94338032Speter *p++ = '\0'; 94438032Speter if (*p != '\0') 94538032Speter { 946120256Sgshapiro i = strlen(p) + 1; 947120256Sgshapiro ep = sm_malloc_x(i); 948120256Sgshapiro cleanstrcpy(ep, p, i); 94990792Sgshapiro macdefine(&BlankEnvelope.e_macro, 95090792Sgshapiro A_HEAP, 's', ep); 95138032Speter } 95238032Speter } 95338032Speter if (*optarg != '\0') 95438032Speter { 955120256Sgshapiro i = strlen(optarg) + 1; 956120256Sgshapiro ep = sm_malloc_x(i); 957120256Sgshapiro cleanstrcpy(ep, optarg, i); 95890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_HEAP, 95990792Sgshapiro 'r', ep); 96038032Speter } 96138032Speter break; 96238032Speter 96390792Sgshapiro case 'Q': /* change quarantining on queued items */ 96490792Sgshapiro /* sanity check */ 96590792Sgshapiro if (OpMode != MD_DELIVER && 96690792Sgshapiro OpMode != MD_QUEUERUN) 96790792Sgshapiro { 96890792Sgshapiro usrerr("Can not use -Q with -b%c", OpMode); 96990792Sgshapiro ExitStat = EX_USAGE; 97090792Sgshapiro break; 97190792Sgshapiro } 97290792Sgshapiro 97390792Sgshapiro if (OpMode == MD_DELIVER) 97490792Sgshapiro set_op_mode(MD_QUEUERUN); 97590792Sgshapiro 97690792Sgshapiro FullName = NULL; 97790792Sgshapiro 97890792Sgshapiro quarantining = newstr(optarg); 97990792Sgshapiro break; 98090792Sgshapiro 98138032Speter case 'q': /* run queue files at intervals */ 98264562Sgshapiro /* sanity check */ 98364562Sgshapiro if (OpMode != MD_DELIVER && 98464562Sgshapiro OpMode != MD_DAEMON && 98564562Sgshapiro OpMode != MD_FGDAEMON && 98664562Sgshapiro OpMode != MD_PRINT && 98790792Sgshapiro OpMode != MD_PRINTNQE && 98864562Sgshapiro OpMode != MD_QUEUERUN) 98964562Sgshapiro { 99064562Sgshapiro usrerr("Can not use -q with -b%c", OpMode); 99164562Sgshapiro ExitStat = EX_USAGE; 99264562Sgshapiro break; 99364562Sgshapiro } 99464562Sgshapiro 99564562Sgshapiro /* don't override -bd, -bD or -bp */ 99664562Sgshapiro if (OpMode == MD_DELIVER) 99790792Sgshapiro set_op_mode(MD_QUEUERUN); 99864562Sgshapiro 99938032Speter FullName = NULL; 100090792Sgshapiro negate = optarg[0] == '!'; 100190792Sgshapiro if (negate) 100290792Sgshapiro { 100390792Sgshapiro /* negate meaning of pattern match */ 100490792Sgshapiro optarg++; /* skip '!' for next switch */ 100590792Sgshapiro } 100664562Sgshapiro 100738032Speter switch (optarg[0]) 100838032Speter { 100990792Sgshapiro case 'G': /* Limit by queue group name */ 101090792Sgshapiro if (negate) 101190792Sgshapiro { 101290792Sgshapiro usrerr("Can not use -q!G"); 101390792Sgshapiro ExitStat = EX_USAGE; 101490792Sgshapiro break; 101590792Sgshapiro } 101690792Sgshapiro if (queuegroup != NULL) 101790792Sgshapiro { 101890792Sgshapiro usrerr("Can not use multiple -qG options"); 101990792Sgshapiro ExitStat = EX_USAGE; 102090792Sgshapiro break; 102190792Sgshapiro } 102290792Sgshapiro queuegroup = newstr(&optarg[1]); 102390792Sgshapiro break; 102490792Sgshapiro 102590792Sgshapiro case 'I': /* Limit by ID */ 1026168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 102738032Speter new->queue_match = newstr(&optarg[1]); 102890792Sgshapiro new->queue_negate = negate; 102938032Speter new->queue_next = QueueLimitId; 103038032Speter QueueLimitId = new; 103138032Speter break; 103238032Speter 103390792Sgshapiro case 'R': /* Limit by recipient */ 1034168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 103538032Speter new->queue_match = newstr(&optarg[1]); 103690792Sgshapiro new->queue_negate = negate; 103738032Speter new->queue_next = QueueLimitRecipient; 103838032Speter QueueLimitRecipient = new; 103938032Speter break; 104038032Speter 104190792Sgshapiro case 'S': /* Limit by sender */ 1042168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 104338032Speter new->queue_match = newstr(&optarg[1]); 104490792Sgshapiro new->queue_negate = negate; 104538032Speter new->queue_next = QueueLimitSender; 104638032Speter QueueLimitSender = new; 104738032Speter break; 104838032Speter 104990792Sgshapiro case 'f': /* foreground queue run */ 105090792Sgshapiro foregroundqueue = true; 105190792Sgshapiro break; 105290792Sgshapiro 105390792Sgshapiro case 'Q': /* Limit by quarantine message */ 105490792Sgshapiro if (optarg[1] != '\0') 105590792Sgshapiro { 1056168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 105790792Sgshapiro new->queue_match = newstr(&optarg[1]); 105890792Sgshapiro new->queue_negate = negate; 105990792Sgshapiro new->queue_next = QueueLimitQuarantine; 106090792Sgshapiro QueueLimitQuarantine = new; 106190792Sgshapiro } 106290792Sgshapiro QueueMode = QM_QUARANTINE; 106390792Sgshapiro break; 106490792Sgshapiro 106590792Sgshapiro case 'L': /* act on lost items */ 106690792Sgshapiro QueueMode = QM_LOST; 106790792Sgshapiro break; 106890792Sgshapiro 106990792Sgshapiro case 'p': /* Persistent queue */ 107090792Sgshapiro queuepersistent = true; 107190792Sgshapiro if (QueueIntvl == 0) 107290792Sgshapiro QueueIntvl = 1; 107390792Sgshapiro if (optarg[1] == '\0') 107490792Sgshapiro break; 107590792Sgshapiro ++optarg; 107690792Sgshapiro /* FALLTHROUGH */ 107790792Sgshapiro 107838032Speter default: 107964562Sgshapiro i = Errors; 108038032Speter QueueIntvl = convtime(optarg, 'm'); 108198841Sgshapiro if (QueueIntvl < 0) 108298841Sgshapiro { 108398841Sgshapiro usrerr("Invalid -q value"); 108498841Sgshapiro ExitStat = EX_USAGE; 108598841Sgshapiro } 108664562Sgshapiro 108764562Sgshapiro /* check for bad conversion */ 108864562Sgshapiro if (i < Errors) 108964562Sgshapiro ExitStat = EX_USAGE; 109038032Speter break; 109138032Speter } 109238032Speter break; 109338032Speter 109438032Speter case 'R': /* DSN RET: what to return */ 109590792Sgshapiro CHECK_AGAINST_OPMODE(j); 109690792Sgshapiro if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags)) 109738032Speter { 109838032Speter usrerr("Duplicate -R flag"); 109938032Speter ExitStat = EX_USAGE; 110038032Speter break; 110138032Speter } 110290792Sgshapiro BlankEnvelope.e_flags |= EF_RET_PARAM; 110390792Sgshapiro if (sm_strcasecmp(optarg, "hdrs") == 0) 110490792Sgshapiro BlankEnvelope.e_flags |= EF_NO_BODY_RETN; 110590792Sgshapiro else if (sm_strcasecmp(optarg, "full") != 0) 110638032Speter { 110738032Speter usrerr("Invalid -R value"); 110838032Speter ExitStat = EX_USAGE; 110938032Speter } 111090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 111190792Sgshapiro macid("{dsn_ret}"), optarg); 111238032Speter break; 111338032Speter 111438032Speter case 't': /* read recipients from message */ 111590792Sgshapiro CHECK_AGAINST_OPMODE(j); 111690792Sgshapiro GrabTo = true; 111738032Speter break; 111838032Speter 111938032Speter case 'V': /* DSN ENVID: set "original" envelope id */ 112090792Sgshapiro CHECK_AGAINST_OPMODE(j); 112138032Speter if (!xtextok(optarg)) 112238032Speter { 112338032Speter usrerr("Invalid syntax in -V flag"); 112438032Speter ExitStat = EX_USAGE; 112538032Speter } 112638032Speter else 112764562Sgshapiro { 112890792Sgshapiro BlankEnvelope.e_envid = newstr(optarg); 112990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 113090792Sgshapiro macid("{dsn_envid}"), optarg); 113164562Sgshapiro } 113238032Speter break; 113338032Speter 113438032Speter case 'X': /* traffic log file */ 113590792Sgshapiro dp = drop_privileges(true); 113664562Sgshapiro setstat(dp); 113764562Sgshapiro if (stat(optarg, &traf_st) == 0 && 113864562Sgshapiro S_ISFIFO(traf_st.st_mode)) 113990792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 114090792Sgshapiro SM_TIME_DEFAULT, 114190792Sgshapiro optarg, 114290792Sgshapiro SM_IO_WRONLY, NULL); 114364562Sgshapiro else 114490792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 114590792Sgshapiro SM_TIME_DEFAULT, 114690792Sgshapiro optarg, 114790792Sgshapiro SM_IO_APPEND, NULL); 114838032Speter if (TrafficLogFile == NULL) 114938032Speter { 115038032Speter syserr("cannot open %s", optarg); 115138032Speter ExitStat = EX_CANTCREAT; 115238032Speter break; 115338032Speter } 115490792Sgshapiro (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT, 115590792Sgshapiro NULL, SM_IO_LBF, 0); 115638032Speter break; 115738032Speter 115838032Speter /* compatibility flags */ 115938032Speter case 'c': /* connect to non-local mailers */ 116038032Speter case 'i': /* don't let dot stop me */ 116138032Speter case 'm': /* send to me too */ 116238032Speter case 'T': /* set timeout interval */ 116338032Speter case 'v': /* give blow-by-blow description */ 116490792Sgshapiro setoption(j, "T", false, true, &BlankEnvelope); 116538032Speter break; 116638032Speter 116738032Speter case 'e': /* error message disposition */ 116838032Speter case 'M': /* define macro */ 116990792Sgshapiro setoption(j, optarg, false, true, &BlankEnvelope); 117038032Speter break; 117138032Speter 117238032Speter case 's': /* save From lines in headers */ 117390792Sgshapiro setoption('f', "T", false, true, &BlankEnvelope); 117438032Speter break; 117538032Speter 117664562Sgshapiro#ifdef DBM 117738032Speter case 'I': /* initialize alias DBM file */ 117890792Sgshapiro set_op_mode(MD_INITALIAS); 117938032Speter break; 118064562Sgshapiro#endif /* DBM */ 118138032Speter 118264562Sgshapiro#if defined(__osf__) || defined(_AIX3) 118338032Speter case 'x': /* random flag that OSF/1 & AIX mailx passes */ 118438032Speter break; 118564562Sgshapiro#endif /* defined(__osf__) || defined(_AIX3) */ 118664562Sgshapiro#if defined(sony_news) 118738032Speter case 'E': 118838032Speter case 'J': /* ignore flags for Japanese code conversion 118964562Sgshapiro implemented on Sony NEWS */ 119038032Speter break; 119164562Sgshapiro#endif /* defined(sony_news) */ 119238032Speter 119338032Speter default: 119490792Sgshapiro finis(true, true, EX_USAGE); 119590792Sgshapiro /* NOTREACHED */ 119638032Speter break; 119738032Speter } 119838032Speter } 119938032Speter 120090792Sgshapiro /* if we've had errors so far, exit now */ 1201203004Sgshapiro if ((ExitStat != EX_OK && OpMode != MD_TEST && OpMode != MD_CHECKCONFIG) || 120290792Sgshapiro ExitStat == EX_OSERR) 120364562Sgshapiro { 120490792Sgshapiro finis(false, true, ExitStat); 120590792Sgshapiro /* NOTREACHED */ 120664562Sgshapiro } 120790792Sgshapiro 120890792Sgshapiro if (bitset(SUBMIT_MTA, SubmitMode)) 120964562Sgshapiro { 121098841Sgshapiro /* If set daemon_flags on command line, don't reset it */ 121198841Sgshapiro if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 121298841Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 121398841Sgshapiro macid("{daemon_flags}"), "CC f"); 121464562Sgshapiro } 121590792Sgshapiro else if (OpMode == MD_DELIVER || OpMode == MD_SMTP) 121664562Sgshapiro { 121790792Sgshapiro SubmitMode = SUBMIT_MSA; 121898841Sgshapiro 121998841Sgshapiro /* If set daemon_flags on command line, don't reset it */ 122098841Sgshapiro if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 122198841Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 122298841Sgshapiro macid("{daemon_flags}"), "c u"); 122364562Sgshapiro } 122464562Sgshapiro 122538032Speter /* 122638032Speter ** Do basic initialization. 122738032Speter ** Read system control file. 122838032Speter ** Extract special fields for local use. 122938032Speter */ 123038032Speter 123138032Speter#if XDEBUG 123238032Speter checkfd012("before readcf"); 123364562Sgshapiro#endif /* XDEBUG */ 123490792Sgshapiro vendor_pre_defaults(&BlankEnvelope); 123564562Sgshapiro 123690792Sgshapiro readcf(getcfname(OpMode, SubmitMode, cftype, conffile), 123790792Sgshapiro safecf, &BlankEnvelope); 123890792Sgshapiro#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 123990792Sgshapiro ConfigFileRead = true; 124090792Sgshapiro#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 124190792Sgshapiro vendor_post_defaults(&BlankEnvelope); 124238032Speter 124390792Sgshapiro /* now we can complain about missing fds */ 124490792Sgshapiro if (MissingFds != 0 && LogLevel > 8) 124590792Sgshapiro { 124690792Sgshapiro char mbuf[MAXLINE]; 124790792Sgshapiro 124890792Sgshapiro mbuf[0] = '\0'; 124990792Sgshapiro if (bitset(1 << STDIN_FILENO, MissingFds)) 1250168515Sgshapiro (void) sm_strlcat(mbuf, ", stdin", sizeof(mbuf)); 125190792Sgshapiro if (bitset(1 << STDOUT_FILENO, MissingFds)) 1252168515Sgshapiro (void) sm_strlcat(mbuf, ", stdout", sizeof(mbuf)); 125390792Sgshapiro if (bitset(1 << STDERR_FILENO, MissingFds)) 1254168515Sgshapiro (void) sm_strlcat(mbuf, ", stderr", sizeof(mbuf)); 125590792Sgshapiro 125690792Sgshapiro /* Notice: fill_errno is from high above: fill_fd() */ 125790792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 125890792Sgshapiro "File descriptors missing on startup: %s; %s", 125990792Sgshapiro &mbuf[2], sm_errstring(fill_errno)); 126090792Sgshapiro } 126190792Sgshapiro 126277349Sgshapiro /* Remove the ability for a normal user to send signals */ 126390792Sgshapiro if (RealUid != 0 && RealUid != geteuid()) 126477349Sgshapiro { 126577349Sgshapiro uid_t new_uid = geteuid(); 126677349Sgshapiro 126777349Sgshapiro#if HASSETREUID 126877349Sgshapiro /* 126977349Sgshapiro ** Since we can differentiate between uid and euid, 127077349Sgshapiro ** make the uid a different user so the real user 127177349Sgshapiro ** can't send signals. However, it doesn't need to be 127277349Sgshapiro ** root (euid has root). 127377349Sgshapiro */ 127477349Sgshapiro 127577349Sgshapiro if (new_uid == 0) 127677349Sgshapiro new_uid = DefUid; 127777349Sgshapiro if (tTd(47, 5)) 127890792Sgshapiro sm_dprintf("Changing real uid to %d\n", (int) new_uid); 127977349Sgshapiro if (setreuid(new_uid, geteuid()) < 0) 128077349Sgshapiro { 128177349Sgshapiro syserr("main: setreuid(%d, %d) failed", 128277349Sgshapiro (int) new_uid, (int) geteuid()); 128390792Sgshapiro finis(false, true, EX_OSERR); 128477349Sgshapiro /* NOTREACHED */ 128577349Sgshapiro } 128677349Sgshapiro if (tTd(47, 10)) 128790792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 128890792Sgshapiro (int) geteuid(), (int) getuid()); 128977349Sgshapiro#else /* HASSETREUID */ 129077349Sgshapiro /* 129177349Sgshapiro ** Have to change both effective and real so need to 129277349Sgshapiro ** change them both to effective to keep privs. 129377349Sgshapiro */ 129477349Sgshapiro 129577349Sgshapiro if (tTd(47, 5)) 129690792Sgshapiro sm_dprintf("Changing uid to %d\n", (int) new_uid); 129777349Sgshapiro if (setuid(new_uid) < 0) 129877349Sgshapiro { 129977349Sgshapiro syserr("main: setuid(%d) failed", (int) new_uid); 130090792Sgshapiro finis(false, true, EX_OSERR); 130177349Sgshapiro /* NOTREACHED */ 130277349Sgshapiro } 130377349Sgshapiro if (tTd(47, 10)) 130490792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 130590792Sgshapiro (int) geteuid(), (int) getuid()); 130677349Sgshapiro#endif /* HASSETREUID */ 130777349Sgshapiro } 130877349Sgshapiro 130990792Sgshapiro#if NAMED_BIND 1310132943Sgshapiro if (FallbackMX != NULL) 1311132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 131290792Sgshapiro#endif /* NAMED_BIND */ 131390792Sgshapiro 1314223067Sgshapiro if (SuperSafe == SAFE_INTERACTIVE && !SM_IS_INTERACTIVE(CurEnv->e_sendmode)) 131590792Sgshapiro { 131690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 131790792Sgshapiro "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n"); 131890792Sgshapiro } 131990792Sgshapiro 132090792Sgshapiro if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)) 132190792Sgshapiro { 132290792Sgshapiro usrerr("Mail submission program cannot be used as daemon"); 132390792Sgshapiro finis(false, true, EX_USAGE); 132490792Sgshapiro } 132590792Sgshapiro 132690792Sgshapiro if (OpMode == MD_DELIVER || OpMode == MD_SMTP || 132790792Sgshapiro OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP || 132890792Sgshapiro OpMode == MD_DAEMON || OpMode == MD_FGDAEMON) 132990792Sgshapiro makeworkgroups(); 133090792Sgshapiro 133177349Sgshapiro /* set up the basic signal handlers */ 133290792Sgshapiro if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN) 133390792Sgshapiro (void) sm_signal(SIGINT, intsig); 133490792Sgshapiro (void) sm_signal(SIGTERM, intsig); 133577349Sgshapiro 133638032Speter /* Enforce use of local time (null string overrides this) */ 133738032Speter if (TimeZoneSpec == NULL) 133838032Speter unsetenv("TZ"); 133938032Speter else if (TimeZoneSpec[0] != '\0') 1340157001Sgshapiro sm_setuserenv("TZ", TimeZoneSpec); 134138032Speter else 1342157001Sgshapiro sm_setuserenv("TZ", NULL); 134338032Speter tzset(); 134438032Speter 134590792Sgshapiro /* initialize mailbox database */ 134690792Sgshapiro i = sm_mbdb_initialize(Mbdb); 134790792Sgshapiro if (i != EX_OK) 134890792Sgshapiro { 134990792Sgshapiro usrerr("Can't initialize mailbox database \"%s\": %s", 135090792Sgshapiro Mbdb, sm_strexit(i)); 135190792Sgshapiro ExitStat = i; 135290792Sgshapiro } 135390792Sgshapiro 135438032Speter /* avoid denial-of-service attacks */ 135538032Speter resetlimits(); 135638032Speter 135790792Sgshapiro if (OpMode == MD_TEST) 135838032Speter { 135990792Sgshapiro /* can't be done after readcf if RunAs* is used */ 136090792Sgshapiro dp = drop_privileges(true); 136190792Sgshapiro if (dp != EX_OK) 136290792Sgshapiro { 136390792Sgshapiro finis(false, true, dp); 136490792Sgshapiro /* NOTREACHED */ 136590792Sgshapiro } 136690792Sgshapiro } 136790792Sgshapiro else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 136890792Sgshapiro { 136938032Speter /* drop privileges -- daemon mode done after socket/bind */ 137090792Sgshapiro dp = drop_privileges(false); 137164562Sgshapiro setstat(dp); 137290792Sgshapiro if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0)) 137390792Sgshapiro { 137490792Sgshapiro usrerr("Mail submission program must have RunAsUser set to non root user"); 137590792Sgshapiro finis(false, true, EX_CONFIG); 137690792Sgshapiro /* NOTREACHED */ 137790792Sgshapiro } 137838032Speter } 137938032Speter 138064562Sgshapiro#if NAMED_BIND 138164562Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 138264562Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 138364562Sgshapiro#endif /* NAMED_BIND */ 138464562Sgshapiro 138538032Speter /* 138638032Speter ** Find our real host name for future logging. 138738032Speter */ 138838032Speter 138964562Sgshapiro authinfo = getauthinfo(STDIN_FILENO, &forged); 139090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 139138032Speter 139238032Speter /* suppress error printing if errors mailed back or whatever */ 139390792Sgshapiro if (BlankEnvelope.e_errormode != EM_PRINT) 139490792Sgshapiro HoldErrs = true; 139538032Speter 139638032Speter /* set up the $=m class now, after .cf has a chance to redefine $m */ 1397168515Sgshapiro expand("\201m", jbuf, sizeof(jbuf), &BlankEnvelope); 139873188Sgshapiro if (jbuf[0] != '\0') 139973188Sgshapiro setclass('m', jbuf); 140038032Speter 140138032Speter /* probe interfaces and locate any additional names */ 140290792Sgshapiro if (DontProbeInterfaces != DPI_PROBENONE) 140338032Speter load_if_names(); 140438032Speter 140590792Sgshapiro if (tTd(0, 10)) 140690792Sgshapiro { 1407110560Sgshapiro char pidpath[MAXPATHLEN]; 1408110560Sgshapiro 140990792Sgshapiro /* Now we know which .cf file we use */ 141090792Sgshapiro sm_dprintf(" Conf file:\t%s (selected)\n", 141190792Sgshapiro getcfname(OpMode, SubmitMode, cftype, conffile)); 1412168515Sgshapiro expand(PidFile, pidpath, sizeof(pidpath), &BlankEnvelope); 1413110560Sgshapiro sm_dprintf(" Pid file:\t%s (selected)\n", pidpath); 141490792Sgshapiro } 141590792Sgshapiro 141638032Speter if (tTd(0, 1)) 141738032Speter { 141890792Sgshapiro sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 141990792Sgshapiro sm_dprintf("\n (short domain name) $w = "); 1420132943Sgshapiro xputs(sm_debug_file(), macvalue('w', &BlankEnvelope)); 142190792Sgshapiro sm_dprintf("\n (canonical domain name) $j = "); 1422132943Sgshapiro xputs(sm_debug_file(), macvalue('j', &BlankEnvelope)); 142390792Sgshapiro sm_dprintf("\n (subdomain name) $m = "); 1424132943Sgshapiro xputs(sm_debug_file(), macvalue('m', &BlankEnvelope)); 142590792Sgshapiro sm_dprintf("\n (node name) $k = "); 1426132943Sgshapiro xputs(sm_debug_file(), macvalue('k', &BlankEnvelope)); 142790792Sgshapiro sm_dprintf("\n========================================================\n\n"); 142838032Speter } 142938032Speter 143038032Speter /* 143138032Speter ** Do more command line checking -- these are things that 143238032Speter ** have to modify the results of reading the config file. 143338032Speter */ 143438032Speter 143538032Speter /* process authorization warnings from command line */ 143638032Speter if (warn_C_flag) 143790792Sgshapiro auth_warning(&BlankEnvelope, "Processed by %s with -C %s", 143890792Sgshapiro RealUserName, conffile); 143964562Sgshapiro if (Warn_Q_option && !wordinclass(RealUserName, 't')) 144090792Sgshapiro auth_warning(&BlankEnvelope, "Processed from queue %s", 144190792Sgshapiro QueueDir); 144290792Sgshapiro if (sysloglabel != NULL && !wordinclass(RealUserName, 't') && 144390792Sgshapiro RealUid != 0 && RealUid != TrustedUid && LogLevel > 1) 144490792Sgshapiro sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label", 144590792Sgshapiro (int) RealUid); 144638032Speter 144738032Speter /* check body type for legality */ 144890792Sgshapiro i = check_bodytype(BlankEnvelope.e_bodytype); 144990792Sgshapiro if (i == BODYTYPE_ILLEGAL) 145038032Speter { 145190792Sgshapiro usrerr("Illegal body type %s", BlankEnvelope.e_bodytype); 145290792Sgshapiro BlankEnvelope.e_bodytype = NULL; 145338032Speter } 145490792Sgshapiro else if (i != BODYTYPE_NONE) 145590792Sgshapiro SevenBitInput = (i == BODYTYPE_7BIT); 145638032Speter 145738032Speter /* tweak default DSN notifications */ 145838032Speter if (DefaultNotify == 0) 145938032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 146038032Speter 146138032Speter /* check for sane configuration level */ 146238032Speter if (ConfigLevel > MAXCONFIGLEVEL) 146338032Speter { 146438032Speter syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 146590792Sgshapiro ConfigLevel, Version, MAXCONFIGLEVEL); 146638032Speter } 146738032Speter 146838032Speter /* need MCI cache to have persistence */ 146938032Speter if (HostStatDir != NULL && MaxMciCache == 0) 147038032Speter { 147138032Speter HostStatDir = NULL; 147290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 147390792Sgshapiro "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 147438032Speter } 147538032Speter 147638032Speter /* need HostStatusDir in order to have SingleThreadDelivery */ 147738032Speter if (SingleThreadDelivery && HostStatDir == NULL) 147838032Speter { 147990792Sgshapiro SingleThreadDelivery = false; 148090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 148190792Sgshapiro "Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 148238032Speter } 148338032Speter 1484157001Sgshapiro#if _FFR_MEMSTAT 1485157001Sgshapiro j = sm_memstat_open(); 1486157001Sgshapiro if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4) 1487157001Sgshapiro { 1488157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 1489157001Sgshapiro "cannot get memory statistics, settings ignored, error=%d" 1490157001Sgshapiro , j); 1491157001Sgshapiro } 1492157001Sgshapiro#endif /* _FFR_MEMSTAT */ 1493157001Sgshapiro 149438032Speter /* check for permissions */ 149590792Sgshapiro if (RealUid != 0 && 149642575Speter RealUid != TrustedUid) 149738032Speter { 149890792Sgshapiro char *action = NULL; 149990792Sgshapiro 150090792Sgshapiro switch (OpMode) 150190792Sgshapiro { 150290792Sgshapiro case MD_QUEUERUN: 150390792Sgshapiro if (quarantining != NULL) 150490792Sgshapiro action = "quarantine jobs"; 150590792Sgshapiro else 1506132943Sgshapiro { 1507132943Sgshapiro /* Normal users can do a single queue run */ 1508132943Sgshapiro if (QueueIntvl == 0) 1509132943Sgshapiro break; 1510132943Sgshapiro } 151190792Sgshapiro 151290792Sgshapiro /* but not persistent queue runners */ 151390792Sgshapiro if (action == NULL) 151490792Sgshapiro action = "start a queue runner daemon"; 151590792Sgshapiro /* FALLTHROUGH */ 151690792Sgshapiro 151790792Sgshapiro case MD_PURGESTAT: 151890792Sgshapiro if (action == NULL) 151990792Sgshapiro action = "purge host status"; 152090792Sgshapiro /* FALLTHROUGH */ 152190792Sgshapiro 152290792Sgshapiro case MD_DAEMON: 152390792Sgshapiro case MD_FGDAEMON: 152490792Sgshapiro if (action == NULL) 152590792Sgshapiro action = "run daemon"; 152690792Sgshapiro 152790792Sgshapiro if (tTd(65, 1)) 152890792Sgshapiro sm_dprintf("Deny user %d attempt to %s\n", 152990792Sgshapiro (int) RealUid, action); 153090792Sgshapiro 153190792Sgshapiro if (LogLevel > 1) 153290792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 153390792Sgshapiro "user %d attempted to %s", 153490792Sgshapiro (int) RealUid, action); 153590792Sgshapiro HoldErrs = false; 153690792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 153790792Sgshapiro finis(false, true, EX_USAGE); 153890792Sgshapiro /* NOTREACHED */ 153990792Sgshapiro break; 154090792Sgshapiro 154190792Sgshapiro case MD_VERIFY: 154290792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags)) 154390792Sgshapiro { 154490792Sgshapiro /* 154590792Sgshapiro ** If -bv and RestrictExpand, 154690792Sgshapiro ** drop privs to prevent normal 154790792Sgshapiro ** users from reading private 154890792Sgshapiro ** aliases/forwards/:include:s 154990792Sgshapiro */ 155090792Sgshapiro 155190792Sgshapiro if (tTd(65, 1)) 155290792Sgshapiro sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n", 155390792Sgshapiro (int) RealUid); 155490792Sgshapiro 155590792Sgshapiro dp = drop_privileges(true); 155690792Sgshapiro 155790792Sgshapiro /* Fake address safety */ 155890792Sgshapiro if (tTd(65, 1)) 155990792Sgshapiro sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n"); 156090792Sgshapiro setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail); 156190792Sgshapiro 156290792Sgshapiro if (dp != EX_OK) 156390792Sgshapiro { 156490792Sgshapiro if (tTd(65, 1)) 156590792Sgshapiro sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n", 156690792Sgshapiro (int) RealUid); 156790792Sgshapiro CurEnv->e_id = NULL; 156890792Sgshapiro finis(true, true, dp); 156990792Sgshapiro /* NOTREACHED */ 157090792Sgshapiro } 157190792Sgshapiro } 157290792Sgshapiro break; 157390792Sgshapiro 157490792Sgshapiro case MD_TEST: 1575203004Sgshapiro case MD_CHECKCONFIG: 157690792Sgshapiro case MD_PRINT: 157790792Sgshapiro case MD_PRINTNQE: 157890792Sgshapiro case MD_FREEZE: 157990792Sgshapiro case MD_HOSTSTAT: 158090792Sgshapiro /* Nothing special to check */ 158190792Sgshapiro break; 158290792Sgshapiro 158390792Sgshapiro case MD_INITALIAS: 158490792Sgshapiro if (!wordinclass(RealUserName, 't')) 158590792Sgshapiro { 158690792Sgshapiro if (tTd(65, 1)) 158790792Sgshapiro sm_dprintf("Deny user %d attempt to rebuild the alias map\n", 158890792Sgshapiro (int) RealUid); 158990792Sgshapiro if (LogLevel > 1) 159090792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 159190792Sgshapiro "user %d attempted to rebuild the alias map", 159290792Sgshapiro (int) RealUid); 159390792Sgshapiro HoldErrs = false; 159490792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 159590792Sgshapiro finis(false, true, EX_USAGE); 159690792Sgshapiro /* NOTREACHED */ 159790792Sgshapiro } 159890792Sgshapiro if (UseMSP) 159990792Sgshapiro { 160090792Sgshapiro HoldErrs = false; 160190792Sgshapiro usrerr("User %d cannot rebuild aliases in mail submission program", 160290792Sgshapiro (int) RealUid); 160390792Sgshapiro finis(false, true, EX_USAGE); 160490792Sgshapiro /* NOTREACHED */ 160590792Sgshapiro } 160690792Sgshapiro /* FALLTHROUGH */ 160790792Sgshapiro 160890792Sgshapiro default: 160990792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) && 161090792Sgshapiro Verbose != 0) 161190792Sgshapiro { 161290792Sgshapiro /* 161390792Sgshapiro ** If -v and RestrictExpand, reset 161490792Sgshapiro ** Verbose to prevent normal users 161590792Sgshapiro ** from seeing the expansion of 161690792Sgshapiro ** aliases/forwards/:include:s 161790792Sgshapiro */ 161890792Sgshapiro 161990792Sgshapiro if (tTd(65, 1)) 162090792Sgshapiro sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n", 162190792Sgshapiro (int) RealUid); 162290792Sgshapiro Verbose = 0; 162390792Sgshapiro } 162490792Sgshapiro break; 162590792Sgshapiro } 162638032Speter } 162738032Speter 162838032Speter if (MeToo) 162938032Speter BlankEnvelope.e_flags |= EF_METOO; 163038032Speter 163138032Speter switch (OpMode) 163238032Speter { 163338032Speter case MD_TEST: 163438032Speter /* don't have persistent host status in test mode */ 163538032Speter HostStatDir = NULL; 1636203004Sgshapiro /* FALLTHROUGH */ 1637203004Sgshapiro 1638203004Sgshapiro case MD_CHECKCONFIG: 163938032Speter if (Verbose == 0) 164038032Speter Verbose = 2; 164190792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 164290792Sgshapiro HoldErrs = false; 164338032Speter break; 164438032Speter 164538032Speter case MD_VERIFY: 164690792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 164790792Sgshapiro HoldErrs = false; 164838032Speter /* arrange to exit cleanly on hangup signal */ 164990792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 165090792Sgshapiro (void) sm_signal(SIGHUP, intsig); 165190792Sgshapiro if (geteuid() != 0) 165290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 165390792Sgshapiro "Notice: -bv may give misleading output for non-privileged user\n"); 165438032Speter break; 165538032Speter 165638032Speter case MD_FGDAEMON: 165790792Sgshapiro run_in_foreground = true; 165890792Sgshapiro set_op_mode(MD_DAEMON); 165964562Sgshapiro /* FALLTHROUGH */ 166038032Speter 166138032Speter case MD_DAEMON: 166290792Sgshapiro vendor_daemon_setup(&BlankEnvelope); 166338032Speter 166438032Speter /* remove things that don't make sense in daemon mode */ 166538032Speter FullName = NULL; 166690792Sgshapiro GrabTo = false; 166738032Speter 166838032Speter /* arrange to restart on hangup signal */ 166938032Speter if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 167038032Speter sm_syslog(LOG_WARNING, NOQID, 167164562Sgshapiro "daemon invoked without full pathname; kill -1 won't work"); 167238032Speter break; 167338032Speter 167438032Speter case MD_INITALIAS: 167538032Speter Verbose = 2; 167690792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 167790792Sgshapiro HoldErrs = false; 167864562Sgshapiro /* FALLTHROUGH */ 167938032Speter 168038032Speter default: 168138032Speter /* arrange to exit cleanly on hangup signal */ 168290792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 168390792Sgshapiro (void) sm_signal(SIGHUP, intsig); 168438032Speter break; 168538032Speter } 168638032Speter 168738032Speter /* special considerations for FullName */ 168838032Speter if (FullName != NULL) 168938032Speter { 169038032Speter char *full = NULL; 169138032Speter 169238032Speter /* full names can't have newlines */ 169364562Sgshapiro if (strchr(FullName, '\n') != NULL) 169438032Speter { 169590792Sgshapiro full = newstr(denlstring(FullName, true, true)); 169673188Sgshapiro FullName = full; 169738032Speter } 169873188Sgshapiro 169938032Speter /* check for characters that may have to be quoted */ 170038032Speter if (!rfc822_string(FullName)) 170138032Speter { 170238032Speter /* 170338032Speter ** Quote a full name with special characters 170438032Speter ** as a comment so crackaddr() doesn't destroy 170538032Speter ** the name portion of the address. 170638032Speter */ 170773188Sgshapiro 170890792Sgshapiro FullName = addquotes(FullName, NULL); 170938032Speter if (full != NULL) 171090792Sgshapiro sm_free(full); /* XXX */ 171138032Speter } 171238032Speter } 171338032Speter 171438032Speter /* do heuristic mode adjustment */ 171538032Speter if (Verbose) 171638032Speter { 171738032Speter /* turn off noconnect option */ 171890792Sgshapiro setoption('c', "F", true, false, &BlankEnvelope); 171938032Speter 172038032Speter /* turn on interactive delivery */ 172190792Sgshapiro setoption('d', "", true, false, &BlankEnvelope); 172238032Speter } 172338032Speter 172442575Speter#ifdef VENDOR_CODE 172542575Speter /* check for vendor mismatch */ 172642575Speter if (VendorCode != VENDOR_CODE) 172742575Speter { 172842575Speter message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 172942575Speter getvendor(VENDOR_CODE), getvendor(VendorCode)); 173042575Speter } 173164562Sgshapiro#endif /* VENDOR_CODE */ 173264562Sgshapiro 173338032Speter /* check for out of date configuration level */ 173438032Speter if (ConfigLevel < MAXCONFIGLEVEL) 173538032Speter { 173638032Speter message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 173738032Speter Version, MAXCONFIGLEVEL, ConfigLevel); 173838032Speter } 173938032Speter 174038032Speter if (ConfigLevel < 3) 174190792Sgshapiro UseErrorsTo = true; 174238032Speter 174338032Speter /* set options that were previous macros */ 174438032Speter if (SmtpGreeting == NULL) 174538032Speter { 174690792Sgshapiro if (ConfigLevel < 7 && 174790792Sgshapiro (p = macvalue('e', &BlankEnvelope)) != NULL) 174838032Speter SmtpGreeting = newstr(p); 174938032Speter else 175038032Speter SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 175138032Speter } 175238032Speter if (UnixFromLine == NULL) 175338032Speter { 175490792Sgshapiro if (ConfigLevel < 7 && 175590792Sgshapiro (p = macvalue('l', &BlankEnvelope)) != NULL) 175638032Speter UnixFromLine = newstr(p); 175738032Speter else 175838032Speter UnixFromLine = "From \201g \201d"; 175938032Speter } 176064562Sgshapiro SmtpError[0] = '\0'; 176138032Speter 176238032Speter /* our name for SMTP codes */ 1763168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope); 176473188Sgshapiro if (jbuf[0] == '\0') 176590792Sgshapiro PSTRSET(MyHostName, "localhost"); 176673188Sgshapiro else 176790792Sgshapiro PSTRSET(MyHostName, jbuf); 176873188Sgshapiro if (strchr(MyHostName, '.') == NULL) 1769132943Sgshapiro message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?", 177073188Sgshapiro MyHostName); 177138032Speter 177238032Speter /* make certain that this name is part of the $=w class */ 177338032Speter setclass('w', MyHostName); 177438032Speter 177590792Sgshapiro /* fill in the structure of the *default* queue */ 177690792Sgshapiro st = stab("mqueue", ST_QUEUE, ST_FIND); 177790792Sgshapiro if (st == NULL) 177890792Sgshapiro syserr("No default queue (mqueue) defined"); 177990792Sgshapiro else 178090792Sgshapiro set_def_queueval(st->s_quegrp, true); 178190792Sgshapiro 178238032Speter /* the indices of built-in mailers */ 178338032Speter st = stab("local", ST_MAILER, ST_FIND); 178438032Speter if (st != NULL) 178538032Speter LocalMailer = st->s_mailer; 178638032Speter else if (OpMode != MD_TEST || !warn_C_flag) 178738032Speter syserr("No local mailer defined"); 178838032Speter 178938032Speter st = stab("prog", ST_MAILER, ST_FIND); 179038032Speter if (st == NULL) 179138032Speter syserr("No prog mailer defined"); 179238032Speter else 179338032Speter { 179438032Speter ProgMailer = st->s_mailer; 179538032Speter clrbitn(M_MUSER, ProgMailer->m_flags); 179638032Speter } 179738032Speter 179838032Speter st = stab("*file*", ST_MAILER, ST_FIND); 179938032Speter if (st == NULL) 180038032Speter syserr("No *file* mailer defined"); 180138032Speter else 180238032Speter { 180338032Speter FileMailer = st->s_mailer; 180438032Speter clrbitn(M_MUSER, FileMailer->m_flags); 180538032Speter } 180638032Speter 180738032Speter st = stab("*include*", ST_MAILER, ST_FIND); 180838032Speter if (st == NULL) 180938032Speter syserr("No *include* mailer defined"); 181038032Speter else 181138032Speter InclMailer = st->s_mailer; 181238032Speter 181338032Speter if (ConfigLevel < 6) 181438032Speter { 181538032Speter /* heuristic tweaking of local mailer for back compat */ 181638032Speter if (LocalMailer != NULL) 181738032Speter { 181838032Speter setbitn(M_ALIASABLE, LocalMailer->m_flags); 181938032Speter setbitn(M_HASPWENT, LocalMailer->m_flags); 182038032Speter setbitn(M_TRYRULESET5, LocalMailer->m_flags); 182138032Speter setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 182238032Speter setbitn(M_CHECKPROG, LocalMailer->m_flags); 182338032Speter setbitn(M_CHECKFILE, LocalMailer->m_flags); 182438032Speter setbitn(M_CHECKUDB, LocalMailer->m_flags); 182538032Speter } 182638032Speter if (ProgMailer != NULL) 182738032Speter setbitn(M_RUNASRCPT, ProgMailer->m_flags); 182838032Speter if (FileMailer != NULL) 182938032Speter setbitn(M_RUNASRCPT, FileMailer->m_flags); 183038032Speter } 183138032Speter if (ConfigLevel < 7) 183238032Speter { 183338032Speter if (LocalMailer != NULL) 183438032Speter setbitn(M_VRFY250, LocalMailer->m_flags); 183538032Speter if (ProgMailer != NULL) 183638032Speter setbitn(M_VRFY250, ProgMailer->m_flags); 183738032Speter if (FileMailer != NULL) 183838032Speter setbitn(M_VRFY250, FileMailer->m_flags); 183938032Speter } 184038032Speter 184138032Speter /* MIME Content-Types that cannot be transfer encoded */ 184238032Speter setclass('n', "multipart/signed"); 184338032Speter 184438032Speter /* MIME message/xxx subtypes that can be treated as messages */ 184538032Speter setclass('s', "rfc822"); 184638032Speter 184738032Speter /* MIME Content-Transfer-Encodings that can be encoded */ 184838032Speter setclass('e', "7bit"); 184938032Speter setclass('e', "8bit"); 185038032Speter setclass('e', "binary"); 185138032Speter 185238032Speter#ifdef USE_B_CLASS 185338032Speter /* MIME Content-Types that should be treated as binary */ 185438032Speter setclass('b', "image"); 185538032Speter setclass('b', "audio"); 185638032Speter setclass('b', "video"); 185738032Speter setclass('b', "application/octet-stream"); 185864562Sgshapiro#endif /* USE_B_CLASS */ 185938032Speter 186042575Speter /* MIME headers which have fields to check for overflow */ 186190792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition"); 186290792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-type"); 186342575Speter 186442575Speter /* MIME headers to check for length overflow */ 186590792Sgshapiro setclass(macid("{checkMIMETextHeaders}"), "content-description"); 186642575Speter 186742575Speter /* MIME headers to check for overflow and rebalance */ 186890792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-disposition"); 186990792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-id"); 187090792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding"); 187190792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-type"); 187290792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "mime-version"); 187342575Speter 187490792Sgshapiro /* Macros to save in the queue file -- don't remove any */ 187590792Sgshapiro setclass(macid("{persistentMacros}"), "r"); 187690792Sgshapiro setclass(macid("{persistentMacros}"), "s"); 187790792Sgshapiro setclass(macid("{persistentMacros}"), "_"); 187890792Sgshapiro setclass(macid("{persistentMacros}"), "{if_addr}"); 187990792Sgshapiro setclass(macid("{persistentMacros}"), "{daemon_flags}"); 188064562Sgshapiro 188138032Speter /* operate in queue directory */ 188290792Sgshapiro if (QueueDir == NULL || *QueueDir == '\0') 188338032Speter { 188438032Speter if (OpMode != MD_TEST) 188538032Speter { 188638032Speter syserr("QueueDirectory (Q) option must be set"); 188738032Speter ExitStat = EX_CONFIG; 188838032Speter } 188938032Speter } 189038032Speter else 189138032Speter { 189264562Sgshapiro if (OpMode != MD_TEST) 189390792Sgshapiro setup_queues(OpMode == MD_DAEMON); 189438032Speter } 189538032Speter 189638032Speter /* check host status directory for validity */ 189790792Sgshapiro if (HostStatDir != NULL && !path_is_dir(HostStatDir, false)) 189838032Speter { 189938032Speter /* cannot use this value */ 190090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 190190792Sgshapiro "Warning: Cannot use HostStatusDirectory = %s: %s\n", 190290792Sgshapiro HostStatDir, sm_errstring(errno)); 190338032Speter HostStatDir = NULL; 190438032Speter } 190538032Speter 190690792Sgshapiro if (OpMode == MD_QUEUERUN && 190790792Sgshapiro RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 190838032Speter { 190938032Speter struct stat stbuf; 191038032Speter 191138032Speter /* check to see if we own the queue directory */ 191238032Speter if (stat(".", &stbuf) < 0) 191338032Speter syserr("main: cannot stat %s", QueueDir); 191438032Speter if (stbuf.st_uid != RealUid) 191538032Speter { 191638032Speter /* nope, really a botch */ 191790792Sgshapiro HoldErrs = false; 191838032Speter usrerr("You do not have permission to process the queue"); 191990792Sgshapiro finis(false, true, EX_NOPERM); 192090792Sgshapiro /* NOTREACHED */ 192138032Speter } 192238032Speter } 192338032Speter 192490792Sgshapiro#if MILTER 192564562Sgshapiro /* sanity checks on milter filters */ 192664562Sgshapiro if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 192790792Sgshapiro { 192890792Sgshapiro milter_config(InputFilterList, InputFilters, MAXFILTERS); 192990792Sgshapiro setup_daemon_milters(); 193090792Sgshapiro } 193190792Sgshapiro#endif /* MILTER */ 193264562Sgshapiro 193390792Sgshapiro /* Convert queuegroup string to qgrp number */ 193490792Sgshapiro if (queuegroup != NULL) 193590792Sgshapiro { 193690792Sgshapiro qgrp = name2qid(queuegroup); 193790792Sgshapiro if (qgrp == NOQGRP) 193890792Sgshapiro { 193990792Sgshapiro HoldErrs = false; 194090792Sgshapiro usrerr("Queue group %s unknown", queuegroup); 194190792Sgshapiro finis(false, true, ExitStat); 194290792Sgshapiro /* NOTREACHED */ 194390792Sgshapiro } 194490792Sgshapiro } 194566494Sgshapiro 1946203004Sgshapiro /* if checking config or have had errors so far, exit now */ 1947203004Sgshapiro if (OpMode == MD_CHECKCONFIG || (ExitStat != EX_OK && OpMode != MD_TEST)) 194890792Sgshapiro { 194990792Sgshapiro finis(false, true, ExitStat); 195090792Sgshapiro /* NOTREACHED */ 195190792Sgshapiro } 195238032Speter 195390792Sgshapiro#if SASL 195490792Sgshapiro /* sendmail specific SASL initialization */ 195590792Sgshapiro sm_sasl_init(); 195690792Sgshapiro#endif /* SASL */ 195790792Sgshapiro 195838032Speter#if XDEBUG 195938032Speter checkfd012("before main() initmaps"); 196064562Sgshapiro#endif /* XDEBUG */ 196138032Speter 196238032Speter /* 196338032Speter ** Do operation-mode-dependent initialization. 196438032Speter */ 196538032Speter 196638032Speter switch (OpMode) 196738032Speter { 196838032Speter case MD_PRINT: 196938032Speter /* print the queue */ 197090792Sgshapiro HoldErrs = false; 1971203004Sgshapiro (void) dropenvelope(&BlankEnvelope, true, false); 197290792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 197390792Sgshapiro if (qgrp != NOQGRP) 197490792Sgshapiro { 197590792Sgshapiro int j; 197690792Sgshapiro 197790792Sgshapiro /* Selecting a particular queue group to run */ 197890792Sgshapiro for (j = 0; j < Queue[qgrp]->qg_numqueues; j++) 197990792Sgshapiro { 198090792Sgshapiro if (StopRequest) 198190792Sgshapiro stop_sendmail(); 198290792Sgshapiro (void) print_single_queue(qgrp, j); 198390792Sgshapiro } 198490792Sgshapiro finis(false, true, EX_OK); 198590792Sgshapiro /* NOTREACHED */ 198690792Sgshapiro } 198738032Speter printqueue(); 198890792Sgshapiro finis(false, true, EX_OK); 198990792Sgshapiro /* NOTREACHED */ 199042575Speter break; 199138032Speter 199290792Sgshapiro case MD_PRINTNQE: 199390792Sgshapiro /* print number of entries in queue */ 1994203004Sgshapiro (void) dropenvelope(&BlankEnvelope, true, false); 199590792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 199690792Sgshapiro printnqe(smioout, NULL); 199790792Sgshapiro finis(false, true, EX_OK); 199890792Sgshapiro /* NOTREACHED */ 199990792Sgshapiro break; 200090792Sgshapiro 200190792Sgshapiro case MD_QUEUERUN: 200290792Sgshapiro /* only handle quarantining here */ 200390792Sgshapiro if (quarantining == NULL) 200490792Sgshapiro break; 200590792Sgshapiro 200690792Sgshapiro if (QueueMode != QM_QUARANTINE && 200790792Sgshapiro QueueMode != QM_NORMAL) 200890792Sgshapiro { 200990792Sgshapiro HoldErrs = false; 201090792Sgshapiro usrerr("Can not use -Q with -q%c", QueueMode); 201190792Sgshapiro ExitStat = EX_USAGE; 201290792Sgshapiro finis(false, true, ExitStat); 201390792Sgshapiro /* NOTREACHED */ 201490792Sgshapiro } 201590792Sgshapiro quarantine_queue(quarantining, qgrp); 201690792Sgshapiro finis(false, true, EX_OK); 201790792Sgshapiro break; 201890792Sgshapiro 201938032Speter case MD_HOSTSTAT: 202090792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 202164562Sgshapiro (void) mci_traverse_persistent(mci_print_persistent, NULL); 202290792Sgshapiro finis(false, true, EX_OK); 202390792Sgshapiro /* NOTREACHED */ 202464562Sgshapiro break; 202538032Speter 202638032Speter case MD_PURGESTAT: 202764562Sgshapiro (void) mci_traverse_persistent(mci_purge_persistent, NULL); 202890792Sgshapiro finis(false, true, EX_OK); 202990792Sgshapiro /* NOTREACHED */ 203064562Sgshapiro break; 203138032Speter 203238032Speter case MD_INITALIAS: 203342575Speter /* initialize maps */ 203464562Sgshapiro initmaps(); 203590792Sgshapiro finis(false, true, ExitStat); 203690792Sgshapiro /* NOTREACHED */ 203742575Speter break; 203838032Speter 203938032Speter case MD_SMTP: 204038032Speter case MD_DAEMON: 204138032Speter /* reset DSN parameters */ 204238032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 204390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 204490792Sgshapiro macid("{dsn_notify}"), NULL); 204590792Sgshapiro BlankEnvelope.e_envid = NULL; 204690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 204790792Sgshapiro macid("{dsn_envid}"), NULL); 204890792Sgshapiro BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 204990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 205090792Sgshapiro macid("{dsn_ret}"), NULL); 205138032Speter 205242575Speter /* don't open maps for daemon -- done below in child */ 205338032Speter break; 205438032Speter } 205538032Speter 205638032Speter if (tTd(0, 15)) 205738032Speter { 205838032Speter /* print configuration table (or at least part of it) */ 205938032Speter if (tTd(0, 90)) 206038032Speter printrules(); 206138032Speter for (i = 0; i < MAXMAILERS; i++) 206238032Speter { 206338032Speter if (Mailer[i] != NULL) 2064132943Sgshapiro printmailer(sm_debug_file(), Mailer[i]); 206538032Speter } 206638032Speter } 206738032Speter 206838032Speter /* 206938032Speter ** Switch to the main envelope. 207038032Speter */ 207138032Speter 207290792Sgshapiro CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope, 207390792Sgshapiro sm_rpool_new_x(NULL)); 207438032Speter MainEnvelope.e_flags = BlankEnvelope.e_flags; 207538032Speter 207638032Speter /* 207738032Speter ** If test mode, read addresses from stdin and process. 207838032Speter */ 207938032Speter 208038032Speter if (OpMode == MD_TEST) 208138032Speter { 208290792Sgshapiro if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL))) 208338032Speter Verbose = 2; 208438032Speter 208538032Speter if (Verbose) 208638032Speter { 208790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 208890792Sgshapiro "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 208990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 209090792Sgshapiro "Enter <ruleset> <address>\n"); 209138032Speter } 209290792Sgshapiro macdefine(&(MainEnvelope.e_macro), A_PERM, 209390792Sgshapiro macid("{addr_type}"), "e r"); 209438032Speter for (;;) 209538032Speter { 209690792Sgshapiro SM_TRY 209790792Sgshapiro { 209890792Sgshapiro (void) sm_signal(SIGINT, intindebug); 209990792Sgshapiro (void) sm_releasesignal(SIGINT); 210090792Sgshapiro if (Verbose == 2) 210190792Sgshapiro (void) sm_io_fprintf(smioout, 210290792Sgshapiro SM_TIME_DEFAULT, 210390792Sgshapiro "> "); 210490792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 210590792Sgshapiro if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, 2106249729Sgshapiro sizeof(buf)) < 0) 210790792Sgshapiro testmodeline("/quit", &MainEnvelope); 210890792Sgshapiro p = strchr(buf, '\n'); 210990792Sgshapiro if (p != NULL) 211090792Sgshapiro *p = '\0'; 211190792Sgshapiro if (Verbose < 2) 211290792Sgshapiro (void) sm_io_fprintf(smioout, 211390792Sgshapiro SM_TIME_DEFAULT, 211490792Sgshapiro "> %s\n", buf); 211590792Sgshapiro testmodeline(buf, &MainEnvelope); 211690792Sgshapiro } 211790792Sgshapiro SM_EXCEPT(exc, "[!F]*") 211890792Sgshapiro { 211990792Sgshapiro /* 212090792Sgshapiro ** 8.10 just prints \n on interrupt. 212190792Sgshapiro ** I'm printing the exception here in case 212290792Sgshapiro ** sendmail is extended to raise additional 212390792Sgshapiro ** exceptions in this context. 212490792Sgshapiro */ 212590792Sgshapiro 212690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 212790792Sgshapiro "\n"); 212890792Sgshapiro sm_exc_print(exc, smioout); 212990792Sgshapiro } 213090792Sgshapiro SM_END_TRY 213138032Speter } 213238032Speter } 213338032Speter 213490792Sgshapiro#if STARTTLS 213590792Sgshapiro tls_ok = true; 2136168515Sgshapiro if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER || 2137168515Sgshapiro OpMode == MD_ARPAFTP) 213890792Sgshapiro { 213990792Sgshapiro /* check whether STARTTLS is turned off for the client */ 214090792Sgshapiro if (chkclientmodifiers(D_NOTLS)) 214190792Sgshapiro tls_ok = false; 214290792Sgshapiro } 214390792Sgshapiro else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON || 214490792Sgshapiro OpMode == MD_SMTP) 214590792Sgshapiro { 2146203004Sgshapiro /* check whether STARTTLS is turned off */ 2147203004Sgshapiro if (chkdaemonmodifiers(D_NOTLS) && chkclientmodifiers(D_NOTLS)) 214890792Sgshapiro tls_ok = false; 214990792Sgshapiro } 215090792Sgshapiro else /* other modes don't need STARTTLS */ 215190792Sgshapiro tls_ok = false; 215264562Sgshapiro 215390792Sgshapiro if (tls_ok) 215490792Sgshapiro { 215590792Sgshapiro /* basic TLS initialization */ 2156249729Sgshapiro tls_ok = init_tls_library(FipsMode); 2157249729Sgshapiro if (!tls_ok && FipsMode) 2158249729Sgshapiro { 2159249729Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2160249729Sgshapiro "ERROR: FIPSMode failed to initialize\n"); 2161249729Sgshapiro exit(EX_USAGE); 2162249729Sgshapiro } 216390792Sgshapiro } 216490792Sgshapiro 216590792Sgshapiro if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)) 216690792Sgshapiro { 216790792Sgshapiro /* disable TLS for client */ 216890792Sgshapiro setclttls(false); 216990792Sgshapiro } 217090792Sgshapiro#endif /* STARTTLS */ 217190792Sgshapiro 217264562Sgshapiro /* 217338032Speter ** If collecting stuff from the queue, go start doing that. 217438032Speter */ 217538032Speter 217664562Sgshapiro if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 217738032Speter { 217890792Sgshapiro pid_t pid = -1; 217990792Sgshapiro 218090792Sgshapiro#if STARTTLS 218190792Sgshapiro /* init TLS for client, ignore result for now */ 218290792Sgshapiro (void) initclttls(tls_ok); 218390792Sgshapiro#endif /* STARTTLS */ 218490792Sgshapiro 218590792Sgshapiro /* 218690792Sgshapiro ** The parent process of the caller of runqueue() needs 218790792Sgshapiro ** to stay around for a possible SIGTERM. The SIGTERM will 218890792Sgshapiro ** tell this process that all of the queue runners children 218990792Sgshapiro ** need to be sent SIGTERM as well. At the same time, we 219090792Sgshapiro ** want to return control to the command line. So we do an 219190792Sgshapiro ** extra fork(). 219290792Sgshapiro */ 219390792Sgshapiro 219490792Sgshapiro if (Verbose || foregroundqueue || (pid = fork()) <= 0) 219564562Sgshapiro { 219690792Sgshapiro /* 219790792Sgshapiro ** If the fork() failed we should still try to do 219890792Sgshapiro ** the queue run. If it succeeded then the child 219990792Sgshapiro ** is going to start the run and wait for all 220090792Sgshapiro ** of the children to finish. 220190792Sgshapiro */ 220290792Sgshapiro 220390792Sgshapiro if (pid == 0) 220490792Sgshapiro { 220590792Sgshapiro /* Reset global flags */ 220690792Sgshapiro RestartRequest = NULL; 220790792Sgshapiro ShutdownRequest = NULL; 220890792Sgshapiro PendingSignal = 0; 220990792Sgshapiro 221090792Sgshapiro /* disconnect from terminal */ 221190792Sgshapiro disconnect(2, CurEnv); 221290792Sgshapiro } 221390792Sgshapiro 221490792Sgshapiro CurrentPid = getpid(); 221590792Sgshapiro if (qgrp != NOQGRP) 221690792Sgshapiro { 2217110560Sgshapiro int rwgflags = RWG_NONE; 2218110560Sgshapiro 221990792Sgshapiro /* 222090792Sgshapiro ** To run a specific queue group mark it to 222190792Sgshapiro ** be run, select the work group it's in and 222290792Sgshapiro ** increment the work counter. 222390792Sgshapiro */ 222490792Sgshapiro 222594334Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 222694334Sgshapiro i++) 222794334Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 222894334Sgshapiro Queue[qgrp]->qg_nextrun = 0; 2229110560Sgshapiro if (Verbose) 2230110560Sgshapiro rwgflags |= RWG_VERBOSE; 2231110560Sgshapiro if (queuepersistent) 2232110560Sgshapiro rwgflags |= RWG_PERSISTENT; 2233110560Sgshapiro rwgflags |= RWG_FORCE; 223490792Sgshapiro (void) run_work_group(Queue[qgrp]->qg_wgrp, 2235110560Sgshapiro rwgflags); 223690792Sgshapiro } 223790792Sgshapiro else 223890792Sgshapiro (void) runqueue(false, Verbose, 223990792Sgshapiro queuepersistent, true); 224090792Sgshapiro 224190792Sgshapiro /* set the title to make it easier to find */ 224290792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 224390792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 224490792Sgshapiro while (CurChildren > 0) 224590792Sgshapiro { 224690792Sgshapiro int status; 224790792Sgshapiro pid_t ret; 224890792Sgshapiro 2249125820Sgshapiro errno = 0; 225090792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 2251125820Sgshapiro { 2252125820Sgshapiro if (errno == ECHILD) 2253125820Sgshapiro { 2254125820Sgshapiro /* 2255125820Sgshapiro ** Oops... something got messed 2256125820Sgshapiro ** up really bad. Waiting for 2257125820Sgshapiro ** non-existent children 2258125820Sgshapiro ** shouldn't happen. Let's get 2259125820Sgshapiro ** out of here. 2260125820Sgshapiro */ 2261125820Sgshapiro 2262125820Sgshapiro CurChildren = 0; 2263125820Sgshapiro break; 2264125820Sgshapiro } 226590792Sgshapiro continue; 2266125820Sgshapiro } 226790792Sgshapiro 2268125820Sgshapiro /* something is really really wrong */ 2269125820Sgshapiro if (errno == ECHILD) 2270125820Sgshapiro { 2271125820Sgshapiro sm_syslog(LOG_ERR, NOQID, 2272125820Sgshapiro "queue control process: lost all children: wait returned ECHILD"); 2273125820Sgshapiro break; 2274125820Sgshapiro } 2275125820Sgshapiro 227690792Sgshapiro /* Only drop when a child gives status */ 227790792Sgshapiro if (WIFSTOPPED(status)) 227890792Sgshapiro continue; 227990792Sgshapiro 228090792Sgshapiro proc_list_drop(ret, status, NULL); 228190792Sgshapiro } 228264562Sgshapiro } 228390792Sgshapiro finis(true, true, ExitStat); 228490792Sgshapiro /* NOTREACHED */ 228538032Speter } 228638032Speter 228771345Sgshapiro# if SASL 228871345Sgshapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 228971345Sgshapiro { 229090792Sgshapiro /* check whether AUTH is turned off for the server */ 229190792Sgshapiro if (!chkdaemonmodifiers(D_NOAUTH) && 229290792Sgshapiro (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 229371345Sgshapiro syserr("!sasl_server_init failed! [%s]", 229490792Sgshapiro sasl_errstring(i, NULL, NULL)); 229571345Sgshapiro } 229671345Sgshapiro# endif /* SASL */ 229771345Sgshapiro 229890792Sgshapiro if (OpMode == MD_SMTP) 229990792Sgshapiro { 230090792Sgshapiro proc_list_add(CurrentPid, "Sendmail SMTP Agent", 2301132943Sgshapiro PROC_DAEMON, 0, -1, NULL); 230290792Sgshapiro 230390792Sgshapiro /* clean up background delivery children */ 230490792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 230590792Sgshapiro } 230690792Sgshapiro 230738032Speter /* 230838032Speter ** If a daemon, wait for a request. 230938032Speter ** getrequests will always return in a child. 231038032Speter ** If we should also be processing the queue, start 231138032Speter ** doing it in background. 231238032Speter ** We check for any errors that might have happened 231338032Speter ** during startup. 231438032Speter */ 231538032Speter 231698841Sgshapiro if (OpMode == MD_DAEMON || QueueIntvl > 0) 231738032Speter { 231838032Speter char dtype[200]; 231938032Speter 2320161389Sgshapiro /* avoid cleanup in finis(), DaemonPid will be set below */ 2321161389Sgshapiro DaemonPid = 0; 232238032Speter if (!run_in_foreground && !tTd(99, 100)) 232338032Speter { 232438032Speter /* put us in background */ 232538032Speter i = fork(); 232638032Speter if (i < 0) 232738032Speter syserr("daemon: cannot fork"); 232838032Speter if (i != 0) 232990792Sgshapiro { 233090792Sgshapiro finis(false, true, EX_OK); 233190792Sgshapiro /* NOTREACHED */ 233290792Sgshapiro } 233338032Speter 233490792Sgshapiro /* 233590792Sgshapiro ** Initialize exception stack and default exception 233690792Sgshapiro ** handler for child process. 233790792Sgshapiro */ 233890792Sgshapiro 233990792Sgshapiro /* Reset global flags */ 234090792Sgshapiro RestartRequest = NULL; 234190792Sgshapiro RestartWorkGroup = false; 234290792Sgshapiro ShutdownRequest = NULL; 234390792Sgshapiro PendingSignal = 0; 234490792Sgshapiro CurrentPid = getpid(); 234590792Sgshapiro 234690792Sgshapiro sm_exc_newthread(fatal_error); 234790792Sgshapiro 234838032Speter /* disconnect from our controlling tty */ 234990792Sgshapiro disconnect(2, &MainEnvelope); 235038032Speter } 235138032Speter 235238032Speter dtype[0] = '\0'; 235338032Speter if (OpMode == MD_DAEMON) 2354161389Sgshapiro { 2355168515Sgshapiro (void) sm_strlcat(dtype, "+SMTP", sizeof(dtype)); 2356161389Sgshapiro DaemonPid = CurrentPid; 2357161389Sgshapiro } 235898841Sgshapiro if (QueueIntvl > 0) 235938032Speter { 236090792Sgshapiro (void) sm_strlcat2(dtype, 236190792Sgshapiro queuepersistent 236290792Sgshapiro ? "+persistent-queueing@" 236390792Sgshapiro : "+queueing@", 236490792Sgshapiro pintvl(QueueIntvl, true), 2365168515Sgshapiro sizeof(dtype)); 236638032Speter } 236738032Speter if (tTd(0, 1)) 2368168515Sgshapiro (void) sm_strlcat(dtype, "+debugging", sizeof(dtype)); 236938032Speter 237038032Speter sm_syslog(LOG_INFO, NOQID, 237164562Sgshapiro "starting daemon (%s): %s", Version, dtype + 1); 237290792Sgshapiro#if XLA 237338032Speter xla_create_file(); 237464562Sgshapiro#endif /* XLA */ 237538032Speter 237664562Sgshapiro /* save daemon type in a macro for possible PidFile use */ 237790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 237890792Sgshapiro macid("{daemon_info}"), dtype + 1); 237964562Sgshapiro 238064562Sgshapiro /* save queue interval in a macro for possible PidFile use */ 238190792Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 238290792Sgshapiro macid("{queue_interval}"), pintvl(QueueIntvl, true)); 238364562Sgshapiro 238490792Sgshapiro /* workaround: can't seem to release the signal in the parent */ 238590792Sgshapiro (void) sm_signal(SIGHUP, sighup); 238690792Sgshapiro (void) sm_releasesignal(SIGHUP); 238790792Sgshapiro (void) sm_signal(SIGTERM, sigterm); 238890792Sgshapiro 238998841Sgshapiro if (QueueIntvl > 0) 239038032Speter { 2391173340Sgshapiro#if _FFR_RUNPQG 2392173340Sgshapiro if (qgrp != NOQGRP) 2393173340Sgshapiro { 2394173340Sgshapiro int rwgflags = RWG_NONE; 239590792Sgshapiro 2396173340Sgshapiro /* 2397173340Sgshapiro ** To run a specific queue group mark it to 2398173340Sgshapiro ** be run, select the work group it's in and 2399173340Sgshapiro ** increment the work counter. 2400173340Sgshapiro */ 2401173340Sgshapiro 2402173340Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 2403173340Sgshapiro i++) 2404173340Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 2405173340Sgshapiro Queue[qgrp]->qg_nextrun = 0; 2406173340Sgshapiro if (Verbose) 2407173340Sgshapiro rwgflags |= RWG_VERBOSE; 2408173340Sgshapiro if (queuepersistent) 2409173340Sgshapiro rwgflags |= RWG_PERSISTENT; 2410173340Sgshapiro rwgflags |= RWG_FORCE; 2411173340Sgshapiro (void) run_work_group(Queue[qgrp]->qg_wgrp, 2412173340Sgshapiro rwgflags); 2413173340Sgshapiro } 2414173340Sgshapiro else 2415173340Sgshapiro#endif /* _FFR_RUNPQG */ 2416173340Sgshapiro (void) runqueue(true, false, queuepersistent, 2417173340Sgshapiro true); 2418173340Sgshapiro 241990792Sgshapiro /* 242090792Sgshapiro ** If queuepersistent but not in daemon mode then 242190792Sgshapiro ** we're going to do the queue runner monitoring here. 242290792Sgshapiro ** If in daemon mode then the monitoring will happen 242390792Sgshapiro ** elsewhere. 242490792Sgshapiro */ 242590792Sgshapiro 242690792Sgshapiro if (OpMode != MD_DAEMON && queuepersistent) 242790792Sgshapiro { 2428132943Sgshapiro /* 2429132943Sgshapiro ** Write the pid to file 2430132943Sgshapiro ** XXX Overwrites sendmail.pid 2431132943Sgshapiro */ 2432132943Sgshapiro 2433132943Sgshapiro log_sendmail_pid(&MainEnvelope); 2434132943Sgshapiro 243590792Sgshapiro /* set the title to make it easier to find */ 243690792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 243790792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 243890792Sgshapiro while (CurChildren > 0) 243990792Sgshapiro { 244090792Sgshapiro int status; 244190792Sgshapiro pid_t ret; 244290792Sgshapiro int group; 244390792Sgshapiro 2444120256Sgshapiro CHECK_RESTART; 2445125820Sgshapiro errno = 0; 244690792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 2447125820Sgshapiro { 2448125820Sgshapiro /* 2449125820Sgshapiro ** Waiting for non-existent 2450125820Sgshapiro ** children shouldn't happen. 2451125820Sgshapiro ** Let's get out of here if 2452125820Sgshapiro ** it occurs. 2453125820Sgshapiro */ 2454125820Sgshapiro 2455125820Sgshapiro if (errno == ECHILD) 2456125820Sgshapiro { 2457125820Sgshapiro CurChildren = 0; 2458125820Sgshapiro break; 2459125820Sgshapiro } 246090792Sgshapiro continue; 2461125820Sgshapiro } 246290792Sgshapiro 2463125820Sgshapiro /* something is really really wrong */ 2464125820Sgshapiro if (errno == ECHILD) 2465125820Sgshapiro { 2466125820Sgshapiro sm_syslog(LOG_ERR, NOQID, 2467125820Sgshapiro "persistent queue runner control process: lost all children: wait returned ECHILD"); 2468125820Sgshapiro break; 2469125820Sgshapiro } 2470125820Sgshapiro 247190792Sgshapiro if (WIFSTOPPED(status)) 247290792Sgshapiro continue; 247390792Sgshapiro 247490792Sgshapiro /* Probe only on a child status */ 247590792Sgshapiro proc_list_drop(ret, status, &group); 247690792Sgshapiro 247790792Sgshapiro if (WIFSIGNALED(status)) 247890792Sgshapiro { 247990792Sgshapiro if (WCOREDUMP(status)) 248090792Sgshapiro { 248190792Sgshapiro sm_syslog(LOG_ERR, NOQID, 248290792Sgshapiro "persistent queue runner=%d core dumped, signal=%d", 248390792Sgshapiro group, WTERMSIG(status)); 248490792Sgshapiro 2485120256Sgshapiro /* don't restart this */ 2486120256Sgshapiro mark_work_group_restart( 2487120256Sgshapiro group, -1); 248890792Sgshapiro continue; 248990792Sgshapiro } 249090792Sgshapiro 249190792Sgshapiro sm_syslog(LOG_ERR, NOQID, 2492168515Sgshapiro "persistent queue runner=%d died, pid=%ld, signal=%d", 2493168515Sgshapiro group, (long) ret, 2494168515Sgshapiro WTERMSIG(status)); 249590792Sgshapiro } 249690792Sgshapiro 249790792Sgshapiro /* 249890792Sgshapiro ** When debugging active, don't 249990792Sgshapiro ** restart the persistent queues. 250090792Sgshapiro ** But do log this as info. 250190792Sgshapiro */ 250290792Sgshapiro 250390792Sgshapiro if (sm_debug_active(&DebugNoPRestart, 250490792Sgshapiro 1)) 250590792Sgshapiro { 250690792Sgshapiro sm_syslog(LOG_DEBUG, NOQID, 250790792Sgshapiro "persistent queue runner=%d, exited", 250890792Sgshapiro group); 2509120256Sgshapiro mark_work_group_restart(group, 2510120256Sgshapiro -1); 251190792Sgshapiro } 2512168515Sgshapiro CHECK_RESTART; 251390792Sgshapiro } 251490792Sgshapiro finis(true, true, ExitStat); 251590792Sgshapiro /* NOTREACHED */ 251690792Sgshapiro } 251790792Sgshapiro 251838032Speter if (OpMode != MD_DAEMON) 251938032Speter { 252090792Sgshapiro char qtype[200]; 252190792Sgshapiro 252290792Sgshapiro /* 252390792Sgshapiro ** Write the pid to file 252490792Sgshapiro ** XXX Overwrites sendmail.pid 252590792Sgshapiro */ 252690792Sgshapiro 252790792Sgshapiro log_sendmail_pid(&MainEnvelope); 252890792Sgshapiro 252990792Sgshapiro /* set the title to make it easier to find */ 253090792Sgshapiro qtype[0] = '\0'; 2531168515Sgshapiro (void) sm_strlcpyn(qtype, sizeof(qtype), 4, 253290792Sgshapiro "Queue runner@", 253390792Sgshapiro pintvl(QueueIntvl, true), 253490792Sgshapiro " for ", 253590792Sgshapiro QueueDir); 253690792Sgshapiro sm_setproctitle(true, CurEnv, qtype); 253738032Speter for (;;) 253838032Speter { 253964562Sgshapiro (void) pause(); 2540132943Sgshapiro 2541120256Sgshapiro CHECK_RESTART; 2542132943Sgshapiro 254390792Sgshapiro if (doqueuerun()) 254490792Sgshapiro (void) runqueue(true, false, 254590792Sgshapiro false, false); 254638032Speter } 254738032Speter } 254838032Speter } 2549203004Sgshapiro (void) dropenvelope(&MainEnvelope, true, false); 255038032Speter 255190792Sgshapiro#if STARTTLS 255264562Sgshapiro /* init TLS for server, ignore result for now */ 255390792Sgshapiro (void) initsrvtls(tls_ok); 255490792Sgshapiro#endif /* STARTTLS */ 2555110560Sgshapiro 255690792Sgshapiro nextreq: 255790792Sgshapiro p_flags = getrequests(&MainEnvelope); 255838032Speter 255938032Speter /* drop privileges */ 256090792Sgshapiro (void) drop_privileges(false); 256138032Speter 256238032Speter /* 256338032Speter ** Get authentication data 256490792Sgshapiro ** Set _ macro in BlankEnvelope before calling newenvelope(). 256538032Speter */ 256638032Speter 256790792Sgshapiro authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 256890792Sgshapiro NULL), &forged); 256990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 2570244833Sgshapiro if (tTd(75, 9)) 2571244833Sgshapiro sm_syslog(LOG_INFO, NOQID, 2572244833Sgshapiro "main: where=after_getauthinfo, RealHostAddr=%s", 2573244833Sgshapiro anynet_ntoa(&RealHostAddr)); 257490792Sgshapiro 257590792Sgshapiro /* at this point we are in a child: reset state */ 257690792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 257790792Sgshapiro (void) newenvelope(&MainEnvelope, &MainEnvelope, 257890792Sgshapiro sm_rpool_new_x(NULL)); 257938032Speter } 258038032Speter 258164562Sgshapiro if (LogLevel > 9) 258264562Sgshapiro { 258364562Sgshapiro /* log connection information */ 2584110560Sgshapiro sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo); 258564562Sgshapiro } 258664562Sgshapiro 258738032Speter /* 258838032Speter ** If running SMTP protocol, start collecting and executing 258938032Speter ** commands. This will never return. 259038032Speter */ 259138032Speter 259238032Speter if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 259338032Speter { 259438032Speter char pbuf[20]; 259538032Speter 259638032Speter /* 259738032Speter ** Save some macros for check_* rulesets. 259838032Speter */ 259938032Speter 260038032Speter if (forged) 260138032Speter { 260238032Speter char ipbuf[103]; 260338032Speter 2604168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), "[%.100s]", 260590792Sgshapiro anynet_ntoa(&RealHostAddr)); 260690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 260790792Sgshapiro macid("{client_name}"), ipbuf); 260838032Speter } 260938032Speter else 261090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 261190792Sgshapiro macid("{client_name}"), RealHostName); 2612132943Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 2613132943Sgshapiro macid("{client_ptr}"), RealHostName); 261490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 261590792Sgshapiro macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 261690792Sgshapiro sm_getla(); 261738032Speter 261890792Sgshapiro switch (RealHostAddr.sa.sa_family) 261964562Sgshapiro { 262090792Sgshapiro#if NETINET 262164562Sgshapiro case AF_INET: 2622168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", 262390792Sgshapiro RealHostAddr.sin.sin_port); 262464562Sgshapiro break; 262590792Sgshapiro#endif /* NETINET */ 262690792Sgshapiro#if NETINET6 262764562Sgshapiro case AF_INET6: 2628168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", 262990792Sgshapiro RealHostAddr.sin6.sin6_port); 263064562Sgshapiro break; 263190792Sgshapiro#endif /* NETINET6 */ 263264562Sgshapiro default: 2633168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "0"); 263464562Sgshapiro break; 263564562Sgshapiro } 263690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 263790792Sgshapiro macid("{client_port}"), pbuf); 263842575Speter 263938032Speter if (OpMode == MD_DAEMON) 264038032Speter { 2641168515Sgshapiro ENVELOPE *saved_env; 2642168515Sgshapiro 264338032Speter /* validate the connection */ 264490792Sgshapiro HoldErrs = true; 2645168515Sgshapiro saved_env = CurEnv; 2646168515Sgshapiro CurEnv = &BlankEnvelope; 264738032Speter nullserver = validate_connection(&RealHostAddr, 2648132943Sgshapiro macvalue(macid("{client_name}"), 2649168515Sgshapiro &BlankEnvelope), 2650168515Sgshapiro &BlankEnvelope); 2651168515Sgshapiro if (bitset(EF_DISCARD, BlankEnvelope.e_flags)) 2652168515Sgshapiro MainEnvelope.e_flags |= EF_DISCARD; 2653168515Sgshapiro CurEnv = saved_env; 265490792Sgshapiro HoldErrs = false; 265538032Speter } 265664562Sgshapiro else if (p_flags == NULL) 265764562Sgshapiro { 2658168515Sgshapiro p_flags = (BITMAP256 *) xalloc(sizeof(*p_flags)); 265964562Sgshapiro clrbitmap(p_flags); 266064562Sgshapiro } 266190792Sgshapiro#if STARTTLS 266264562Sgshapiro if (OpMode == MD_SMTP) 266390792Sgshapiro (void) initsrvtls(tls_ok); 266490792Sgshapiro#endif /* STARTTLS */ 266571345Sgshapiro 266690792Sgshapiro /* turn off profiling */ 266790792Sgshapiro SM_PROF(1); 266890792Sgshapiro smtp(nullserver, *p_flags, &MainEnvelope); 2669110560Sgshapiro 2670110560Sgshapiro if (tTd(93, 100)) 2671110560Sgshapiro { 2672110560Sgshapiro /* turn off profiling */ 2673110560Sgshapiro SM_PROF(0); 2674110560Sgshapiro if (OpMode == MD_DAEMON) 2675110560Sgshapiro goto nextreq; 2676110560Sgshapiro } 267738032Speter } 267838032Speter 267990792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 268090792Sgshapiro clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 268138032Speter if (OpMode == MD_VERIFY) 268238032Speter { 268390792Sgshapiro set_delivery_mode(SM_VERIFY, &MainEnvelope); 268438032Speter PostMasterCopy = NULL; 268538032Speter } 268638032Speter else 268738032Speter { 268838032Speter /* interactive -- all errors are global */ 268990792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 269038032Speter } 269138032Speter 269238032Speter /* 269338032Speter ** Do basic system initialization and set the sender 269438032Speter */ 269538032Speter 269690792Sgshapiro initsys(&MainEnvelope); 269790792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 269890792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 269990792Sgshapiro setsender(from, &MainEnvelope, NULL, '\0', false); 270064562Sgshapiro if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 270190792Sgshapiro (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 270290792Sgshapiro strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 270364562Sgshapiro { 270490792Sgshapiro auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 270590792Sgshapiro RealUserName, from, warn_f_flag); 270664562Sgshapiro#if SASL 270790792Sgshapiro auth = false; 270864562Sgshapiro#endif /* SASL */ 270964562Sgshapiro } 271064562Sgshapiro if (auth) 271164562Sgshapiro { 271264562Sgshapiro char *fv; 271364562Sgshapiro 271464562Sgshapiro /* set the initial sender for AUTH= to $f@$j */ 271590792Sgshapiro fv = macvalue('f', &MainEnvelope); 271664562Sgshapiro if (fv == NULL || *fv == '\0') 271790792Sgshapiro MainEnvelope.e_auth_param = NULL; 271864562Sgshapiro else 271964562Sgshapiro { 272064562Sgshapiro if (strchr(fv, '@') == NULL) 272164562Sgshapiro { 272290792Sgshapiro i = strlen(fv) + strlen(macvalue('j', 272390792Sgshapiro &MainEnvelope)) + 2; 272490792Sgshapiro p = sm_malloc_x(i); 272590792Sgshapiro (void) sm_strlcpyn(p, i, 3, fv, "@", 272690792Sgshapiro macvalue('j', 272790792Sgshapiro &MainEnvelope)); 272864562Sgshapiro } 272964562Sgshapiro else 273090792Sgshapiro p = sm_strdup_x(fv); 273190792Sgshapiro MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 273290792Sgshapiro xtextify(p, "=")); 273390792Sgshapiro sm_free(p); /* XXX */ 273464562Sgshapiro } 273564562Sgshapiro } 273690792Sgshapiro if (macvalue('s', &MainEnvelope) == NULL) 273790792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 273838032Speter 273990792Sgshapiro av = argv + optind; 274038032Speter if (*av == NULL && !GrabTo) 274138032Speter { 274290792Sgshapiro MainEnvelope.e_to = NULL; 274390792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 274490792Sgshapiro HoldErrs = false; 274590792Sgshapiro SuperSafe = SAFE_NO; 274638032Speter usrerr("Recipient names must be specified"); 274738032Speter 274838032Speter /* collect body for UUCP return */ 274938032Speter if (OpMode != MD_VERIFY) 2750120256Sgshapiro collect(InChannel, false, NULL, &MainEnvelope, true); 275190792Sgshapiro finis(true, true, EX_USAGE); 275290792Sgshapiro /* NOTREACHED */ 275338032Speter } 275438032Speter 275538032Speter /* 275638032Speter ** Scan argv and deliver the message to everyone. 275738032Speter */ 275838032Speter 275990792Sgshapiro save_val = LogUsrErrs; 276090792Sgshapiro LogUsrErrs = true; 276190792Sgshapiro sendtoargv(av, &MainEnvelope); 276290792Sgshapiro LogUsrErrs = save_val; 276338032Speter 276438032Speter /* if we have had errors sofar, arrange a meaningful exit stat */ 276538032Speter if (Errors > 0 && ExitStat == EX_OK) 276638032Speter ExitStat = EX_USAGE; 276738032Speter 276838032Speter#if _FFR_FIX_DASHT 276938032Speter /* 277038032Speter ** If using -t, force not sending to argv recipients, even 277138032Speter ** if they are mentioned in the headers. 277238032Speter */ 277338032Speter 277438032Speter if (GrabTo) 277538032Speter { 277638032Speter ADDRESS *q; 277764562Sgshapiro 277890792Sgshapiro for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 277964562Sgshapiro q->q_state = QS_REMOVED; 278038032Speter } 278164562Sgshapiro#endif /* _FFR_FIX_DASHT */ 278238032Speter 278338032Speter /* 278438032Speter ** Read the input mail. 278538032Speter */ 278638032Speter 278790792Sgshapiro MainEnvelope.e_to = NULL; 278838032Speter if (OpMode != MD_VERIFY || GrabTo) 278938032Speter { 279090792Sgshapiro int savederrors; 279190792Sgshapiro unsigned long savedflags; 279238032Speter 279390792Sgshapiro /* 279490792Sgshapiro ** workaround for compiler warning on Irix: 279590792Sgshapiro ** do not initialize variable in the definition, but 279690792Sgshapiro ** later on: 279790792Sgshapiro ** warning(1548): transfer of control bypasses 279890792Sgshapiro ** initialization of: 279990792Sgshapiro ** variable "savederrors" (declared at line 2570) 280090792Sgshapiro ** variable "savedflags" (declared at line 2571) 280190792Sgshapiro ** goto giveup; 280290792Sgshapiro */ 280390792Sgshapiro 280490792Sgshapiro savederrors = Errors; 280590792Sgshapiro savedflags = MainEnvelope.e_flags & EF_FATALERRS; 280690792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 280790792Sgshapiro MainEnvelope.e_flags &= ~EF_FATALERRS; 280864562Sgshapiro Errors = 0; 280964562Sgshapiro buffer_errors(); 2810120256Sgshapiro collect(InChannel, false, NULL, &MainEnvelope, true); 281138032Speter 281264562Sgshapiro /* header checks failed */ 281364562Sgshapiro if (Errors > 0) 281464562Sgshapiro { 281590792Sgshapiro giveup: 281690792Sgshapiro if (!GrabTo) 281764562Sgshapiro { 281890792Sgshapiro /* Log who the mail would have gone to */ 281990792Sgshapiro logundelrcpts(&MainEnvelope, 282090792Sgshapiro MainEnvelope.e_message, 282190792Sgshapiro 8, false); 282264562Sgshapiro } 282390792Sgshapiro flush_errors(true); 282490792Sgshapiro finis(true, true, ExitStat); 282564562Sgshapiro /* NOTREACHED */ 282664562Sgshapiro return -1; 282764562Sgshapiro } 282864562Sgshapiro 282938032Speter /* bail out if message too large */ 283090792Sgshapiro if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 283138032Speter { 283290792Sgshapiro finis(true, true, ExitStat != EX_OK ? ExitStat 283390792Sgshapiro : EX_DATAERR); 283464562Sgshapiro /* NOTREACHED */ 283538032Speter return -1; 283638032Speter } 283798121Sgshapiro 283898121Sgshapiro /* set message size */ 2839168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", 2840244833Sgshapiro PRT_NONNEGL(MainEnvelope.e_msgsize)); 284198121Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 284298121Sgshapiro macid("{msg_size}"), buf); 284398121Sgshapiro 284464562Sgshapiro Errors = savederrors; 284590792Sgshapiro MainEnvelope.e_flags |= savedflags; 284638032Speter } 284738032Speter errno = 0; 284838032Speter 284938032Speter if (tTd(1, 1)) 285090792Sgshapiro sm_dprintf("From person = \"%s\"\n", 285190792Sgshapiro MainEnvelope.e_from.q_paddr); 285238032Speter 285390792Sgshapiro /* Check if quarantining stats should be updated */ 285490792Sgshapiro if (MainEnvelope.e_quarmsg != NULL) 285590792Sgshapiro markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 285690792Sgshapiro 285738032Speter /* 285838032Speter ** Actually send everything. 285938032Speter ** If verifying, just ack. 286038032Speter */ 286138032Speter 286290792Sgshapiro if (Errors == 0) 286338032Speter { 286490792Sgshapiro if (!split_by_recipient(&MainEnvelope) && 286590792Sgshapiro bitset(EF_FATALERRS, MainEnvelope.e_flags)) 286690792Sgshapiro goto giveup; 286738032Speter } 286890792Sgshapiro 286990792Sgshapiro /* make sure we deliver at least the first envelope */ 287090792Sgshapiro i = FastSplit > 0 ? 0 : -1; 287190792Sgshapiro for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 287290792Sgshapiro { 287390792Sgshapiro ENVELOPE *next; 287490792Sgshapiro 287590792Sgshapiro e->e_from.q_state = QS_SENDER; 287690792Sgshapiro if (tTd(1, 5)) 287790792Sgshapiro { 287890792Sgshapiro sm_dprintf("main[%d]: QS_SENDER ", i); 2879132943Sgshapiro printaddr(sm_debug_file(), &e->e_from, false); 288090792Sgshapiro } 288190792Sgshapiro e->e_to = NULL; 288290792Sgshapiro sm_getla(); 288390792Sgshapiro GrabTo = false; 288464562Sgshapiro#if NAMED_BIND 288590792Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 288690792Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 288764562Sgshapiro#endif /* NAMED_BIND */ 288890792Sgshapiro next = e->e_sibling; 288990792Sgshapiro e->e_sibling = NULL; 289038032Speter 289190792Sgshapiro /* after FastSplit envelopes: queue up */ 289290792Sgshapiro sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 289390792Sgshapiro e->e_sibling = next; 289490792Sgshapiro } 289590792Sgshapiro 289638032Speter /* 289738032Speter ** All done. 289838032Speter ** Don't send return error message if in VERIFY mode. 289938032Speter */ 290038032Speter 290190792Sgshapiro finis(true, true, ExitStat); 290264562Sgshapiro /* NOTREACHED */ 290364562Sgshapiro return ExitStat; 290438032Speter} 290590792Sgshapiro/* 290677349Sgshapiro** STOP_SENDMAIL -- Stop the running program 290777349Sgshapiro** 290877349Sgshapiro** Parameters: 290977349Sgshapiro** none. 291077349Sgshapiro** 291177349Sgshapiro** Returns: 291277349Sgshapiro** none. 291377349Sgshapiro** 291477349Sgshapiro** Side Effects: 291577349Sgshapiro** exits. 291677349Sgshapiro*/ 291738032Speter 291877349Sgshapirovoid 291977349Sgshapirostop_sendmail() 292077349Sgshapiro{ 292177349Sgshapiro /* reset uid for process accounting */ 292277349Sgshapiro endpwent(); 292377349Sgshapiro (void) setuid(RealUid); 292477349Sgshapiro exit(EX_OK); 292577349Sgshapiro} 292690792Sgshapiro/* 292738032Speter** FINIS -- Clean up and exit. 292838032Speter** 292938032Speter** Parameters: 293042575Speter** drop -- whether or not to drop CurEnv envelope 293190792Sgshapiro** cleanup -- call exit() or _exit()? 293242575Speter** exitstat -- exit status to use for exit() call 293338032Speter** 293438032Speter** Returns: 293538032Speter** never 293638032Speter** 293738032Speter** Side Effects: 293838032Speter** exits sendmail 293938032Speter*/ 294038032Speter 294138032Spetervoid 294290792Sgshapirofinis(drop, cleanup, exitstat) 294342575Speter bool drop; 294490792Sgshapiro bool cleanup; 294542575Speter volatile int exitstat; 294638032Speter{ 2947132943Sgshapiro char pidpath[MAXPATHLEN]; 2948159609Sgshapiro pid_t pid; 294998121Sgshapiro 295077349Sgshapiro /* Still want to process new timeouts added below */ 295190792Sgshapiro sm_clear_events(); 295290792Sgshapiro (void) sm_releasesignal(SIGALRM); 295342575Speter 295438032Speter if (tTd(2, 1)) 295538032Speter { 295690792Sgshapiro sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 295790792Sgshapiro exitstat, 295890792Sgshapiro CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 295938032Speter printenvflags(CurEnv); 296038032Speter } 296138032Speter if (tTd(2, 9)) 296290792Sgshapiro printopenfds(false); 296338032Speter 296490792Sgshapiro SM_TRY 296590792Sgshapiro /* 296690792Sgshapiro ** Clean up. This might raise E:mta.quickabort 296790792Sgshapiro */ 296838032Speter 296990792Sgshapiro /* clean up temp files */ 297090792Sgshapiro CurEnv->e_to = NULL; 297190792Sgshapiro if (drop) 297290792Sgshapiro { 297390792Sgshapiro if (CurEnv->e_id != NULL) 297490792Sgshapiro { 2975203004Sgshapiro int r; 2976203004Sgshapiro 2977203004Sgshapiro r = dropenvelope(CurEnv, true, false); 2978203004Sgshapiro if (exitstat == EX_OK) 2979203004Sgshapiro exitstat = r; 298090792Sgshapiro sm_rpool_free(CurEnv->e_rpool); 298190792Sgshapiro CurEnv->e_rpool = NULL; 2982161389Sgshapiro 2983168515Sgshapiro /* these may have pointed to the rpool */ 2984161389Sgshapiro CurEnv->e_to = NULL; 2985168515Sgshapiro CurEnv->e_message = NULL; 2986168515Sgshapiro CurEnv->e_statmsg = NULL; 2987168515Sgshapiro CurEnv->e_quarmsg = NULL; 2988168515Sgshapiro CurEnv->e_bodytype = NULL; 2989168515Sgshapiro CurEnv->e_id = NULL; 2990168515Sgshapiro CurEnv->e_envid = NULL; 2991168515Sgshapiro CurEnv->e_auth_param = NULL; 299290792Sgshapiro } 299390792Sgshapiro else 299490792Sgshapiro poststats(StatFile); 299590792Sgshapiro } 299638032Speter 299790792Sgshapiro /* flush any cached connections */ 299890792Sgshapiro mci_flush(true, NULL); 299938032Speter 300090792Sgshapiro /* close maps belonging to this pid */ 300190792Sgshapiro closemaps(false); 300242575Speter 300364562Sgshapiro#if USERDB 300490792Sgshapiro /* close UserDatabase */ 300590792Sgshapiro _udbx_close(); 300664562Sgshapiro#endif /* USERDB */ 300742575Speter 300890792Sgshapiro#if SASL 300990792Sgshapiro stop_sasl_client(); 301090792Sgshapiro#endif /* SASL */ 301190792Sgshapiro 301290792Sgshapiro#if XLA 301390792Sgshapiro /* clean up extended load average stuff */ 301490792Sgshapiro xla_all_end(); 301564562Sgshapiro#endif /* XLA */ 301638032Speter 301790792Sgshapiro SM_FINALLY 301890792Sgshapiro /* 301990792Sgshapiro ** And exit. 302090792Sgshapiro */ 302138032Speter 302290792Sgshapiro if (LogLevel > 78) 302390792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 302490792Sgshapiro (int) CurrentPid); 302590792Sgshapiro if (exitstat == EX_TEMPFAIL || 302690792Sgshapiro CurEnv->e_errormode == EM_BERKNET) 302790792Sgshapiro exitstat = EX_OK; 302864562Sgshapiro 302990792Sgshapiro /* XXX clean up queues and related data structures */ 303090792Sgshapiro cleanup_queues(); 3031159609Sgshapiro pid = getpid(); 303290792Sgshapiro#if SM_CONF_SHM 3033159609Sgshapiro cleanup_shm(DaemonPid == pid); 303490792Sgshapiro#endif /* SM_CONF_SHM */ 303590792Sgshapiro 3036132943Sgshapiro /* close locked pid file */ 3037132943Sgshapiro close_sendmail_pid(); 3038132943Sgshapiro 3039159609Sgshapiro if (DaemonPid == pid || PidFilePid == pid) 3040132943Sgshapiro { 3041132943Sgshapiro /* blow away the pid file */ 3042168515Sgshapiro expand(PidFile, pidpath, sizeof(pidpath), CurEnv); 3043132943Sgshapiro (void) unlink(pidpath); 3044132943Sgshapiro } 3045132943Sgshapiro 304690792Sgshapiro /* reset uid for process accounting */ 304790792Sgshapiro endpwent(); 304890792Sgshapiro sm_mbdb_terminate(); 3049157001Sgshapiro#if _FFR_MEMSTAT 3050157001Sgshapiro (void) sm_memstat_close(); 3051157001Sgshapiro#endif /* _FFR_MEMSTAT */ 305290792Sgshapiro (void) setuid(RealUid); 305390792Sgshapiro#if SM_HEAP_CHECK 305490792Sgshapiro /* dump the heap, if we are checking for memory leaks */ 305590792Sgshapiro if (sm_debug_active(&SmHeapCheck, 2)) 305690792Sgshapiro sm_heap_report(smioout, 305790792Sgshapiro sm_debug_level(&SmHeapCheck) - 1); 305890792Sgshapiro#endif /* SM_HEAP_CHECK */ 305990792Sgshapiro if (sm_debug_active(&SmXtrapReport, 1)) 306090792Sgshapiro sm_dprintf("xtrap count = %d\n", SmXtrapCount); 306190792Sgshapiro if (cleanup) 306290792Sgshapiro exit(exitstat); 306390792Sgshapiro else 306490792Sgshapiro _exit(exitstat); 306590792Sgshapiro SM_END_TRY 306638032Speter} 306790792Sgshapiro/* 306890792Sgshapiro** INTINDEBUG -- signal handler for SIGINT in -bt mode 306977349Sgshapiro** 307077349Sgshapiro** Parameters: 307190792Sgshapiro** sig -- incoming signal. 307290792Sgshapiro** 307390792Sgshapiro** Returns: 307490792Sgshapiro** none. 307590792Sgshapiro** 307690792Sgshapiro** Side Effects: 307790792Sgshapiro** longjmps back to test mode loop. 307890792Sgshapiro** 307990792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 308090792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 308190792Sgshapiro** DOING. 308290792Sgshapiro*/ 308390792Sgshapiro 308490792Sgshapiro/* Type of an exception generated on SIGINT during address test mode. */ 308590792Sgshapirostatic const SM_EXC_TYPE_T EtypeInterrupt = 308690792Sgshapiro{ 308790792Sgshapiro SmExcTypeMagic, 308890792Sgshapiro "S:mta.interrupt", 308990792Sgshapiro "", 309090792Sgshapiro sm_etype_printf, 309190792Sgshapiro "interrupt", 309290792Sgshapiro}; 309390792Sgshapiro 309490792Sgshapiro/* ARGSUSED */ 309590792Sgshapirostatic SIGFUNC_DECL 309690792Sgshapirointindebug(sig) 309790792Sgshapiro int sig; 309890792Sgshapiro{ 309990792Sgshapiro int save_errno = errno; 310090792Sgshapiro 310190792Sgshapiro FIX_SYSV_SIGNAL(sig, intindebug); 310290792Sgshapiro errno = save_errno; 310390792Sgshapiro CHECK_CRITICAL(sig); 310490792Sgshapiro errno = save_errno; 310590792Sgshapiro sm_exc_raisenew_x(&EtypeInterrupt); 310690792Sgshapiro errno = save_errno; 310790792Sgshapiro return SIGFUNC_RETURN; 310890792Sgshapiro} 310990792Sgshapiro/* 311090792Sgshapiro** SIGTERM -- SIGTERM handler for the daemon 311190792Sgshapiro** 311290792Sgshapiro** Parameters: 311377349Sgshapiro** sig -- signal number. 311477349Sgshapiro** 311577349Sgshapiro** Returns: 311677349Sgshapiro** none. 311777349Sgshapiro** 311877349Sgshapiro** Side Effects: 311977349Sgshapiro** Sets ShutdownRequest which will hopefully trigger 312077349Sgshapiro** the daemon to exit. 312177349Sgshapiro** 312277349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 312377349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 312477349Sgshapiro** DOING. 312577349Sgshapiro*/ 312677349Sgshapiro 312777349Sgshapiro/* ARGSUSED */ 312877349Sgshapirostatic SIGFUNC_DECL 312990792Sgshapirosigterm(sig) 313077349Sgshapiro int sig; 313177349Sgshapiro{ 313277349Sgshapiro int save_errno = errno; 313377349Sgshapiro 313490792Sgshapiro FIX_SYSV_SIGNAL(sig, sigterm); 313577349Sgshapiro ShutdownRequest = "signal"; 313677349Sgshapiro errno = save_errno; 313777349Sgshapiro return SIGFUNC_RETURN; 313877349Sgshapiro} 313990792Sgshapiro/* 314090792Sgshapiro** SIGHUP -- handle a SIGHUP signal 314177349Sgshapiro** 314277349Sgshapiro** Parameters: 314390792Sgshapiro** sig -- incoming signal. 314477349Sgshapiro** 314577349Sgshapiro** Returns: 314677349Sgshapiro** none. 314777349Sgshapiro** 314877349Sgshapiro** Side Effects: 314990792Sgshapiro** Sets RestartRequest which should cause the daemon 315090792Sgshapiro** to restart. 315190792Sgshapiro** 315290792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 315390792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 315490792Sgshapiro** DOING. 315577349Sgshapiro*/ 315677349Sgshapiro 315790792Sgshapiro/* ARGSUSED */ 315890792Sgshapirostatic SIGFUNC_DECL 315990792Sgshapirosighup(sig) 316090792Sgshapiro int sig; 316177349Sgshapiro{ 316290792Sgshapiro int save_errno = errno; 316377349Sgshapiro 316490792Sgshapiro FIX_SYSV_SIGNAL(sig, sighup); 316590792Sgshapiro RestartRequest = "signal"; 316690792Sgshapiro errno = save_errno; 316790792Sgshapiro return SIGFUNC_RETURN; 316890792Sgshapiro} 316990792Sgshapiro/* 317090792Sgshapiro** SIGPIPE -- signal handler for SIGPIPE 317190792Sgshapiro** 317290792Sgshapiro** Parameters: 317390792Sgshapiro** sig -- incoming signal. 317490792Sgshapiro** 317590792Sgshapiro** Returns: 317690792Sgshapiro** none. 317790792Sgshapiro** 317890792Sgshapiro** Side Effects: 317990792Sgshapiro** Sets StopRequest which should cause the mailq/hoststatus 318090792Sgshapiro** display to stop. 318190792Sgshapiro** 318290792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 318390792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 318490792Sgshapiro** DOING. 318590792Sgshapiro*/ 318677349Sgshapiro 318790792Sgshapiro/* ARGSUSED */ 318890792Sgshapirostatic SIGFUNC_DECL 318990792Sgshapirosigpipe(sig) 319090792Sgshapiro int sig; 319190792Sgshapiro{ 319290792Sgshapiro int save_errno = errno; 319377349Sgshapiro 319490792Sgshapiro FIX_SYSV_SIGNAL(sig, sigpipe); 319590792Sgshapiro StopRequest = true; 319690792Sgshapiro errno = save_errno; 319790792Sgshapiro return SIGFUNC_RETURN; 319877349Sgshapiro} 319990792Sgshapiro/* 320038032Speter** INTSIG -- clean up on interrupt 320138032Speter** 320264562Sgshapiro** This just arranges to exit. It pessimizes in that it 320338032Speter** may resend a message. 320438032Speter** 320538032Speter** Parameters: 3206223067Sgshapiro** sig -- incoming signal. 320738032Speter** 320838032Speter** Returns: 320938032Speter** none. 321038032Speter** 321138032Speter** Side Effects: 321238032Speter** Unlocks the current job. 321377349Sgshapiro** 321477349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 321577349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 321677349Sgshapiro** DOING. 321738032Speter*/ 321838032Speter 321938032Speter/* ARGSUSED */ 322038032SpeterSIGFUNC_DECL 322138032Speterintsig(sig) 322238032Speter int sig; 322338032Speter{ 322490792Sgshapiro bool drop = false; 322577349Sgshapiro int save_errno = errno; 322664562Sgshapiro 322777349Sgshapiro FIX_SYSV_SIGNAL(sig, intsig); 322877349Sgshapiro errno = save_errno; 322977349Sgshapiro CHECK_CRITICAL(sig); 323090792Sgshapiro sm_allsignals(true); 3231223067Sgshapiro IntSig = true; 323290792Sgshapiro 323338032Speter FileName = NULL; 323464562Sgshapiro 323564562Sgshapiro /* Clean-up on aborted stdin message submission */ 3236223067Sgshapiro if (OpMode == MD_SMTP || 323764562Sgshapiro OpMode == MD_DELIVER || 3238223067Sgshapiro OpMode == MD_ARPAFTP) 323964562Sgshapiro { 3240223067Sgshapiro if (CurEnv->e_id != NULL) 3241223067Sgshapiro { 3242223067Sgshapiro char *fn; 324364562Sgshapiro 3244223067Sgshapiro fn = queuename(CurEnv, DATAFL_LETTER); 3245223067Sgshapiro if (fn != NULL) 3246223067Sgshapiro (void) unlink(fn); 3247223067Sgshapiro fn = queuename(CurEnv, ANYQFL_LETTER); 3248223067Sgshapiro if (fn != NULL) 3249223067Sgshapiro (void) unlink(fn); 3250223067Sgshapiro } 3251223067Sgshapiro _exit(EX_OK); 3252223067Sgshapiro /* NOTREACHED */ 3253223067Sgshapiro } 325464562Sgshapiro 3255223067Sgshapiro if (sig != 0 && LogLevel > 79) 3256223067Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 3257223067Sgshapiro if (OpMode != MD_TEST) 325864562Sgshapiro unlockqueue(CurEnv); 325938032Speter 326090792Sgshapiro finis(drop, false, EX_OK); 326190792Sgshapiro /* NOTREACHED */ 326238032Speter} 326390792Sgshapiro/* 326438032Speter** DISCONNECT -- remove our connection with any foreground process 326538032Speter** 326638032Speter** Parameters: 326738032Speter** droplev -- how "deeply" we should drop the line. 326838032Speter** 0 -- ignore signals, mail back errors, make sure 326938032Speter** output goes to stdout. 327064562Sgshapiro** 1 -- also, make stdout go to /dev/null. 327138032Speter** 2 -- also, disconnect from controlling terminal 327238032Speter** (only for daemon mode). 327338032Speter** e -- the current envelope. 327438032Speter** 327538032Speter** Returns: 327638032Speter** none 327738032Speter** 327838032Speter** Side Effects: 327938032Speter** Trys to insure that we are immune to vagaries of 328038032Speter** the controlling tty. 328138032Speter*/ 328238032Speter 328338032Spetervoid 328438032Speterdisconnect(droplev, e) 328538032Speter int droplev; 328638032Speter register ENVELOPE *e; 328738032Speter{ 328838032Speter int fd; 328938032Speter 329038032Speter if (tTd(52, 1)) 329190792Sgshapiro sm_dprintf("disconnect: In %d Out %d, e=%p\n", 329290792Sgshapiro sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 329390792Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e); 329438032Speter if (tTd(52, 100)) 329538032Speter { 329690792Sgshapiro sm_dprintf("don't\n"); 329738032Speter return; 329838032Speter } 329938032Speter if (LogLevel > 93) 330038032Speter sm_syslog(LOG_DEBUG, e->e_id, 330164562Sgshapiro "disconnect level %d", 330264562Sgshapiro droplev); 330338032Speter 330438032Speter /* be sure we don't get nasty signals */ 330590792Sgshapiro (void) sm_signal(SIGINT, SIG_IGN); 330690792Sgshapiro (void) sm_signal(SIGQUIT, SIG_IGN); 330738032Speter 330838032Speter /* we can't communicate with our caller, so.... */ 330990792Sgshapiro HoldErrs = true; 331038032Speter CurEnv->e_errormode = EM_MAIL; 331138032Speter Verbose = 0; 331290792Sgshapiro DisConnected = true; 331338032Speter 331438032Speter /* all input from /dev/null */ 331590792Sgshapiro if (InChannel != smioin) 331638032Speter { 331790792Sgshapiro (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 331890792Sgshapiro InChannel = smioin; 331938032Speter } 332090792Sgshapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 332190792Sgshapiro SM_IO_RDONLY, NULL, smioin) == NULL) 332238032Speter sm_syslog(LOG_ERR, e->e_id, 332390792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 332490792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 332538032Speter 332690792Sgshapiro /* 332790792Sgshapiro ** output to the transcript 332890792Sgshapiro ** We also compare the fd numbers here since OutChannel 332990792Sgshapiro ** might be a layer on top of smioout due to encryption 333090792Sgshapiro ** (see sfsasl.c). 333190792Sgshapiro */ 333290792Sgshapiro 333390792Sgshapiro if (OutChannel != smioout && 333490792Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 333590792Sgshapiro sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 333638032Speter { 333790792Sgshapiro (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 333890792Sgshapiro OutChannel = smioout; 333990792Sgshapiro 334090792Sgshapiro#if 0 334190792Sgshapiro /* 334290792Sgshapiro ** Has smioout been closed? Reopen it. 334390792Sgshapiro ** This shouldn't happen anymore, the code is here 334490792Sgshapiro ** just as a reminder. 334590792Sgshapiro */ 334690792Sgshapiro 334790792Sgshapiro if (smioout->sm_magic == NULL && 334890792Sgshapiro sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 334990792Sgshapiro SM_IO_WRONLY, NULL, smioout) == NULL) 335090792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 335190792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 335290792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 335390792Sgshapiro#endif /* 0 */ 335438032Speter } 335538032Speter if (droplev > 0) 335638032Speter { 335790792Sgshapiro fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 335864562Sgshapiro if (fd == -1) 3359159609Sgshapiro { 336064562Sgshapiro sm_syslog(LOG_ERR, e->e_id, 336190792Sgshapiro "disconnect: open(\"%s\") failed: %s", 336290792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 3363159609Sgshapiro } 336490792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 3365159609Sgshapiro if (fd >= 0) 3366159609Sgshapiro { 3367159609Sgshapiro (void) dup2(fd, STDOUT_FILENO); 3368159609Sgshapiro (void) dup2(fd, STDERR_FILENO); 3369159609Sgshapiro (void) close(fd); 3370159609Sgshapiro } 337138032Speter } 337238032Speter 337338032Speter /* drop our controlling TTY completely if possible */ 337438032Speter if (droplev > 1) 337538032Speter { 337638032Speter (void) setsid(); 337738032Speter errno = 0; 337838032Speter } 337938032Speter 338038032Speter#if XDEBUG 338138032Speter checkfd012("disconnect"); 338264562Sgshapiro#endif /* XDEBUG */ 338338032Speter 338438032Speter if (LogLevel > 71) 338590792Sgshapiro sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 338690792Sgshapiro (int) CurrentPid); 338738032Speter 338838032Speter errno = 0; 338938032Speter} 339038032Speter 339138032Speterstatic void 339238032Speterobsolete(argv) 339338032Speter char *argv[]; 339438032Speter{ 339538032Speter register char *ap; 339638032Speter register char *op; 339738032Speter 339838032Speter while ((ap = *++argv) != NULL) 339938032Speter { 340038032Speter /* Return if "--" or not an option of any form. */ 340138032Speter if (ap[0] != '-' || ap[1] == '-') 340238032Speter return; 340338032Speter 340490792Sgshapiro /* Don't allow users to use "-Q." or "-Q ." */ 340590792Sgshapiro if ((ap[1] == 'Q' && ap[2] == '.') || 340690792Sgshapiro (ap[1] == 'Q' && argv[1] != NULL && 340790792Sgshapiro argv[1][0] == '.' && argv[1][1] == '\0')) 340890792Sgshapiro { 340990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 341090792Sgshapiro "Can not use -Q.\n"); 341190792Sgshapiro exit(EX_USAGE); 341290792Sgshapiro } 341390792Sgshapiro 341438032Speter /* skip over options that do have a value */ 341538032Speter op = strchr(OPTIONS, ap[1]); 341638032Speter if (op != NULL && *++op == ':' && ap[2] == '\0' && 341738032Speter ap[1] != 'd' && 341838032Speter#if defined(sony_news) 341938032Speter ap[1] != 'E' && ap[1] != 'J' && 342064562Sgshapiro#endif /* defined(sony_news) */ 342138032Speter argv[1] != NULL && argv[1][0] != '-') 342238032Speter { 342338032Speter argv++; 342438032Speter continue; 342538032Speter } 342638032Speter 342738032Speter /* If -C doesn't have an argument, use sendmail.cf. */ 342890792Sgshapiro#define __DEFPATH "sendmail.cf" 342938032Speter if (ap[1] == 'C' && ap[2] == '\0') 343038032Speter { 343138032Speter *argv = xalloc(sizeof(__DEFPATH) + 2); 343290792Sgshapiro (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 343390792Sgshapiro "-C", __DEFPATH); 343438032Speter } 343538032Speter 343638032Speter /* If -q doesn't have an argument, run it once. */ 343738032Speter if (ap[1] == 'q' && ap[2] == '\0') 343838032Speter *argv = "-q0"; 343938032Speter 344090792Sgshapiro /* If -Q doesn't have an argument, disable quarantining */ 344190792Sgshapiro if (ap[1] == 'Q' && ap[2] == '\0') 344290792Sgshapiro *argv = "-Q."; 344390792Sgshapiro 344438032Speter /* if -d doesn't have an argument, use 0-99.1 */ 344538032Speter if (ap[1] == 'd' && ap[2] == '\0') 344638032Speter *argv = "-d0-99.1"; 344738032Speter 344864562Sgshapiro#if defined(sony_news) 344938032Speter /* if -E doesn't have an argument, use -EC */ 345038032Speter if (ap[1] == 'E' && ap[2] == '\0') 345138032Speter *argv = "-EC"; 345238032Speter 345338032Speter /* if -J doesn't have an argument, use -JJ */ 345438032Speter if (ap[1] == 'J' && ap[2] == '\0') 345538032Speter *argv = "-JJ"; 345664562Sgshapiro#endif /* defined(sony_news) */ 345738032Speter } 345838032Speter} 345990792Sgshapiro/* 346038032Speter** AUTH_WARNING -- specify authorization warning 346138032Speter** 346238032Speter** Parameters: 346338032Speter** e -- the current envelope. 346438032Speter** msg -- the text of the message. 346538032Speter** args -- arguments to the message. 346638032Speter** 346738032Speter** Returns: 346838032Speter** none. 346938032Speter*/ 347038032Speter 347138032Spetervoid 347238032Speter#ifdef __STDC__ 347338032Speterauth_warning(register ENVELOPE *e, const char *msg, ...) 347464562Sgshapiro#else /* __STDC__ */ 347538032Speterauth_warning(e, msg, va_alist) 347638032Speter register ENVELOPE *e; 347738032Speter const char *msg; 347838032Speter va_dcl 347964562Sgshapiro#endif /* __STDC__ */ 348038032Speter{ 348138032Speter char buf[MAXLINE]; 348290792Sgshapiro SM_VA_LOCAL_DECL 348338032Speter 348438032Speter if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 348538032Speter { 348638032Speter register char *p; 348738032Speter static char hostbuf[48]; 348838032Speter 348938032Speter if (hostbuf[0] == '\0') 349071345Sgshapiro { 349171345Sgshapiro struct hostent *hp; 349238032Speter 3493168515Sgshapiro hp = myhostname(hostbuf, sizeof(hostbuf)); 349490792Sgshapiro#if NETINET6 349571345Sgshapiro if (hp != NULL) 349671345Sgshapiro { 349771345Sgshapiro freehostent(hp); 349871345Sgshapiro hp = NULL; 349971345Sgshapiro } 350090792Sgshapiro#endif /* NETINET6 */ 350171345Sgshapiro } 350271345Sgshapiro 3503168515Sgshapiro (void) sm_strlcpyn(buf, sizeof(buf), 2, hostbuf, ": "); 350438032Speter p = &buf[strlen(buf)]; 350590792Sgshapiro SM_VA_START(ap, msg); 350690792Sgshapiro (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 350790792Sgshapiro SM_VA_END(ap); 3508168515Sgshapiro addheader("X-Authentication-Warning", buf, 0, e, true); 350938032Speter if (LogLevel > 3) 351038032Speter sm_syslog(LOG_INFO, e->e_id, 351164562Sgshapiro "Authentication-Warning: %.400s", 351264562Sgshapiro buf); 351338032Speter } 351438032Speter} 351590792Sgshapiro/* 351638032Speter** GETEXTENV -- get from external environment 351738032Speter** 351838032Speter** Parameters: 351938032Speter** envar -- the name of the variable to retrieve 352038032Speter** 352138032Speter** Returns: 352238032Speter** The value, if any. 352338032Speter*/ 352438032Speter 352590792Sgshapirostatic char * 352638032Spetergetextenv(envar) 352738032Speter const char *envar; 352838032Speter{ 352938032Speter char **envp; 353038032Speter int l; 353138032Speter 353238032Speter l = strlen(envar); 3533102528Sgshapiro for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++) 353438032Speter { 353538032Speter if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 353638032Speter return &(*envp)[l + 1]; 353738032Speter } 353838032Speter return NULL; 353938032Speter} 354090792Sgshapiro/* 3541157001Sgshapiro** SM_SETUSERENV -- set an environment variable in the propagated environment 354238032Speter** 354338032Speter** Parameters: 354438032Speter** envar -- the name of the environment variable. 354538032Speter** value -- the value to which it should be set. If 354638032Speter** null, this is extracted from the incoming 354738032Speter** environment. If that is not set, the call 3548157001Sgshapiro** to sm_setuserenv is ignored. 354938032Speter** 355038032Speter** Returns: 355138032Speter** none. 355238032Speter*/ 355338032Speter 355438032Spetervoid 3555157001Sgshapirosm_setuserenv(envar, value) 355638032Speter const char *envar; 355738032Speter const char *value; 355838032Speter{ 355964562Sgshapiro int i, l; 356038032Speter char **evp = UserEnviron; 356138032Speter char *p; 356238032Speter 356338032Speter if (value == NULL) 356438032Speter { 356538032Speter value = getextenv(envar); 356638032Speter if (value == NULL) 356738032Speter return; 356838032Speter } 356938032Speter 357090792Sgshapiro /* XXX enforce reasonable size? */ 357164562Sgshapiro i = strlen(envar) + 1; 357264562Sgshapiro l = strlen(value) + i + 1; 357364562Sgshapiro p = (char *) xalloc(l); 357490792Sgshapiro (void) sm_strlcpyn(p, l, 3, envar, "=", value); 357538032Speter 357638032Speter while (*evp != NULL && strncmp(*evp, p, i) != 0) 357738032Speter evp++; 357838032Speter if (*evp != NULL) 357938032Speter { 358038032Speter *evp++ = p; 358138032Speter } 358238032Speter else if (evp < &UserEnviron[MAXUSERENVIRON]) 358338032Speter { 358438032Speter *evp++ = p; 358538032Speter *evp = NULL; 358638032Speter } 358738032Speter 358838032Speter /* make sure it is in our environment as well */ 358938032Speter if (putenv(p) < 0) 3590157001Sgshapiro syserr("sm_setuserenv: putenv(%s) failed", p); 359138032Speter} 359290792Sgshapiro/* 359338032Speter** DUMPSTATE -- dump state 359438032Speter** 359538032Speter** For debugging. 359638032Speter*/ 359738032Speter 359838032Spetervoid 359938032Speterdumpstate(when) 360038032Speter char *when; 360138032Speter{ 360238032Speter register char *j = macvalue('j', CurEnv); 360338032Speter int rs; 360464562Sgshapiro extern int NextMacroId; 360538032Speter 360638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 360764562Sgshapiro "--- dumping state on %s: $j = %s ---", 360864562Sgshapiro when, 360964562Sgshapiro j == NULL ? "<NULL>" : j); 361038032Speter if (j != NULL) 361138032Speter { 361238032Speter if (!wordinclass(j, 'w')) 361338032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 361464562Sgshapiro "*** $j not in $=w ***"); 361538032Speter } 361638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 361790792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 361864562Sgshapiro NextMacroId, MAXMACROID); 361938032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 362090792Sgshapiro printopenfds(true); 362138032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 3622132943Sgshapiro mci_dump_all(smioout, true); 362338032Speter rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 362438032Speter if (rs > 0) 362538032Speter { 362664562Sgshapiro int status; 362738032Speter register char **pvp; 362838032Speter char *pv[MAXATOM + 1]; 362938032Speter 363038032Speter pv[0] = NULL; 363190792Sgshapiro status = REWRITE(pv, rs, CurEnv); 363238032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 363364562Sgshapiro "--- ruleset debug_dumpstate returns stat %d, pv: ---", 363464562Sgshapiro status); 363538032Speter for (pvp = pv; *pvp != NULL; pvp++) 363638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 363738032Speter } 363838032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 363938032Speter} 364090792Sgshapiro 364180785Sgshapiro#ifdef SIGUSR1 364290792Sgshapiro/* 364377349Sgshapiro** SIGUSR1 -- Signal a request to dump state. 364477349Sgshapiro** 364577349Sgshapiro** Parameters: 364677349Sgshapiro** sig -- calling signal. 364777349Sgshapiro** 364877349Sgshapiro** Returns: 364977349Sgshapiro** none. 365077349Sgshapiro** 365177349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 365277349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 365377349Sgshapiro** DOING. 365477349Sgshapiro** 365577349Sgshapiro** XXX: More work is needed for this signal handler. 365677349Sgshapiro*/ 365738032Speter 365838032Speter/* ARGSUSED */ 365977349Sgshapirostatic SIGFUNC_DECL 366038032Spetersigusr1(sig) 366138032Speter int sig; 366238032Speter{ 366377349Sgshapiro int save_errno = errno; 366477349Sgshapiro 366577349Sgshapiro FIX_SYSV_SIGNAL(sig, sigusr1); 366677349Sgshapiro errno = save_errno; 366777349Sgshapiro CHECK_CRITICAL(sig); 366838032Speter dumpstate("user signal"); 366990792Sgshapiro# if SM_HEAP_CHECK 367090792Sgshapiro dumpstab(); 367190792Sgshapiro# endif /* SM_HEAP_CHECK */ 367277349Sgshapiro errno = save_errno; 367338032Speter return SIGFUNC_RETURN; 367438032Speter} 367590792Sgshapiro#endif /* SIGUSR1 */ 367690792Sgshapiro 367790792Sgshapiro/* 367838032Speter** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 367938032Speter** 368038032Speter** Parameters: 368138032Speter** to_real_uid -- if set, drop to the real uid instead 368238032Speter** of the RunAsUser. 368338032Speter** 368438032Speter** Returns: 368538032Speter** EX_OSERR if the setuid failed. 368638032Speter** EX_OK otherwise. 368738032Speter*/ 368838032Speter 368938032Speterint 369038032Speterdrop_privileges(to_real_uid) 369138032Speter bool to_real_uid; 369238032Speter{ 369338032Speter int rval = EX_OK; 369438032Speter GIDSET_T emptygidset[1]; 369538032Speter 369638032Speter if (tTd(47, 1)) 369790792Sgshapiro 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", 369890792Sgshapiro (int) to_real_uid, 369990792Sgshapiro (int) RealUid, (int) RealGid, 370090792Sgshapiro (int) getuid(), (int) getgid(), 370190792Sgshapiro (int) geteuid(), (int) getegid(), 370290792Sgshapiro (int) RunAsUid, (int) RunAsGid); 370338032Speter 370438032Speter if (to_real_uid) 370538032Speter { 370638032Speter RunAsUserName = RealUserName; 370738032Speter RunAsUid = RealUid; 370838032Speter RunAsGid = RealGid; 370994334Sgshapiro EffGid = RunAsGid; 371038032Speter } 371138032Speter 371238032Speter /* make sure no one can grab open descriptors for secret files */ 371338032Speter endpwent(); 371490792Sgshapiro sm_mbdb_terminate(); 371538032Speter 371638032Speter /* reset group permissions; these can be set later */ 371738032Speter emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 371890792Sgshapiro 371990792Sgshapiro /* 372090792Sgshapiro ** Notice: on some OS (Linux...) the setgroups() call causes 372190792Sgshapiro ** a logfile entry if sendmail is not run by root. 372290792Sgshapiro ** However, it is unclear (no POSIX standard) whether 372390792Sgshapiro ** setgroups() can only succeed if executed by root. 372490792Sgshapiro ** So for now we keep it as it is; if you want to change it, use 372590792Sgshapiro ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 372690792Sgshapiro */ 372790792Sgshapiro 372838032Speter if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 372964562Sgshapiro { 373064562Sgshapiro syserr("drop_privileges: setgroups(1, %d) failed", 373190792Sgshapiro (int) emptygidset[0]); 373238032Speter rval = EX_OSERR; 373364562Sgshapiro } 373438032Speter 373590792Sgshapiro /* reset primary group id */ 373690792Sgshapiro if (to_real_uid) 373764562Sgshapiro { 373890792Sgshapiro /* 373990792Sgshapiro ** Drop gid to real gid. 374090792Sgshapiro ** On some OS we must reset the effective[/real[/saved]] gid, 374190792Sgshapiro ** and then use setgid() to finally drop all group privileges. 374290792Sgshapiro ** Later on we check whether we can get back the 374390792Sgshapiro ** effective gid. 374490792Sgshapiro */ 374590792Sgshapiro 374690792Sgshapiro#if HASSETEGID 374790792Sgshapiro if (setegid(RunAsGid) < 0) 374890792Sgshapiro { 374990792Sgshapiro syserr("drop_privileges: setegid(%d) failed", 375090792Sgshapiro (int) RunAsGid); 375190792Sgshapiro rval = EX_OSERR; 375290792Sgshapiro } 375390792Sgshapiro#else /* HASSETEGID */ 375490792Sgshapiro# if HASSETREGID 375590792Sgshapiro if (setregid(RunAsGid, RunAsGid) < 0) 375690792Sgshapiro { 375790792Sgshapiro syserr("drop_privileges: setregid(%d, %d) failed", 375890792Sgshapiro (int) RunAsGid, (int) RunAsGid); 375990792Sgshapiro rval = EX_OSERR; 376090792Sgshapiro } 376190792Sgshapiro# else /* HASSETREGID */ 376290792Sgshapiro# if HASSETRESGID 376390792Sgshapiro if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 376490792Sgshapiro { 376590792Sgshapiro syserr("drop_privileges: setresgid(%d, %d, %d) failed", 376690792Sgshapiro (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 376790792Sgshapiro rval = EX_OSERR; 376890792Sgshapiro } 376990792Sgshapiro# endif /* HASSETRESGID */ 377090792Sgshapiro# endif /* HASSETREGID */ 377190792Sgshapiro#endif /* HASSETEGID */ 377264562Sgshapiro } 377390792Sgshapiro if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 377490792Sgshapiro { 377590792Sgshapiro if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 377690792Sgshapiro { 377790792Sgshapiro syserr("drop_privileges: setgid(%d) failed", 377890792Sgshapiro (int) RunAsGid); 377990792Sgshapiro rval = EX_OSERR; 378090792Sgshapiro } 378190792Sgshapiro errno = 0; 378290792Sgshapiro if (rval == EX_OK && getegid() != RunAsGid) 378390792Sgshapiro { 378490792Sgshapiro syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", 378590792Sgshapiro (int) getegid(), (int) RunAsGid); 378690792Sgshapiro rval = EX_OSERR; 378790792Sgshapiro } 378890792Sgshapiro } 378990792Sgshapiro 379090792Sgshapiro /* fiddle with uid */ 379164562Sgshapiro if (to_real_uid || RunAsUid != 0) 379264562Sgshapiro { 379394334Sgshapiro uid_t euid; 379464562Sgshapiro 379590792Sgshapiro /* 379690792Sgshapiro ** Try to setuid(RunAsUid). 379790792Sgshapiro ** euid must be RunAsUid, 379894334Sgshapiro ** ruid must be RunAsUid unless (e|r)uid wasn't 0 379994334Sgshapiro ** and we didn't have to drop privileges to the real uid. 380090792Sgshapiro */ 380190792Sgshapiro 380290792Sgshapiro if (setuid(RunAsUid) < 0 || 380394334Sgshapiro geteuid() != RunAsUid || 380494334Sgshapiro (getuid() != RunAsUid && 380594334Sgshapiro (to_real_uid || geteuid() == 0 || getuid() == 0))) 380664562Sgshapiro { 380790792Sgshapiro#if HASSETREUID 380890792Sgshapiro /* 380990792Sgshapiro ** if ruid != RunAsUid, euid == RunAsUid, then 381090792Sgshapiro ** try resetting just the real uid, then using 381190792Sgshapiro ** setuid() to drop the saved-uid as well. 381290792Sgshapiro */ 381390792Sgshapiro 381494334Sgshapiro if (geteuid() == RunAsUid) 381590792Sgshapiro { 381690792Sgshapiro if (setreuid(RunAsUid, -1) < 0) 381790792Sgshapiro { 381890792Sgshapiro syserr("drop_privileges: setreuid(%d, -1) failed", 381990792Sgshapiro (int) RunAsUid); 382090792Sgshapiro rval = EX_OSERR; 382190792Sgshapiro } 382290792Sgshapiro if (setuid(RunAsUid) < 0) 382390792Sgshapiro { 382490792Sgshapiro syserr("drop_privileges: second setuid(%d) attempt failed", 382590792Sgshapiro (int) RunAsUid); 382690792Sgshapiro rval = EX_OSERR; 382790792Sgshapiro } 382890792Sgshapiro } 382990792Sgshapiro else 383090792Sgshapiro#endif /* HASSETREUID */ 383190792Sgshapiro { 383290792Sgshapiro syserr("drop_privileges: setuid(%d) failed", 383390792Sgshapiro (int) RunAsUid); 383490792Sgshapiro rval = EX_OSERR; 383590792Sgshapiro } 383664562Sgshapiro } 383794334Sgshapiro euid = geteuid(); 383890792Sgshapiro if (RunAsUid != 0 && setuid(0) == 0) 383964562Sgshapiro { 384064562Sgshapiro /* 384164562Sgshapiro ** Believe it or not, the Linux capability model 384264562Sgshapiro ** allows a non-root process to override setuid() 384364562Sgshapiro ** on a process running as root and prevent that 384464562Sgshapiro ** process from dropping privileges. 384564562Sgshapiro */ 384664562Sgshapiro 384764562Sgshapiro syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 384864562Sgshapiro rval = EX_OSERR; 384964562Sgshapiro } 385064562Sgshapiro else if (RunAsUid != euid && setuid(euid) == 0) 385164562Sgshapiro { 385264562Sgshapiro /* 385364562Sgshapiro ** Some operating systems will keep the saved-uid 385464562Sgshapiro ** if a non-root effective-uid calls setuid(real-uid) 385564562Sgshapiro ** making it possible to set it back again later. 385664562Sgshapiro */ 385764562Sgshapiro 385890792Sgshapiro syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 385964562Sgshapiro rval = EX_OSERR; 386064562Sgshapiro } 386164562Sgshapiro } 386290792Sgshapiro 386390792Sgshapiro if ((to_real_uid || RunAsGid != 0) && 386490792Sgshapiro rval == EX_OK && RunAsGid != EffGid && 386590792Sgshapiro getuid() != 0 && geteuid() != 0) 386690792Sgshapiro { 386790792Sgshapiro errno = 0; 386890792Sgshapiro if (setgid(EffGid) == 0) 386990792Sgshapiro { 387090792Sgshapiro syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 387190792Sgshapiro (int) EffGid); 387290792Sgshapiro rval = EX_OSERR; 387390792Sgshapiro } 387490792Sgshapiro } 387590792Sgshapiro 387638032Speter if (tTd(47, 5)) 387738032Speter { 387890792Sgshapiro sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 387990792Sgshapiro (int) geteuid(), (int) getuid(), 388090792Sgshapiro (int) getegid(), (int) getgid()); 388190792Sgshapiro sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 388290792Sgshapiro (int) RunAsUid, (int) RunAsGid); 388364562Sgshapiro if (tTd(47, 10)) 388490792Sgshapiro sm_dprintf("drop_privileges: rval = %d\n", rval); 388538032Speter } 388638032Speter return rval; 388738032Speter} 388890792Sgshapiro/* 388938032Speter** FILL_FD -- make sure a file descriptor has been properly allocated 389038032Speter** 389138032Speter** Used to make sure that stdin/out/err are allocated on startup 389238032Speter** 389338032Speter** Parameters: 389438032Speter** fd -- the file descriptor to be filled. 389538032Speter** where -- a string used for logging. If NULL, this is 389638032Speter** being called on startup, and logging should 389738032Speter** not be done. 389838032Speter** 389938032Speter** Returns: 390038032Speter** none 390190792Sgshapiro** 390290792Sgshapiro** Side Effects: 390390792Sgshapiro** possibly changes MissingFds 390438032Speter*/ 390538032Speter 390638032Spetervoid 390738032Speterfill_fd(fd, where) 390838032Speter int fd; 390938032Speter char *where; 391038032Speter{ 391138032Speter int i; 391238032Speter struct stat stbuf; 391338032Speter 391438032Speter if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 391538032Speter return; 391638032Speter 391738032Speter if (where != NULL) 391838032Speter syserr("fill_fd: %s: fd %d not open", where, fd); 391938032Speter else 392038032Speter MissingFds |= 1 << fd; 392190792Sgshapiro i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 392238032Speter if (i < 0) 392338032Speter { 392490792Sgshapiro syserr("!fill_fd: %s: cannot open %s", 392590792Sgshapiro where == NULL ? "startup" : where, SM_PATH_DEVNULL); 392638032Speter } 392738032Speter if (fd != i) 392838032Speter { 392938032Speter (void) dup2(i, fd); 393038032Speter (void) close(i); 393138032Speter } 393238032Speter} 393390792Sgshapiro/* 393490792Sgshapiro** SM_PRINTOPTIONS -- print options 393590792Sgshapiro** 393690792Sgshapiro** Parameters: 393790792Sgshapiro** options -- array of options. 393890792Sgshapiro** 393990792Sgshapiro** Returns: 394090792Sgshapiro** none. 394190792Sgshapiro*/ 394290792Sgshapiro 394390792Sgshapirostatic void 394490792Sgshapirosm_printoptions(options) 394590792Sgshapiro char **options; 394690792Sgshapiro{ 394790792Sgshapiro int ll; 394890792Sgshapiro char **av; 394990792Sgshapiro 395090792Sgshapiro av = options; 395190792Sgshapiro ll = 7; 395290792Sgshapiro while (*av != NULL) 395390792Sgshapiro { 395490792Sgshapiro if (ll + strlen(*av) > 63) 395590792Sgshapiro { 395690792Sgshapiro sm_dprintf("\n"); 395790792Sgshapiro ll = 0; 395890792Sgshapiro } 395990792Sgshapiro if (ll == 0) 396090792Sgshapiro sm_dprintf("\t\t"); 396190792Sgshapiro else 396290792Sgshapiro sm_dprintf(" "); 396390792Sgshapiro sm_dprintf("%s", *av); 396490792Sgshapiro ll += strlen(*av++) + 1; 396590792Sgshapiro } 396690792Sgshapiro sm_dprintf("\n"); 396790792Sgshapiro} 3968168515Sgshapiro 396990792Sgshapiro/* 3970168515Sgshapiro** TO8BIT -- convert \octal sequences in a test mode input line 3971168515Sgshapiro** 3972168515Sgshapiro** Parameters: 3973168515Sgshapiro** str -- the input line. 3974168515Sgshapiro** 3975168515Sgshapiro** Returns: 3976168515Sgshapiro** none. 3977168515Sgshapiro** 3978168515Sgshapiro** Side Effects: 3979168515Sgshapiro** replaces \0octal in str with octal value. 3980168515Sgshapiro*/ 3981168515Sgshapiro 3982168515Sgshapirostatic bool to8bit __P((char *)); 3983168515Sgshapiro 3984168515Sgshapirostatic bool 3985168515Sgshapiroto8bit(str) 3986168515Sgshapiro char *str; 3987168515Sgshapiro{ 3988168515Sgshapiro int c, len; 3989168515Sgshapiro char *out, *in; 3990168515Sgshapiro bool changed; 3991168515Sgshapiro 3992168515Sgshapiro if (str == NULL) 3993168515Sgshapiro return false; 3994168515Sgshapiro in = out = str; 3995168515Sgshapiro changed = false; 3996168515Sgshapiro len = 0; 3997168515Sgshapiro while ((c = (*str++ & 0377)) != '\0') 3998168515Sgshapiro { 3999168515Sgshapiro int oct, nxtc; 4000168515Sgshapiro 4001168515Sgshapiro ++len; 4002168515Sgshapiro if (c == '\\' && 4003168515Sgshapiro (nxtc = (*str & 0377)) == '0') 4004168515Sgshapiro { 4005168515Sgshapiro oct = 0; 4006168515Sgshapiro while ((nxtc = (*str & 0377)) != '\0' && 4007168515Sgshapiro isascii(nxtc) && isdigit(nxtc)) 4008168515Sgshapiro { 4009168515Sgshapiro oct <<= 3; 4010168515Sgshapiro oct += nxtc - '0'; 4011168515Sgshapiro ++str; 4012168515Sgshapiro ++len; 4013168515Sgshapiro } 4014168515Sgshapiro changed = true; 4015168515Sgshapiro c = oct; 4016168515Sgshapiro } 4017168515Sgshapiro *out++ = c; 4018168515Sgshapiro } 4019168515Sgshapiro *out++ = c; 4020168515Sgshapiro if (changed) 4021168515Sgshapiro { 4022168515Sgshapiro char *q; 4023168515Sgshapiro 4024168515Sgshapiro q = quote_internal_chars(in, in, &len); 4025168515Sgshapiro if (q != in) 4026168515Sgshapiro sm_strlcpy(in, q, len); 4027168515Sgshapiro } 4028168515Sgshapiro return changed; 4029168515Sgshapiro} 4030168515Sgshapiro 4031168515Sgshapiro/* 403238032Speter** TESTMODELINE -- process a test mode input line 403338032Speter** 403438032Speter** Parameters: 403538032Speter** line -- the input line. 403638032Speter** e -- the current environment. 403738032Speter** Syntax: 403838032Speter** # a comment 403938032Speter** .X process X as a configuration line 404038032Speter** =X dump a configuration item (such as mailers) 404138032Speter** $X dump a macro or class 404238032Speter** /X try an activity 404338032Speter** X normal process through rule set X 404438032Speter*/ 404538032Speter 404664562Sgshapirostatic void 404738032Spetertestmodeline(line, e) 404838032Speter char *line; 404938032Speter ENVELOPE *e; 405038032Speter{ 405138032Speter register char *p; 405238032Speter char *q; 405338032Speter auto char *delimptr; 405438032Speter int mid; 405538032Speter int i, rs; 405638032Speter STAB *map; 405738032Speter char **s; 405838032Speter struct rewrite *rw; 405938032Speter ADDRESS a; 4060168515Sgshapiro char *lbp; 4061168515Sgshapiro auto int lbs; 406238032Speter static int tryflags = RF_COPYNONE; 406338032Speter char exbuf[MAXLINE]; 4064168515Sgshapiro char lbuf[MAXLINE]; 406590792Sgshapiro extern unsigned char TokTypeNoC[]; 4066168515Sgshapiro bool eightbit; 406738032Speter 406866494Sgshapiro /* skip leading spaces */ 406966494Sgshapiro while (*line == ' ') 407066494Sgshapiro line++; 407166494Sgshapiro 4072168515Sgshapiro lbp = NULL; 4073168515Sgshapiro eightbit = false; 407438032Speter switch (line[0]) 407538032Speter { 407638032Speter case '#': 407764562Sgshapiro case '\0': 407838032Speter return; 407938032Speter 408038032Speter case '?': 408164562Sgshapiro help("-bt", e); 408238032Speter return; 408338032Speter 408438032Speter case '.': /* config-style settings */ 408538032Speter switch (line[1]) 408638032Speter { 408738032Speter case 'D': 408890792Sgshapiro mid = macid_parse(&line[2], &delimptr); 408971345Sgshapiro if (mid == 0) 409038032Speter return; 4091168515Sgshapiro lbs = sizeof(lbuf); 4092168515Sgshapiro lbp = translate_dollars(delimptr, lbuf, &lbs); 4093168515Sgshapiro macdefine(&e->e_macro, A_TEMP, mid, lbp); 4094168515Sgshapiro if (lbp != lbuf) 4095168515Sgshapiro SM_FREE(lbp); 409638032Speter break; 409738032Speter 409838032Speter case 'C': 409938032Speter if (line[2] == '\0') /* not to call syserr() */ 410038032Speter return; 410138032Speter 410290792Sgshapiro mid = macid_parse(&line[2], &delimptr); 410371345Sgshapiro if (mid == 0) 410438032Speter return; 4105168515Sgshapiro lbs = sizeof(lbuf); 4106168515Sgshapiro lbp = translate_dollars(delimptr, lbuf, &lbs); 4107168515Sgshapiro expand(lbp, exbuf, sizeof(exbuf), e); 4108168515Sgshapiro if (lbp != lbuf) 4109168515Sgshapiro SM_FREE(lbp); 411038032Speter p = exbuf; 411138032Speter while (*p != '\0') 411238032Speter { 411338032Speter register char *wd; 411438032Speter char delim; 411538032Speter 411638032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 411738032Speter p++; 411838032Speter wd = p; 411938032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 412038032Speter p++; 412138032Speter delim = *p; 412238032Speter *p = '\0'; 412338032Speter if (wd[0] != '\0') 412438032Speter setclass(mid, wd); 412538032Speter *p = delim; 412638032Speter } 412738032Speter break; 412838032Speter 412938032Speter case '\0': 413090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 413190792Sgshapiro "Usage: .[DC]macro value(s)\n"); 413238032Speter break; 413338032Speter 413438032Speter default: 413590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 413690792Sgshapiro "Unknown \".\" command %s\n", line); 413738032Speter break; 413838032Speter } 413938032Speter return; 414038032Speter 414138032Speter case '=': /* config-style settings */ 414238032Speter switch (line[1]) 414338032Speter { 414438032Speter case 'S': /* dump rule set */ 414538032Speter rs = strtorwset(&line[2], NULL, ST_FIND); 414638032Speter if (rs < 0) 414738032Speter { 414890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 414990792Sgshapiro "Undefined ruleset %s\n", &line[2]); 415038032Speter return; 415138032Speter } 415238032Speter rw = RewriteRules[rs]; 415338032Speter if (rw == NULL) 415438032Speter return; 415538032Speter do 415638032Speter { 415790792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 415890792Sgshapiro 'R'); 415938032Speter s = rw->r_lhs; 416038032Speter while (*s != NULL) 416138032Speter { 4162132943Sgshapiro xputs(smioout, *s++); 416390792Sgshapiro (void) sm_io_putc(smioout, 416490792Sgshapiro SM_TIME_DEFAULT, ' '); 416538032Speter } 416690792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 416790792Sgshapiro '\t'); 416890792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 416990792Sgshapiro '\t'); 417038032Speter s = rw->r_rhs; 417138032Speter while (*s != NULL) 417238032Speter { 4173132943Sgshapiro xputs(smioout, *s++); 417490792Sgshapiro (void) sm_io_putc(smioout, 417590792Sgshapiro SM_TIME_DEFAULT, ' '); 417638032Speter } 417790792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 417890792Sgshapiro '\n'); 417938032Speter } while ((rw = rw->r_next) != NULL); 418038032Speter break; 418138032Speter 418238032Speter case 'M': 418338032Speter for (i = 0; i < MAXMAILERS; i++) 418438032Speter { 418538032Speter if (Mailer[i] != NULL) 4186132943Sgshapiro printmailer(smioout, Mailer[i]); 418738032Speter } 418838032Speter break; 418938032Speter 419038032Speter case '\0': 419190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 419290792Sgshapiro "Usage: =Sruleset or =M\n"); 419338032Speter break; 419438032Speter 419538032Speter default: 419690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 419790792Sgshapiro "Unknown \"=\" command %s\n", line); 419838032Speter break; 419938032Speter } 420038032Speter return; 420138032Speter 420238032Speter case '-': /* set command-line-like opts */ 420338032Speter switch (line[1]) 420438032Speter { 420538032Speter case 'd': 420638032Speter tTflag(&line[2]); 420738032Speter break; 420838032Speter 420938032Speter case '\0': 421090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 421190792Sgshapiro "Usage: -d{debug arguments}\n"); 421238032Speter break; 421338032Speter 421438032Speter default: 421590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 421690792Sgshapiro "Unknown \"-\" command %s\n", line); 421738032Speter break; 421838032Speter } 421938032Speter return; 422038032Speter 422138032Speter case '$': 422238032Speter if (line[1] == '=') 422338032Speter { 422490792Sgshapiro mid = macid(&line[2]); 422571345Sgshapiro if (mid != 0) 422638032Speter stabapply(dump_class, mid); 422738032Speter return; 422838032Speter } 422990792Sgshapiro mid = macid(&line[1]); 423071345Sgshapiro if (mid == 0) 423138032Speter return; 423238032Speter p = macvalue(mid, e); 423338032Speter if (p == NULL) 423490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 423590792Sgshapiro "Undefined\n"); 423638032Speter else 423738032Speter { 4238132943Sgshapiro xputs(smioout, p); 423990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 424090792Sgshapiro "\n"); 424138032Speter } 424238032Speter return; 424338032Speter 424438032Speter case '/': /* miscellaneous commands */ 424538032Speter p = &line[strlen(line)]; 424638032Speter while (--p >= line && isascii(*p) && isspace(*p)) 424738032Speter *p = '\0'; 424838032Speter p = strpbrk(line, " \t"); 424938032Speter if (p != NULL) 425038032Speter { 425138032Speter while (isascii(*p) && isspace(*p)) 425238032Speter *p++ = '\0'; 425338032Speter } 425438032Speter else 425538032Speter p = ""; 425638032Speter if (line[1] == '\0') 425738032Speter { 425890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 425990792Sgshapiro "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 426038032Speter return; 426138032Speter } 426290792Sgshapiro if (sm_strcasecmp(&line[1], "quit") == 0) 426364562Sgshapiro { 426464562Sgshapiro CurEnv->e_id = NULL; 426590792Sgshapiro finis(true, true, ExitStat); 426690792Sgshapiro /* NOTREACHED */ 426764562Sgshapiro } 426890792Sgshapiro if (sm_strcasecmp(&line[1], "mx") == 0) 426938032Speter { 427038032Speter#if NAMED_BIND 427138032Speter /* look up MX records */ 427238032Speter int nmx; 427338032Speter auto int rcode; 427438032Speter char *mxhosts[MAXMXHOSTS + 1]; 427538032Speter 427638032Speter if (*p == '\0') 427738032Speter { 427890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 427990792Sgshapiro "Usage: /mx address\n"); 428038032Speter return; 428138032Speter } 428290792Sgshapiro nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true, 428390792Sgshapiro NULL); 428490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 428590792Sgshapiro "getmxrr(%s) returns %d value(s):\n", 428690792Sgshapiro p, nmx); 428738032Speter for (i = 0; i < nmx; i++) 428890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 428990792Sgshapiro "\t%s\n", mxhosts[i]); 429064562Sgshapiro#else /* NAMED_BIND */ 429190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 429290792Sgshapiro "No MX code compiled in\n"); 429364562Sgshapiro#endif /* NAMED_BIND */ 429438032Speter } 429590792Sgshapiro else if (sm_strcasecmp(&line[1], "canon") == 0) 429638032Speter { 429738032Speter char host[MAXHOSTNAMELEN]; 429838032Speter 429938032Speter if (*p == '\0') 430038032Speter { 430190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 430290792Sgshapiro "Usage: /canon address\n"); 430338032Speter return; 430438032Speter } 4305168515Sgshapiro else if (sm_strlcpy(host, p, sizeof(host)) >= sizeof(host)) 430638032Speter { 430790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 430890792Sgshapiro "Name too long\n"); 430938032Speter return; 431038032Speter } 4311168515Sgshapiro (void) getcanonname(host, sizeof(host), !HasWildcardMX, 431290792Sgshapiro NULL); 431390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 431490792Sgshapiro "getcanonname(%s) returns %s\n", 431590792Sgshapiro p, host); 431638032Speter } 431790792Sgshapiro else if (sm_strcasecmp(&line[1], "map") == 0) 431838032Speter { 431938032Speter auto int rcode = EX_OK; 432038032Speter char *av[2]; 432138032Speter 432238032Speter if (*p == '\0') 432338032Speter { 432490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 432590792Sgshapiro "Usage: /map mapname key\n"); 432638032Speter return; 432738032Speter } 432890792Sgshapiro for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 432938032Speter continue; 433038032Speter if (*q == '\0') 433138032Speter { 433290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 433390792Sgshapiro "No key specified\n"); 433438032Speter return; 433538032Speter } 433638032Speter *q++ = '\0'; 433738032Speter map = stab(p, ST_MAP, ST_FIND); 433838032Speter if (map == NULL) 433938032Speter { 434090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 434190792Sgshapiro "Map named \"%s\" not found\n", p); 434238032Speter return; 434338032Speter } 434464562Sgshapiro if (!bitset(MF_OPEN, map->s_map.map_mflags) && 434564562Sgshapiro !openmap(&(map->s_map))) 434638032Speter { 434790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 434890792Sgshapiro "Map named \"%s\" not open\n", p); 434938032Speter return; 435038032Speter } 435190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 435290792Sgshapiro "map_lookup: %s (%s) ", p, q); 435338032Speter av[0] = q; 435438032Speter av[1] = NULL; 435538032Speter p = (*map->s_map.map_class->map_lookup) 435638032Speter (&map->s_map, q, av, &rcode); 435738032Speter if (p == NULL) 435890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 435990792Sgshapiro "no match (%d)\n", 436090792Sgshapiro rcode); 436138032Speter else 436290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 436390792Sgshapiro "returns %s (%d)\n", p, 436490792Sgshapiro rcode); 436538032Speter } 436690792Sgshapiro else if (sm_strcasecmp(&line[1], "try") == 0) 436738032Speter { 436838032Speter MAILER *m; 436964562Sgshapiro STAB *st; 437038032Speter auto int rcode = EX_OK; 437138032Speter 437238032Speter q = strpbrk(p, " \t"); 437338032Speter if (q != NULL) 437438032Speter { 437538032Speter while (isascii(*q) && isspace(*q)) 437638032Speter *q++ = '\0'; 437738032Speter } 437838032Speter if (q == NULL || *q == '\0') 437938032Speter { 438090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 438190792Sgshapiro "Usage: /try mailer address\n"); 438238032Speter return; 438338032Speter } 438464562Sgshapiro st = stab(p, ST_MAILER, ST_FIND); 438564562Sgshapiro if (st == NULL) 438638032Speter { 438790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 438890792Sgshapiro "Unknown mailer %s\n", p); 438938032Speter return; 439038032Speter } 439164562Sgshapiro m = st->s_mailer; 439290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 439390792Sgshapiro "Trying %s %s address %s for mailer %s\n", 439490792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? "header" 439590792Sgshapiro : "envelope", 439690792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? "sender" 439790792Sgshapiro : "recipient", q, p); 439838032Speter p = remotename(q, m, tryflags, &rcode, CurEnv); 439990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 440090792Sgshapiro "Rcode = %d, addr = %s\n", 440190792Sgshapiro rcode, p == NULL ? "<NULL>" : p); 440238032Speter e->e_to = NULL; 440338032Speter } 440490792Sgshapiro else if (sm_strcasecmp(&line[1], "tryflags") == 0) 440538032Speter { 440638032Speter if (*p == '\0') 440738032Speter { 440890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 440990792Sgshapiro "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 441038032Speter return; 441138032Speter } 441238032Speter for (; *p != '\0'; p++) 441338032Speter { 441438032Speter switch (*p) 441538032Speter { 441638032Speter case 'H': 441738032Speter case 'h': 441838032Speter tryflags |= RF_HEADERADDR; 441938032Speter break; 442038032Speter 442138032Speter case 'E': 442238032Speter case 'e': 442338032Speter tryflags &= ~RF_HEADERADDR; 442438032Speter break; 442538032Speter 442638032Speter case 'S': 442738032Speter case 's': 442838032Speter tryflags |= RF_SENDERADDR; 442938032Speter break; 443038032Speter 443138032Speter case 'R': 443238032Speter case 'r': 443338032Speter tryflags &= ~RF_SENDERADDR; 443438032Speter break; 443538032Speter } 443638032Speter } 443764562Sgshapiro exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 443864562Sgshapiro exbuf[1] = ' '; 443964562Sgshapiro exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 444064562Sgshapiro exbuf[3] = '\0'; 444190792Sgshapiro macdefine(&e->e_macro, A_TEMP, 444290792Sgshapiro macid("{addr_type}"), exbuf); 444338032Speter } 444490792Sgshapiro else if (sm_strcasecmp(&line[1], "parse") == 0) 444538032Speter { 444638032Speter if (*p == '\0') 444738032Speter { 444890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 444990792Sgshapiro "Usage: /parse address\n"); 445038032Speter return; 445138032Speter } 4452111823Sgshapiro q = crackaddr(p, e); 445390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 445490792Sgshapiro "Cracked address = "); 4455132943Sgshapiro xputs(smioout, q); 445690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 445790792Sgshapiro "\nParsing %s %s address\n", 445890792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? 445990792Sgshapiro "header" : "envelope", 446090792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? 446190792Sgshapiro "sender" : "recipient"); 446290792Sgshapiro if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 446390792Sgshapiro == NULL) 446490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 446590792Sgshapiro "Cannot parse\n"); 446638032Speter else if (a.q_host != NULL && a.q_host[0] != '\0') 446790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 446890792Sgshapiro "mailer %s, host %s, user %s\n", 446990792Sgshapiro a.q_mailer->m_name, 447090792Sgshapiro a.q_host, 447190792Sgshapiro a.q_user); 447238032Speter else 447390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 447490792Sgshapiro "mailer %s, user %s\n", 447590792Sgshapiro a.q_mailer->m_name, 447690792Sgshapiro a.q_user); 447738032Speter e->e_to = NULL; 447838032Speter } 4479168515Sgshapiro else if (sm_strcasecmp(&line[1], "header") == 0) 4480168515Sgshapiro { 4481168515Sgshapiro unsigned long ul; 4482168515Sgshapiro 4483168515Sgshapiro ul = chompheader(p, CHHDR_CHECK|CHHDR_USER, NULL, e); 4484168515Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4485168515Sgshapiro "ul = %lu\n", ul); 4486168515Sgshapiro } 448738032Speter else 448838032Speter { 448990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 449090792Sgshapiro "Unknown \"/\" command %s\n", 449190792Sgshapiro line); 449238032Speter } 4493168515Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 449438032Speter return; 449538032Speter } 449638032Speter 449738032Speter for (p = line; isascii(*p) && isspace(*p); p++) 449838032Speter continue; 449938032Speter q = p; 450038032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 450138032Speter p++; 450238032Speter if (*p == '\0') 450338032Speter { 450490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 450590792Sgshapiro "No address!\n"); 450638032Speter return; 450738032Speter } 450838032Speter *p = '\0'; 4509168515Sgshapiro if (tTd(23, 101)) 4510168515Sgshapiro eightbit = to8bit(p + 1); 451190792Sgshapiro if (invalidaddr(p + 1, NULL, true)) 451238032Speter return; 451338032Speter do 451438032Speter { 451538032Speter register char **pvp; 451638032Speter char pvpbuf[PSBUFSIZE]; 451738032Speter 4518168515Sgshapiro pvp = prescan(++p, ',', pvpbuf, sizeof(pvpbuf), &delimptr, 4519168515Sgshapiro ConfigLevel >= 9 ? TokTypeNoC : ExtTokenTab, false); 452038032Speter if (pvp == NULL) 452138032Speter continue; 452238032Speter p = q; 452338032Speter while (*p != '\0') 452438032Speter { 452564562Sgshapiro int status; 452638032Speter 452738032Speter rs = strtorwset(p, NULL, ST_FIND); 452838032Speter if (rs < 0) 452938032Speter { 453090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 453190792Sgshapiro "Undefined ruleset %s\n", 453290792Sgshapiro p); 453338032Speter break; 453438032Speter } 453590792Sgshapiro status = REWRITE(pvp, rs, e); 453664562Sgshapiro if (status != EX_OK) 453790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 453890792Sgshapiro "== Ruleset %s (%d) status %d\n", 453990792Sgshapiro p, rs, status); 4540168515Sgshapiro else if (eightbit) 4541168515Sgshapiro { 4542168515Sgshapiro cataddr(pvp, NULL, exbuf, sizeof(exbuf), '\0', 4543168515Sgshapiro true); 4544168515Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4545168515Sgshapiro "cataddr: %s\n", 4546168515Sgshapiro str2prt(exbuf)); 4547168515Sgshapiro } 454838032Speter while (*p != '\0' && *p++ != ',') 454938032Speter continue; 455038032Speter } 455138032Speter } while (*(p = delimptr) != '\0'); 4552168515Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 455338032Speter} 455438032Speter 455564562Sgshapirostatic void 455638032Speterdump_class(s, id) 455738032Speter register STAB *s; 455838032Speter int id; 455938032Speter{ 456090792Sgshapiro if (s->s_symtype != ST_CLASS) 456138032Speter return; 456271345Sgshapiro if (bitnset(bitidx(id), s->s_class)) 456390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 456490792Sgshapiro "%s\n", s->s_name); 456538032Speter} 456690792Sgshapiro 456790792Sgshapiro/* 456890792Sgshapiro** An exception type used to create QuickAbort exceptions. 456990792Sgshapiro** This is my first cut at converting QuickAbort from longjmp to exceptions. 457090792Sgshapiro** These exceptions have a single integer argument, which is the argument 457190792Sgshapiro** to longjmp in the original code (either 1 or 2). I don't know the 457290792Sgshapiro** significance of 1 vs 2: the calls to setjmp don't care. 457390792Sgshapiro*/ 457490792Sgshapiro 457590792Sgshapiroconst SM_EXC_TYPE_T EtypeQuickAbort = 457690792Sgshapiro{ 457790792Sgshapiro SmExcTypeMagic, 457890792Sgshapiro "E:mta.quickabort", 457990792Sgshapiro "i", 458090792Sgshapiro sm_etype_printf, 458190792Sgshapiro "quick abort %0", 458290792Sgshapiro}; 4583