138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2006, 2008, 2009, 2011 Proofpoint, 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> 19363466Sgshapiro#include <tls.h> 2090792Sgshapiro 2138032Speter#ifndef lint 2290792SgshapiroSM_UNUSED(static char copyright[]) = 23261194Sgshapiro"@(#) Copyright (c) 1998-2013 Proofpoint, Inc. and its suppliers.\n\ 2464562Sgshapiro All rights reserved.\n\ 2538032Speter Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 2638032Speter Copyright (c) 1988, 1993\n\ 2738032Speter The Regents of the University of California. All rights reserved.\n"; 2864562Sgshapiro#endif /* ! lint */ 2938032Speter 30266527SgshapiroSM_RCSID("@(#)$Id: main.c,v 8.988 2013-11-23 02:52:37 gshapiro Exp $") 3138032Speter 3238032Speter 3364562Sgshapiro#if NETINET || NETINET6 3464562Sgshapiro# include <arpa/inet.h> 35363466Sgshapiro# if DANE 36363466Sgshapiro# include "sm_resolve.h" 37363466Sgshapiro# endif 38363466Sgshapiro#endif 3964562Sgshapiro 4090792Sgshapiro/* for getcfname() */ 4190792Sgshapiro#include <sendmail/pathnames.h> 42363466Sgshapiro#include <ratectrl.h> 4390792Sgshapiro 4490792Sgshapirostatic SM_DEBUG_T 4590792SgshapiroDebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart", 4690792Sgshapiro "@(#)$Debug: no_persistent_restart - don't restart, log only $"); 4790792Sgshapiro 4890792Sgshapirostatic void dump_class __P((STAB *, int)); 4990792Sgshapirostatic void obsolete __P((char **)); 5090792Sgshapirostatic void testmodeline __P((char *, ENVELOPE *)); 5190792Sgshapirostatic char *getextenv __P((const char *)); 5290792Sgshapirostatic void sm_printoptions __P((char **)); 5377349Sgshapirostatic SIGFUNC_DECL intindebug __P((int)); 5490792Sgshapirostatic SIGFUNC_DECL sighup __P((int)); 5590792Sgshapirostatic SIGFUNC_DECL sigpipe __P((int)); 5690792Sgshapirostatic SIGFUNC_DECL sigterm __P((int)); 5780785Sgshapiro#ifdef SIGUSR1 5877349Sgshapirostatic SIGFUNC_DECL sigusr1 __P((int)); 59363466Sgshapiro#endif 6064562Sgshapiro 6138032Speter/* 6238032Speter** SENDMAIL -- Post mail to a set of destinations. 6338032Speter** 6438032Speter** This is the basic mail router. All user mail programs should 6538032Speter** call this routine to actually deliver mail. Sendmail in 6638032Speter** turn calls a bunch of mail servers that do the real work of 6738032Speter** delivering the mail. 6838032Speter** 6964562Sgshapiro** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 7038032Speter** (read by readcf.c). 7138032Speter** 7238032Speter** Usage: 7338032Speter** /usr/lib/sendmail [flags] addr ... 7438032Speter** 7538032Speter** See the associated documentation for details. 7638032Speter** 7790792Sgshapiro** Authors: 7838032Speter** Eric Allman, UCB/INGRES (until 10/81). 7938032Speter** Britton-Lee, Inc., purveyors of fine 8038032Speter** database computers (11/81 - 10/88). 8138032Speter** International Computer Science Institute 8238032Speter** (11/88 - 9/89). 8338032Speter** UCB/Mammoth Project (10/89 - 7/95). 8438032Speter** InReference, Inc. (8/95 - 1/97). 85261194Sgshapiro** Sendmail, Inc. (1/98 - 9/13). 86111823Sgshapiro** The support of my employers is gratefully acknowledged. 8738032Speter** Few of them (Britton-Lee in particular) have had 8838032Speter** anything to gain from my involvement in this project. 8990792Sgshapiro** 9090792Sgshapiro** Gregory Neil Shapiro, 9190792Sgshapiro** Worcester Polytechnic Institute (until 3/98). 92261194Sgshapiro** Sendmail, Inc. (3/98 - 10/13). 93261194Sgshapiro** Proofpoint, Inc. (10/13 - present). 9490792Sgshapiro** 9590792Sgshapiro** Claus Assmann, 96261194Sgshapiro** Sendmail, Inc. (12/98 - 10/13). 97261194Sgshapiro** Proofpoint, Inc. (10/13 - present). 9838032Speter*/ 9938032Speter 10038032Speterchar *FullName; /* sender's full name */ 10138032SpeterENVELOPE BlankEnvelope; /* a "blank" envelope */ 10264562Sgshapirostatic ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 10338032SpeterADDRESS NullAddress = /* a null address */ 10438032Speter { "", "", NULL, "" }; 10538032Speterchar *CommandLineArgs; /* command line args for pid file */ 10690792Sgshapirobool Warn_Q_option = false; /* warn about Q option use */ 10764562Sgshapirostatic int MissingFds = 0; /* bit map of fds missing on startup */ 10890792Sgshapirochar *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */ 10938032Speter 11038032Speter#ifdef NGROUPS_MAX 11138032SpeterGIDSET_T InitialGidSet[NGROUPS_MAX]; 112363466Sgshapiro#endif 11338032Speter 11490792Sgshapiro#define MAXCONFIGLEVEL 10 /* highest config version level known */ 11538032Speter 11664562Sgshapiro#if SASL 11764562Sgshapirostatic sasl_callback_t srvcallbacks[] = 11864562Sgshapiro{ 119225906Sume { SASL_CB_VERIFYFILE, (sasl_callback_ft)&safesaslfile, NULL }, 120225906Sume { SASL_CB_PROXY_POLICY, (sasl_callback_ft)&proxy_policy, NULL }, 12164562Sgshapiro { SASL_CB_LIST_END, NULL, NULL } 12264562Sgshapiro}; 12364562Sgshapiro#endif /* SASL */ 12464562Sgshapiro 12590792Sgshapirounsigned int SubmitMode; 12690792Sgshapiroint SyslogPrefixLen; /* estimated length of syslog prefix */ 12790792Sgshapiro#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 12890792Sgshapiro#ifndef SL_FUDGE 12990792Sgshapiro# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 130363466Sgshapiro#endif 13190792Sgshapiro#define SLDLL 8 /* est. length of default syslog label */ 13264562Sgshapiro 13390792Sgshapiro 13490792Sgshapiro/* Some options are dangerous to allow users to use in non-submit mode */ 13590792Sgshapiro#define CHECK_AGAINST_OPMODE(cmd) \ 13690792Sgshapiro{ \ 13790792Sgshapiro if (extraprivs && \ 13890792Sgshapiro OpMode != MD_DELIVER && OpMode != MD_SMTP && \ 139203004Sgshapiro OpMode != MD_ARPAFTP && OpMode != MD_CHECKCONFIG && \ 14090792Sgshapiro OpMode != MD_VERIFY && OpMode != MD_TEST) \ 14190792Sgshapiro { \ 14290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 14390792Sgshapiro "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \ 14490792Sgshapiro (cmd)); \ 14590792Sgshapiro break; \ 14690792Sgshapiro } \ 14790792Sgshapiro if (extraprivs && queuerun) \ 14890792Sgshapiro { \ 14990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 15090792Sgshapiro "WARNING: Ignoring submission mode -%c option with -q\n", \ 15190792Sgshapiro (cmd)); \ 15290792Sgshapiro break; \ 15390792Sgshapiro } \ 15490792Sgshapiro} 15590792Sgshapiro 15638032Speterint 15738032Spetermain(argc, argv, envp) 15838032Speter int argc; 15938032Speter char **argv; 16038032Speter char **envp; 16138032Speter{ 16238032Speter register char *p; 16338032Speter char **av; 16438032Speter extern char Version[]; 16538032Speter char *ep, *from; 16638032Speter STAB *st; 16738032Speter register int i; 16838032Speter int j; 16964562Sgshapiro int dp; 17090792Sgshapiro int fill_errno; 17190792Sgshapiro int qgrp = NOQGRP; /* queue group to process */ 17290792Sgshapiro bool safecf = true; 17364562Sgshapiro BITMAP256 *p_flags = NULL; /* daemon flags */ 17490792Sgshapiro bool warn_C_flag = false; 17590792Sgshapiro bool auth = true; /* whether to set e_auth_param */ 17638032Speter char warn_f_flag = '\0'; 17790792Sgshapiro bool run_in_foreground = false; /* -bD mode */ 17890792Sgshapiro bool queuerun = false, debug = false; 17938032Speter struct passwd *pw; 18038032Speter struct hostent *hp; 18138032Speter char *nullserver = NULL; 18264562Sgshapiro char *authinfo = NULL; 18364562Sgshapiro char *sysloglabel = NULL; /* label for syslog */ 18490792Sgshapiro char *conffile = NULL; /* name of .cf file */ 18590792Sgshapiro char *queuegroup = NULL; /* queue group to process */ 18690792Sgshapiro char *quarantining = NULL; /* quarantine queue items? */ 18790792Sgshapiro bool extraprivs; 18890792Sgshapiro bool forged, negate; 18990792Sgshapiro bool queuepersistent = false; /* queue runner process runs forever */ 19090792Sgshapiro bool foregroundqueue = false; /* queue run in foreground */ 19190792Sgshapiro bool save_val; /* to save some bool var. */ 19290792Sgshapiro int cftype; /* which cf file to use? */ 193132943Sgshapiro SM_FILE_T *smdebug; 19490792Sgshapiro static time_t starttime = 0; /* when was process started */ 19564562Sgshapiro struct stat traf_st; /* for TrafficLog FIFO check */ 19690792Sgshapiro char buf[MAXLINE]; 19738032Speter char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 19838032Speter static char rnamebuf[MAXNAME]; /* holds RealUserName */ 19938032Speter char *emptyenviron[1]; 20090792Sgshapiro#if STARTTLS 20166494Sgshapiro bool tls_ok; 202363466Sgshapiro#endif 20338032Speter QUEUE_CHAR *new; 20490792Sgshapiro ENVELOPE *e; 20538032Speter extern int DtableSize; 20638032Speter extern int optind; 20738032Speter extern int opterr; 20838032Speter extern char *optarg; 20938032Speter extern char **environ; 21090792Sgshapiro#if SASL 21190792Sgshapiro extern void sm_sasl_init __P((void)); 212363466Sgshapiro#endif 21338032Speter 21490792Sgshapiro#if USE_ENVIRON 21590792Sgshapiro envp = environ; 216363466Sgshapiro#endif 21790792Sgshapiro 21890792Sgshapiro /* turn off profiling */ 21990792Sgshapiro SM_PROF(0); 22090792Sgshapiro 22190792Sgshapiro /* install default exception handler */ 22290792Sgshapiro sm_exc_newthread(fatal_error); 22390792Sgshapiro 224110560Sgshapiro /* set the default in/out channel so errors reported to screen */ 225110560Sgshapiro InChannel = smioin; 226110560Sgshapiro OutChannel = smioout; 227110560Sgshapiro 22838032Speter /* 22938032Speter ** Check to see if we reentered. 23038032Speter ** This would normally happen if e_putheader or e_putbody 23138032Speter ** were NULL when invoked. 23238032Speter */ 23338032Speter 23490792Sgshapiro if (starttime != 0) 23538032Speter { 23638032Speter syserr("main: reentered!"); 23738032Speter abort(); 23838032Speter } 23990792Sgshapiro starttime = curtime(); 24038032Speter 24138032Speter /* avoid null pointer dereferences */ 242168515Sgshapiro TermEscape.te_rv_on = TermEscape.te_under_on = TermEscape.te_normal = ""; 24338032Speter 24490792Sgshapiro RealUid = getuid(); 24590792Sgshapiro RealGid = getgid(); 24677349Sgshapiro 24790792Sgshapiro /* Check if sendmail is running with extra privs */ 24890792Sgshapiro extraprivs = (RealUid != 0 && 24990792Sgshapiro (geteuid() != getuid() || getegid() != getgid())); 25077349Sgshapiro 25190792Sgshapiro CurrentPid = getpid(); 25238032Speter 25390792Sgshapiro /* get whatever .cf file is right for the opmode */ 25490792Sgshapiro cftype = SM_GET_RIGHT_CF; 25564562Sgshapiro 25638032Speter /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 25738032Speter DtableSize = getdtsize(); 25838032Speter if (DtableSize > 256) 25938032Speter DtableSize = 256; 26038032Speter 26138032Speter /* 26238032Speter ** Be sure we have enough file descriptors. 26338032Speter ** But also be sure that 0, 1, & 2 are open. 26438032Speter */ 26538032Speter 26690792Sgshapiro /* reset errno and fill_errno; the latter is used way down below */ 26790792Sgshapiro errno = fill_errno = 0; 26838032Speter fill_fd(STDIN_FILENO, NULL); 26990792Sgshapiro if (errno != 0) 27090792Sgshapiro fill_errno = errno; 27138032Speter fill_fd(STDOUT_FILENO, NULL); 27290792Sgshapiro if (errno != 0) 27390792Sgshapiro fill_errno = errno; 27438032Speter fill_fd(STDERR_FILENO, NULL); 27590792Sgshapiro if (errno != 0) 27690792Sgshapiro fill_errno = errno; 27738032Speter 278132943Sgshapiro sm_closefrom(STDERR_FILENO + 1, DtableSize); 27938032Speter errno = 0; 280132943Sgshapiro smdebug = NULL; 28138032Speter 28238032Speter#if LOG 28390792Sgshapiro# ifndef SM_LOG_STR 28490792Sgshapiro# define SM_LOG_STR "sendmail" 285363466Sgshapiro# endif 286363466Sgshapiro# ifdef LOG_MAIL 28790792Sgshapiro openlog(SM_LOG_STR, LOG_PID, LOG_MAIL); 288363466Sgshapiro# else 28990792Sgshapiro openlog(SM_LOG_STR, LOG_PID); 290363466Sgshapiro# endif 29164562Sgshapiro#endif /* LOG */ 29238032Speter 29390792Sgshapiro /* 29490792Sgshapiro ** Seed the random number generator. 29590792Sgshapiro ** Used for queue file names, picking a queue directory, and 29690792Sgshapiro ** MX randomization. 29790792Sgshapiro */ 29838032Speter 29990792Sgshapiro seed_random(); 30038032Speter 30190792Sgshapiro /* do machine-dependent initializations */ 30290792Sgshapiro init_md(argc, argv); 30390792Sgshapiro 30490792Sgshapiro 30590792Sgshapiro SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL; 30690792Sgshapiro 30738032Speter /* reset status from syserr() calls for missing file descriptors */ 30838032Speter Errors = 0; 30938032Speter ExitStat = EX_OK; 31038032Speter 31164562Sgshapiro SubmitMode = SUBMIT_UNKNOWN; 312182352Sgshapiro#if _FFR_LOCAL_DAEMON 313182352Sgshapiro LocalDaemon = false; 314223067Sgshapiro# if NETINET6 315223067Sgshapiro V6LoopbackAddrFound = false; 316363466Sgshapiro# endif 317363466Sgshapiro#endif 31838032Speter#if XDEBUG 31938032Speter checkfd012("after openlog"); 320363466Sgshapiro#endif 32138032Speter 322168515Sgshapiro tTsetup(tTdvect, sizeof(tTdvect), "0-99.1,*_trace_*.1"); 32338032Speter 32438032Speter#ifdef NGROUPS_MAX 32538032Speter /* save initial group set for future checks */ 32638032Speter i = getgroups(NGROUPS_MAX, InitialGidSet); 32790792Sgshapiro if (i <= 0) 32890792Sgshapiro { 32938032Speter InitialGidSet[0] = (GID_T) -1; 33090792Sgshapiro i = 0; 33190792Sgshapiro } 33238032Speter while (i < NGROUPS_MAX) 33338032Speter InitialGidSet[i++] = InitialGidSet[0]; 33464562Sgshapiro#endif /* NGROUPS_MAX */ 33538032Speter 33638032Speter /* drop group id privileges (RunAsUser not yet set) */ 33790792Sgshapiro dp = drop_privileges(false); 33864562Sgshapiro setstat(dp); 33938032Speter 34090792Sgshapiro#ifdef SIGUSR1 34177349Sgshapiro /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 34294334Sgshapiro if (!extraprivs) 34377349Sgshapiro { 34477349Sgshapiro /* arrange to dump state on user-1 signal */ 34590792Sgshapiro (void) sm_signal(SIGUSR1, sigusr1); 34677349Sgshapiro } 34794334Sgshapiro else 34894334Sgshapiro { 34994334Sgshapiro /* ignore user-1 signal */ 35094334Sgshapiro (void) sm_signal(SIGUSR1, SIG_IGN); 35194334Sgshapiro } 35290792Sgshapiro#endif /* SIGUSR1 */ 35338032Speter 35438032Speter /* initialize for setproctitle */ 35538032Speter initsetproctitle(argc, argv, envp); 35638032Speter 35738032Speter /* Handle any non-getoptable constructions. */ 35838032Speter obsolete(argv); 35938032Speter 36038032Speter /* 36138032Speter ** Do a quick prescan of the argument list. 36238032Speter */ 36338032Speter 36464562Sgshapiro 36590792Sgshapiro /* find initial opMode */ 36690792Sgshapiro OpMode = MD_DELIVER; 36790792Sgshapiro av = argv; 36890792Sgshapiro p = strrchr(*av, '/'); 36990792Sgshapiro if (p++ == NULL) 37090792Sgshapiro p = *av; 37190792Sgshapiro if (strcmp(p, "newaliases") == 0) 37290792Sgshapiro OpMode = MD_INITALIAS; 37390792Sgshapiro else if (strcmp(p, "mailq") == 0) 37490792Sgshapiro OpMode = MD_PRINT; 37590792Sgshapiro else if (strcmp(p, "smtpd") == 0) 37690792Sgshapiro OpMode = MD_DAEMON; 37790792Sgshapiro else if (strcmp(p, "hoststat") == 0) 37890792Sgshapiro OpMode = MD_HOSTSTAT; 37990792Sgshapiro else if (strcmp(p, "purgestat") == 0) 38090792Sgshapiro OpMode = MD_PURGESTAT; 38190792Sgshapiro 382132943Sgshapiro#if defined(__osf__) || defined(_AIX3) 383132943Sgshapiro# 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" 384132943Sgshapiro#endif /* defined(__osf__) || defined(_AIX3) */ 385132943Sgshapiro#if defined(sony_news) 386132943Sgshapiro# 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:" 387132943Sgshapiro#endif /* defined(sony_news) */ 388132943Sgshapiro#ifndef OPTIONS 389132943Sgshapiro# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" 390363466Sgshapiro#endif 39190792Sgshapiro 392112810Sgshapiro /* Set to 0 to allow -b; need to check optarg before using it! */ 39338032Speter opterr = 0; 39438032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 39538032Speter { 39638032Speter switch (j) 39738032Speter { 39890792Sgshapiro case 'b': /* operations mode */ 39994334Sgshapiro j = (optarg == NULL) ? ' ' : *optarg; 40094334Sgshapiro switch (j) 40138032Speter { 40290792Sgshapiro case MD_DAEMON: 40390792Sgshapiro case MD_FGDAEMON: 40490792Sgshapiro case MD_SMTP: 40590792Sgshapiro case MD_INITALIAS: 40690792Sgshapiro case MD_DELIVER: 40790792Sgshapiro case MD_VERIFY: 40890792Sgshapiro case MD_TEST: 40990792Sgshapiro case MD_PRINT: 41090792Sgshapiro case MD_PRINTNQE: 41190792Sgshapiro case MD_HOSTSTAT: 41290792Sgshapiro case MD_PURGESTAT: 41390792Sgshapiro case MD_ARPAFTP: 414203004Sgshapiro case MD_CHECKCONFIG: 41590792Sgshapiro OpMode = j; 41638032Speter break; 41790792Sgshapiro 418182352Sgshapiro#if _FFR_LOCAL_DAEMON 419182352Sgshapiro case MD_LOCAL: 420182352Sgshapiro OpMode = MD_DAEMON; 421182352Sgshapiro LocalDaemon = true; 422182352Sgshapiro break; 423182352Sgshapiro#endif /* _FFR_LOCAL_DAEMON */ 424182352Sgshapiro 42590792Sgshapiro case MD_FREEZE: 42690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42790792Sgshapiro "Frozen configurations unsupported\n"); 42890792Sgshapiro return EX_USAGE; 42990792Sgshapiro 43090792Sgshapiro default: 43190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43290792Sgshapiro "Invalid operation mode %c\n", 43390792Sgshapiro j); 43490792Sgshapiro return EX_USAGE; 43538032Speter } 43690792Sgshapiro break; 43790792Sgshapiro 438132943Sgshapiro case 'D': 439132943Sgshapiro if (debug) 440132943Sgshapiro { 441132943Sgshapiro errno = 0; 442132943Sgshapiro syserr("-D file must be before -d"); 443132943Sgshapiro ExitStat = EX_USAGE; 444132943Sgshapiro break; 445132943Sgshapiro } 446132943Sgshapiro dp = drop_privileges(true); 447132943Sgshapiro setstat(dp); 448132943Sgshapiro smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 449132943Sgshapiro optarg, SM_IO_APPEND, NULL); 450132943Sgshapiro if (smdebug == NULL) 451132943Sgshapiro { 452132943Sgshapiro syserr("cannot open %s", optarg); 453132943Sgshapiro ExitStat = EX_CANTCREAT; 454132943Sgshapiro break; 455132943Sgshapiro } 456132943Sgshapiro sm_debug_setfile(smdebug); 457132943Sgshapiro break; 458132943Sgshapiro 45990792Sgshapiro case 'd': 46090792Sgshapiro debug = true; 46138032Speter tTflag(optarg); 462132943Sgshapiro (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT, 46390792Sgshapiro (char *) NULL, SM_IO_NBF, 46490792Sgshapiro SM_IO_BUFSIZ); 46538032Speter break; 46664562Sgshapiro 46764562Sgshapiro case 'G': /* relay (gateway) submission */ 46890792Sgshapiro SubmitMode = SUBMIT_MTA; 46964562Sgshapiro break; 47064562Sgshapiro 47164562Sgshapiro case 'L': 472112810Sgshapiro if (optarg == NULL) 473112810Sgshapiro { 474112810Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 475112810Sgshapiro "option requires an argument -- '%c'", 476112810Sgshapiro (char) j); 477112810Sgshapiro return EX_USAGE; 478112810Sgshapiro } 479132943Sgshapiro j = SM_MIN(strlen(optarg), 32) + 1; 48064562Sgshapiro sysloglabel = xalloc(j); 48190792Sgshapiro (void) sm_strlcpy(sysloglabel, optarg, j); 48290792Sgshapiro SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + 48390792Sgshapiro SL_FUDGE + j; 48464562Sgshapiro break; 48564562Sgshapiro 48690792Sgshapiro case 'Q': 48790792Sgshapiro case 'q': 48890792Sgshapiro /* just check if it is there */ 48990792Sgshapiro queuerun = true; 49064562Sgshapiro break; 49138032Speter } 49238032Speter } 49338032Speter opterr = 1; 49438032Speter 49590792Sgshapiro /* Don't leak queue information via debug flags */ 49690792Sgshapiro if (extraprivs && queuerun && debug) 49790792Sgshapiro { 49890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 49990792Sgshapiro "WARNING: Can not use -d with -q. Disabling debugging.\n"); 500132943Sgshapiro sm_debug_close(); 50190792Sgshapiro sm_debug_setfile(NULL); 502168515Sgshapiro (void) memset(tTdvect, '\0', sizeof(tTdvect)); 50390792Sgshapiro } 50490792Sgshapiro 50577349Sgshapiro#if LOG 50664562Sgshapiro if (sysloglabel != NULL) 50764562Sgshapiro { 50877349Sgshapiro /* Sanitize the string */ 50977349Sgshapiro for (p = sysloglabel; *p != '\0'; p++) 51077349Sgshapiro { 51177349Sgshapiro if (!isascii(*p) || !isprint(*p) || *p == '%') 51277349Sgshapiro *p = '*'; 51377349Sgshapiro } 51464562Sgshapiro closelog(); 515363466Sgshapiro# ifdef LOG_MAIL 51664562Sgshapiro openlog(sysloglabel, LOG_PID, LOG_MAIL); 517363466Sgshapiro# else 51864562Sgshapiro openlog(sysloglabel, LOG_PID); 519363466Sgshapiro# endif 52077349Sgshapiro } 52164562Sgshapiro#endif /* LOG */ 52264562Sgshapiro 52338032Speter /* set up the blank envelope */ 52438032Speter BlankEnvelope.e_puthdr = putheader; 52538032Speter BlankEnvelope.e_putbody = putbody; 52638032Speter BlankEnvelope.e_xfp = NULL; 52738032Speter STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 52838032Speter CurEnv = &BlankEnvelope; 52938032Speter STRUCTCOPY(NullAddress, MainEnvelope.e_from); 53038032Speter 53138032Speter /* 53238032Speter ** Set default values for variables. 53338032Speter ** These cannot be in initialized data space. 53438032Speter */ 53538032Speter 53638032Speter setdefaults(&BlankEnvelope); 53790792Sgshapiro initmacros(&BlankEnvelope); 53838032Speter 53990792Sgshapiro /* reset macro */ 54090792Sgshapiro set_op_mode(OpMode); 541159609Sgshapiro if (OpMode == MD_DAEMON) 542159609Sgshapiro DaemonPid = CurrentPid; /* needed for finis() to work */ 54338032Speter 54438032Speter pw = sm_getpwuid(RealUid); 54538032Speter if (pw != NULL) 546168515Sgshapiro (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof(rnamebuf)); 54738032Speter else 548168515Sgshapiro (void) sm_snprintf(rnamebuf, sizeof(rnamebuf), "Unknown UID %d", 54990792Sgshapiro (int) RealUid); 55064562Sgshapiro 55138032Speter RealUserName = rnamebuf; 55238032Speter 55338032Speter if (tTd(0, 101)) 55438032Speter { 55590792Sgshapiro sm_dprintf("Version %s\n", Version); 55690792Sgshapiro finis(false, true, EX_OK); 55790792Sgshapiro /* NOTREACHED */ 55838032Speter } 55938032Speter 56038032Speter /* 56190792Sgshapiro ** if running non-set-user-ID binary as non-root, pretend 56238032Speter ** we are the RunAsUid 56338032Speter */ 56477349Sgshapiro 56538032Speter if (RealUid != 0 && geteuid() == RealUid) 56638032Speter { 56738032Speter if (tTd(47, 1)) 56890792Sgshapiro sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n", 56990792Sgshapiro (int) RealUid); 57038032Speter RunAsUid = RealUid; 57138032Speter } 57238032Speter else if (geteuid() != 0) 57338032Speter RunAsUid = geteuid(); 57438032Speter 57590792Sgshapiro EffGid = getegid(); 57690792Sgshapiro if (RealUid != 0 && EffGid == RealGid) 57738032Speter RunAsGid = RealGid; 57838032Speter 57938032Speter if (tTd(47, 5)) 58038032Speter { 58190792Sgshapiro sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 58290792Sgshapiro (int) geteuid(), (int) getuid(), 58390792Sgshapiro (int) getegid(), (int) getgid()); 58490792Sgshapiro sm_dprintf("main: RunAsUser = %d:%d\n", 58590792Sgshapiro (int) RunAsUid, (int) RunAsGid); 58638032Speter } 58738032Speter 58838032Speter /* save command line arguments */ 58964562Sgshapiro j = 0; 59038032Speter for (av = argv; *av != NULL; ) 59164562Sgshapiro j += strlen(*av++) + 1; 592168515Sgshapiro SaveArgv = (char **) xalloc(sizeof(char *) * (argc + 1)); 59364562Sgshapiro CommandLineArgs = xalloc(j); 59438032Speter p = CommandLineArgs; 59538032Speter for (av = argv, i = 0; *av != NULL; ) 59638032Speter { 59764562Sgshapiro int h; 59864562Sgshapiro 59938032Speter SaveArgv[i++] = newstr(*av); 60038032Speter if (av != argv) 60138032Speter *p++ = ' '; 60290792Sgshapiro (void) sm_strlcpy(p, *av++, j); 60364562Sgshapiro h = strlen(p); 60464562Sgshapiro p += h; 60564562Sgshapiro j -= h + 1; 60638032Speter } 60738032Speter SaveArgv[i] = NULL; 60838032Speter 60938032Speter if (tTd(0, 1)) 61038032Speter { 61138032Speter extern char *CompileOptions[]; 61238032Speter 61390792Sgshapiro sm_dprintf("Version %s\n Compiled with:", Version); 61490792Sgshapiro sm_printoptions(CompileOptions); 61538032Speter } 61638032Speter if (tTd(0, 10)) 61738032Speter { 61838032Speter extern char *OsCompileOptions[]; 61938032Speter 62090792Sgshapiro sm_dprintf(" OS Defines:"); 62190792Sgshapiro sm_printoptions(OsCompileOptions); 62238032Speter#ifdef _PATH_UNIX 62390792Sgshapiro sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 624363466Sgshapiro#endif 62590792Sgshapiro 62690792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MSP)\n", 62790792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF, 62890792Sgshapiro conffile)); 62990792Sgshapiro sm_dprintf(" Conf file:\t%s (default for MTA)\n", 63090792Sgshapiro getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF, 63190792Sgshapiro conffile)); 63290792Sgshapiro sm_dprintf(" Pid file:\t%s (default)\n", PidFile); 63338032Speter } 63438032Speter 63590792Sgshapiro if (tTd(0, 12)) 63690792Sgshapiro { 63790792Sgshapiro extern char *SmCompileOptions[]; 63838032Speter 63990792Sgshapiro sm_dprintf(" libsm Defines:"); 64090792Sgshapiro sm_printoptions(SmCompileOptions); 64190792Sgshapiro } 64290792Sgshapiro 64390792Sgshapiro if (tTd(0, 13)) 64490792Sgshapiro { 64590792Sgshapiro extern char *FFRCompileOptions[]; 64690792Sgshapiro 64790792Sgshapiro sm_dprintf(" FFR Defines:"); 64890792Sgshapiro sm_printoptions(FFRCompileOptions); 64990792Sgshapiro } 65090792Sgshapiro 651285229Sgshapiro#if STARTTLS 652285229Sgshapiro if (tTd(0, 14)) 653285229Sgshapiro { 654285229Sgshapiro /* exit(EX_CONFIG) if different? */ 655285229Sgshapiro sm_dprintf(" OpenSSL: compiled 0x%08x\n", 656285229Sgshapiro (uint) OPENSSL_VERSION_NUMBER); 657285229Sgshapiro sm_dprintf(" OpenSSL: linked 0x%08x\n", 658363466Sgshapiro (uint) TLS_version_num()); 659285229Sgshapiro } 660285229Sgshapiro#endif /* STARTTLS */ 661285229Sgshapiro 66238032Speter /* clear sendmail's environment */ 66338032Speter ExternalEnviron = environ; 66438032Speter emptyenviron[0] = NULL; 66538032Speter environ = emptyenviron; 66638032Speter 66738032Speter /* 66842575Speter ** restore any original TZ setting until TimeZoneSpec has been 66942575Speter ** determined - or early log messages may get bogus time stamps 67038032Speter */ 67190792Sgshapiro 67238032Speter if ((p = getextenv("TZ")) != NULL) 67338032Speter { 67438032Speter char *tz; 67538032Speter int tzlen; 67638032Speter 67790792Sgshapiro /* XXX check for reasonable length? */ 67838032Speter tzlen = strlen(p) + 4; 67938032Speter tz = xalloc(tzlen); 68090792Sgshapiro (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p); 68190792Sgshapiro 68290792Sgshapiro /* XXX check return code? */ 68364562Sgshapiro (void) putenv(tz); 68438032Speter } 68538032Speter 68638032Speter /* prime the child environment */ 687157001Sgshapiro sm_setuserenv("AGENT", "sendmail"); 68838032Speter 68990792Sgshapiro (void) sm_signal(SIGPIPE, SIG_IGN); 69038032Speter OldUmask = umask(022); 69138032Speter FullName = getextenv("NAME"); 69295154Sgshapiro if (FullName != NULL) 69395154Sgshapiro FullName = newstr(FullName); 69438032Speter 69538032Speter /* 69638032Speter ** Initialize name server if it is going to be used. 69738032Speter */ 69838032Speter 69938032Speter#if NAMED_BIND 70038032Speter if (!bitset(RES_INIT, _res.options)) 70164562Sgshapiro (void) res_init(); 70238032Speter if (tTd(8, 8)) 70338032Speter _res.options |= RES_DEBUG; 70438032Speter else 70538032Speter _res.options &= ~RES_DEBUG; 70638032Speter# ifdef RES_NOALIASES 70738032Speter _res.options |= RES_NOALIASES; 708363466Sgshapiro# endif 70964562Sgshapiro TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 71064562Sgshapiro TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 71164562Sgshapiro TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 71264562Sgshapiro TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 71364562Sgshapiro TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 71464562Sgshapiro TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 71564562Sgshapiro#endif /* NAMED_BIND */ 71638032Speter 71738032Speter errno = 0; 71838032Speter from = NULL; 71938032Speter 72038032Speter /* initialize some macros, etc. */ 72190792Sgshapiro init_vendor_macros(&BlankEnvelope); 72238032Speter 72338032Speter /* version */ 72490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version); 72538032Speter 72638032Speter /* hostname */ 727168515Sgshapiro hp = myhostname(jbuf, sizeof(jbuf)); 72838032Speter if (jbuf[0] != '\0') 72938032Speter { 73090792Sgshapiro struct utsname utsname; 73138032Speter 73238032Speter if (tTd(0, 4)) 73390792Sgshapiro sm_dprintf("Canonical name: %s\n", jbuf); 73490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf); 73590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf); 73638032Speter setclass('w', jbuf); 73738032Speter 73838032Speter p = strchr(jbuf, '.'); 739132943Sgshapiro if (p != NULL && p[1] != '\0') 740132943Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]); 74138032Speter 74238032Speter if (uname(&utsname) >= 0) 74338032Speter p = utsname.nodename; 74438032Speter else 74538032Speter { 74638032Speter if (tTd(0, 22)) 74790792Sgshapiro sm_dprintf("uname failed (%s)\n", 74890792Sgshapiro sm_errstring(errno)); 74938032Speter makelower(jbuf); 75038032Speter p = jbuf; 75138032Speter } 75238032Speter if (tTd(0, 4)) 75390792Sgshapiro sm_dprintf(" UUCP nodename: %s\n", p); 75490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p); 75538032Speter setclass('k', p); 75638032Speter setclass('w', p); 75738032Speter } 75838032Speter if (hp != NULL) 75938032Speter { 76038032Speter for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 76138032Speter { 76238032Speter if (tTd(0, 4)) 76390792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", *av); 76438032Speter setclass('w', *av); 76538032Speter } 76664562Sgshapiro#if NETINET || NETINET6 76790792Sgshapiro for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++) 76838032Speter { 76964562Sgshapiro# if NETINET6 77064562Sgshapiro char *addr; 77164562Sgshapiro char buf6[INET6_ADDRSTRLEN]; 77264562Sgshapiro struct in6_addr ia6; 77364562Sgshapiro# endif /* NETINET6 */ 77464562Sgshapiro# if NETINET 77564562Sgshapiro struct in_addr ia; 776363466Sgshapiro# endif 77764562Sgshapiro char ipbuf[103]; 77864562Sgshapiro 77964562Sgshapiro ipbuf[0] = '\0'; 78064562Sgshapiro switch (hp->h_addrtype) 78138032Speter { 78264562Sgshapiro# if NETINET 78364562Sgshapiro case AF_INET: 78464562Sgshapiro if (hp->h_length != INADDRSZ) 78564562Sgshapiro break; 78638032Speter 78764562Sgshapiro memmove(&ia, hp->h_addr_list[i], INADDRSZ); 788168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), 78990792Sgshapiro "[%.100s]", inet_ntoa(ia)); 79064562Sgshapiro break; 79164562Sgshapiro# endif /* NETINET */ 79264562Sgshapiro 79364562Sgshapiro# if NETINET6 79464562Sgshapiro case AF_INET6: 79564562Sgshapiro if (hp->h_length != IN6ADDRSZ) 79664562Sgshapiro break; 79764562Sgshapiro 79864562Sgshapiro memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 799168515Sgshapiro addr = anynet_ntop(&ia6, buf6, sizeof(buf6)); 80064562Sgshapiro if (addr != NULL) 801168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), 80290792Sgshapiro "[%.100s]", addr); 80364562Sgshapiro break; 80464562Sgshapiro# endif /* NETINET6 */ 80538032Speter } 80664562Sgshapiro if (ipbuf[0] == '\0') 80764562Sgshapiro break; 80864562Sgshapiro 80964562Sgshapiro if (tTd(0, 4)) 81090792Sgshapiro sm_dprintf("\ta.k.a.: %s\n", ipbuf); 81164562Sgshapiro setclass('w', ipbuf); 81238032Speter } 81364562Sgshapiro#endif /* NETINET || NETINET6 */ 81490792Sgshapiro#if NETINET6 81571345Sgshapiro freehostent(hp); 81671345Sgshapiro hp = NULL; 817363466Sgshapiro#endif 81838032Speter } 81938032Speter 82038032Speter /* current time */ 82190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL)); 82290792Sgshapiro 82364562Sgshapiro /* current load average */ 82490792Sgshapiro sm_getla(); 82538032Speter 82638032Speter QueueLimitRecipient = (QUEUE_CHAR *) NULL; 82738032Speter QueueLimitSender = (QUEUE_CHAR *) NULL; 82838032Speter QueueLimitId = (QUEUE_CHAR *) NULL; 82990792Sgshapiro QueueLimitQuarantine = (QUEUE_CHAR *) NULL; 83038032Speter 83138032Speter /* 83242575Speter ** Crack argv. 83338032Speter */ 83438032Speter 83538032Speter optind = 1; 83638032Speter while ((j = getopt(argc, argv, OPTIONS)) != -1) 83738032Speter { 83838032Speter switch (j) 83938032Speter { 84038032Speter case 'b': /* operations mode */ 84190792Sgshapiro /* already done */ 84290792Sgshapiro break; 84338032Speter 84490792Sgshapiro case 'A': /* use Alternate sendmail/submit.cf */ 84590792Sgshapiro cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF 84690792Sgshapiro : SM_GET_SENDMAIL_CF; 84738032Speter break; 84838032Speter 84938032Speter case 'B': /* body type */ 85090792Sgshapiro CHECK_AGAINST_OPMODE(j); 85190792Sgshapiro BlankEnvelope.e_bodytype = newstr(optarg); 85238032Speter break; 85338032Speter 85438032Speter case 'C': /* select configuration file (already done) */ 85538032Speter if (RealUid != 0) 85690792Sgshapiro warn_C_flag = true; 85790792Sgshapiro conffile = newstr(optarg); 85890792Sgshapiro dp = drop_privileges(true); 85964562Sgshapiro setstat(dp); 86090792Sgshapiro safecf = false; 86138032Speter break; 86238032Speter 863132943Sgshapiro case 'D': 86490792Sgshapiro case 'd': /* debugging */ 86590792Sgshapiro /* already done */ 86638032Speter break; 86738032Speter 86838032Speter case 'f': /* from address */ 86938032Speter case 'r': /* obsolete -f flag */ 87090792Sgshapiro CHECK_AGAINST_OPMODE(j); 87138032Speter if (from != NULL) 87238032Speter { 87338032Speter usrerr("More than one \"from\" person"); 87438032Speter ExitStat = EX_USAGE; 87538032Speter break; 87638032Speter } 877110560Sgshapiro if (optarg[0] == '\0') 878110560Sgshapiro from = newstr("<>"); 879110560Sgshapiro else 880110560Sgshapiro from = newstr(denlstring(optarg, true, true)); 88138032Speter if (strcmp(RealUserName, from) != 0) 88238032Speter warn_f_flag = j; 88338032Speter break; 88438032Speter 88538032Speter case 'F': /* set full name */ 88690792Sgshapiro CHECK_AGAINST_OPMODE(j); 88738032Speter FullName = newstr(optarg); 88838032Speter break; 88938032Speter 89064562Sgshapiro case 'G': /* relay (gateway) submission */ 89164562Sgshapiro /* already set */ 89290792Sgshapiro CHECK_AGAINST_OPMODE(j); 89364562Sgshapiro break; 89464562Sgshapiro 89538032Speter case 'h': /* hop count */ 89690792Sgshapiro CHECK_AGAINST_OPMODE(j); 89790792Sgshapiro BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep, 89890792Sgshapiro 10); 899168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", 90090792Sgshapiro BlankEnvelope.e_hopcount); 90190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf); 90290792Sgshapiro 90338032Speter if (*ep) 90438032Speter { 90538032Speter usrerr("Bad hop count (%s)", optarg); 90638032Speter ExitStat = EX_USAGE; 90738032Speter } 90838032Speter break; 90964562Sgshapiro 91064562Sgshapiro case 'L': /* program label */ 91164562Sgshapiro /* already set */ 91264562Sgshapiro break; 91364562Sgshapiro 91438032Speter case 'n': /* don't alias */ 91590792Sgshapiro CHECK_AGAINST_OPMODE(j); 91690792Sgshapiro NoAlias = true; 91738032Speter break; 91838032Speter 91938032Speter case 'N': /* delivery status notifications */ 92090792Sgshapiro CHECK_AGAINST_OPMODE(j); 92138032Speter DefaultNotify |= QHASNOTIFY; 92290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 92390792Sgshapiro macid("{dsn_notify}"), optarg); 92490792Sgshapiro if (sm_strcasecmp(optarg, "never") == 0) 92538032Speter break; 92638032Speter for (p = optarg; p != NULL; optarg = p) 92738032Speter { 92838032Speter p = strchr(p, ','); 92938032Speter if (p != NULL) 93038032Speter *p++ = '\0'; 93190792Sgshapiro if (sm_strcasecmp(optarg, "success") == 0) 93238032Speter DefaultNotify |= QPINGONSUCCESS; 93390792Sgshapiro else if (sm_strcasecmp(optarg, "failure") == 0) 93438032Speter DefaultNotify |= QPINGONFAILURE; 93590792Sgshapiro else if (sm_strcasecmp(optarg, "delay") == 0) 93638032Speter DefaultNotify |= QPINGONDELAY; 93738032Speter else 93838032Speter { 93938032Speter usrerr("Invalid -N argument"); 94038032Speter ExitStat = EX_USAGE; 94138032Speter } 94238032Speter } 94338032Speter break; 94438032Speter 94538032Speter case 'o': /* set option */ 94690792Sgshapiro setoption(*optarg, optarg + 1, false, true, 94790792Sgshapiro &BlankEnvelope); 94838032Speter break; 94938032Speter 95038032Speter case 'O': /* set option (long form) */ 95190792Sgshapiro setoption(' ', optarg, false, true, &BlankEnvelope); 95238032Speter break; 95338032Speter 95438032Speter case 'p': /* set protocol */ 95590792Sgshapiro CHECK_AGAINST_OPMODE(j); 95638032Speter p = strchr(optarg, ':'); 95738032Speter if (p != NULL) 95838032Speter { 95938032Speter *p++ = '\0'; 96038032Speter if (*p != '\0') 96138032Speter { 962120256Sgshapiro i = strlen(p) + 1; 963120256Sgshapiro ep = sm_malloc_x(i); 964120256Sgshapiro cleanstrcpy(ep, p, i); 96590792Sgshapiro macdefine(&BlankEnvelope.e_macro, 96690792Sgshapiro A_HEAP, 's', ep); 96738032Speter } 96838032Speter } 96938032Speter if (*optarg != '\0') 97038032Speter { 971120256Sgshapiro i = strlen(optarg) + 1; 972120256Sgshapiro ep = sm_malloc_x(i); 973120256Sgshapiro cleanstrcpy(ep, optarg, i); 97490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_HEAP, 97590792Sgshapiro 'r', ep); 97638032Speter } 97738032Speter break; 97838032Speter 97990792Sgshapiro case 'Q': /* change quarantining on queued items */ 98090792Sgshapiro /* sanity check */ 98190792Sgshapiro if (OpMode != MD_DELIVER && 98290792Sgshapiro OpMode != MD_QUEUERUN) 98390792Sgshapiro { 98490792Sgshapiro usrerr("Can not use -Q with -b%c", OpMode); 98590792Sgshapiro ExitStat = EX_USAGE; 98690792Sgshapiro break; 98790792Sgshapiro } 98890792Sgshapiro 98990792Sgshapiro if (OpMode == MD_DELIVER) 99090792Sgshapiro set_op_mode(MD_QUEUERUN); 99190792Sgshapiro 99290792Sgshapiro FullName = NULL; 99390792Sgshapiro 99490792Sgshapiro quarantining = newstr(optarg); 99590792Sgshapiro break; 99690792Sgshapiro 99738032Speter case 'q': /* run queue files at intervals */ 99864562Sgshapiro /* sanity check */ 99964562Sgshapiro if (OpMode != MD_DELIVER && 100064562Sgshapiro OpMode != MD_DAEMON && 100164562Sgshapiro OpMode != MD_FGDAEMON && 100264562Sgshapiro OpMode != MD_PRINT && 100390792Sgshapiro OpMode != MD_PRINTNQE && 100464562Sgshapiro OpMode != MD_QUEUERUN) 100564562Sgshapiro { 100664562Sgshapiro usrerr("Can not use -q with -b%c", OpMode); 100764562Sgshapiro ExitStat = EX_USAGE; 100864562Sgshapiro break; 100964562Sgshapiro } 101064562Sgshapiro 101164562Sgshapiro /* don't override -bd, -bD or -bp */ 101264562Sgshapiro if (OpMode == MD_DELIVER) 101390792Sgshapiro set_op_mode(MD_QUEUERUN); 101464562Sgshapiro 101538032Speter FullName = NULL; 101690792Sgshapiro negate = optarg[0] == '!'; 101790792Sgshapiro if (negate) 101890792Sgshapiro { 101990792Sgshapiro /* negate meaning of pattern match */ 102090792Sgshapiro optarg++; /* skip '!' for next switch */ 102190792Sgshapiro } 102264562Sgshapiro 102338032Speter switch (optarg[0]) 102438032Speter { 102590792Sgshapiro case 'G': /* Limit by queue group name */ 102690792Sgshapiro if (negate) 102790792Sgshapiro { 102890792Sgshapiro usrerr("Can not use -q!G"); 102990792Sgshapiro ExitStat = EX_USAGE; 103090792Sgshapiro break; 103190792Sgshapiro } 103290792Sgshapiro if (queuegroup != NULL) 103390792Sgshapiro { 103490792Sgshapiro usrerr("Can not use multiple -qG options"); 103590792Sgshapiro ExitStat = EX_USAGE; 103690792Sgshapiro break; 103790792Sgshapiro } 103890792Sgshapiro queuegroup = newstr(&optarg[1]); 103990792Sgshapiro break; 104090792Sgshapiro 104190792Sgshapiro case 'I': /* Limit by ID */ 1042168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 104338032Speter new->queue_match = newstr(&optarg[1]); 104490792Sgshapiro new->queue_negate = negate; 104538032Speter new->queue_next = QueueLimitId; 104638032Speter QueueLimitId = new; 104738032Speter break; 104838032Speter 104990792Sgshapiro case 'R': /* Limit by recipient */ 1050168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 105138032Speter new->queue_match = newstr(&optarg[1]); 105290792Sgshapiro new->queue_negate = negate; 105338032Speter new->queue_next = QueueLimitRecipient; 105438032Speter QueueLimitRecipient = new; 105538032Speter break; 105638032Speter 105790792Sgshapiro case 'S': /* Limit by sender */ 1058168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 105938032Speter new->queue_match = newstr(&optarg[1]); 106090792Sgshapiro new->queue_negate = negate; 106138032Speter new->queue_next = QueueLimitSender; 106238032Speter QueueLimitSender = new; 106338032Speter break; 106438032Speter 106590792Sgshapiro case 'f': /* foreground queue run */ 106690792Sgshapiro foregroundqueue = true; 106790792Sgshapiro break; 106890792Sgshapiro 106990792Sgshapiro case 'Q': /* Limit by quarantine message */ 107090792Sgshapiro if (optarg[1] != '\0') 107190792Sgshapiro { 1072168515Sgshapiro new = (QUEUE_CHAR *) xalloc(sizeof(*new)); 107390792Sgshapiro new->queue_match = newstr(&optarg[1]); 107490792Sgshapiro new->queue_negate = negate; 107590792Sgshapiro new->queue_next = QueueLimitQuarantine; 107690792Sgshapiro QueueLimitQuarantine = new; 107790792Sgshapiro } 107890792Sgshapiro QueueMode = QM_QUARANTINE; 107990792Sgshapiro break; 108090792Sgshapiro 108190792Sgshapiro case 'L': /* act on lost items */ 108290792Sgshapiro QueueMode = QM_LOST; 108390792Sgshapiro break; 108490792Sgshapiro 108590792Sgshapiro case 'p': /* Persistent queue */ 108690792Sgshapiro queuepersistent = true; 108790792Sgshapiro if (QueueIntvl == 0) 108890792Sgshapiro QueueIntvl = 1; 108990792Sgshapiro if (optarg[1] == '\0') 109090792Sgshapiro break; 109190792Sgshapiro ++optarg; 109290792Sgshapiro /* FALLTHROUGH */ 109390792Sgshapiro 109438032Speter default: 109564562Sgshapiro i = Errors; 109638032Speter QueueIntvl = convtime(optarg, 'm'); 109798841Sgshapiro if (QueueIntvl < 0) 109898841Sgshapiro { 109998841Sgshapiro usrerr("Invalid -q value"); 110098841Sgshapiro ExitStat = EX_USAGE; 110198841Sgshapiro } 110264562Sgshapiro 110364562Sgshapiro /* check for bad conversion */ 110464562Sgshapiro if (i < Errors) 110564562Sgshapiro ExitStat = EX_USAGE; 110638032Speter break; 110738032Speter } 110838032Speter break; 110938032Speter 111038032Speter case 'R': /* DSN RET: what to return */ 111190792Sgshapiro CHECK_AGAINST_OPMODE(j); 111290792Sgshapiro if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags)) 111338032Speter { 111438032Speter usrerr("Duplicate -R flag"); 111538032Speter ExitStat = EX_USAGE; 111638032Speter break; 111738032Speter } 111890792Sgshapiro BlankEnvelope.e_flags |= EF_RET_PARAM; 111990792Sgshapiro if (sm_strcasecmp(optarg, "hdrs") == 0) 112090792Sgshapiro BlankEnvelope.e_flags |= EF_NO_BODY_RETN; 112190792Sgshapiro else if (sm_strcasecmp(optarg, "full") != 0) 112238032Speter { 112338032Speter usrerr("Invalid -R value"); 112438032Speter ExitStat = EX_USAGE; 112538032Speter } 112690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 112790792Sgshapiro macid("{dsn_ret}"), optarg); 112838032Speter break; 112938032Speter 113038032Speter case 't': /* read recipients from message */ 113190792Sgshapiro CHECK_AGAINST_OPMODE(j); 113290792Sgshapiro GrabTo = true; 113338032Speter break; 113438032Speter 113538032Speter case 'V': /* DSN ENVID: set "original" envelope id */ 113690792Sgshapiro CHECK_AGAINST_OPMODE(j); 113738032Speter if (!xtextok(optarg)) 113838032Speter { 113938032Speter usrerr("Invalid syntax in -V flag"); 114038032Speter ExitStat = EX_USAGE; 114138032Speter } 114238032Speter else 114364562Sgshapiro { 114490792Sgshapiro BlankEnvelope.e_envid = newstr(optarg); 114590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 114690792Sgshapiro macid("{dsn_envid}"), optarg); 114764562Sgshapiro } 114838032Speter break; 114938032Speter 115038032Speter case 'X': /* traffic log file */ 115190792Sgshapiro dp = drop_privileges(true); 115264562Sgshapiro setstat(dp); 115364562Sgshapiro if (stat(optarg, &traf_st) == 0 && 115464562Sgshapiro S_ISFIFO(traf_st.st_mode)) 115590792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 115690792Sgshapiro SM_TIME_DEFAULT, 115790792Sgshapiro optarg, 115890792Sgshapiro SM_IO_WRONLY, NULL); 115964562Sgshapiro else 116090792Sgshapiro TrafficLogFile = sm_io_open(SmFtStdio, 116190792Sgshapiro SM_TIME_DEFAULT, 116290792Sgshapiro optarg, 116390792Sgshapiro SM_IO_APPEND, NULL); 116438032Speter if (TrafficLogFile == NULL) 116538032Speter { 116638032Speter syserr("cannot open %s", optarg); 116738032Speter ExitStat = EX_CANTCREAT; 116838032Speter break; 116938032Speter } 117090792Sgshapiro (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT, 117190792Sgshapiro NULL, SM_IO_LBF, 0); 117238032Speter break; 117338032Speter 117438032Speter /* compatibility flags */ 117538032Speter case 'c': /* connect to non-local mailers */ 117638032Speter case 'i': /* don't let dot stop me */ 117738032Speter case 'm': /* send to me too */ 117838032Speter case 'T': /* set timeout interval */ 117938032Speter case 'v': /* give blow-by-blow description */ 118090792Sgshapiro setoption(j, "T", false, true, &BlankEnvelope); 118138032Speter break; 118238032Speter 118338032Speter case 'e': /* error message disposition */ 118438032Speter case 'M': /* define macro */ 118590792Sgshapiro setoption(j, optarg, false, true, &BlankEnvelope); 118638032Speter break; 118738032Speter 118838032Speter case 's': /* save From lines in headers */ 118990792Sgshapiro setoption('f', "T", false, true, &BlankEnvelope); 119038032Speter break; 119138032Speter 119264562Sgshapiro#ifdef DBM 119338032Speter case 'I': /* initialize alias DBM file */ 119490792Sgshapiro set_op_mode(MD_INITALIAS); 119538032Speter break; 119664562Sgshapiro#endif /* DBM */ 119738032Speter 119864562Sgshapiro#if defined(__osf__) || defined(_AIX3) 119938032Speter case 'x': /* random flag that OSF/1 & AIX mailx passes */ 120038032Speter break; 1201363466Sgshapiro#endif 120264562Sgshapiro#if defined(sony_news) 120338032Speter case 'E': 120438032Speter case 'J': /* ignore flags for Japanese code conversion 120564562Sgshapiro implemented on Sony NEWS */ 120638032Speter break; 120764562Sgshapiro#endif /* defined(sony_news) */ 120838032Speter 120938032Speter default: 121090792Sgshapiro finis(true, true, EX_USAGE); 121190792Sgshapiro /* NOTREACHED */ 121238032Speter break; 121338032Speter } 121438032Speter } 121538032Speter 121690792Sgshapiro /* if we've had errors so far, exit now */ 1217203004Sgshapiro if ((ExitStat != EX_OK && OpMode != MD_TEST && OpMode != MD_CHECKCONFIG) || 121890792Sgshapiro ExitStat == EX_OSERR) 121964562Sgshapiro { 122090792Sgshapiro finis(false, true, ExitStat); 122190792Sgshapiro /* NOTREACHED */ 122264562Sgshapiro } 122390792Sgshapiro 122490792Sgshapiro if (bitset(SUBMIT_MTA, SubmitMode)) 122564562Sgshapiro { 122698841Sgshapiro /* If set daemon_flags on command line, don't reset it */ 122798841Sgshapiro if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 122898841Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 122998841Sgshapiro macid("{daemon_flags}"), "CC f"); 123064562Sgshapiro } 123190792Sgshapiro else if (OpMode == MD_DELIVER || OpMode == MD_SMTP) 123264562Sgshapiro { 123390792Sgshapiro SubmitMode = SUBMIT_MSA; 123498841Sgshapiro 123598841Sgshapiro /* If set daemon_flags on command line, don't reset it */ 123698841Sgshapiro if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 123798841Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 123898841Sgshapiro macid("{daemon_flags}"), "c u"); 123964562Sgshapiro } 124064562Sgshapiro 124138032Speter /* 124238032Speter ** Do basic initialization. 124338032Speter ** Read system control file. 124438032Speter ** Extract special fields for local use. 124538032Speter */ 124638032Speter 124738032Speter#if XDEBUG 124838032Speter checkfd012("before readcf"); 1249363466Sgshapiro#endif 125090792Sgshapiro vendor_pre_defaults(&BlankEnvelope); 125164562Sgshapiro 125290792Sgshapiro readcf(getcfname(OpMode, SubmitMode, cftype, conffile), 125390792Sgshapiro safecf, &BlankEnvelope); 125490792Sgshapiro#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 125590792Sgshapiro ConfigFileRead = true; 1256363466Sgshapiro#endif 125790792Sgshapiro vendor_post_defaults(&BlankEnvelope); 125838032Speter 125990792Sgshapiro /* now we can complain about missing fds */ 126090792Sgshapiro if (MissingFds != 0 && LogLevel > 8) 126190792Sgshapiro { 126290792Sgshapiro char mbuf[MAXLINE]; 126390792Sgshapiro 126490792Sgshapiro mbuf[0] = '\0'; 126590792Sgshapiro if (bitset(1 << STDIN_FILENO, MissingFds)) 1266168515Sgshapiro (void) sm_strlcat(mbuf, ", stdin", sizeof(mbuf)); 126790792Sgshapiro if (bitset(1 << STDOUT_FILENO, MissingFds)) 1268168515Sgshapiro (void) sm_strlcat(mbuf, ", stdout", sizeof(mbuf)); 126990792Sgshapiro if (bitset(1 << STDERR_FILENO, MissingFds)) 1270168515Sgshapiro (void) sm_strlcat(mbuf, ", stderr", sizeof(mbuf)); 127190792Sgshapiro 127290792Sgshapiro /* Notice: fill_errno is from high above: fill_fd() */ 127390792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 127490792Sgshapiro "File descriptors missing on startup: %s; %s", 127590792Sgshapiro &mbuf[2], sm_errstring(fill_errno)); 127690792Sgshapiro } 127790792Sgshapiro 127877349Sgshapiro /* Remove the ability for a normal user to send signals */ 127990792Sgshapiro if (RealUid != 0 && RealUid != geteuid()) 128077349Sgshapiro { 128177349Sgshapiro uid_t new_uid = geteuid(); 128277349Sgshapiro 128377349Sgshapiro#if HASSETREUID 128477349Sgshapiro /* 128577349Sgshapiro ** Since we can differentiate between uid and euid, 128677349Sgshapiro ** make the uid a different user so the real user 128777349Sgshapiro ** can't send signals. However, it doesn't need to be 128877349Sgshapiro ** root (euid has root). 128977349Sgshapiro */ 129077349Sgshapiro 129177349Sgshapiro if (new_uid == 0) 129277349Sgshapiro new_uid = DefUid; 129377349Sgshapiro if (tTd(47, 5)) 129490792Sgshapiro sm_dprintf("Changing real uid to %d\n", (int) new_uid); 129577349Sgshapiro if (setreuid(new_uid, geteuid()) < 0) 129677349Sgshapiro { 129777349Sgshapiro syserr("main: setreuid(%d, %d) failed", 129877349Sgshapiro (int) new_uid, (int) geteuid()); 129990792Sgshapiro finis(false, true, EX_OSERR); 130077349Sgshapiro /* NOTREACHED */ 130177349Sgshapiro } 130277349Sgshapiro if (tTd(47, 10)) 130390792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 130490792Sgshapiro (int) geteuid(), (int) getuid()); 130577349Sgshapiro#else /* HASSETREUID */ 130677349Sgshapiro /* 130777349Sgshapiro ** Have to change both effective and real so need to 130877349Sgshapiro ** change them both to effective to keep privs. 130977349Sgshapiro */ 131077349Sgshapiro 131177349Sgshapiro if (tTd(47, 5)) 131290792Sgshapiro sm_dprintf("Changing uid to %d\n", (int) new_uid); 131377349Sgshapiro if (setuid(new_uid) < 0) 131477349Sgshapiro { 131577349Sgshapiro syserr("main: setuid(%d) failed", (int) new_uid); 131690792Sgshapiro finis(false, true, EX_OSERR); 131777349Sgshapiro /* NOTREACHED */ 131877349Sgshapiro } 131977349Sgshapiro if (tTd(47, 10)) 132090792Sgshapiro sm_dprintf("Now running as e/ruid %d:%d\n", 132190792Sgshapiro (int) geteuid(), (int) getuid()); 132277349Sgshapiro#endif /* HASSETREUID */ 132377349Sgshapiro } 132477349Sgshapiro 132590792Sgshapiro#if NAMED_BIND 1326132943Sgshapiro if (FallbackMX != NULL) 1327132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 1328363466Sgshapiro#endif 132990792Sgshapiro 1330223067Sgshapiro if (SuperSafe == SAFE_INTERACTIVE && !SM_IS_INTERACTIVE(CurEnv->e_sendmode)) 133190792Sgshapiro { 133290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 133390792Sgshapiro "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n"); 133490792Sgshapiro } 133590792Sgshapiro 133690792Sgshapiro if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)) 133790792Sgshapiro { 133890792Sgshapiro usrerr("Mail submission program cannot be used as daemon"); 133990792Sgshapiro finis(false, true, EX_USAGE); 134090792Sgshapiro } 134190792Sgshapiro 134290792Sgshapiro if (OpMode == MD_DELIVER || OpMode == MD_SMTP || 134390792Sgshapiro OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP || 134490792Sgshapiro OpMode == MD_DAEMON || OpMode == MD_FGDAEMON) 134590792Sgshapiro makeworkgroups(); 134690792Sgshapiro 134777349Sgshapiro /* set up the basic signal handlers */ 134890792Sgshapiro if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN) 134990792Sgshapiro (void) sm_signal(SIGINT, intsig); 135090792Sgshapiro (void) sm_signal(SIGTERM, intsig); 135177349Sgshapiro 135238032Speter /* Enforce use of local time (null string overrides this) */ 135338032Speter if (TimeZoneSpec == NULL) 135438032Speter unsetenv("TZ"); 135538032Speter else if (TimeZoneSpec[0] != '\0') 1356157001Sgshapiro sm_setuserenv("TZ", TimeZoneSpec); 135738032Speter else 1358157001Sgshapiro sm_setuserenv("TZ", NULL); 135938032Speter tzset(); 136038032Speter 136190792Sgshapiro /* initialize mailbox database */ 136290792Sgshapiro i = sm_mbdb_initialize(Mbdb); 136390792Sgshapiro if (i != EX_OK) 136490792Sgshapiro { 136590792Sgshapiro usrerr("Can't initialize mailbox database \"%s\": %s", 136690792Sgshapiro Mbdb, sm_strexit(i)); 136790792Sgshapiro ExitStat = i; 136890792Sgshapiro } 136990792Sgshapiro 137038032Speter /* avoid denial-of-service attacks */ 137138032Speter resetlimits(); 137238032Speter 137390792Sgshapiro if (OpMode == MD_TEST) 137438032Speter { 137590792Sgshapiro /* can't be done after readcf if RunAs* is used */ 137690792Sgshapiro dp = drop_privileges(true); 137790792Sgshapiro if (dp != EX_OK) 137890792Sgshapiro { 137990792Sgshapiro finis(false, true, dp); 138090792Sgshapiro /* NOTREACHED */ 138190792Sgshapiro } 138290792Sgshapiro } 138390792Sgshapiro else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 138490792Sgshapiro { 138538032Speter /* drop privileges -- daemon mode done after socket/bind */ 138690792Sgshapiro dp = drop_privileges(false); 138764562Sgshapiro setstat(dp); 138890792Sgshapiro if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0)) 138990792Sgshapiro { 139090792Sgshapiro usrerr("Mail submission program must have RunAsUser set to non root user"); 139190792Sgshapiro finis(false, true, EX_CONFIG); 139290792Sgshapiro /* NOTREACHED */ 139390792Sgshapiro } 139438032Speter } 139538032Speter 139664562Sgshapiro#if NAMED_BIND 139764562Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 139864562Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 1399363466Sgshapiro#endif 140064562Sgshapiro 140138032Speter /* 140238032Speter ** Find our real host name for future logging. 140338032Speter */ 140438032Speter 140564562Sgshapiro authinfo = getauthinfo(STDIN_FILENO, &forged); 140690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 140738032Speter 140838032Speter /* suppress error printing if errors mailed back or whatever */ 140990792Sgshapiro if (BlankEnvelope.e_errormode != EM_PRINT) 141090792Sgshapiro HoldErrs = true; 141138032Speter 141238032Speter /* set up the $=m class now, after .cf has a chance to redefine $m */ 1413168515Sgshapiro expand("\201m", jbuf, sizeof(jbuf), &BlankEnvelope); 141473188Sgshapiro if (jbuf[0] != '\0') 141573188Sgshapiro setclass('m', jbuf); 141638032Speter 141738032Speter /* probe interfaces and locate any additional names */ 141890792Sgshapiro if (DontProbeInterfaces != DPI_PROBENONE) 141938032Speter load_if_names(); 142038032Speter 142190792Sgshapiro if (tTd(0, 10)) 142290792Sgshapiro { 1423110560Sgshapiro char pidpath[MAXPATHLEN]; 1424110560Sgshapiro 142590792Sgshapiro /* Now we know which .cf file we use */ 142690792Sgshapiro sm_dprintf(" Conf file:\t%s (selected)\n", 142790792Sgshapiro getcfname(OpMode, SubmitMode, cftype, conffile)); 1428168515Sgshapiro expand(PidFile, pidpath, sizeof(pidpath), &BlankEnvelope); 1429110560Sgshapiro sm_dprintf(" Pid file:\t%s (selected)\n", pidpath); 143090792Sgshapiro } 143190792Sgshapiro 143238032Speter if (tTd(0, 1)) 143338032Speter { 143490792Sgshapiro sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 143590792Sgshapiro sm_dprintf("\n (short domain name) $w = "); 1436132943Sgshapiro xputs(sm_debug_file(), macvalue('w', &BlankEnvelope)); 143790792Sgshapiro sm_dprintf("\n (canonical domain name) $j = "); 1438132943Sgshapiro xputs(sm_debug_file(), macvalue('j', &BlankEnvelope)); 143990792Sgshapiro sm_dprintf("\n (subdomain name) $m = "); 1440132943Sgshapiro xputs(sm_debug_file(), macvalue('m', &BlankEnvelope)); 144190792Sgshapiro sm_dprintf("\n (node name) $k = "); 1442132943Sgshapiro xputs(sm_debug_file(), macvalue('k', &BlankEnvelope)); 144390792Sgshapiro sm_dprintf("\n========================================================\n\n"); 144438032Speter } 144538032Speter 144638032Speter /* 144738032Speter ** Do more command line checking -- these are things that 144838032Speter ** have to modify the results of reading the config file. 144938032Speter */ 145038032Speter 145138032Speter /* process authorization warnings from command line */ 145238032Speter if (warn_C_flag) 145390792Sgshapiro auth_warning(&BlankEnvelope, "Processed by %s with -C %s", 145490792Sgshapiro RealUserName, conffile); 145564562Sgshapiro if (Warn_Q_option && !wordinclass(RealUserName, 't')) 145690792Sgshapiro auth_warning(&BlankEnvelope, "Processed from queue %s", 145790792Sgshapiro QueueDir); 145890792Sgshapiro if (sysloglabel != NULL && !wordinclass(RealUserName, 't') && 145990792Sgshapiro RealUid != 0 && RealUid != TrustedUid && LogLevel > 1) 146090792Sgshapiro sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label", 146190792Sgshapiro (int) RealUid); 146238032Speter 146338032Speter /* check body type for legality */ 146490792Sgshapiro i = check_bodytype(BlankEnvelope.e_bodytype); 146590792Sgshapiro if (i == BODYTYPE_ILLEGAL) 146638032Speter { 146790792Sgshapiro usrerr("Illegal body type %s", BlankEnvelope.e_bodytype); 146890792Sgshapiro BlankEnvelope.e_bodytype = NULL; 146938032Speter } 147090792Sgshapiro else if (i != BODYTYPE_NONE) 147190792Sgshapiro SevenBitInput = (i == BODYTYPE_7BIT); 147238032Speter 147338032Speter /* tweak default DSN notifications */ 147438032Speter if (DefaultNotify == 0) 147538032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 147638032Speter 147738032Speter /* check for sane configuration level */ 147838032Speter if (ConfigLevel > MAXCONFIGLEVEL) 147938032Speter { 148038032Speter syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 148190792Sgshapiro ConfigLevel, Version, MAXCONFIGLEVEL); 148238032Speter } 148338032Speter 148438032Speter /* need MCI cache to have persistence */ 148538032Speter if (HostStatDir != NULL && MaxMciCache == 0) 148638032Speter { 148738032Speter HostStatDir = NULL; 148890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 148990792Sgshapiro "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 149038032Speter } 149138032Speter 149238032Speter /* need HostStatusDir in order to have SingleThreadDelivery */ 149338032Speter if (SingleThreadDelivery && HostStatDir == NULL) 149438032Speter { 149590792Sgshapiro SingleThreadDelivery = false; 149690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 149790792Sgshapiro "Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 149838032Speter } 149938032Speter 1500157001Sgshapiro#if _FFR_MEMSTAT 1501157001Sgshapiro j = sm_memstat_open(); 1502157001Sgshapiro if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4) 1503157001Sgshapiro { 1504157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 1505157001Sgshapiro "cannot get memory statistics, settings ignored, error=%d" 1506157001Sgshapiro , j); 1507157001Sgshapiro } 1508157001Sgshapiro#endif /* _FFR_MEMSTAT */ 1509157001Sgshapiro 151038032Speter /* check for permissions */ 151190792Sgshapiro if (RealUid != 0 && 151242575Speter RealUid != TrustedUid) 151338032Speter { 151490792Sgshapiro char *action = NULL; 151590792Sgshapiro 151690792Sgshapiro switch (OpMode) 151790792Sgshapiro { 151890792Sgshapiro case MD_QUEUERUN: 151990792Sgshapiro if (quarantining != NULL) 152090792Sgshapiro action = "quarantine jobs"; 152190792Sgshapiro else 1522132943Sgshapiro { 1523132943Sgshapiro /* Normal users can do a single queue run */ 1524132943Sgshapiro if (QueueIntvl == 0) 1525132943Sgshapiro break; 1526132943Sgshapiro } 152790792Sgshapiro 152890792Sgshapiro /* but not persistent queue runners */ 152990792Sgshapiro if (action == NULL) 153090792Sgshapiro action = "start a queue runner daemon"; 153190792Sgshapiro /* FALLTHROUGH */ 153290792Sgshapiro 153390792Sgshapiro case MD_PURGESTAT: 153490792Sgshapiro if (action == NULL) 153590792Sgshapiro action = "purge host status"; 153690792Sgshapiro /* FALLTHROUGH */ 153790792Sgshapiro 153890792Sgshapiro case MD_DAEMON: 153990792Sgshapiro case MD_FGDAEMON: 154090792Sgshapiro if (action == NULL) 154190792Sgshapiro action = "run daemon"; 154290792Sgshapiro 154390792Sgshapiro if (tTd(65, 1)) 154490792Sgshapiro sm_dprintf("Deny user %d attempt to %s\n", 154590792Sgshapiro (int) RealUid, action); 154690792Sgshapiro 154790792Sgshapiro if (LogLevel > 1) 154890792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 154990792Sgshapiro "user %d attempted to %s", 155090792Sgshapiro (int) RealUid, action); 155190792Sgshapiro HoldErrs = false; 155290792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 155390792Sgshapiro finis(false, true, EX_USAGE); 155490792Sgshapiro /* NOTREACHED */ 155590792Sgshapiro break; 155690792Sgshapiro 155790792Sgshapiro case MD_VERIFY: 155890792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags)) 155990792Sgshapiro { 156090792Sgshapiro /* 156190792Sgshapiro ** If -bv and RestrictExpand, 156290792Sgshapiro ** drop privs to prevent normal 156390792Sgshapiro ** users from reading private 156490792Sgshapiro ** aliases/forwards/:include:s 156590792Sgshapiro */ 156690792Sgshapiro 156790792Sgshapiro if (tTd(65, 1)) 156890792Sgshapiro sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n", 156990792Sgshapiro (int) RealUid); 157090792Sgshapiro 157190792Sgshapiro dp = drop_privileges(true); 157290792Sgshapiro 157390792Sgshapiro /* Fake address safety */ 157490792Sgshapiro if (tTd(65, 1)) 157590792Sgshapiro sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n"); 157690792Sgshapiro setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail); 157790792Sgshapiro 157890792Sgshapiro if (dp != EX_OK) 157990792Sgshapiro { 158090792Sgshapiro if (tTd(65, 1)) 158190792Sgshapiro sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n", 158290792Sgshapiro (int) RealUid); 158390792Sgshapiro CurEnv->e_id = NULL; 158490792Sgshapiro finis(true, true, dp); 158590792Sgshapiro /* NOTREACHED */ 158690792Sgshapiro } 158790792Sgshapiro } 158890792Sgshapiro break; 158990792Sgshapiro 159090792Sgshapiro case MD_TEST: 1591203004Sgshapiro case MD_CHECKCONFIG: 159290792Sgshapiro case MD_PRINT: 159390792Sgshapiro case MD_PRINTNQE: 159490792Sgshapiro case MD_FREEZE: 159590792Sgshapiro case MD_HOSTSTAT: 159690792Sgshapiro /* Nothing special to check */ 159790792Sgshapiro break; 159890792Sgshapiro 159990792Sgshapiro case MD_INITALIAS: 160090792Sgshapiro if (!wordinclass(RealUserName, 't')) 160190792Sgshapiro { 160290792Sgshapiro if (tTd(65, 1)) 160390792Sgshapiro sm_dprintf("Deny user %d attempt to rebuild the alias map\n", 160490792Sgshapiro (int) RealUid); 160590792Sgshapiro if (LogLevel > 1) 160690792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 160790792Sgshapiro "user %d attempted to rebuild the alias map", 160890792Sgshapiro (int) RealUid); 160990792Sgshapiro HoldErrs = false; 161090792Sgshapiro usrerr("Permission denied (real uid not trusted)"); 161190792Sgshapiro finis(false, true, EX_USAGE); 161290792Sgshapiro /* NOTREACHED */ 161390792Sgshapiro } 161490792Sgshapiro if (UseMSP) 161590792Sgshapiro { 161690792Sgshapiro HoldErrs = false; 161790792Sgshapiro usrerr("User %d cannot rebuild aliases in mail submission program", 161890792Sgshapiro (int) RealUid); 161990792Sgshapiro finis(false, true, EX_USAGE); 162090792Sgshapiro /* NOTREACHED */ 162190792Sgshapiro } 162290792Sgshapiro /* FALLTHROUGH */ 162390792Sgshapiro 162490792Sgshapiro default: 162590792Sgshapiro if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) && 162690792Sgshapiro Verbose != 0) 162790792Sgshapiro { 162890792Sgshapiro /* 162990792Sgshapiro ** If -v and RestrictExpand, reset 163090792Sgshapiro ** Verbose to prevent normal users 163190792Sgshapiro ** from seeing the expansion of 163290792Sgshapiro ** aliases/forwards/:include:s 163390792Sgshapiro */ 163490792Sgshapiro 163590792Sgshapiro if (tTd(65, 1)) 163690792Sgshapiro sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n", 163790792Sgshapiro (int) RealUid); 163890792Sgshapiro Verbose = 0; 163990792Sgshapiro } 164090792Sgshapiro break; 164190792Sgshapiro } 164238032Speter } 164338032Speter 164438032Speter if (MeToo) 164538032Speter BlankEnvelope.e_flags |= EF_METOO; 164638032Speter 164738032Speter switch (OpMode) 164838032Speter { 164938032Speter case MD_TEST: 165038032Speter /* don't have persistent host status in test mode */ 165138032Speter HostStatDir = NULL; 1652203004Sgshapiro /* FALLTHROUGH */ 1653203004Sgshapiro 1654203004Sgshapiro case MD_CHECKCONFIG: 165538032Speter if (Verbose == 0) 165638032Speter Verbose = 2; 165790792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 165890792Sgshapiro HoldErrs = false; 165938032Speter break; 166038032Speter 166138032Speter case MD_VERIFY: 166290792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 166390792Sgshapiro HoldErrs = false; 166438032Speter /* arrange to exit cleanly on hangup signal */ 166590792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 166690792Sgshapiro (void) sm_signal(SIGHUP, intsig); 166790792Sgshapiro if (geteuid() != 0) 166890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 166990792Sgshapiro "Notice: -bv may give misleading output for non-privileged user\n"); 167038032Speter break; 167138032Speter 167238032Speter case MD_FGDAEMON: 167390792Sgshapiro run_in_foreground = true; 167490792Sgshapiro set_op_mode(MD_DAEMON); 167564562Sgshapiro /* FALLTHROUGH */ 167638032Speter 167738032Speter case MD_DAEMON: 167890792Sgshapiro vendor_daemon_setup(&BlankEnvelope); 167938032Speter 168038032Speter /* remove things that don't make sense in daemon mode */ 168138032Speter FullName = NULL; 168290792Sgshapiro GrabTo = false; 168338032Speter 168438032Speter /* arrange to restart on hangup signal */ 168538032Speter if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 168638032Speter sm_syslog(LOG_WARNING, NOQID, 168764562Sgshapiro "daemon invoked without full pathname; kill -1 won't work"); 168838032Speter break; 168938032Speter 169038032Speter case MD_INITALIAS: 169138032Speter Verbose = 2; 169290792Sgshapiro BlankEnvelope.e_errormode = EM_PRINT; 169390792Sgshapiro HoldErrs = false; 169464562Sgshapiro /* FALLTHROUGH */ 169538032Speter 169638032Speter default: 169738032Speter /* arrange to exit cleanly on hangup signal */ 169890792Sgshapiro if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 169990792Sgshapiro (void) sm_signal(SIGHUP, intsig); 170038032Speter break; 170138032Speter } 170238032Speter 170338032Speter /* special considerations for FullName */ 170438032Speter if (FullName != NULL) 170538032Speter { 170638032Speter char *full = NULL; 170738032Speter 170838032Speter /* full names can't have newlines */ 170964562Sgshapiro if (strchr(FullName, '\n') != NULL) 171038032Speter { 171190792Sgshapiro full = newstr(denlstring(FullName, true, true)); 171273188Sgshapiro FullName = full; 171338032Speter } 171473188Sgshapiro 171538032Speter /* check for characters that may have to be quoted */ 171638032Speter if (!rfc822_string(FullName)) 171738032Speter { 171838032Speter /* 171938032Speter ** Quote a full name with special characters 172038032Speter ** as a comment so crackaddr() doesn't destroy 172138032Speter ** the name portion of the address. 172238032Speter */ 172373188Sgshapiro 172490792Sgshapiro FullName = addquotes(FullName, NULL); 172538032Speter if (full != NULL) 172690792Sgshapiro sm_free(full); /* XXX */ 172738032Speter } 172838032Speter } 172938032Speter 173038032Speter /* do heuristic mode adjustment */ 173138032Speter if (Verbose) 173238032Speter { 173338032Speter /* turn off noconnect option */ 173490792Sgshapiro setoption('c', "F", true, false, &BlankEnvelope); 173538032Speter 173638032Speter /* turn on interactive delivery */ 173790792Sgshapiro setoption('d', "", true, false, &BlankEnvelope); 173838032Speter } 173938032Speter 174042575Speter#ifdef VENDOR_CODE 174142575Speter /* check for vendor mismatch */ 174242575Speter if (VendorCode != VENDOR_CODE) 174342575Speter { 174442575Speter message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 174542575Speter getvendor(VENDOR_CODE), getvendor(VendorCode)); 174642575Speter } 174764562Sgshapiro#endif /* VENDOR_CODE */ 174864562Sgshapiro 174938032Speter /* check for out of date configuration level */ 175038032Speter if (ConfigLevel < MAXCONFIGLEVEL) 175138032Speter { 175238032Speter message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 175338032Speter Version, MAXCONFIGLEVEL, ConfigLevel); 175438032Speter } 175538032Speter 175638032Speter if (ConfigLevel < 3) 175790792Sgshapiro UseErrorsTo = true; 175838032Speter 175938032Speter /* set options that were previous macros */ 176038032Speter if (SmtpGreeting == NULL) 176138032Speter { 176290792Sgshapiro if (ConfigLevel < 7 && 176390792Sgshapiro (p = macvalue('e', &BlankEnvelope)) != NULL) 176438032Speter SmtpGreeting = newstr(p); 176538032Speter else 176638032Speter SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 176738032Speter } 176838032Speter if (UnixFromLine == NULL) 176938032Speter { 177090792Sgshapiro if (ConfigLevel < 7 && 177190792Sgshapiro (p = macvalue('l', &BlankEnvelope)) != NULL) 177238032Speter UnixFromLine = newstr(p); 177338032Speter else 177438032Speter UnixFromLine = "From \201g \201d"; 177538032Speter } 177664562Sgshapiro SmtpError[0] = '\0'; 177738032Speter 177838032Speter /* our name for SMTP codes */ 1779168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope); 178073188Sgshapiro if (jbuf[0] == '\0') 178190792Sgshapiro PSTRSET(MyHostName, "localhost"); 178273188Sgshapiro else 178390792Sgshapiro PSTRSET(MyHostName, jbuf); 178473188Sgshapiro if (strchr(MyHostName, '.') == NULL) 1785132943Sgshapiro message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?", 178673188Sgshapiro MyHostName); 178738032Speter 178838032Speter /* make certain that this name is part of the $=w class */ 178938032Speter setclass('w', MyHostName); 179038032Speter 179190792Sgshapiro /* fill in the structure of the *default* queue */ 179290792Sgshapiro st = stab("mqueue", ST_QUEUE, ST_FIND); 179390792Sgshapiro if (st == NULL) 179490792Sgshapiro syserr("No default queue (mqueue) defined"); 179590792Sgshapiro else 179690792Sgshapiro set_def_queueval(st->s_quegrp, true); 179790792Sgshapiro 179838032Speter /* the indices of built-in mailers */ 179938032Speter st = stab("local", ST_MAILER, ST_FIND); 180038032Speter if (st != NULL) 180138032Speter LocalMailer = st->s_mailer; 180238032Speter else if (OpMode != MD_TEST || !warn_C_flag) 180338032Speter syserr("No local mailer defined"); 180438032Speter 180538032Speter st = stab("prog", ST_MAILER, ST_FIND); 180638032Speter if (st == NULL) 180738032Speter syserr("No prog mailer defined"); 180838032Speter else 180938032Speter { 181038032Speter ProgMailer = st->s_mailer; 181138032Speter clrbitn(M_MUSER, ProgMailer->m_flags); 181238032Speter } 181338032Speter 181438032Speter st = stab("*file*", ST_MAILER, ST_FIND); 181538032Speter if (st == NULL) 181638032Speter syserr("No *file* mailer defined"); 181738032Speter else 181838032Speter { 181938032Speter FileMailer = st->s_mailer; 182038032Speter clrbitn(M_MUSER, FileMailer->m_flags); 182138032Speter } 182238032Speter 182338032Speter st = stab("*include*", ST_MAILER, ST_FIND); 182438032Speter if (st == NULL) 182538032Speter syserr("No *include* mailer defined"); 182638032Speter else 182738032Speter InclMailer = st->s_mailer; 182838032Speter 182938032Speter if (ConfigLevel < 6) 183038032Speter { 183138032Speter /* heuristic tweaking of local mailer for back compat */ 183238032Speter if (LocalMailer != NULL) 183338032Speter { 183438032Speter setbitn(M_ALIASABLE, LocalMailer->m_flags); 183538032Speter setbitn(M_HASPWENT, LocalMailer->m_flags); 183638032Speter setbitn(M_TRYRULESET5, LocalMailer->m_flags); 183738032Speter setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 183838032Speter setbitn(M_CHECKPROG, LocalMailer->m_flags); 183938032Speter setbitn(M_CHECKFILE, LocalMailer->m_flags); 184038032Speter setbitn(M_CHECKUDB, LocalMailer->m_flags); 184138032Speter } 184238032Speter if (ProgMailer != NULL) 184338032Speter setbitn(M_RUNASRCPT, ProgMailer->m_flags); 184438032Speter if (FileMailer != NULL) 184538032Speter setbitn(M_RUNASRCPT, FileMailer->m_flags); 184638032Speter } 184738032Speter if (ConfigLevel < 7) 184838032Speter { 184938032Speter if (LocalMailer != NULL) 185038032Speter setbitn(M_VRFY250, LocalMailer->m_flags); 185138032Speter if (ProgMailer != NULL) 185238032Speter setbitn(M_VRFY250, ProgMailer->m_flags); 185338032Speter if (FileMailer != NULL) 185438032Speter setbitn(M_VRFY250, FileMailer->m_flags); 185538032Speter } 185638032Speter 185738032Speter /* MIME Content-Types that cannot be transfer encoded */ 185838032Speter setclass('n', "multipart/signed"); 185938032Speter 186038032Speter /* MIME message/xxx subtypes that can be treated as messages */ 186138032Speter setclass('s', "rfc822"); 1862363466Sgshapiro#if _FFR_EAI 1863363466Sgshapiro setclass('s', "global"); 1864363466Sgshapiro#endif 186538032Speter 186638032Speter /* MIME Content-Transfer-Encodings that can be encoded */ 186738032Speter setclass('e', "7bit"); 186838032Speter setclass('e', "8bit"); 186938032Speter setclass('e', "binary"); 187038032Speter 187138032Speter#ifdef USE_B_CLASS 187238032Speter /* MIME Content-Types that should be treated as binary */ 187338032Speter setclass('b', "image"); 187438032Speter setclass('b', "audio"); 187538032Speter setclass('b', "video"); 187638032Speter setclass('b', "application/octet-stream"); 187764562Sgshapiro#endif /* USE_B_CLASS */ 187838032Speter 187942575Speter /* MIME headers which have fields to check for overflow */ 188090792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition"); 188190792Sgshapiro setclass(macid("{checkMIMEFieldHeaders}"), "content-type"); 188242575Speter 188342575Speter /* MIME headers to check for length overflow */ 188490792Sgshapiro setclass(macid("{checkMIMETextHeaders}"), "content-description"); 188542575Speter 188642575Speter /* MIME headers to check for overflow and rebalance */ 188790792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-disposition"); 188890792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-id"); 188990792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding"); 189090792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "content-type"); 189190792Sgshapiro setclass(macid("{checkMIMEHeaders}"), "mime-version"); 189242575Speter 189390792Sgshapiro /* Macros to save in the queue file -- don't remove any */ 189490792Sgshapiro setclass(macid("{persistentMacros}"), "r"); 189590792Sgshapiro setclass(macid("{persistentMacros}"), "s"); 189690792Sgshapiro setclass(macid("{persistentMacros}"), "_"); 189790792Sgshapiro setclass(macid("{persistentMacros}"), "{if_addr}"); 189890792Sgshapiro setclass(macid("{persistentMacros}"), "{daemon_flags}"); 189964562Sgshapiro 190038032Speter /* operate in queue directory */ 190190792Sgshapiro if (QueueDir == NULL || *QueueDir == '\0') 190238032Speter { 190338032Speter if (OpMode != MD_TEST) 190438032Speter { 190538032Speter syserr("QueueDirectory (Q) option must be set"); 190638032Speter ExitStat = EX_CONFIG; 190738032Speter } 190838032Speter } 190938032Speter else 191038032Speter { 191164562Sgshapiro if (OpMode != MD_TEST) 191290792Sgshapiro setup_queues(OpMode == MD_DAEMON); 191338032Speter } 191438032Speter 191538032Speter /* check host status directory for validity */ 191690792Sgshapiro if (HostStatDir != NULL && !path_is_dir(HostStatDir, false)) 191738032Speter { 191838032Speter /* cannot use this value */ 191990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 192090792Sgshapiro "Warning: Cannot use HostStatusDirectory = %s: %s\n", 192190792Sgshapiro HostStatDir, sm_errstring(errno)); 192238032Speter HostStatDir = NULL; 192338032Speter } 192438032Speter 192590792Sgshapiro if (OpMode == MD_QUEUERUN && 192690792Sgshapiro RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 192738032Speter { 192838032Speter struct stat stbuf; 192938032Speter 193038032Speter /* check to see if we own the queue directory */ 193138032Speter if (stat(".", &stbuf) < 0) 193238032Speter syserr("main: cannot stat %s", QueueDir); 193338032Speter if (stbuf.st_uid != RealUid) 193438032Speter { 193538032Speter /* nope, really a botch */ 193690792Sgshapiro HoldErrs = false; 193738032Speter usrerr("You do not have permission to process the queue"); 193890792Sgshapiro finis(false, true, EX_NOPERM); 193990792Sgshapiro /* NOTREACHED */ 194038032Speter } 194138032Speter } 194238032Speter 194390792Sgshapiro#if MILTER 194464562Sgshapiro /* sanity checks on milter filters */ 194564562Sgshapiro if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 194690792Sgshapiro { 194790792Sgshapiro milter_config(InputFilterList, InputFilters, MAXFILTERS); 194890792Sgshapiro setup_daemon_milters(); 194990792Sgshapiro } 195090792Sgshapiro#endif /* MILTER */ 195164562Sgshapiro 195290792Sgshapiro /* Convert queuegroup string to qgrp number */ 195390792Sgshapiro if (queuegroup != NULL) 195490792Sgshapiro { 195590792Sgshapiro qgrp = name2qid(queuegroup); 195690792Sgshapiro if (qgrp == NOQGRP) 195790792Sgshapiro { 195890792Sgshapiro HoldErrs = false; 195990792Sgshapiro usrerr("Queue group %s unknown", queuegroup); 196090792Sgshapiro finis(false, true, ExitStat); 196190792Sgshapiro /* NOTREACHED */ 196290792Sgshapiro } 196390792Sgshapiro } 196466494Sgshapiro 1965203004Sgshapiro /* if checking config or have had errors so far, exit now */ 1966203004Sgshapiro if (OpMode == MD_CHECKCONFIG || (ExitStat != EX_OK && OpMode != MD_TEST)) 196790792Sgshapiro { 196890792Sgshapiro finis(false, true, ExitStat); 196990792Sgshapiro /* NOTREACHED */ 197090792Sgshapiro } 197138032Speter 197290792Sgshapiro#if SASL 197390792Sgshapiro /* sendmail specific SASL initialization */ 197490792Sgshapiro sm_sasl_init(); 1975363466Sgshapiro#endif 197690792Sgshapiro 197738032Speter#if XDEBUG 197838032Speter checkfd012("before main() initmaps"); 1979363466Sgshapiro#endif 198038032Speter 198138032Speter /* 198238032Speter ** Do operation-mode-dependent initialization. 198338032Speter */ 198438032Speter 198538032Speter switch (OpMode) 198638032Speter { 198738032Speter case MD_PRINT: 198838032Speter /* print the queue */ 198990792Sgshapiro HoldErrs = false; 1990203004Sgshapiro (void) dropenvelope(&BlankEnvelope, true, false); 199190792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 199290792Sgshapiro if (qgrp != NOQGRP) 199390792Sgshapiro { 199490792Sgshapiro /* Selecting a particular queue group to run */ 199590792Sgshapiro for (j = 0; j < Queue[qgrp]->qg_numqueues; j++) 199690792Sgshapiro { 199790792Sgshapiro if (StopRequest) 199890792Sgshapiro stop_sendmail(); 199990792Sgshapiro (void) print_single_queue(qgrp, j); 200090792Sgshapiro } 200190792Sgshapiro finis(false, true, EX_OK); 200290792Sgshapiro /* NOTREACHED */ 200390792Sgshapiro } 200438032Speter printqueue(); 200590792Sgshapiro finis(false, true, EX_OK); 200690792Sgshapiro /* NOTREACHED */ 200742575Speter break; 200838032Speter 200990792Sgshapiro case MD_PRINTNQE: 201090792Sgshapiro /* print number of entries in queue */ 2011203004Sgshapiro (void) dropenvelope(&BlankEnvelope, true, false); 201290792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 201390792Sgshapiro printnqe(smioout, NULL); 201490792Sgshapiro finis(false, true, EX_OK); 201590792Sgshapiro /* NOTREACHED */ 201690792Sgshapiro break; 201790792Sgshapiro 201890792Sgshapiro case MD_QUEUERUN: 201990792Sgshapiro /* only handle quarantining here */ 202090792Sgshapiro if (quarantining == NULL) 202190792Sgshapiro break; 202290792Sgshapiro 202390792Sgshapiro if (QueueMode != QM_QUARANTINE && 202490792Sgshapiro QueueMode != QM_NORMAL) 202590792Sgshapiro { 202690792Sgshapiro HoldErrs = false; 202790792Sgshapiro usrerr("Can not use -Q with -q%c", QueueMode); 202890792Sgshapiro ExitStat = EX_USAGE; 202990792Sgshapiro finis(false, true, ExitStat); 203090792Sgshapiro /* NOTREACHED */ 203190792Sgshapiro } 203290792Sgshapiro quarantine_queue(quarantining, qgrp); 203390792Sgshapiro finis(false, true, EX_OK); 203490792Sgshapiro break; 203590792Sgshapiro 203638032Speter case MD_HOSTSTAT: 203790792Sgshapiro (void) sm_signal(SIGPIPE, sigpipe); 203864562Sgshapiro (void) mci_traverse_persistent(mci_print_persistent, NULL); 203990792Sgshapiro finis(false, true, EX_OK); 204090792Sgshapiro /* NOTREACHED */ 204164562Sgshapiro break; 204238032Speter 204338032Speter case MD_PURGESTAT: 204464562Sgshapiro (void) mci_traverse_persistent(mci_purge_persistent, NULL); 204590792Sgshapiro finis(false, true, EX_OK); 204690792Sgshapiro /* NOTREACHED */ 204764562Sgshapiro break; 204838032Speter 204938032Speter case MD_INITALIAS: 205042575Speter /* initialize maps */ 205164562Sgshapiro initmaps(); 205290792Sgshapiro finis(false, true, ExitStat); 205390792Sgshapiro /* NOTREACHED */ 205442575Speter break; 205538032Speter 205638032Speter case MD_SMTP: 205738032Speter case MD_DAEMON: 205838032Speter /* reset DSN parameters */ 205938032Speter DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 206090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 206190792Sgshapiro macid("{dsn_notify}"), NULL); 206290792Sgshapiro BlankEnvelope.e_envid = NULL; 206390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 206490792Sgshapiro macid("{dsn_envid}"), NULL); 206590792Sgshapiro BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 206690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 206790792Sgshapiro macid("{dsn_ret}"), NULL); 206838032Speter 206942575Speter /* don't open maps for daemon -- done below in child */ 207038032Speter break; 207138032Speter } 207238032Speter 207338032Speter if (tTd(0, 15)) 207438032Speter { 207538032Speter /* print configuration table (or at least part of it) */ 207638032Speter if (tTd(0, 90)) 207738032Speter printrules(); 207838032Speter for (i = 0; i < MAXMAILERS; i++) 207938032Speter { 208038032Speter if (Mailer[i] != NULL) 2081132943Sgshapiro printmailer(sm_debug_file(), Mailer[i]); 208238032Speter } 208338032Speter } 208438032Speter 208538032Speter /* 208638032Speter ** Switch to the main envelope. 208738032Speter */ 208838032Speter 208990792Sgshapiro CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope, 209090792Sgshapiro sm_rpool_new_x(NULL)); 209138032Speter MainEnvelope.e_flags = BlankEnvelope.e_flags; 209238032Speter 209338032Speter /* 209438032Speter ** If test mode, read addresses from stdin and process. 209538032Speter */ 209638032Speter 209738032Speter if (OpMode == MD_TEST) 209838032Speter { 209990792Sgshapiro if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL))) 210038032Speter Verbose = 2; 210138032Speter 210238032Speter if (Verbose) 210338032Speter { 210490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 210590792Sgshapiro "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 210690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 210790792Sgshapiro "Enter <ruleset> <address>\n"); 210838032Speter } 210990792Sgshapiro macdefine(&(MainEnvelope.e_macro), A_PERM, 211090792Sgshapiro macid("{addr_type}"), "e r"); 211138032Speter for (;;) 211238032Speter { 211390792Sgshapiro SM_TRY 211490792Sgshapiro { 211590792Sgshapiro (void) sm_signal(SIGINT, intindebug); 211690792Sgshapiro (void) sm_releasesignal(SIGINT); 211790792Sgshapiro if (Verbose == 2) 211890792Sgshapiro (void) sm_io_fprintf(smioout, 211990792Sgshapiro SM_TIME_DEFAULT, 212090792Sgshapiro "> "); 212190792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 212290792Sgshapiro if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, 2123249729Sgshapiro sizeof(buf)) < 0) 212490792Sgshapiro testmodeline("/quit", &MainEnvelope); 212590792Sgshapiro p = strchr(buf, '\n'); 212690792Sgshapiro if (p != NULL) 212790792Sgshapiro *p = '\0'; 212890792Sgshapiro if (Verbose < 2) 212990792Sgshapiro (void) sm_io_fprintf(smioout, 213090792Sgshapiro SM_TIME_DEFAULT, 213190792Sgshapiro "> %s\n", buf); 213290792Sgshapiro testmodeline(buf, &MainEnvelope); 213390792Sgshapiro } 213490792Sgshapiro SM_EXCEPT(exc, "[!F]*") 213590792Sgshapiro { 213690792Sgshapiro /* 213790792Sgshapiro ** 8.10 just prints \n on interrupt. 213890792Sgshapiro ** I'm printing the exception here in case 213990792Sgshapiro ** sendmail is extended to raise additional 214090792Sgshapiro ** exceptions in this context. 214190792Sgshapiro */ 214290792Sgshapiro 214390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 214490792Sgshapiro "\n"); 214590792Sgshapiro sm_exc_print(exc, smioout); 214690792Sgshapiro } 214790792Sgshapiro SM_END_TRY 214838032Speter } 214938032Speter } 215038032Speter 215190792Sgshapiro#if STARTTLS 215290792Sgshapiro tls_ok = true; 2153168515Sgshapiro if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER || 2154168515Sgshapiro OpMode == MD_ARPAFTP) 215590792Sgshapiro { 215690792Sgshapiro /* check whether STARTTLS is turned off for the client */ 215790792Sgshapiro if (chkclientmodifiers(D_NOTLS)) 215890792Sgshapiro tls_ok = false; 215990792Sgshapiro } 216090792Sgshapiro else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON || 216190792Sgshapiro OpMode == MD_SMTP) 216290792Sgshapiro { 2163203004Sgshapiro /* check whether STARTTLS is turned off */ 2164203004Sgshapiro if (chkdaemonmodifiers(D_NOTLS) && chkclientmodifiers(D_NOTLS)) 216590792Sgshapiro tls_ok = false; 216690792Sgshapiro } 216790792Sgshapiro else /* other modes don't need STARTTLS */ 216890792Sgshapiro tls_ok = false; 216964562Sgshapiro 217090792Sgshapiro if (tls_ok) 217190792Sgshapiro { 217290792Sgshapiro /* basic TLS initialization */ 2173363466Sgshapiro j = init_tls_library(FipsMode); 2174363466Sgshapiro if (j < 0) 2175249729Sgshapiro { 2176249729Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2177363466Sgshapiro "ERROR: TLS failed to initialize\n"); 2178249729Sgshapiro exit(EX_USAGE); 2179249729Sgshapiro } 2180363466Sgshapiro if (j > 0) 2181363466Sgshapiro tls_ok = false; 218290792Sgshapiro } 218390792Sgshapiro 218490792Sgshapiro if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)) 218590792Sgshapiro { 218690792Sgshapiro /* disable TLS for client */ 218790792Sgshapiro setclttls(false); 218890792Sgshapiro } 218990792Sgshapiro#endif /* STARTTLS */ 219090792Sgshapiro 219164562Sgshapiro /* 219238032Speter ** If collecting stuff from the queue, go start doing that. 219338032Speter */ 219438032Speter 219564562Sgshapiro if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 219638032Speter { 219790792Sgshapiro pid_t pid = -1; 219890792Sgshapiro 219990792Sgshapiro#if STARTTLS 220090792Sgshapiro /* init TLS for client, ignore result for now */ 220190792Sgshapiro (void) initclttls(tls_ok); 2202363466Sgshapiro#endif 220390792Sgshapiro 220490792Sgshapiro /* 220590792Sgshapiro ** The parent process of the caller of runqueue() needs 220690792Sgshapiro ** to stay around for a possible SIGTERM. The SIGTERM will 220790792Sgshapiro ** tell this process that all of the queue runners children 220890792Sgshapiro ** need to be sent SIGTERM as well. At the same time, we 220990792Sgshapiro ** want to return control to the command line. So we do an 221090792Sgshapiro ** extra fork(). 221190792Sgshapiro */ 221290792Sgshapiro 221390792Sgshapiro if (Verbose || foregroundqueue || (pid = fork()) <= 0) 221464562Sgshapiro { 221590792Sgshapiro /* 221690792Sgshapiro ** If the fork() failed we should still try to do 221790792Sgshapiro ** the queue run. If it succeeded then the child 221890792Sgshapiro ** is going to start the run and wait for all 221990792Sgshapiro ** of the children to finish. 222090792Sgshapiro */ 222190792Sgshapiro 222290792Sgshapiro if (pid == 0) 222390792Sgshapiro { 222490792Sgshapiro /* Reset global flags */ 222590792Sgshapiro RestartRequest = NULL; 222690792Sgshapiro ShutdownRequest = NULL; 222790792Sgshapiro PendingSignal = 0; 222890792Sgshapiro 222990792Sgshapiro /* disconnect from terminal */ 223090792Sgshapiro disconnect(2, CurEnv); 223190792Sgshapiro } 223290792Sgshapiro 223390792Sgshapiro CurrentPid = getpid(); 223490792Sgshapiro if (qgrp != NOQGRP) 223590792Sgshapiro { 2236110560Sgshapiro int rwgflags = RWG_NONE; 2237110560Sgshapiro 223890792Sgshapiro /* 223990792Sgshapiro ** To run a specific queue group mark it to 224090792Sgshapiro ** be run, select the work group it's in and 224190792Sgshapiro ** increment the work counter. 224290792Sgshapiro */ 224390792Sgshapiro 224494334Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 224594334Sgshapiro i++) 224694334Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 224794334Sgshapiro Queue[qgrp]->qg_nextrun = 0; 2248110560Sgshapiro if (Verbose) 2249110560Sgshapiro rwgflags |= RWG_VERBOSE; 2250110560Sgshapiro if (queuepersistent) 2251110560Sgshapiro rwgflags |= RWG_PERSISTENT; 2252110560Sgshapiro rwgflags |= RWG_FORCE; 225390792Sgshapiro (void) run_work_group(Queue[qgrp]->qg_wgrp, 2254110560Sgshapiro rwgflags); 225590792Sgshapiro } 225690792Sgshapiro else 225790792Sgshapiro (void) runqueue(false, Verbose, 225890792Sgshapiro queuepersistent, true); 225990792Sgshapiro 226090792Sgshapiro /* set the title to make it easier to find */ 226190792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 226290792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 226390792Sgshapiro while (CurChildren > 0) 226490792Sgshapiro { 226590792Sgshapiro int status; 226690792Sgshapiro pid_t ret; 226790792Sgshapiro 2268125820Sgshapiro errno = 0; 226990792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 2270125820Sgshapiro { 2271125820Sgshapiro if (errno == ECHILD) 2272125820Sgshapiro { 2273125820Sgshapiro /* 2274125820Sgshapiro ** Oops... something got messed 2275125820Sgshapiro ** up really bad. Waiting for 2276125820Sgshapiro ** non-existent children 2277125820Sgshapiro ** shouldn't happen. Let's get 2278125820Sgshapiro ** out of here. 2279125820Sgshapiro */ 2280125820Sgshapiro 2281125820Sgshapiro CurChildren = 0; 2282125820Sgshapiro break; 2283125820Sgshapiro } 228490792Sgshapiro continue; 2285125820Sgshapiro } 228690792Sgshapiro 2287125820Sgshapiro /* something is really really wrong */ 2288125820Sgshapiro if (errno == ECHILD) 2289125820Sgshapiro { 2290125820Sgshapiro sm_syslog(LOG_ERR, NOQID, 2291125820Sgshapiro "queue control process: lost all children: wait returned ECHILD"); 2292125820Sgshapiro break; 2293125820Sgshapiro } 2294125820Sgshapiro 229590792Sgshapiro /* Only drop when a child gives status */ 229690792Sgshapiro if (WIFSTOPPED(status)) 229790792Sgshapiro continue; 229890792Sgshapiro 229990792Sgshapiro proc_list_drop(ret, status, NULL); 230090792Sgshapiro } 230164562Sgshapiro } 230290792Sgshapiro finis(true, true, ExitStat); 230390792Sgshapiro /* NOTREACHED */ 230438032Speter } 230538032Speter 2306363466Sgshapiro#if SASL 230771345Sgshapiro if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 230871345Sgshapiro { 230990792Sgshapiro /* check whether AUTH is turned off for the server */ 231090792Sgshapiro if (!chkdaemonmodifiers(D_NOAUTH) && 231190792Sgshapiro (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 231271345Sgshapiro syserr("!sasl_server_init failed! [%s]", 231390792Sgshapiro sasl_errstring(i, NULL, NULL)); 231471345Sgshapiro } 2315363466Sgshapiro#endif /* SASL */ 231671345Sgshapiro 231790792Sgshapiro if (OpMode == MD_SMTP) 231890792Sgshapiro { 231990792Sgshapiro proc_list_add(CurrentPid, "Sendmail SMTP Agent", 2320132943Sgshapiro PROC_DAEMON, 0, -1, NULL); 232190792Sgshapiro 232290792Sgshapiro /* clean up background delivery children */ 232390792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 232490792Sgshapiro } 232590792Sgshapiro 232638032Speter /* 232738032Speter ** If a daemon, wait for a request. 232838032Speter ** getrequests will always return in a child. 232938032Speter ** If we should also be processing the queue, start 233038032Speter ** doing it in background. 233138032Speter ** We check for any errors that might have happened 233238032Speter ** during startup. 233338032Speter */ 233438032Speter 233598841Sgshapiro if (OpMode == MD_DAEMON || QueueIntvl > 0) 233638032Speter { 233738032Speter char dtype[200]; 233838032Speter 2339161389Sgshapiro /* avoid cleanup in finis(), DaemonPid will be set below */ 2340161389Sgshapiro DaemonPid = 0; 234138032Speter if (!run_in_foreground && !tTd(99, 100)) 234238032Speter { 234338032Speter /* put us in background */ 234438032Speter i = fork(); 234538032Speter if (i < 0) 234638032Speter syserr("daemon: cannot fork"); 234738032Speter if (i != 0) 234890792Sgshapiro { 234990792Sgshapiro finis(false, true, EX_OK); 235090792Sgshapiro /* NOTREACHED */ 235190792Sgshapiro } 235238032Speter 235390792Sgshapiro /* 235490792Sgshapiro ** Initialize exception stack and default exception 235590792Sgshapiro ** handler for child process. 235690792Sgshapiro */ 235790792Sgshapiro 235890792Sgshapiro /* Reset global flags */ 235990792Sgshapiro RestartRequest = NULL; 236090792Sgshapiro RestartWorkGroup = false; 236190792Sgshapiro ShutdownRequest = NULL; 236290792Sgshapiro PendingSignal = 0; 236390792Sgshapiro CurrentPid = getpid(); 236490792Sgshapiro 236590792Sgshapiro sm_exc_newthread(fatal_error); 236690792Sgshapiro 236738032Speter /* disconnect from our controlling tty */ 236890792Sgshapiro disconnect(2, &MainEnvelope); 236938032Speter } 237038032Speter 237138032Speter dtype[0] = '\0'; 237238032Speter if (OpMode == MD_DAEMON) 2373161389Sgshapiro { 2374168515Sgshapiro (void) sm_strlcat(dtype, "+SMTP", sizeof(dtype)); 2375161389Sgshapiro DaemonPid = CurrentPid; 2376161389Sgshapiro } 237798841Sgshapiro if (QueueIntvl > 0) 237838032Speter { 237990792Sgshapiro (void) sm_strlcat2(dtype, 238090792Sgshapiro queuepersistent 238190792Sgshapiro ? "+persistent-queueing@" 238290792Sgshapiro : "+queueing@", 238390792Sgshapiro pintvl(QueueIntvl, true), 2384168515Sgshapiro sizeof(dtype)); 238538032Speter } 238638032Speter if (tTd(0, 1)) 2387168515Sgshapiro (void) sm_strlcat(dtype, "+debugging", sizeof(dtype)); 238838032Speter 238938032Speter sm_syslog(LOG_INFO, NOQID, 239064562Sgshapiro "starting daemon (%s): %s", Version, dtype + 1); 239190792Sgshapiro#if XLA 239238032Speter xla_create_file(); 2393363466Sgshapiro#endif 239438032Speter 239564562Sgshapiro /* save daemon type in a macro for possible PidFile use */ 239690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 239790792Sgshapiro macid("{daemon_info}"), dtype + 1); 239864562Sgshapiro 239964562Sgshapiro /* save queue interval in a macro for possible PidFile use */ 240090792Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 240190792Sgshapiro macid("{queue_interval}"), pintvl(QueueIntvl, true)); 240264562Sgshapiro 240390792Sgshapiro /* workaround: can't seem to release the signal in the parent */ 240490792Sgshapiro (void) sm_signal(SIGHUP, sighup); 240590792Sgshapiro (void) sm_releasesignal(SIGHUP); 240690792Sgshapiro (void) sm_signal(SIGTERM, sigterm); 240790792Sgshapiro 240898841Sgshapiro if (QueueIntvl > 0) 240938032Speter { 2410173340Sgshapiro#if _FFR_RUNPQG 2411173340Sgshapiro if (qgrp != NOQGRP) 2412173340Sgshapiro { 2413173340Sgshapiro int rwgflags = RWG_NONE; 241490792Sgshapiro 2415173340Sgshapiro /* 2416173340Sgshapiro ** To run a specific queue group mark it to 2417173340Sgshapiro ** be run, select the work group it's in and 2418173340Sgshapiro ** increment the work counter. 2419173340Sgshapiro */ 2420173340Sgshapiro 2421173340Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 2422173340Sgshapiro i++) 2423173340Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 2424173340Sgshapiro Queue[qgrp]->qg_nextrun = 0; 2425173340Sgshapiro if (Verbose) 2426173340Sgshapiro rwgflags |= RWG_VERBOSE; 2427173340Sgshapiro if (queuepersistent) 2428173340Sgshapiro rwgflags |= RWG_PERSISTENT; 2429173340Sgshapiro rwgflags |= RWG_FORCE; 2430173340Sgshapiro (void) run_work_group(Queue[qgrp]->qg_wgrp, 2431173340Sgshapiro rwgflags); 2432173340Sgshapiro } 2433173340Sgshapiro else 2434173340Sgshapiro#endif /* _FFR_RUNPQG */ 2435173340Sgshapiro (void) runqueue(true, false, queuepersistent, 2436173340Sgshapiro true); 2437173340Sgshapiro 243890792Sgshapiro /* 243990792Sgshapiro ** If queuepersistent but not in daemon mode then 244090792Sgshapiro ** we're going to do the queue runner monitoring here. 244190792Sgshapiro ** If in daemon mode then the monitoring will happen 244290792Sgshapiro ** elsewhere. 244390792Sgshapiro */ 244490792Sgshapiro 244590792Sgshapiro if (OpMode != MD_DAEMON && queuepersistent) 244690792Sgshapiro { 2447132943Sgshapiro /* 2448132943Sgshapiro ** Write the pid to file 2449132943Sgshapiro ** XXX Overwrites sendmail.pid 2450132943Sgshapiro */ 2451132943Sgshapiro 2452132943Sgshapiro log_sendmail_pid(&MainEnvelope); 2453132943Sgshapiro 245490792Sgshapiro /* set the title to make it easier to find */ 245590792Sgshapiro sm_setproctitle(true, CurEnv, "Queue control"); 245690792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 245790792Sgshapiro while (CurChildren > 0) 245890792Sgshapiro { 245990792Sgshapiro int status; 246090792Sgshapiro pid_t ret; 246190792Sgshapiro int group; 246290792Sgshapiro 2463120256Sgshapiro CHECK_RESTART; 2464125820Sgshapiro errno = 0; 246590792Sgshapiro while ((ret = sm_wait(&status)) <= 0) 2466125820Sgshapiro { 2467125820Sgshapiro /* 2468125820Sgshapiro ** Waiting for non-existent 2469125820Sgshapiro ** children shouldn't happen. 2470125820Sgshapiro ** Let's get out of here if 2471125820Sgshapiro ** it occurs. 2472125820Sgshapiro */ 2473125820Sgshapiro 2474125820Sgshapiro if (errno == ECHILD) 2475125820Sgshapiro { 2476125820Sgshapiro CurChildren = 0; 2477125820Sgshapiro break; 2478125820Sgshapiro } 247990792Sgshapiro continue; 2480125820Sgshapiro } 248190792Sgshapiro 2482125820Sgshapiro /* something is really really wrong */ 2483125820Sgshapiro if (errno == ECHILD) 2484125820Sgshapiro { 2485125820Sgshapiro sm_syslog(LOG_ERR, NOQID, 2486125820Sgshapiro "persistent queue runner control process: lost all children: wait returned ECHILD"); 2487125820Sgshapiro break; 2488125820Sgshapiro } 2489125820Sgshapiro 249090792Sgshapiro if (WIFSTOPPED(status)) 249190792Sgshapiro continue; 249290792Sgshapiro 249390792Sgshapiro /* Probe only on a child status */ 249490792Sgshapiro proc_list_drop(ret, status, &group); 249590792Sgshapiro 249690792Sgshapiro if (WIFSIGNALED(status)) 249790792Sgshapiro { 249890792Sgshapiro if (WCOREDUMP(status)) 249990792Sgshapiro { 250090792Sgshapiro sm_syslog(LOG_ERR, NOQID, 250190792Sgshapiro "persistent queue runner=%d core dumped, signal=%d", 250290792Sgshapiro group, WTERMSIG(status)); 250390792Sgshapiro 2504120256Sgshapiro /* don't restart this */ 2505120256Sgshapiro mark_work_group_restart( 2506120256Sgshapiro group, -1); 250790792Sgshapiro continue; 250890792Sgshapiro } 250990792Sgshapiro 251090792Sgshapiro sm_syslog(LOG_ERR, NOQID, 2511168515Sgshapiro "persistent queue runner=%d died, pid=%ld, signal=%d", 2512168515Sgshapiro group, (long) ret, 2513168515Sgshapiro WTERMSIG(status)); 251490792Sgshapiro } 251590792Sgshapiro 251690792Sgshapiro /* 251790792Sgshapiro ** When debugging active, don't 251890792Sgshapiro ** restart the persistent queues. 251990792Sgshapiro ** But do log this as info. 252090792Sgshapiro */ 252190792Sgshapiro 252290792Sgshapiro if (sm_debug_active(&DebugNoPRestart, 252390792Sgshapiro 1)) 252490792Sgshapiro { 252590792Sgshapiro sm_syslog(LOG_DEBUG, NOQID, 252690792Sgshapiro "persistent queue runner=%d, exited", 252790792Sgshapiro group); 2528120256Sgshapiro mark_work_group_restart(group, 2529120256Sgshapiro -1); 253090792Sgshapiro } 2531168515Sgshapiro CHECK_RESTART; 253290792Sgshapiro } 253390792Sgshapiro finis(true, true, ExitStat); 253490792Sgshapiro /* NOTREACHED */ 253590792Sgshapiro } 253690792Sgshapiro 253738032Speter if (OpMode != MD_DAEMON) 253838032Speter { 253990792Sgshapiro char qtype[200]; 254090792Sgshapiro 254190792Sgshapiro /* 254290792Sgshapiro ** Write the pid to file 254390792Sgshapiro ** XXX Overwrites sendmail.pid 254490792Sgshapiro */ 254590792Sgshapiro 254690792Sgshapiro log_sendmail_pid(&MainEnvelope); 254790792Sgshapiro 254890792Sgshapiro /* set the title to make it easier to find */ 254990792Sgshapiro qtype[0] = '\0'; 2550168515Sgshapiro (void) sm_strlcpyn(qtype, sizeof(qtype), 4, 255190792Sgshapiro "Queue runner@", 255290792Sgshapiro pintvl(QueueIntvl, true), 255390792Sgshapiro " for ", 255490792Sgshapiro QueueDir); 255590792Sgshapiro sm_setproctitle(true, CurEnv, qtype); 255638032Speter for (;;) 255738032Speter { 255864562Sgshapiro (void) pause(); 2559132943Sgshapiro 2560120256Sgshapiro CHECK_RESTART; 2561132943Sgshapiro 256290792Sgshapiro if (doqueuerun()) 256390792Sgshapiro (void) runqueue(true, false, 256490792Sgshapiro false, false); 256538032Speter } 256638032Speter } 256738032Speter } 2568203004Sgshapiro (void) dropenvelope(&MainEnvelope, true, false); 256938032Speter 257090792Sgshapiro#if STARTTLS 257164562Sgshapiro /* init TLS for server, ignore result for now */ 257290792Sgshapiro (void) initsrvtls(tls_ok); 2573363466Sgshapiro#endif 2574110560Sgshapiro 257590792Sgshapiro nextreq: 257690792Sgshapiro p_flags = getrequests(&MainEnvelope); 257738032Speter 257838032Speter /* drop privileges */ 257990792Sgshapiro (void) drop_privileges(false); 258038032Speter 258138032Speter /* 258238032Speter ** Get authentication data 258390792Sgshapiro ** Set _ macro in BlankEnvelope before calling newenvelope(). 258438032Speter */ 258538032Speter 2586285229Sgshapiro#if _FFR_XCNCT 2587285229Sgshapiro if (bitnset(D_XCNCT, *p_flags) || bitnset(D_XCNCT_M, *p_flags)) 2588285229Sgshapiro { 2589285229Sgshapiro /* copied from getauthinfo() */ 2590285229Sgshapiro if (RealHostName == NULL) 2591285229Sgshapiro { 2592285229Sgshapiro RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 2593285229Sgshapiro if (strlen(RealHostName) > MAXNAME) 2594285229Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 2595285229Sgshapiro } 2596285229Sgshapiro snprintf(buf, sizeof(buf), "%s [%s]", 2597285229Sgshapiro RealHostName, anynet_ntoa(&RealHostAddr)); 2598285229Sgshapiro 2599285229Sgshapiro forged = bitnset(D_XCNCT_M, *p_flags); 2600285229Sgshapiro if (forged) 2601285229Sgshapiro { 2602285229Sgshapiro (void) sm_strlcat(buf, " (may be forged)", 2603285229Sgshapiro sizeof(buf)); 2604285229Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 2605285229Sgshapiro macid("{client_resolve}"), "FORGED"); 2606285229Sgshapiro } 2607285229Sgshapiro 2608285229Sgshapiro /* HACK! variable used only two times right below */ 2609285229Sgshapiro authinfo = buf; 2610285229Sgshapiro if (tTd(75, 9)) 2611285229Sgshapiro sm_syslog(LOG_INFO, NOQID, 2612285229Sgshapiro "main: where=not_calling_getauthinfo, RealHostAddr=%s", 2613285229Sgshapiro anynet_ntoa(&RealHostAddr)); 2614285229Sgshapiro } 2615285229Sgshapiro else 2616285229Sgshapiro /* WARNING: "non-braced" else */ 2617285229Sgshapiro#endif /* _FFR_XCNCT */ 261890792Sgshapiro authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 261990792Sgshapiro NULL), &forged); 262090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 2621244833Sgshapiro if (tTd(75, 9)) 2622244833Sgshapiro sm_syslog(LOG_INFO, NOQID, 2623244833Sgshapiro "main: where=after_getauthinfo, RealHostAddr=%s", 2624244833Sgshapiro anynet_ntoa(&RealHostAddr)); 262590792Sgshapiro 262690792Sgshapiro /* at this point we are in a child: reset state */ 262790792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 262890792Sgshapiro (void) newenvelope(&MainEnvelope, &MainEnvelope, 262990792Sgshapiro sm_rpool_new_x(NULL)); 263038032Speter } 263138032Speter 263264562Sgshapiro if (LogLevel > 9) 263364562Sgshapiro { 2634363466Sgshapiro p = authinfo; 2635363466Sgshapiro if (NULL == p) 2636363466Sgshapiro { 2637363466Sgshapiro if (NULL != RealHostName) 2638363466Sgshapiro p = RealHostName; 2639363466Sgshapiro else 2640363466Sgshapiro p = anynet_ntoa(&RealHostAddr); 2641363466Sgshapiro if (NULL == p) 2642363466Sgshapiro p = "unknown"; 2643363466Sgshapiro } 2644363466Sgshapiro 264564562Sgshapiro /* log connection information */ 2646363466Sgshapiro sm_syslog(LOG_INFO, NULL, "connect from %s", p); 264764562Sgshapiro } 264864562Sgshapiro 264938032Speter /* 265038032Speter ** If running SMTP protocol, start collecting and executing 265138032Speter ** commands. This will never return. 265238032Speter */ 265338032Speter 265438032Speter if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 265538032Speter { 265638032Speter char pbuf[20]; 265738032Speter 265838032Speter /* 265938032Speter ** Save some macros for check_* rulesets. 266038032Speter */ 266138032Speter 266238032Speter if (forged) 266338032Speter { 266438032Speter char ipbuf[103]; 266538032Speter 2666168515Sgshapiro (void) sm_snprintf(ipbuf, sizeof(ipbuf), "[%.100s]", 266790792Sgshapiro anynet_ntoa(&RealHostAddr)); 266890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 266990792Sgshapiro macid("{client_name}"), ipbuf); 267038032Speter } 267138032Speter else 267290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 267390792Sgshapiro macid("{client_name}"), RealHostName); 2674132943Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 2675132943Sgshapiro macid("{client_ptr}"), RealHostName); 267690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 267790792Sgshapiro macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 267890792Sgshapiro sm_getla(); 267938032Speter 268090792Sgshapiro switch (RealHostAddr.sa.sa_family) 268164562Sgshapiro { 268290792Sgshapiro#if NETINET 268364562Sgshapiro case AF_INET: 2684168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", 2685285229Sgshapiro ntohs(RealHostAddr.sin.sin_port)); 268664562Sgshapiro break; 268790792Sgshapiro#endif /* NETINET */ 268890792Sgshapiro#if NETINET6 268964562Sgshapiro case AF_INET6: 2690168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "%d", 2691285229Sgshapiro ntohs(RealHostAddr.sin6.sin6_port)); 269264562Sgshapiro break; 269390792Sgshapiro#endif /* NETINET6 */ 269464562Sgshapiro default: 2695168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), "0"); 269664562Sgshapiro break; 269764562Sgshapiro } 269890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 269990792Sgshapiro macid("{client_port}"), pbuf); 270042575Speter 270138032Speter if (OpMode == MD_DAEMON) 270238032Speter { 2703168515Sgshapiro ENVELOPE *saved_env; 2704168515Sgshapiro 270538032Speter /* validate the connection */ 270690792Sgshapiro HoldErrs = true; 2707168515Sgshapiro saved_env = CurEnv; 2708168515Sgshapiro CurEnv = &BlankEnvelope; 270938032Speter nullserver = validate_connection(&RealHostAddr, 2710132943Sgshapiro macvalue(macid("{client_name}"), 2711168515Sgshapiro &BlankEnvelope), 2712168515Sgshapiro &BlankEnvelope); 2713168515Sgshapiro if (bitset(EF_DISCARD, BlankEnvelope.e_flags)) 2714168515Sgshapiro MainEnvelope.e_flags |= EF_DISCARD; 2715168515Sgshapiro CurEnv = saved_env; 271690792Sgshapiro HoldErrs = false; 271738032Speter } 271864562Sgshapiro else if (p_flags == NULL) 271964562Sgshapiro { 2720168515Sgshapiro p_flags = (BITMAP256 *) xalloc(sizeof(*p_flags)); 272164562Sgshapiro clrbitmap(p_flags); 272264562Sgshapiro } 272390792Sgshapiro#if STARTTLS 272464562Sgshapiro if (OpMode == MD_SMTP) 272590792Sgshapiro (void) initsrvtls(tls_ok); 2726363466Sgshapiro#endif 272771345Sgshapiro 272890792Sgshapiro /* turn off profiling */ 272990792Sgshapiro SM_PROF(1); 273090792Sgshapiro smtp(nullserver, *p_flags, &MainEnvelope); 2731110560Sgshapiro 2732110560Sgshapiro if (tTd(93, 100)) 2733110560Sgshapiro { 2734110560Sgshapiro /* turn off profiling */ 2735110560Sgshapiro SM_PROF(0); 2736110560Sgshapiro if (OpMode == MD_DAEMON) 2737110560Sgshapiro goto nextreq; 2738110560Sgshapiro } 273938032Speter } 274038032Speter 274190792Sgshapiro sm_rpool_free(MainEnvelope.e_rpool); 274290792Sgshapiro clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 274338032Speter if (OpMode == MD_VERIFY) 274438032Speter { 274590792Sgshapiro set_delivery_mode(SM_VERIFY, &MainEnvelope); 274638032Speter PostMasterCopy = NULL; 274738032Speter } 274838032Speter else 274938032Speter { 275038032Speter /* interactive -- all errors are global */ 275190792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 275238032Speter } 275338032Speter 275438032Speter /* 275538032Speter ** Do basic system initialization and set the sender 275638032Speter */ 275738032Speter 275890792Sgshapiro initsys(&MainEnvelope); 275990792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 276090792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 276190792Sgshapiro setsender(from, &MainEnvelope, NULL, '\0', false); 276264562Sgshapiro if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 276390792Sgshapiro (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 276490792Sgshapiro strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 276564562Sgshapiro { 276690792Sgshapiro auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 276790792Sgshapiro RealUserName, from, warn_f_flag); 276864562Sgshapiro#if SASL 276990792Sgshapiro auth = false; 2770363466Sgshapiro#endif 277164562Sgshapiro } 277264562Sgshapiro if (auth) 277364562Sgshapiro { 277464562Sgshapiro char *fv; 277564562Sgshapiro 277664562Sgshapiro /* set the initial sender for AUTH= to $f@$j */ 277790792Sgshapiro fv = macvalue('f', &MainEnvelope); 277864562Sgshapiro if (fv == NULL || *fv == '\0') 277990792Sgshapiro MainEnvelope.e_auth_param = NULL; 278064562Sgshapiro else 278164562Sgshapiro { 278264562Sgshapiro if (strchr(fv, '@') == NULL) 278364562Sgshapiro { 278490792Sgshapiro i = strlen(fv) + strlen(macvalue('j', 278590792Sgshapiro &MainEnvelope)) + 2; 278690792Sgshapiro p = sm_malloc_x(i); 278790792Sgshapiro (void) sm_strlcpyn(p, i, 3, fv, "@", 278890792Sgshapiro macvalue('j', 278990792Sgshapiro &MainEnvelope)); 279064562Sgshapiro } 279164562Sgshapiro else 279290792Sgshapiro p = sm_strdup_x(fv); 279390792Sgshapiro MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 279490792Sgshapiro xtextify(p, "=")); 279590792Sgshapiro sm_free(p); /* XXX */ 279664562Sgshapiro } 279764562Sgshapiro } 279890792Sgshapiro if (macvalue('s', &MainEnvelope) == NULL) 279990792Sgshapiro macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 280038032Speter 280190792Sgshapiro av = argv + optind; 280238032Speter if (*av == NULL && !GrabTo) 280338032Speter { 280490792Sgshapiro MainEnvelope.e_to = NULL; 280590792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 280690792Sgshapiro HoldErrs = false; 280790792Sgshapiro SuperSafe = SAFE_NO; 280838032Speter usrerr("Recipient names must be specified"); 280938032Speter 281038032Speter /* collect body for UUCP return */ 281138032Speter if (OpMode != MD_VERIFY) 2812120256Sgshapiro collect(InChannel, false, NULL, &MainEnvelope, true); 281390792Sgshapiro finis(true, true, EX_USAGE); 281490792Sgshapiro /* NOTREACHED */ 281538032Speter } 281638032Speter 281738032Speter /* 281838032Speter ** Scan argv and deliver the message to everyone. 281938032Speter */ 282038032Speter 282190792Sgshapiro save_val = LogUsrErrs; 282290792Sgshapiro LogUsrErrs = true; 282390792Sgshapiro sendtoargv(av, &MainEnvelope); 282490792Sgshapiro LogUsrErrs = save_val; 282538032Speter 282638032Speter /* if we have had errors sofar, arrange a meaningful exit stat */ 282738032Speter if (Errors > 0 && ExitStat == EX_OK) 282838032Speter ExitStat = EX_USAGE; 282938032Speter 283038032Speter#if _FFR_FIX_DASHT 283138032Speter /* 283238032Speter ** If using -t, force not sending to argv recipients, even 283338032Speter ** if they are mentioned in the headers. 283438032Speter */ 283538032Speter 283638032Speter if (GrabTo) 283738032Speter { 283838032Speter ADDRESS *q; 283964562Sgshapiro 284090792Sgshapiro for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 284164562Sgshapiro q->q_state = QS_REMOVED; 284238032Speter } 284364562Sgshapiro#endif /* _FFR_FIX_DASHT */ 284438032Speter 284538032Speter /* 284638032Speter ** Read the input mail. 284738032Speter */ 284838032Speter 284990792Sgshapiro MainEnvelope.e_to = NULL; 285038032Speter if (OpMode != MD_VERIFY || GrabTo) 285138032Speter { 285290792Sgshapiro int savederrors; 285390792Sgshapiro unsigned long savedflags; 285438032Speter 285590792Sgshapiro /* 285690792Sgshapiro ** workaround for compiler warning on Irix: 285790792Sgshapiro ** do not initialize variable in the definition, but 285890792Sgshapiro ** later on: 285990792Sgshapiro ** warning(1548): transfer of control bypasses 286090792Sgshapiro ** initialization of: 286190792Sgshapiro ** variable "savederrors" (declared at line 2570) 286290792Sgshapiro ** variable "savedflags" (declared at line 2571) 286390792Sgshapiro ** goto giveup; 286490792Sgshapiro */ 286590792Sgshapiro 286690792Sgshapiro savederrors = Errors; 286790792Sgshapiro savedflags = MainEnvelope.e_flags & EF_FATALERRS; 286890792Sgshapiro MainEnvelope.e_flags |= EF_GLOBALERRS; 286990792Sgshapiro MainEnvelope.e_flags &= ~EF_FATALERRS; 287064562Sgshapiro Errors = 0; 287164562Sgshapiro buffer_errors(); 2872120256Sgshapiro collect(InChannel, false, NULL, &MainEnvelope, true); 287338032Speter 287464562Sgshapiro /* header checks failed */ 287564562Sgshapiro if (Errors > 0) 287664562Sgshapiro { 287790792Sgshapiro giveup: 287890792Sgshapiro if (!GrabTo) 287964562Sgshapiro { 288090792Sgshapiro /* Log who the mail would have gone to */ 288190792Sgshapiro logundelrcpts(&MainEnvelope, 288290792Sgshapiro MainEnvelope.e_message, 288390792Sgshapiro 8, false); 288464562Sgshapiro } 288590792Sgshapiro flush_errors(true); 288690792Sgshapiro finis(true, true, ExitStat); 288764562Sgshapiro /* NOTREACHED */ 288864562Sgshapiro return -1; 288964562Sgshapiro } 289064562Sgshapiro 289138032Speter /* bail out if message too large */ 289290792Sgshapiro if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 289338032Speter { 289490792Sgshapiro finis(true, true, ExitStat != EX_OK ? ExitStat 289590792Sgshapiro : EX_DATAERR); 289664562Sgshapiro /* NOTREACHED */ 289738032Speter return -1; 289838032Speter } 289998121Sgshapiro 290098121Sgshapiro /* set message size */ 2901168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", 2902244833Sgshapiro PRT_NONNEGL(MainEnvelope.e_msgsize)); 290398121Sgshapiro macdefine(&MainEnvelope.e_macro, A_TEMP, 290498121Sgshapiro macid("{msg_size}"), buf); 290598121Sgshapiro 290664562Sgshapiro Errors = savederrors; 290790792Sgshapiro MainEnvelope.e_flags |= savedflags; 290838032Speter } 290938032Speter errno = 0; 291038032Speter 291138032Speter if (tTd(1, 1)) 291290792Sgshapiro sm_dprintf("From person = \"%s\"\n", 291390792Sgshapiro MainEnvelope.e_from.q_paddr); 291438032Speter 291590792Sgshapiro /* Check if quarantining stats should be updated */ 291690792Sgshapiro if (MainEnvelope.e_quarmsg != NULL) 291790792Sgshapiro markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 291890792Sgshapiro 291938032Speter /* 292038032Speter ** Actually send everything. 292138032Speter ** If verifying, just ack. 292238032Speter */ 292338032Speter 292490792Sgshapiro if (Errors == 0) 292538032Speter { 292690792Sgshapiro if (!split_by_recipient(&MainEnvelope) && 292790792Sgshapiro bitset(EF_FATALERRS, MainEnvelope.e_flags)) 292890792Sgshapiro goto giveup; 292938032Speter } 293090792Sgshapiro 293190792Sgshapiro /* make sure we deliver at least the first envelope */ 293290792Sgshapiro i = FastSplit > 0 ? 0 : -1; 293390792Sgshapiro for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 293490792Sgshapiro { 293590792Sgshapiro ENVELOPE *next; 293690792Sgshapiro 293790792Sgshapiro e->e_from.q_state = QS_SENDER; 293890792Sgshapiro if (tTd(1, 5)) 293990792Sgshapiro { 294090792Sgshapiro sm_dprintf("main[%d]: QS_SENDER ", i); 2941132943Sgshapiro printaddr(sm_debug_file(), &e->e_from, false); 294290792Sgshapiro } 294390792Sgshapiro e->e_to = NULL; 294490792Sgshapiro sm_getla(); 294590792Sgshapiro GrabTo = false; 294664562Sgshapiro#if NAMED_BIND 294790792Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 294890792Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 2949363466Sgshapiro#endif 295090792Sgshapiro next = e->e_sibling; 295190792Sgshapiro e->e_sibling = NULL; 295238032Speter 295390792Sgshapiro /* after FastSplit envelopes: queue up */ 295490792Sgshapiro sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 295590792Sgshapiro e->e_sibling = next; 295690792Sgshapiro } 295790792Sgshapiro 295838032Speter /* 295938032Speter ** All done. 296038032Speter ** Don't send return error message if in VERIFY mode. 296138032Speter */ 296238032Speter 296390792Sgshapiro finis(true, true, ExitStat); 296464562Sgshapiro /* NOTREACHED */ 296564562Sgshapiro return ExitStat; 296638032Speter} 296790792Sgshapiro/* 296877349Sgshapiro** STOP_SENDMAIL -- Stop the running program 296977349Sgshapiro** 297077349Sgshapiro** Parameters: 297177349Sgshapiro** none. 297277349Sgshapiro** 297377349Sgshapiro** Returns: 297477349Sgshapiro** none. 297577349Sgshapiro** 297677349Sgshapiro** Side Effects: 297777349Sgshapiro** exits. 297877349Sgshapiro*/ 297938032Speter 298077349Sgshapirovoid 298177349Sgshapirostop_sendmail() 298277349Sgshapiro{ 298377349Sgshapiro /* reset uid for process accounting */ 298477349Sgshapiro endpwent(); 298577349Sgshapiro (void) setuid(RealUid); 298677349Sgshapiro exit(EX_OK); 298777349Sgshapiro} 298890792Sgshapiro/* 298938032Speter** FINIS -- Clean up and exit. 299038032Speter** 299138032Speter** Parameters: 299242575Speter** drop -- whether or not to drop CurEnv envelope 299390792Sgshapiro** cleanup -- call exit() or _exit()? 299442575Speter** exitstat -- exit status to use for exit() call 299538032Speter** 299638032Speter** Returns: 299738032Speter** never 299838032Speter** 299938032Speter** Side Effects: 300038032Speter** exits sendmail 300138032Speter*/ 300238032Speter 300338032Spetervoid 300490792Sgshapirofinis(drop, cleanup, exitstat) 300542575Speter bool drop; 300690792Sgshapiro bool cleanup; 300742575Speter volatile int exitstat; 300838032Speter{ 3009132943Sgshapiro char pidpath[MAXPATHLEN]; 3010159609Sgshapiro pid_t pid; 301198121Sgshapiro 301277349Sgshapiro /* Still want to process new timeouts added below */ 301390792Sgshapiro sm_clear_events(); 301490792Sgshapiro (void) sm_releasesignal(SIGALRM); 301542575Speter 3016363466Sgshapiro#if RATECTL_DEBUG || _FFR_OCC 3017363466Sgshapiro /* do this only in "main" process */ 3018363466Sgshapiro if (DaemonPid == getpid()) 3019363466Sgshapiro { 3020363466Sgshapiro SM_FILE_T *fp; 3021363466Sgshapiro 3022363466Sgshapiro fp = sm_debug_file(); 3023363466Sgshapiro if (fp != NULL) 3024363466Sgshapiro dump_ch(fp); 3025363466Sgshapiro } 3026363466Sgshapiro#endif 302738032Speter if (tTd(2, 1)) 302838032Speter { 302990792Sgshapiro sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 303090792Sgshapiro exitstat, 303190792Sgshapiro CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 303238032Speter printenvflags(CurEnv); 303338032Speter } 303438032Speter if (tTd(2, 9)) 303590792Sgshapiro printopenfds(false); 303638032Speter 303790792Sgshapiro SM_TRY 303890792Sgshapiro /* 303990792Sgshapiro ** Clean up. This might raise E:mta.quickabort 304090792Sgshapiro */ 304138032Speter 304290792Sgshapiro /* clean up temp files */ 304390792Sgshapiro CurEnv->e_to = NULL; 304490792Sgshapiro if (drop) 304590792Sgshapiro { 304690792Sgshapiro if (CurEnv->e_id != NULL) 304790792Sgshapiro { 3048203004Sgshapiro int r; 3049203004Sgshapiro 3050203004Sgshapiro r = dropenvelope(CurEnv, true, false); 3051203004Sgshapiro if (exitstat == EX_OK) 3052203004Sgshapiro exitstat = r; 305390792Sgshapiro sm_rpool_free(CurEnv->e_rpool); 305490792Sgshapiro CurEnv->e_rpool = NULL; 3055161389Sgshapiro 3056168515Sgshapiro /* these may have pointed to the rpool */ 3057161389Sgshapiro CurEnv->e_to = NULL; 3058168515Sgshapiro CurEnv->e_message = NULL; 3059168515Sgshapiro CurEnv->e_statmsg = NULL; 3060168515Sgshapiro CurEnv->e_quarmsg = NULL; 3061168515Sgshapiro CurEnv->e_bodytype = NULL; 3062168515Sgshapiro CurEnv->e_id = NULL; 3063168515Sgshapiro CurEnv->e_envid = NULL; 3064168515Sgshapiro CurEnv->e_auth_param = NULL; 306590792Sgshapiro } 306690792Sgshapiro else 306790792Sgshapiro poststats(StatFile); 306890792Sgshapiro } 306938032Speter 307090792Sgshapiro /* flush any cached connections */ 307190792Sgshapiro mci_flush(true, NULL); 307238032Speter 307390792Sgshapiro /* close maps belonging to this pid */ 307490792Sgshapiro closemaps(false); 307542575Speter 307664562Sgshapiro#if USERDB 307790792Sgshapiro /* close UserDatabase */ 307890792Sgshapiro _udbx_close(); 3079363466Sgshapiro#endif 308042575Speter 308190792Sgshapiro#if SASL 308290792Sgshapiro stop_sasl_client(); 3083363466Sgshapiro#endif 308490792Sgshapiro 308590792Sgshapiro#if XLA 308690792Sgshapiro /* clean up extended load average stuff */ 308790792Sgshapiro xla_all_end(); 3088363466Sgshapiro#endif 308938032Speter 309090792Sgshapiro SM_FINALLY 309190792Sgshapiro /* 309290792Sgshapiro ** And exit. 309390792Sgshapiro */ 309438032Speter 309590792Sgshapiro if (LogLevel > 78) 309690792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 309790792Sgshapiro (int) CurrentPid); 309890792Sgshapiro if (exitstat == EX_TEMPFAIL || 309990792Sgshapiro CurEnv->e_errormode == EM_BERKNET) 310090792Sgshapiro exitstat = EX_OK; 310164562Sgshapiro 310290792Sgshapiro /* XXX clean up queues and related data structures */ 310390792Sgshapiro cleanup_queues(); 3104159609Sgshapiro pid = getpid(); 310590792Sgshapiro#if SM_CONF_SHM 3106159609Sgshapiro cleanup_shm(DaemonPid == pid); 3107363466Sgshapiro#endif 310890792Sgshapiro 3109132943Sgshapiro /* close locked pid file */ 3110132943Sgshapiro close_sendmail_pid(); 3111132943Sgshapiro 3112159609Sgshapiro if (DaemonPid == pid || PidFilePid == pid) 3113132943Sgshapiro { 3114132943Sgshapiro /* blow away the pid file */ 3115168515Sgshapiro expand(PidFile, pidpath, sizeof(pidpath), CurEnv); 3116132943Sgshapiro (void) unlink(pidpath); 3117132943Sgshapiro } 3118132943Sgshapiro 311990792Sgshapiro /* reset uid for process accounting */ 312090792Sgshapiro endpwent(); 312190792Sgshapiro sm_mbdb_terminate(); 3122157001Sgshapiro#if _FFR_MEMSTAT 3123157001Sgshapiro (void) sm_memstat_close(); 3124363466Sgshapiro#endif 312590792Sgshapiro (void) setuid(RealUid); 312690792Sgshapiro#if SM_HEAP_CHECK 312790792Sgshapiro /* dump the heap, if we are checking for memory leaks */ 312890792Sgshapiro if (sm_debug_active(&SmHeapCheck, 2)) 312990792Sgshapiro sm_heap_report(smioout, 313090792Sgshapiro sm_debug_level(&SmHeapCheck) - 1); 3131363466Sgshapiro#endif 313290792Sgshapiro if (sm_debug_active(&SmXtrapReport, 1)) 313390792Sgshapiro sm_dprintf("xtrap count = %d\n", SmXtrapCount); 313490792Sgshapiro if (cleanup) 313590792Sgshapiro exit(exitstat); 313690792Sgshapiro else 313790792Sgshapiro _exit(exitstat); 313890792Sgshapiro SM_END_TRY 313938032Speter} 314090792Sgshapiro/* 314190792Sgshapiro** INTINDEBUG -- signal handler for SIGINT in -bt mode 314277349Sgshapiro** 314377349Sgshapiro** Parameters: 314490792Sgshapiro** sig -- incoming signal. 314590792Sgshapiro** 314690792Sgshapiro** Returns: 314790792Sgshapiro** none. 314890792Sgshapiro** 314990792Sgshapiro** Side Effects: 315090792Sgshapiro** longjmps back to test mode loop. 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. 315590792Sgshapiro*/ 315690792Sgshapiro 315790792Sgshapiro/* Type of an exception generated on SIGINT during address test mode. */ 315890792Sgshapirostatic const SM_EXC_TYPE_T EtypeInterrupt = 315990792Sgshapiro{ 316090792Sgshapiro SmExcTypeMagic, 316190792Sgshapiro "S:mta.interrupt", 316290792Sgshapiro "", 316390792Sgshapiro sm_etype_printf, 316490792Sgshapiro "interrupt", 316590792Sgshapiro}; 316690792Sgshapiro 316790792Sgshapiro/* ARGSUSED */ 316890792Sgshapirostatic SIGFUNC_DECL 316990792Sgshapirointindebug(sig) 317090792Sgshapiro int sig; 317190792Sgshapiro{ 317290792Sgshapiro int save_errno = errno; 317390792Sgshapiro 317490792Sgshapiro FIX_SYSV_SIGNAL(sig, intindebug); 317590792Sgshapiro errno = save_errno; 317690792Sgshapiro CHECK_CRITICAL(sig); 317790792Sgshapiro errno = save_errno; 317890792Sgshapiro sm_exc_raisenew_x(&EtypeInterrupt); 317990792Sgshapiro errno = save_errno; 318090792Sgshapiro return SIGFUNC_RETURN; 318190792Sgshapiro} 318290792Sgshapiro/* 318390792Sgshapiro** SIGTERM -- SIGTERM handler for the daemon 318490792Sgshapiro** 318590792Sgshapiro** Parameters: 318677349Sgshapiro** sig -- signal number. 318777349Sgshapiro** 318877349Sgshapiro** Returns: 318977349Sgshapiro** none. 319077349Sgshapiro** 319177349Sgshapiro** Side Effects: 319277349Sgshapiro** Sets ShutdownRequest which will hopefully trigger 319377349Sgshapiro** the daemon to exit. 319477349Sgshapiro** 319577349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 319677349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 319777349Sgshapiro** DOING. 319877349Sgshapiro*/ 319977349Sgshapiro 320077349Sgshapiro/* ARGSUSED */ 320177349Sgshapirostatic SIGFUNC_DECL 320290792Sgshapirosigterm(sig) 320377349Sgshapiro int sig; 320477349Sgshapiro{ 320577349Sgshapiro int save_errno = errno; 320677349Sgshapiro 320790792Sgshapiro FIX_SYSV_SIGNAL(sig, sigterm); 320877349Sgshapiro ShutdownRequest = "signal"; 320977349Sgshapiro errno = save_errno; 321077349Sgshapiro return SIGFUNC_RETURN; 321177349Sgshapiro} 321290792Sgshapiro/* 321390792Sgshapiro** SIGHUP -- handle a SIGHUP signal 321477349Sgshapiro** 321577349Sgshapiro** Parameters: 321690792Sgshapiro** sig -- incoming signal. 321777349Sgshapiro** 321877349Sgshapiro** Returns: 321977349Sgshapiro** none. 322077349Sgshapiro** 322177349Sgshapiro** Side Effects: 322290792Sgshapiro** Sets RestartRequest which should cause the daemon 322390792Sgshapiro** to restart. 322490792Sgshapiro** 322590792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 322690792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 322790792Sgshapiro** DOING. 322877349Sgshapiro*/ 322977349Sgshapiro 323090792Sgshapiro/* ARGSUSED */ 323190792Sgshapirostatic SIGFUNC_DECL 323290792Sgshapirosighup(sig) 323390792Sgshapiro int sig; 323477349Sgshapiro{ 323590792Sgshapiro int save_errno = errno; 323677349Sgshapiro 323790792Sgshapiro FIX_SYSV_SIGNAL(sig, sighup); 323890792Sgshapiro RestartRequest = "signal"; 323990792Sgshapiro errno = save_errno; 324090792Sgshapiro return SIGFUNC_RETURN; 324190792Sgshapiro} 324290792Sgshapiro/* 324390792Sgshapiro** SIGPIPE -- signal handler for SIGPIPE 324490792Sgshapiro** 324590792Sgshapiro** Parameters: 324690792Sgshapiro** sig -- incoming signal. 324790792Sgshapiro** 324890792Sgshapiro** Returns: 324990792Sgshapiro** none. 325090792Sgshapiro** 325190792Sgshapiro** Side Effects: 325290792Sgshapiro** Sets StopRequest which should cause the mailq/hoststatus 325390792Sgshapiro** display to stop. 325490792Sgshapiro** 325590792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 325690792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 325790792Sgshapiro** DOING. 325890792Sgshapiro*/ 325977349Sgshapiro 326090792Sgshapiro/* ARGSUSED */ 326190792Sgshapirostatic SIGFUNC_DECL 326290792Sgshapirosigpipe(sig) 326390792Sgshapiro int sig; 326490792Sgshapiro{ 326590792Sgshapiro int save_errno = errno; 326677349Sgshapiro 326790792Sgshapiro FIX_SYSV_SIGNAL(sig, sigpipe); 326890792Sgshapiro StopRequest = true; 326990792Sgshapiro errno = save_errno; 327090792Sgshapiro return SIGFUNC_RETURN; 327177349Sgshapiro} 327290792Sgshapiro/* 327338032Speter** INTSIG -- clean up on interrupt 327438032Speter** 327564562Sgshapiro** This just arranges to exit. It pessimizes in that it 327638032Speter** may resend a message. 327738032Speter** 327838032Speter** Parameters: 3279223067Sgshapiro** sig -- incoming signal. 328038032Speter** 328138032Speter** Returns: 328238032Speter** none. 328338032Speter** 328438032Speter** Side Effects: 328538032Speter** Unlocks the current job. 328677349Sgshapiro** 328777349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 328877349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 328977349Sgshapiro** DOING. 329038032Speter*/ 329138032Speter 329238032Speter/* ARGSUSED */ 329338032SpeterSIGFUNC_DECL 329438032Speterintsig(sig) 329538032Speter int sig; 329638032Speter{ 329790792Sgshapiro bool drop = false; 329877349Sgshapiro int save_errno = errno; 329964562Sgshapiro 330077349Sgshapiro FIX_SYSV_SIGNAL(sig, intsig); 330177349Sgshapiro errno = save_errno; 330277349Sgshapiro CHECK_CRITICAL(sig); 330390792Sgshapiro sm_allsignals(true); 3304223067Sgshapiro IntSig = true; 330590792Sgshapiro 330638032Speter FileName = NULL; 330764562Sgshapiro 330864562Sgshapiro /* Clean-up on aborted stdin message submission */ 3309223067Sgshapiro if (OpMode == MD_SMTP || 331064562Sgshapiro OpMode == MD_DELIVER || 3311223067Sgshapiro OpMode == MD_ARPAFTP) 331264562Sgshapiro { 3313223067Sgshapiro if (CurEnv->e_id != NULL) 3314223067Sgshapiro { 3315223067Sgshapiro char *fn; 331664562Sgshapiro 3317223067Sgshapiro fn = queuename(CurEnv, DATAFL_LETTER); 3318223067Sgshapiro if (fn != NULL) 3319223067Sgshapiro (void) unlink(fn); 3320223067Sgshapiro fn = queuename(CurEnv, ANYQFL_LETTER); 3321223067Sgshapiro if (fn != NULL) 3322223067Sgshapiro (void) unlink(fn); 3323223067Sgshapiro } 3324223067Sgshapiro _exit(EX_OK); 3325223067Sgshapiro /* NOTREACHED */ 3326223067Sgshapiro } 332764562Sgshapiro 3328223067Sgshapiro if (sig != 0 && LogLevel > 79) 3329223067Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 3330223067Sgshapiro if (OpMode != MD_TEST) 333164562Sgshapiro unlockqueue(CurEnv); 333238032Speter 333390792Sgshapiro finis(drop, false, EX_OK); 333490792Sgshapiro /* NOTREACHED */ 333538032Speter} 333690792Sgshapiro/* 333738032Speter** DISCONNECT -- remove our connection with any foreground process 333838032Speter** 333938032Speter** Parameters: 334038032Speter** droplev -- how "deeply" we should drop the line. 334138032Speter** 0 -- ignore signals, mail back errors, make sure 334238032Speter** output goes to stdout. 334364562Sgshapiro** 1 -- also, make stdout go to /dev/null. 334438032Speter** 2 -- also, disconnect from controlling terminal 334538032Speter** (only for daemon mode). 334638032Speter** e -- the current envelope. 334738032Speter** 334838032Speter** Returns: 334938032Speter** none 335038032Speter** 335138032Speter** Side Effects: 335238032Speter** Trys to insure that we are immune to vagaries of 335338032Speter** the controlling tty. 335438032Speter*/ 335538032Speter 335638032Spetervoid 335738032Speterdisconnect(droplev, e) 335838032Speter int droplev; 335938032Speter register ENVELOPE *e; 336038032Speter{ 336138032Speter int fd; 336238032Speter 336338032Speter if (tTd(52, 1)) 336490792Sgshapiro sm_dprintf("disconnect: In %d Out %d, e=%p\n", 336590792Sgshapiro sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 3366363466Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), 3367363466Sgshapiro (void *)e); 336838032Speter if (tTd(52, 100)) 336938032Speter { 337090792Sgshapiro sm_dprintf("don't\n"); 337138032Speter return; 337238032Speter } 337338032Speter if (LogLevel > 93) 337438032Speter sm_syslog(LOG_DEBUG, e->e_id, 337564562Sgshapiro "disconnect level %d", 337664562Sgshapiro droplev); 337738032Speter 337838032Speter /* be sure we don't get nasty signals */ 337990792Sgshapiro (void) sm_signal(SIGINT, SIG_IGN); 338090792Sgshapiro (void) sm_signal(SIGQUIT, SIG_IGN); 338138032Speter 338238032Speter /* we can't communicate with our caller, so.... */ 338390792Sgshapiro HoldErrs = true; 338438032Speter CurEnv->e_errormode = EM_MAIL; 338538032Speter Verbose = 0; 338690792Sgshapiro DisConnected = true; 338738032Speter 338838032Speter /* all input from /dev/null */ 338990792Sgshapiro if (InChannel != smioin) 339038032Speter { 339190792Sgshapiro (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 339290792Sgshapiro InChannel = smioin; 339338032Speter } 339490792Sgshapiro if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 339590792Sgshapiro SM_IO_RDONLY, NULL, smioin) == NULL) 339638032Speter sm_syslog(LOG_ERR, e->e_id, 339790792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 339890792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 339938032Speter 340090792Sgshapiro /* 340190792Sgshapiro ** output to the transcript 340290792Sgshapiro ** We also compare the fd numbers here since OutChannel 340390792Sgshapiro ** might be a layer on top of smioout due to encryption 340490792Sgshapiro ** (see sfsasl.c). 340590792Sgshapiro */ 340690792Sgshapiro 340790792Sgshapiro if (OutChannel != smioout && 340890792Sgshapiro sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 340990792Sgshapiro sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 341038032Speter { 341190792Sgshapiro (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 341290792Sgshapiro OutChannel = smioout; 341390792Sgshapiro 341490792Sgshapiro#if 0 341590792Sgshapiro /* 341690792Sgshapiro ** Has smioout been closed? Reopen it. 341790792Sgshapiro ** This shouldn't happen anymore, the code is here 341890792Sgshapiro ** just as a reminder. 341990792Sgshapiro */ 342090792Sgshapiro 342190792Sgshapiro if (smioout->sm_magic == NULL && 342290792Sgshapiro sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 342390792Sgshapiro SM_IO_WRONLY, NULL, smioout) == NULL) 342490792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 342590792Sgshapiro "disconnect: sm_io_reopen(\"%s\") failed: %s", 342690792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 342790792Sgshapiro#endif /* 0 */ 342838032Speter } 342938032Speter if (droplev > 0) 343038032Speter { 343190792Sgshapiro fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 343264562Sgshapiro if (fd == -1) 3433159609Sgshapiro { 343464562Sgshapiro sm_syslog(LOG_ERR, e->e_id, 343590792Sgshapiro "disconnect: open(\"%s\") failed: %s", 343690792Sgshapiro SM_PATH_DEVNULL, sm_errstring(errno)); 3437159609Sgshapiro } 343890792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 3439159609Sgshapiro if (fd >= 0) 3440159609Sgshapiro { 3441159609Sgshapiro (void) dup2(fd, STDOUT_FILENO); 3442159609Sgshapiro (void) dup2(fd, STDERR_FILENO); 3443159609Sgshapiro (void) close(fd); 3444159609Sgshapiro } 344538032Speter } 344638032Speter 344738032Speter /* drop our controlling TTY completely if possible */ 344838032Speter if (droplev > 1) 344938032Speter { 345038032Speter (void) setsid(); 345138032Speter errno = 0; 345238032Speter } 345338032Speter 345438032Speter#if XDEBUG 345538032Speter checkfd012("disconnect"); 3456363466Sgshapiro#endif 345738032Speter 345838032Speter if (LogLevel > 71) 345990792Sgshapiro sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 346090792Sgshapiro (int) CurrentPid); 346138032Speter 346238032Speter errno = 0; 346338032Speter} 346438032Speter 346538032Speterstatic void 346638032Speterobsolete(argv) 346738032Speter char *argv[]; 346838032Speter{ 346938032Speter register char *ap; 347038032Speter register char *op; 347138032Speter 347238032Speter while ((ap = *++argv) != NULL) 347338032Speter { 347438032Speter /* Return if "--" or not an option of any form. */ 347538032Speter if (ap[0] != '-' || ap[1] == '-') 347638032Speter return; 347738032Speter 347890792Sgshapiro /* Don't allow users to use "-Q." or "-Q ." */ 347990792Sgshapiro if ((ap[1] == 'Q' && ap[2] == '.') || 348090792Sgshapiro (ap[1] == 'Q' && argv[1] != NULL && 348190792Sgshapiro argv[1][0] == '.' && argv[1][1] == '\0')) 348290792Sgshapiro { 348390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 348490792Sgshapiro "Can not use -Q.\n"); 348590792Sgshapiro exit(EX_USAGE); 348690792Sgshapiro } 348790792Sgshapiro 348838032Speter /* skip over options that do have a value */ 348938032Speter op = strchr(OPTIONS, ap[1]); 349038032Speter if (op != NULL && *++op == ':' && ap[2] == '\0' && 349138032Speter ap[1] != 'd' && 349238032Speter#if defined(sony_news) 349338032Speter ap[1] != 'E' && ap[1] != 'J' && 3494363466Sgshapiro#endif 349538032Speter argv[1] != NULL && argv[1][0] != '-') 349638032Speter { 349738032Speter argv++; 349838032Speter continue; 349938032Speter } 350038032Speter 350138032Speter /* If -C doesn't have an argument, use sendmail.cf. */ 350290792Sgshapiro#define __DEFPATH "sendmail.cf" 350338032Speter if (ap[1] == 'C' && ap[2] == '\0') 350438032Speter { 350538032Speter *argv = xalloc(sizeof(__DEFPATH) + 2); 350690792Sgshapiro (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 350790792Sgshapiro "-C", __DEFPATH); 350838032Speter } 350938032Speter 351038032Speter /* If -q doesn't have an argument, run it once. */ 351138032Speter if (ap[1] == 'q' && ap[2] == '\0') 351238032Speter *argv = "-q0"; 351338032Speter 351490792Sgshapiro /* If -Q doesn't have an argument, disable quarantining */ 351590792Sgshapiro if (ap[1] == 'Q' && ap[2] == '\0') 351690792Sgshapiro *argv = "-Q."; 351790792Sgshapiro 351838032Speter /* if -d doesn't have an argument, use 0-99.1 */ 351938032Speter if (ap[1] == 'd' && ap[2] == '\0') 352038032Speter *argv = "-d0-99.1"; 352138032Speter 352264562Sgshapiro#if defined(sony_news) 352338032Speter /* if -E doesn't have an argument, use -EC */ 352438032Speter if (ap[1] == 'E' && ap[2] == '\0') 352538032Speter *argv = "-EC"; 352638032Speter 352738032Speter /* if -J doesn't have an argument, use -JJ */ 352838032Speter if (ap[1] == 'J' && ap[2] == '\0') 352938032Speter *argv = "-JJ"; 353064562Sgshapiro#endif /* defined(sony_news) */ 353138032Speter } 353238032Speter} 353390792Sgshapiro/* 353438032Speter** AUTH_WARNING -- specify authorization warning 353538032Speter** 353638032Speter** Parameters: 353738032Speter** e -- the current envelope. 353838032Speter** msg -- the text of the message. 353938032Speter** args -- arguments to the message. 354038032Speter** 354138032Speter** Returns: 354238032Speter** none. 354338032Speter*/ 354438032Speter 354538032Spetervoid 354638032Speter#ifdef __STDC__ 354738032Speterauth_warning(register ENVELOPE *e, const char *msg, ...) 354864562Sgshapiro#else /* __STDC__ */ 354938032Speterauth_warning(e, msg, va_alist) 355038032Speter register ENVELOPE *e; 355138032Speter const char *msg; 355238032Speter va_dcl 355364562Sgshapiro#endif /* __STDC__ */ 355438032Speter{ 355538032Speter char buf[MAXLINE]; 355690792Sgshapiro SM_VA_LOCAL_DECL 355738032Speter 355838032Speter if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 355938032Speter { 356038032Speter register char *p; 356138032Speter static char hostbuf[48]; 356238032Speter 356338032Speter if (hostbuf[0] == '\0') 356471345Sgshapiro { 356571345Sgshapiro struct hostent *hp; 356638032Speter 3567168515Sgshapiro hp = myhostname(hostbuf, sizeof(hostbuf)); 356890792Sgshapiro#if NETINET6 356971345Sgshapiro if (hp != NULL) 357071345Sgshapiro { 357171345Sgshapiro freehostent(hp); 357271345Sgshapiro hp = NULL; 357371345Sgshapiro } 357490792Sgshapiro#endif /* NETINET6 */ 357571345Sgshapiro } 357671345Sgshapiro 3577168515Sgshapiro (void) sm_strlcpyn(buf, sizeof(buf), 2, hostbuf, ": "); 357838032Speter p = &buf[strlen(buf)]; 357990792Sgshapiro SM_VA_START(ap, msg); 358090792Sgshapiro (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 358190792Sgshapiro SM_VA_END(ap); 3582168515Sgshapiro addheader("X-Authentication-Warning", buf, 0, e, true); 358338032Speter if (LogLevel > 3) 358438032Speter sm_syslog(LOG_INFO, e->e_id, 358564562Sgshapiro "Authentication-Warning: %.400s", 358664562Sgshapiro buf); 358738032Speter } 358838032Speter} 358990792Sgshapiro/* 359038032Speter** GETEXTENV -- get from external environment 359138032Speter** 359238032Speter** Parameters: 359338032Speter** envar -- the name of the variable to retrieve 359438032Speter** 359538032Speter** Returns: 359638032Speter** The value, if any. 359738032Speter*/ 359838032Speter 359990792Sgshapirostatic char * 360038032Spetergetextenv(envar) 360138032Speter const char *envar; 360238032Speter{ 360338032Speter char **envp; 360438032Speter int l; 360538032Speter 360638032Speter l = strlen(envar); 3607102528Sgshapiro for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++) 360838032Speter { 360938032Speter if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 361038032Speter return &(*envp)[l + 1]; 361138032Speter } 361238032Speter return NULL; 361338032Speter} 361490792Sgshapiro/* 3615157001Sgshapiro** SM_SETUSERENV -- set an environment variable in the propagated environment 361638032Speter** 361738032Speter** Parameters: 361838032Speter** envar -- the name of the environment variable. 361938032Speter** value -- the value to which it should be set. If 362038032Speter** null, this is extracted from the incoming 362138032Speter** environment. If that is not set, the call 3622157001Sgshapiro** to sm_setuserenv is ignored. 362338032Speter** 362438032Speter** Returns: 362538032Speter** none. 362638032Speter*/ 362738032Speter 362838032Spetervoid 3629157001Sgshapirosm_setuserenv(envar, value) 363038032Speter const char *envar; 363138032Speter const char *value; 363238032Speter{ 363364562Sgshapiro int i, l; 363438032Speter char **evp = UserEnviron; 363538032Speter char *p; 363638032Speter 363738032Speter if (value == NULL) 363838032Speter { 363938032Speter value = getextenv(envar); 364038032Speter if (value == NULL) 364138032Speter return; 364238032Speter } 364338032Speter 364490792Sgshapiro /* XXX enforce reasonable size? */ 364564562Sgshapiro i = strlen(envar) + 1; 364664562Sgshapiro l = strlen(value) + i + 1; 364764562Sgshapiro p = (char *) xalloc(l); 364890792Sgshapiro (void) sm_strlcpyn(p, l, 3, envar, "=", value); 364938032Speter 365038032Speter while (*evp != NULL && strncmp(*evp, p, i) != 0) 365138032Speter evp++; 365238032Speter if (*evp != NULL) 365338032Speter { 365438032Speter *evp++ = p; 365538032Speter } 365638032Speter else if (evp < &UserEnviron[MAXUSERENVIRON]) 365738032Speter { 365838032Speter *evp++ = p; 365938032Speter *evp = NULL; 366038032Speter } 366138032Speter 366238032Speter /* make sure it is in our environment as well */ 366338032Speter if (putenv(p) < 0) 3664157001Sgshapiro syserr("sm_setuserenv: putenv(%s) failed", p); 366538032Speter} 366690792Sgshapiro/* 366738032Speter** DUMPSTATE -- dump state 366838032Speter** 366938032Speter** For debugging. 367038032Speter*/ 367138032Speter 367238032Spetervoid 367338032Speterdumpstate(when) 367438032Speter char *when; 367538032Speter{ 367638032Speter register char *j = macvalue('j', CurEnv); 367738032Speter int rs; 367864562Sgshapiro extern int NextMacroId; 367938032Speter 368038032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 368164562Sgshapiro "--- dumping state on %s: $j = %s ---", 368264562Sgshapiro when, 368364562Sgshapiro j == NULL ? "<NULL>" : j); 368438032Speter if (j != NULL) 368538032Speter { 368638032Speter if (!wordinclass(j, 'w')) 368738032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 368864562Sgshapiro "*** $j not in $=w ***"); 368938032Speter } 369038032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 369190792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 369264562Sgshapiro NextMacroId, MAXMACROID); 369338032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 369490792Sgshapiro printopenfds(true); 369538032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 3696132943Sgshapiro mci_dump_all(smioout, true); 369738032Speter rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 369838032Speter if (rs > 0) 369938032Speter { 370064562Sgshapiro int status; 370138032Speter register char **pvp; 370238032Speter char *pv[MAXATOM + 1]; 370338032Speter 370438032Speter pv[0] = NULL; 370590792Sgshapiro status = REWRITE(pv, rs, CurEnv); 370638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 370764562Sgshapiro "--- ruleset debug_dumpstate returns stat %d, pv: ---", 370864562Sgshapiro status); 370938032Speter for (pvp = pv; *pvp != NULL; pvp++) 371038032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 371138032Speter } 371238032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 371338032Speter} 371490792Sgshapiro 371580785Sgshapiro#ifdef SIGUSR1 371690792Sgshapiro/* 371777349Sgshapiro** SIGUSR1 -- Signal a request to dump state. 371877349Sgshapiro** 371977349Sgshapiro** Parameters: 372077349Sgshapiro** sig -- calling signal. 372177349Sgshapiro** 372277349Sgshapiro** Returns: 372377349Sgshapiro** none. 372477349Sgshapiro** 372577349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 372677349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 372777349Sgshapiro** DOING. 372877349Sgshapiro** 372977349Sgshapiro** XXX: More work is needed for this signal handler. 373077349Sgshapiro*/ 373138032Speter 373238032Speter/* ARGSUSED */ 373377349Sgshapirostatic SIGFUNC_DECL 373438032Spetersigusr1(sig) 373538032Speter int sig; 373638032Speter{ 373777349Sgshapiro int save_errno = errno; 373877349Sgshapiro 373977349Sgshapiro FIX_SYSV_SIGNAL(sig, sigusr1); 374077349Sgshapiro errno = save_errno; 374177349Sgshapiro CHECK_CRITICAL(sig); 374238032Speter dumpstate("user signal"); 374390792Sgshapiro# if SM_HEAP_CHECK 374490792Sgshapiro dumpstab(); 3745363466Sgshapiro# endif 374677349Sgshapiro errno = save_errno; 374738032Speter return SIGFUNC_RETURN; 374838032Speter} 374990792Sgshapiro#endif /* SIGUSR1 */ 375090792Sgshapiro 375190792Sgshapiro/* 375238032Speter** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 375338032Speter** 375438032Speter** Parameters: 375538032Speter** to_real_uid -- if set, drop to the real uid instead 375638032Speter** of the RunAsUser. 375738032Speter** 375838032Speter** Returns: 375938032Speter** EX_OSERR if the setuid failed. 376038032Speter** EX_OK otherwise. 376138032Speter*/ 376238032Speter 376338032Speterint 376438032Speterdrop_privileges(to_real_uid) 376538032Speter bool to_real_uid; 376638032Speter{ 376738032Speter int rval = EX_OK; 376838032Speter GIDSET_T emptygidset[1]; 376938032Speter 377038032Speter if (tTd(47, 1)) 3771285229Sgshapiro sm_dprintf("drop_privileges(%d): Real[UG]id=%ld:%ld, get[ug]id=%ld:%ld, gete[ug]id=%ld:%ld, RunAs[UG]id=%ld:%ld\n", 377290792Sgshapiro (int) to_real_uid, 3773285229Sgshapiro (long) RealUid, (long) RealGid, 3774285229Sgshapiro (long) getuid(), (long) getgid(), 3775285229Sgshapiro (long) geteuid(), (long) getegid(), 3776285229Sgshapiro (long) RunAsUid, (long) RunAsGid); 377738032Speter 377838032Speter if (to_real_uid) 377938032Speter { 378038032Speter RunAsUserName = RealUserName; 378138032Speter RunAsUid = RealUid; 378238032Speter RunAsGid = RealGid; 378394334Sgshapiro EffGid = RunAsGid; 378438032Speter } 378538032Speter 378638032Speter /* make sure no one can grab open descriptors for secret files */ 378738032Speter endpwent(); 378890792Sgshapiro sm_mbdb_terminate(); 378938032Speter 379038032Speter /* reset group permissions; these can be set later */ 379138032Speter emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 379290792Sgshapiro 379390792Sgshapiro /* 379490792Sgshapiro ** Notice: on some OS (Linux...) the setgroups() call causes 379590792Sgshapiro ** a logfile entry if sendmail is not run by root. 379690792Sgshapiro ** However, it is unclear (no POSIX standard) whether 379790792Sgshapiro ** setgroups() can only succeed if executed by root. 379890792Sgshapiro ** So for now we keep it as it is; if you want to change it, use 379990792Sgshapiro ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 380090792Sgshapiro */ 380190792Sgshapiro 380238032Speter if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 380364562Sgshapiro { 380464562Sgshapiro syserr("drop_privileges: setgroups(1, %d) failed", 380590792Sgshapiro (int) emptygidset[0]); 380638032Speter rval = EX_OSERR; 380764562Sgshapiro } 380838032Speter 380990792Sgshapiro /* reset primary group id */ 381090792Sgshapiro if (to_real_uid) 381164562Sgshapiro { 381290792Sgshapiro /* 381390792Sgshapiro ** Drop gid to real gid. 381490792Sgshapiro ** On some OS we must reset the effective[/real[/saved]] gid, 381590792Sgshapiro ** and then use setgid() to finally drop all group privileges. 381690792Sgshapiro ** Later on we check whether we can get back the 381790792Sgshapiro ** effective gid. 381890792Sgshapiro */ 381990792Sgshapiro 382090792Sgshapiro#if HASSETEGID 382190792Sgshapiro if (setegid(RunAsGid) < 0) 382290792Sgshapiro { 382390792Sgshapiro syserr("drop_privileges: setegid(%d) failed", 382490792Sgshapiro (int) RunAsGid); 382590792Sgshapiro rval = EX_OSERR; 382690792Sgshapiro } 382790792Sgshapiro#else /* HASSETEGID */ 382890792Sgshapiro# if HASSETREGID 382990792Sgshapiro if (setregid(RunAsGid, RunAsGid) < 0) 383090792Sgshapiro { 383190792Sgshapiro syserr("drop_privileges: setregid(%d, %d) failed", 383290792Sgshapiro (int) RunAsGid, (int) RunAsGid); 383390792Sgshapiro rval = EX_OSERR; 383490792Sgshapiro } 383590792Sgshapiro# else /* HASSETREGID */ 383690792Sgshapiro# if HASSETRESGID 383790792Sgshapiro if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 383890792Sgshapiro { 383990792Sgshapiro syserr("drop_privileges: setresgid(%d, %d, %d) failed", 384090792Sgshapiro (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 384190792Sgshapiro rval = EX_OSERR; 384290792Sgshapiro } 384390792Sgshapiro# endif /* HASSETRESGID */ 384490792Sgshapiro# endif /* HASSETREGID */ 384590792Sgshapiro#endif /* HASSETEGID */ 384664562Sgshapiro } 384790792Sgshapiro if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 384890792Sgshapiro { 384990792Sgshapiro if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 385090792Sgshapiro { 3851285229Sgshapiro syserr("drop_privileges: setgid(%ld) failed", 3852285229Sgshapiro (long) RunAsGid); 385390792Sgshapiro rval = EX_OSERR; 385490792Sgshapiro } 385590792Sgshapiro errno = 0; 385690792Sgshapiro if (rval == EX_OK && getegid() != RunAsGid) 385790792Sgshapiro { 3858285229Sgshapiro syserr("drop_privileges: Unable to set effective gid=%ld to RunAsGid=%ld", 3859285229Sgshapiro (long) getegid(), (long) RunAsGid); 386090792Sgshapiro rval = EX_OSERR; 386190792Sgshapiro } 386290792Sgshapiro } 386390792Sgshapiro 386490792Sgshapiro /* fiddle with uid */ 386564562Sgshapiro if (to_real_uid || RunAsUid != 0) 386664562Sgshapiro { 386794334Sgshapiro uid_t euid; 386864562Sgshapiro 386990792Sgshapiro /* 387090792Sgshapiro ** Try to setuid(RunAsUid). 387190792Sgshapiro ** euid must be RunAsUid, 387294334Sgshapiro ** ruid must be RunAsUid unless (e|r)uid wasn't 0 387394334Sgshapiro ** and we didn't have to drop privileges to the real uid. 387490792Sgshapiro */ 387590792Sgshapiro 387690792Sgshapiro if (setuid(RunAsUid) < 0 || 387794334Sgshapiro geteuid() != RunAsUid || 387894334Sgshapiro (getuid() != RunAsUid && 387994334Sgshapiro (to_real_uid || geteuid() == 0 || getuid() == 0))) 388064562Sgshapiro { 388190792Sgshapiro#if HASSETREUID 388290792Sgshapiro /* 388390792Sgshapiro ** if ruid != RunAsUid, euid == RunAsUid, then 388490792Sgshapiro ** try resetting just the real uid, then using 388590792Sgshapiro ** setuid() to drop the saved-uid as well. 388690792Sgshapiro */ 388790792Sgshapiro 388894334Sgshapiro if (geteuid() == RunAsUid) 388990792Sgshapiro { 389090792Sgshapiro if (setreuid(RunAsUid, -1) < 0) 389190792Sgshapiro { 389290792Sgshapiro syserr("drop_privileges: setreuid(%d, -1) failed", 389390792Sgshapiro (int) RunAsUid); 389490792Sgshapiro rval = EX_OSERR; 389590792Sgshapiro } 389690792Sgshapiro if (setuid(RunAsUid) < 0) 389790792Sgshapiro { 389890792Sgshapiro syserr("drop_privileges: second setuid(%d) attempt failed", 389990792Sgshapiro (int) RunAsUid); 390090792Sgshapiro rval = EX_OSERR; 390190792Sgshapiro } 390290792Sgshapiro } 390390792Sgshapiro else 390490792Sgshapiro#endif /* HASSETREUID */ 390590792Sgshapiro { 390690792Sgshapiro syserr("drop_privileges: setuid(%d) failed", 390790792Sgshapiro (int) RunAsUid); 390890792Sgshapiro rval = EX_OSERR; 390990792Sgshapiro } 391064562Sgshapiro } 391194334Sgshapiro euid = geteuid(); 391290792Sgshapiro if (RunAsUid != 0 && setuid(0) == 0) 391364562Sgshapiro { 391464562Sgshapiro /* 391564562Sgshapiro ** Believe it or not, the Linux capability model 391664562Sgshapiro ** allows a non-root process to override setuid() 391764562Sgshapiro ** on a process running as root and prevent that 391864562Sgshapiro ** process from dropping privileges. 391964562Sgshapiro */ 392064562Sgshapiro 392164562Sgshapiro syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 392264562Sgshapiro rval = EX_OSERR; 392364562Sgshapiro } 392464562Sgshapiro else if (RunAsUid != euid && setuid(euid) == 0) 392564562Sgshapiro { 392664562Sgshapiro /* 392764562Sgshapiro ** Some operating systems will keep the saved-uid 392864562Sgshapiro ** if a non-root effective-uid calls setuid(real-uid) 392964562Sgshapiro ** making it possible to set it back again later. 393064562Sgshapiro */ 393164562Sgshapiro 393290792Sgshapiro syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 393364562Sgshapiro rval = EX_OSERR; 393464562Sgshapiro } 393564562Sgshapiro } 393690792Sgshapiro 393790792Sgshapiro if ((to_real_uid || RunAsGid != 0) && 393890792Sgshapiro rval == EX_OK && RunAsGid != EffGid && 393990792Sgshapiro getuid() != 0 && geteuid() != 0) 394090792Sgshapiro { 394190792Sgshapiro errno = 0; 394290792Sgshapiro if (setgid(EffGid) == 0) 394390792Sgshapiro { 394490792Sgshapiro syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 394590792Sgshapiro (int) EffGid); 394690792Sgshapiro rval = EX_OSERR; 394790792Sgshapiro } 394890792Sgshapiro } 394990792Sgshapiro 395038032Speter if (tTd(47, 5)) 395138032Speter { 395290792Sgshapiro sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 395390792Sgshapiro (int) geteuid(), (int) getuid(), 395490792Sgshapiro (int) getegid(), (int) getgid()); 395590792Sgshapiro sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 395690792Sgshapiro (int) RunAsUid, (int) RunAsGid); 395764562Sgshapiro if (tTd(47, 10)) 395890792Sgshapiro sm_dprintf("drop_privileges: rval = %d\n", rval); 395938032Speter } 396038032Speter return rval; 396138032Speter} 396290792Sgshapiro/* 396338032Speter** FILL_FD -- make sure a file descriptor has been properly allocated 396438032Speter** 396538032Speter** Used to make sure that stdin/out/err are allocated on startup 396638032Speter** 396738032Speter** Parameters: 396838032Speter** fd -- the file descriptor to be filled. 396938032Speter** where -- a string used for logging. If NULL, this is 397038032Speter** being called on startup, and logging should 397138032Speter** not be done. 397238032Speter** 397338032Speter** Returns: 397438032Speter** none 397590792Sgshapiro** 397690792Sgshapiro** Side Effects: 397790792Sgshapiro** possibly changes MissingFds 397838032Speter*/ 397938032Speter 398038032Spetervoid 398138032Speterfill_fd(fd, where) 398238032Speter int fd; 398338032Speter char *where; 398438032Speter{ 398538032Speter int i; 398638032Speter struct stat stbuf; 398738032Speter 398838032Speter if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 398938032Speter return; 399038032Speter 399138032Speter if (where != NULL) 399238032Speter syserr("fill_fd: %s: fd %d not open", where, fd); 399338032Speter else 399438032Speter MissingFds |= 1 << fd; 399590792Sgshapiro i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 399638032Speter if (i < 0) 399738032Speter { 399890792Sgshapiro syserr("!fill_fd: %s: cannot open %s", 399990792Sgshapiro where == NULL ? "startup" : where, SM_PATH_DEVNULL); 400038032Speter } 400138032Speter if (fd != i) 400238032Speter { 400338032Speter (void) dup2(i, fd); 400438032Speter (void) close(i); 400538032Speter } 400638032Speter} 400790792Sgshapiro/* 400890792Sgshapiro** SM_PRINTOPTIONS -- print options 400990792Sgshapiro** 401090792Sgshapiro** Parameters: 401190792Sgshapiro** options -- array of options. 401290792Sgshapiro** 401390792Sgshapiro** Returns: 401490792Sgshapiro** none. 401590792Sgshapiro*/ 401690792Sgshapiro 401790792Sgshapirostatic void 401890792Sgshapirosm_printoptions(options) 401990792Sgshapiro char **options; 402090792Sgshapiro{ 402190792Sgshapiro int ll; 402290792Sgshapiro char **av; 402390792Sgshapiro 402490792Sgshapiro av = options; 402590792Sgshapiro ll = 7; 402690792Sgshapiro while (*av != NULL) 402790792Sgshapiro { 402890792Sgshapiro if (ll + strlen(*av) > 63) 402990792Sgshapiro { 403090792Sgshapiro sm_dprintf("\n"); 403190792Sgshapiro ll = 0; 403290792Sgshapiro } 403390792Sgshapiro if (ll == 0) 403490792Sgshapiro sm_dprintf("\t\t"); 403590792Sgshapiro else 403690792Sgshapiro sm_dprintf(" "); 403790792Sgshapiro sm_dprintf("%s", *av); 403890792Sgshapiro ll += strlen(*av++) + 1; 403990792Sgshapiro } 404090792Sgshapiro sm_dprintf("\n"); 404190792Sgshapiro} 4042168515Sgshapiro 404390792Sgshapiro/* 4044168515Sgshapiro** TO8BIT -- convert \octal sequences in a test mode input line 4045168515Sgshapiro** 4046168515Sgshapiro** Parameters: 4047168515Sgshapiro** str -- the input line. 4048168515Sgshapiro** 4049168515Sgshapiro** Returns: 4050168515Sgshapiro** none. 4051168515Sgshapiro** 4052168515Sgshapiro** Side Effects: 4053168515Sgshapiro** replaces \0octal in str with octal value. 4054168515Sgshapiro*/ 4055168515Sgshapiro 4056168515Sgshapirostatic bool to8bit __P((char *)); 4057168515Sgshapiro 4058168515Sgshapirostatic bool 4059168515Sgshapiroto8bit(str) 4060168515Sgshapiro char *str; 4061168515Sgshapiro{ 4062168515Sgshapiro int c, len; 4063168515Sgshapiro char *out, *in; 4064168515Sgshapiro bool changed; 4065168515Sgshapiro 4066168515Sgshapiro if (str == NULL) 4067168515Sgshapiro return false; 4068168515Sgshapiro in = out = str; 4069168515Sgshapiro changed = false; 4070168515Sgshapiro len = 0; 4071168515Sgshapiro while ((c = (*str++ & 0377)) != '\0') 4072168515Sgshapiro { 4073168515Sgshapiro int oct, nxtc; 4074168515Sgshapiro 4075168515Sgshapiro ++len; 4076168515Sgshapiro if (c == '\\' && 4077168515Sgshapiro (nxtc = (*str & 0377)) == '0') 4078168515Sgshapiro { 4079168515Sgshapiro oct = 0; 4080168515Sgshapiro while ((nxtc = (*str & 0377)) != '\0' && 4081168515Sgshapiro isascii(nxtc) && isdigit(nxtc)) 4082168515Sgshapiro { 4083168515Sgshapiro oct <<= 3; 4084168515Sgshapiro oct += nxtc - '0'; 4085168515Sgshapiro ++str; 4086168515Sgshapiro ++len; 4087168515Sgshapiro } 4088168515Sgshapiro changed = true; 4089168515Sgshapiro c = oct; 4090168515Sgshapiro } 4091168515Sgshapiro *out++ = c; 4092168515Sgshapiro } 4093168515Sgshapiro *out++ = c; 4094168515Sgshapiro if (changed) 4095168515Sgshapiro { 4096168515Sgshapiro char *q; 4097168515Sgshapiro 4098168515Sgshapiro q = quote_internal_chars(in, in, &len); 4099168515Sgshapiro if (q != in) 4100168515Sgshapiro sm_strlcpy(in, q, len); 4101168515Sgshapiro } 4102168515Sgshapiro return changed; 4103168515Sgshapiro} 4104168515Sgshapiro 4105168515Sgshapiro/* 410638032Speter** TESTMODELINE -- process a test mode input line 410738032Speter** 410838032Speter** Parameters: 410938032Speter** line -- the input line. 411038032Speter** e -- the current environment. 411138032Speter** Syntax: 411238032Speter** # a comment 411338032Speter** .X process X as a configuration line 411438032Speter** =X dump a configuration item (such as mailers) 411538032Speter** $X dump a macro or class 411638032Speter** /X try an activity 411738032Speter** X normal process through rule set X 411838032Speter*/ 411938032Speter 412064562Sgshapirostatic void 412138032Spetertestmodeline(line, e) 412238032Speter char *line; 412338032Speter ENVELOPE *e; 412438032Speter{ 412538032Speter register char *p; 412638032Speter char *q; 412738032Speter auto char *delimptr; 412838032Speter int mid; 412938032Speter int i, rs; 413038032Speter STAB *map; 413138032Speter char **s; 413238032Speter struct rewrite *rw; 413338032Speter ADDRESS a; 4134168515Sgshapiro char *lbp; 4135168515Sgshapiro auto int lbs; 413638032Speter static int tryflags = RF_COPYNONE; 413738032Speter char exbuf[MAXLINE]; 4138168515Sgshapiro char lbuf[MAXLINE]; 413990792Sgshapiro extern unsigned char TokTypeNoC[]; 4140168515Sgshapiro bool eightbit; 414138032Speter 414266494Sgshapiro /* skip leading spaces */ 414366494Sgshapiro while (*line == ' ') 414466494Sgshapiro line++; 414566494Sgshapiro 4146168515Sgshapiro lbp = NULL; 4147168515Sgshapiro eightbit = false; 414838032Speter switch (line[0]) 414938032Speter { 415038032Speter case '#': 415164562Sgshapiro case '\0': 415238032Speter return; 415338032Speter 415438032Speter case '?': 415564562Sgshapiro help("-bt", e); 415638032Speter return; 415738032Speter 415838032Speter case '.': /* config-style settings */ 415938032Speter switch (line[1]) 416038032Speter { 416138032Speter case 'D': 416290792Sgshapiro mid = macid_parse(&line[2], &delimptr); 416371345Sgshapiro if (mid == 0) 416438032Speter return; 4165168515Sgshapiro lbs = sizeof(lbuf); 4166168515Sgshapiro lbp = translate_dollars(delimptr, lbuf, &lbs); 4167168515Sgshapiro macdefine(&e->e_macro, A_TEMP, mid, lbp); 4168168515Sgshapiro if (lbp != lbuf) 4169168515Sgshapiro SM_FREE(lbp); 417038032Speter break; 417138032Speter 417238032Speter case 'C': 417338032Speter if (line[2] == '\0') /* not to call syserr() */ 417438032Speter return; 417538032Speter 417690792Sgshapiro mid = macid_parse(&line[2], &delimptr); 417771345Sgshapiro if (mid == 0) 417838032Speter return; 4179168515Sgshapiro lbs = sizeof(lbuf); 4180168515Sgshapiro lbp = translate_dollars(delimptr, lbuf, &lbs); 4181168515Sgshapiro expand(lbp, exbuf, sizeof(exbuf), e); 4182168515Sgshapiro if (lbp != lbuf) 4183168515Sgshapiro SM_FREE(lbp); 418438032Speter p = exbuf; 418538032Speter while (*p != '\0') 418638032Speter { 418738032Speter register char *wd; 418838032Speter char delim; 418938032Speter 4190363466Sgshapiro while (*p != '\0' && SM_ISSPACE(*p)) 419138032Speter p++; 419238032Speter wd = p; 4193363466Sgshapiro while (*p != '\0' && !(SM_ISSPACE(*p))) 419438032Speter p++; 419538032Speter delim = *p; 419638032Speter *p = '\0'; 419738032Speter if (wd[0] != '\0') 419838032Speter setclass(mid, wd); 419938032Speter *p = delim; 420038032Speter } 420138032Speter break; 420238032Speter 420338032Speter case '\0': 420490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 420590792Sgshapiro "Usage: .[DC]macro value(s)\n"); 420638032Speter break; 420738032Speter 420838032Speter default: 420990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 421090792Sgshapiro "Unknown \".\" command %s\n", line); 421138032Speter break; 421238032Speter } 421338032Speter return; 421438032Speter 421538032Speter case '=': /* config-style settings */ 421638032Speter switch (line[1]) 421738032Speter { 421838032Speter case 'S': /* dump rule set */ 421938032Speter rs = strtorwset(&line[2], NULL, ST_FIND); 422038032Speter if (rs < 0) 422138032Speter { 422290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 422390792Sgshapiro "Undefined ruleset %s\n", &line[2]); 422438032Speter return; 422538032Speter } 422638032Speter rw = RewriteRules[rs]; 422738032Speter if (rw == NULL) 422838032Speter return; 422938032Speter do 423038032Speter { 423190792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 423290792Sgshapiro 'R'); 423338032Speter s = rw->r_lhs; 423438032Speter while (*s != NULL) 423538032Speter { 4236132943Sgshapiro xputs(smioout, *s++); 423790792Sgshapiro (void) sm_io_putc(smioout, 423890792Sgshapiro SM_TIME_DEFAULT, ' '); 423938032Speter } 424090792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 424190792Sgshapiro '\t'); 424290792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 424390792Sgshapiro '\t'); 424438032Speter s = rw->r_rhs; 424538032Speter while (*s != NULL) 424638032Speter { 4247132943Sgshapiro xputs(smioout, *s++); 424890792Sgshapiro (void) sm_io_putc(smioout, 424990792Sgshapiro SM_TIME_DEFAULT, ' '); 425038032Speter } 425190792Sgshapiro (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 425290792Sgshapiro '\n'); 425338032Speter } while ((rw = rw->r_next) != NULL); 425438032Speter break; 425538032Speter 425638032Speter case 'M': 425738032Speter for (i = 0; i < MAXMAILERS; i++) 425838032Speter { 425938032Speter if (Mailer[i] != NULL) 4260132943Sgshapiro printmailer(smioout, Mailer[i]); 426138032Speter } 426238032Speter break; 426338032Speter 426438032Speter case '\0': 426590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 426690792Sgshapiro "Usage: =Sruleset or =M\n"); 426738032Speter break; 426838032Speter 426938032Speter default: 427090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 427190792Sgshapiro "Unknown \"=\" command %s\n", line); 427238032Speter break; 427338032Speter } 427438032Speter return; 427538032Speter 427638032Speter case '-': /* set command-line-like opts */ 427738032Speter switch (line[1]) 427838032Speter { 427938032Speter case 'd': 428038032Speter tTflag(&line[2]); 428138032Speter break; 428238032Speter 428338032Speter case '\0': 428490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 428590792Sgshapiro "Usage: -d{debug arguments}\n"); 428638032Speter break; 428738032Speter 428838032Speter default: 428990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 429090792Sgshapiro "Unknown \"-\" command %s\n", line); 429138032Speter break; 429238032Speter } 429338032Speter return; 429438032Speter 429538032Speter case '$': 429638032Speter if (line[1] == '=') 429738032Speter { 429890792Sgshapiro mid = macid(&line[2]); 429971345Sgshapiro if (mid != 0) 430038032Speter stabapply(dump_class, mid); 430138032Speter return; 430238032Speter } 430390792Sgshapiro mid = macid(&line[1]); 430471345Sgshapiro if (mid == 0) 430538032Speter return; 430638032Speter p = macvalue(mid, e); 430738032Speter if (p == NULL) 430890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 430990792Sgshapiro "Undefined\n"); 431038032Speter else 431138032Speter { 4312132943Sgshapiro xputs(smioout, p); 431390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 431490792Sgshapiro "\n"); 431538032Speter } 431638032Speter return; 431738032Speter 431838032Speter case '/': /* miscellaneous commands */ 431938032Speter p = &line[strlen(line)]; 4320363466Sgshapiro while (--p >= line && SM_ISSPACE(*p)) 432138032Speter *p = '\0'; 432238032Speter p = strpbrk(line, " \t"); 432338032Speter if (p != NULL) 432438032Speter { 4325363466Sgshapiro while (SM_ISSPACE(*p)) 432638032Speter *p++ = '\0'; 432738032Speter } 432838032Speter else 432938032Speter p = ""; 433038032Speter if (line[1] == '\0') 433138032Speter { 433290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 433390792Sgshapiro "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 433438032Speter return; 433538032Speter } 433690792Sgshapiro if (sm_strcasecmp(&line[1], "quit") == 0) 433764562Sgshapiro { 433864562Sgshapiro CurEnv->e_id = NULL; 433990792Sgshapiro finis(true, true, ExitStat); 434090792Sgshapiro /* NOTREACHED */ 434164562Sgshapiro } 434290792Sgshapiro if (sm_strcasecmp(&line[1], "mx") == 0) 434338032Speter { 434438032Speter#if NAMED_BIND 434538032Speter /* look up MX records */ 434638032Speter int nmx; 434738032Speter auto int rcode; 434838032Speter char *mxhosts[MAXMXHOSTS + 1]; 434938032Speter 435038032Speter if (*p == '\0') 435138032Speter { 435290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 435390792Sgshapiro "Usage: /mx address\n"); 435438032Speter return; 435538032Speter } 4356363466Sgshapiro nmx = getmxrr(p, mxhosts, NULL, TRYFALLBACK, &rcode, 4357363466Sgshapiro NULL, -1); 4358363466Sgshapiro if (nmx == NULLMX) 4359363466Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4360363466Sgshapiro "getmxrr(%s) returns null MX (See RFC7505)\n", 4361363466Sgshapiro p); 4362363466Sgshapiro else 4363363466Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4364363466Sgshapiro "getmxrr(%s) returns %d value(s):\n", 4365363466Sgshapiro p, nmx); 436638032Speter for (i = 0; i < nmx; i++) 436790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 436890792Sgshapiro "\t%s\n", mxhosts[i]); 436964562Sgshapiro#else /* NAMED_BIND */ 437090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 437190792Sgshapiro "No MX code compiled in\n"); 437264562Sgshapiro#endif /* NAMED_BIND */ 437338032Speter } 437490792Sgshapiro else if (sm_strcasecmp(&line[1], "canon") == 0) 437538032Speter { 437638032Speter char host[MAXHOSTNAMELEN]; 437738032Speter 437838032Speter if (*p == '\0') 437938032Speter { 438090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 438190792Sgshapiro "Usage: /canon address\n"); 438238032Speter return; 438338032Speter } 4384168515Sgshapiro else if (sm_strlcpy(host, p, sizeof(host)) >= sizeof(host)) 438538032Speter { 438690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 438790792Sgshapiro "Name too long\n"); 438838032Speter return; 438938032Speter } 4390168515Sgshapiro (void) getcanonname(host, sizeof(host), !HasWildcardMX, 439190792Sgshapiro NULL); 439290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 439390792Sgshapiro "getcanonname(%s) returns %s\n", 439490792Sgshapiro p, host); 439538032Speter } 439690792Sgshapiro else if (sm_strcasecmp(&line[1], "map") == 0) 439738032Speter { 439838032Speter auto int rcode = EX_OK; 439938032Speter char *av[2]; 440038032Speter 440138032Speter if (*p == '\0') 440238032Speter { 440390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 440490792Sgshapiro "Usage: /map mapname key\n"); 440538032Speter return; 440638032Speter } 4407363466Sgshapiro for (q = p; *q != '\0' && !(SM_ISSPACE(*q)); q++) 440838032Speter continue; 440938032Speter if (*q == '\0') 441038032Speter { 441190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 441290792Sgshapiro "No key specified\n"); 441338032Speter return; 441438032Speter } 441538032Speter *q++ = '\0'; 441638032Speter map = stab(p, ST_MAP, ST_FIND); 441738032Speter if (map == NULL) 441838032Speter { 441990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 442090792Sgshapiro "Map named \"%s\" not found\n", p); 442138032Speter return; 442238032Speter } 442364562Sgshapiro if (!bitset(MF_OPEN, map->s_map.map_mflags) && 442464562Sgshapiro !openmap(&(map->s_map))) 442538032Speter { 442690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 442790792Sgshapiro "Map named \"%s\" not open\n", p); 442838032Speter return; 442938032Speter } 443090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 443190792Sgshapiro "map_lookup: %s (%s) ", p, q); 443238032Speter av[0] = q; 443338032Speter av[1] = NULL; 443438032Speter p = (*map->s_map.map_class->map_lookup) 443538032Speter (&map->s_map, q, av, &rcode); 443638032Speter if (p == NULL) 443790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 443890792Sgshapiro "no match (%d)\n", 443990792Sgshapiro rcode); 444038032Speter else 444190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 444290792Sgshapiro "returns %s (%d)\n", p, 444390792Sgshapiro rcode); 444438032Speter } 444590792Sgshapiro else if (sm_strcasecmp(&line[1], "try") == 0) 444638032Speter { 444738032Speter MAILER *m; 444864562Sgshapiro STAB *st; 444938032Speter auto int rcode = EX_OK; 445038032Speter 445138032Speter q = strpbrk(p, " \t"); 445238032Speter if (q != NULL) 445338032Speter { 4454363466Sgshapiro while (SM_ISSPACE(*q)) 445538032Speter *q++ = '\0'; 445638032Speter } 445738032Speter if (q == NULL || *q == '\0') 445838032Speter { 445990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 446090792Sgshapiro "Usage: /try mailer address\n"); 446138032Speter return; 446238032Speter } 446364562Sgshapiro st = stab(p, ST_MAILER, ST_FIND); 446464562Sgshapiro if (st == NULL) 446538032Speter { 446690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 446790792Sgshapiro "Unknown mailer %s\n", p); 446838032Speter return; 446938032Speter } 447064562Sgshapiro m = st->s_mailer; 447190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 447290792Sgshapiro "Trying %s %s address %s for mailer %s\n", 447390792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? "header" 447490792Sgshapiro : "envelope", 447590792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? "sender" 447690792Sgshapiro : "recipient", q, p); 447738032Speter p = remotename(q, m, tryflags, &rcode, CurEnv); 447890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 447990792Sgshapiro "Rcode = %d, addr = %s\n", 448090792Sgshapiro rcode, p == NULL ? "<NULL>" : p); 448138032Speter e->e_to = NULL; 448238032Speter } 448390792Sgshapiro else if (sm_strcasecmp(&line[1], "tryflags") == 0) 448438032Speter { 448538032Speter if (*p == '\0') 448638032Speter { 448790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 448890792Sgshapiro "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 448938032Speter return; 449038032Speter } 449138032Speter for (; *p != '\0'; p++) 449238032Speter { 449338032Speter switch (*p) 449438032Speter { 449538032Speter case 'H': 449638032Speter case 'h': 449738032Speter tryflags |= RF_HEADERADDR; 449838032Speter break; 449938032Speter 450038032Speter case 'E': 450138032Speter case 'e': 450238032Speter tryflags &= ~RF_HEADERADDR; 450338032Speter break; 450438032Speter 450538032Speter case 'S': 450638032Speter case 's': 450738032Speter tryflags |= RF_SENDERADDR; 450838032Speter break; 450938032Speter 451038032Speter case 'R': 451138032Speter case 'r': 451238032Speter tryflags &= ~RF_SENDERADDR; 451338032Speter break; 451438032Speter } 451538032Speter } 451664562Sgshapiro exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 451764562Sgshapiro exbuf[1] = ' '; 451864562Sgshapiro exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 451964562Sgshapiro exbuf[3] = '\0'; 452090792Sgshapiro macdefine(&e->e_macro, A_TEMP, 452190792Sgshapiro macid("{addr_type}"), exbuf); 452238032Speter } 452390792Sgshapiro else if (sm_strcasecmp(&line[1], "parse") == 0) 452438032Speter { 452538032Speter if (*p == '\0') 452638032Speter { 452790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 452890792Sgshapiro "Usage: /parse address\n"); 452938032Speter return; 453038032Speter } 4531111823Sgshapiro q = crackaddr(p, e); 453290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 453390792Sgshapiro "Cracked address = "); 4534132943Sgshapiro xputs(smioout, q); 453590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 453690792Sgshapiro "\nParsing %s %s address\n", 453790792Sgshapiro bitset(RF_HEADERADDR, tryflags) ? 453890792Sgshapiro "header" : "envelope", 453990792Sgshapiro bitset(RF_SENDERADDR, tryflags) ? 454090792Sgshapiro "sender" : "recipient"); 454190792Sgshapiro if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 454290792Sgshapiro == NULL) 454390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 454490792Sgshapiro "Cannot parse\n"); 454538032Speter else if (a.q_host != NULL && a.q_host[0] != '\0') 454690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 454790792Sgshapiro "mailer %s, host %s, user %s\n", 454890792Sgshapiro a.q_mailer->m_name, 454990792Sgshapiro a.q_host, 455090792Sgshapiro a.q_user); 455138032Speter else 455290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 455390792Sgshapiro "mailer %s, user %s\n", 455490792Sgshapiro a.q_mailer->m_name, 455590792Sgshapiro a.q_user); 455638032Speter e->e_to = NULL; 455738032Speter } 4558168515Sgshapiro else if (sm_strcasecmp(&line[1], "header") == 0) 4559168515Sgshapiro { 4560168515Sgshapiro unsigned long ul; 4561168515Sgshapiro 4562168515Sgshapiro ul = chompheader(p, CHHDR_CHECK|CHHDR_USER, NULL, e); 4563168515Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4564168515Sgshapiro "ul = %lu\n", ul); 4565168515Sgshapiro } 4566261194Sgshapiro#if NETINET || NETINET6 4567261194Sgshapiro else if (sm_strcasecmp(&line[1], "gethostbyname") == 0) 4568261194Sgshapiro { 4569261194Sgshapiro int family = AF_INET; 4570261194Sgshapiro 4571261194Sgshapiro q = strpbrk(p, " \t"); 4572261194Sgshapiro if (q != NULL) 4573261194Sgshapiro { 4574363466Sgshapiro while (SM_ISSPACE(*q)) 4575261194Sgshapiro *q++ = '\0'; 4576261194Sgshapiro# if NETINET6 4577261194Sgshapiro if (*q != '\0' && (strcmp(q, "inet6") == 0 || 4578261194Sgshapiro strcmp(q, "AAAA") == 0)) 4579261194Sgshapiro family = AF_INET6; 4580261194Sgshapiro# endif /* NETINET6 */ 4581261194Sgshapiro } 4582261194Sgshapiro (void) sm_gethostbyname(p, family); 4583261194Sgshapiro } 4584261194Sgshapiro#endif /* NETINET || NETINET6 */ 4585363466Sgshapiro#if DANE 4586363466Sgshapiro else if (sm_strcasecmp(&line[1], "dnslookup") == 0) 4587363466Sgshapiro { 4588363466Sgshapiro DNS_REPLY_T *r; 4589363466Sgshapiro int rr_type, family; 4590363466Sgshapiro unsigned int flags; 4591363466Sgshapiro 4592363466Sgshapiro rr_type = T_A; 4593363466Sgshapiro family = AF_INET; 4594363466Sgshapiro flags = RR_AS_TEXT; 4595363466Sgshapiro q = strpbrk(p, " \t"); 4596363466Sgshapiro if (q != NULL) 4597363466Sgshapiro { 4598363466Sgshapiro char *pflags; 4599363466Sgshapiro 4600363466Sgshapiro while (SM_ISSPACE(*q)) 4601363466Sgshapiro *q++ = '\0'; 4602363466Sgshapiro pflags = strpbrk(q, " \t"); 4603363466Sgshapiro if (pflags != NULL) 4604363466Sgshapiro { 4605363466Sgshapiro while (SM_ISSPACE(*pflags)) 4606363466Sgshapiro *pflags++ = '\0'; 4607363466Sgshapiro } 4608363466Sgshapiro rr_type = dns_string_to_type(q); 4609363466Sgshapiro if (rr_type == T_A) 4610363466Sgshapiro family = AF_INET; 4611363466Sgshapiro# if NETINET6 4612363466Sgshapiro if (rr_type == T_AAAA) 4613363466Sgshapiro family = AF_INET6; 4614363466Sgshapiro# endif 4615363466Sgshapiro while (pflags != NULL && *pflags != '\0' && 4616363466Sgshapiro !SM_ISSPACE(*pflags)) 4617363466Sgshapiro { 4618363466Sgshapiro if (*pflags == 'c') 4619363466Sgshapiro flags |= RR_NO_CNAME; 4620363466Sgshapiro else if (*pflags == 'o') 4621363466Sgshapiro flags |= RR_ONLY_CNAME; 4622363466Sgshapiro else if (*pflags == 'T') 4623363466Sgshapiro flags &= ~RR_AS_TEXT; 4624363466Sgshapiro ++pflags; 4625363466Sgshapiro } 4626363466Sgshapiro } 4627363466Sgshapiro r = dns_lookup_int(p, C_IN, rr_type, 4628363466Sgshapiro 0, 0, 0, flags, NULL, NULL); 4629363466Sgshapiro if (r != NULL && family >= 0) 4630363466Sgshapiro { 4631363466Sgshapiro (void) dns2he(r, family); 4632363466Sgshapiro dns_free_data(r); 4633363466Sgshapiro r = NULL; 4634363466Sgshapiro } 4635363466Sgshapiro } 4636363466Sgshapiro#endif /* DANE */ 463738032Speter else 463838032Speter { 463990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 464090792Sgshapiro "Unknown \"/\" command %s\n", 464190792Sgshapiro line); 464238032Speter } 4643168515Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 464438032Speter return; 464538032Speter } 464638032Speter 4647363466Sgshapiro for (p = line; SM_ISSPACE(*p); p++) 464838032Speter continue; 464938032Speter q = p; 4650363466Sgshapiro while (*p != '\0' && !(SM_ISSPACE(*p))) 465138032Speter p++; 465238032Speter if (*p == '\0') 465338032Speter { 465490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 465590792Sgshapiro "No address!\n"); 465638032Speter return; 465738032Speter } 465838032Speter *p = '\0'; 4659168515Sgshapiro if (tTd(23, 101)) 4660168515Sgshapiro eightbit = to8bit(p + 1); 466190792Sgshapiro if (invalidaddr(p + 1, NULL, true)) 466238032Speter return; 466338032Speter do 466438032Speter { 466538032Speter register char **pvp; 466638032Speter char pvpbuf[PSBUFSIZE]; 466738032Speter 4668168515Sgshapiro pvp = prescan(++p, ',', pvpbuf, sizeof(pvpbuf), &delimptr, 4669168515Sgshapiro ConfigLevel >= 9 ? TokTypeNoC : ExtTokenTab, false); 467038032Speter if (pvp == NULL) 467138032Speter continue; 467238032Speter p = q; 467338032Speter while (*p != '\0') 467438032Speter { 467564562Sgshapiro int status; 467638032Speter 467738032Speter rs = strtorwset(p, NULL, ST_FIND); 467838032Speter if (rs < 0) 467938032Speter { 468090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 468190792Sgshapiro "Undefined ruleset %s\n", 468290792Sgshapiro p); 468338032Speter break; 468438032Speter } 468590792Sgshapiro status = REWRITE(pvp, rs, e); 468664562Sgshapiro if (status != EX_OK) 468790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 468890792Sgshapiro "== Ruleset %s (%d) status %d\n", 468990792Sgshapiro p, rs, status); 4690168515Sgshapiro else if (eightbit) 4691168515Sgshapiro { 4692168515Sgshapiro cataddr(pvp, NULL, exbuf, sizeof(exbuf), '\0', 4693168515Sgshapiro true); 4694168515Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4695168515Sgshapiro "cataddr: %s\n", 4696168515Sgshapiro str2prt(exbuf)); 4697168515Sgshapiro } 469838032Speter while (*p != '\0' && *p++ != ',') 469938032Speter continue; 470038032Speter } 470138032Speter } while (*(p = delimptr) != '\0'); 4702168515Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 470338032Speter} 470438032Speter 470564562Sgshapirostatic void 470638032Speterdump_class(s, id) 470738032Speter register STAB *s; 470838032Speter int id; 470938032Speter{ 471090792Sgshapiro if (s->s_symtype != ST_CLASS) 471138032Speter return; 471271345Sgshapiro if (bitnset(bitidx(id), s->s_class)) 471390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 471490792Sgshapiro "%s\n", s->s_name); 471538032Speter} 471690792Sgshapiro 471790792Sgshapiro/* 471890792Sgshapiro** An exception type used to create QuickAbort exceptions. 471990792Sgshapiro** This is my first cut at converting QuickAbort from longjmp to exceptions. 472090792Sgshapiro** These exceptions have a single integer argument, which is the argument 472190792Sgshapiro** to longjmp in the original code (either 1 or 2). I don't know the 472290792Sgshapiro** significance of 1 vs 2: the calls to setjmp don't care. 472390792Sgshapiro*/ 472490792Sgshapiro 472590792Sgshapiroconst SM_EXC_TYPE_T EtypeQuickAbort = 472690792Sgshapiro{ 472790792Sgshapiro SmExcTypeMagic, 472890792Sgshapiro "E:mta.quickabort", 472990792Sgshapiro "i", 473090792Sgshapiro sm_etype_printf, 473190792Sgshapiro "quick abort %0", 473290792Sgshapiro}; 4733