10Sstevel@tonic-gate /* 22197Sjbeck * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers. 30Sstevel@tonic-gate * All rights reserved. 40Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 50Sstevel@tonic-gate * Copyright (c) 1988, 1993 60Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 90Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 100Sstevel@tonic-gate * the sendmail distribution. 110Sstevel@tonic-gate * 120Sstevel@tonic-gate */ 130Sstevel@tonic-gate 140Sstevel@tonic-gate /* 151658Sjbeck * Copyright 1996-2006 Sun Microsystems, Inc. All rights reserved. 160Sstevel@tonic-gate * Use is subject to license terms. 170Sstevel@tonic-gate */ 180Sstevel@tonic-gate 190Sstevel@tonic-gate #define _DEFINE 200Sstevel@tonic-gate #include <sendmail.h> 210Sstevel@tonic-gate #include <sm/xtrap.h> 220Sstevel@tonic-gate #include <sm/signal.h> 230Sstevel@tonic-gate 240Sstevel@tonic-gate #ifndef lint 250Sstevel@tonic-gate SM_UNUSED(static char copyright[]) = 260Sstevel@tonic-gate "@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\ 270Sstevel@tonic-gate @(#) All rights reserved.\n\ 280Sstevel@tonic-gate @(#) Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 290Sstevel@tonic-gate @(#) Copyright (c) 1988, 1993\n\ 300Sstevel@tonic-gate @(#) The Regents of the University of California. All rights reserved.\n\ 311658Sjbeck @(#) Copyright 1996-2006 Sun Microsystems, Inc. All rights reserved.\n\ 320Sstevel@tonic-gate @(#) Use is subject to license terms.\n"; 330Sstevel@tonic-gate #endif /* ! lint */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 360Sstevel@tonic-gate 37*2526Sjbeck SM_RCSID("@(#)$Id: main.c,v 8.944.2.2 2006/08/03 22:05:03 ca Exp $") 380Sstevel@tonic-gate SM_IDSTR(i2, "%W% (Sun) %G%") 390Sstevel@tonic-gate 400Sstevel@tonic-gate #if NETINET || NETINET6 410Sstevel@tonic-gate # include <arpa/inet.h> 420Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate /* for getcfname() */ 450Sstevel@tonic-gate #include <sendmail/pathnames.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate static SM_DEBUG_T 480Sstevel@tonic-gate DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart", 490Sstevel@tonic-gate "@(#)$Debug: no_persistent_restart - don't restart, log only $"); 500Sstevel@tonic-gate 510Sstevel@tonic-gate static void dump_class __P((STAB *, int)); 520Sstevel@tonic-gate static void obsolete __P((char **)); 530Sstevel@tonic-gate static void testmodeline __P((char *, ENVELOPE *)); 540Sstevel@tonic-gate static char *getextenv __P((const char *)); 550Sstevel@tonic-gate static void sm_printoptions __P((char **)); 560Sstevel@tonic-gate static SIGFUNC_DECL intindebug __P((int)); 570Sstevel@tonic-gate static SIGFUNC_DECL sighup __P((int)); 580Sstevel@tonic-gate static SIGFUNC_DECL sigpipe __P((int)); 590Sstevel@tonic-gate static SIGFUNC_DECL sigterm __P((int)); 600Sstevel@tonic-gate #ifdef SIGUSR1 610Sstevel@tonic-gate static SIGFUNC_DECL sigusr1 __P((int)); 620Sstevel@tonic-gate #endif /* SIGUSR1 */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate ** SENDMAIL -- Post mail to a set of destinations. 660Sstevel@tonic-gate ** 670Sstevel@tonic-gate ** This is the basic mail router. All user mail programs should 680Sstevel@tonic-gate ** call this routine to actually deliver mail. Sendmail in 690Sstevel@tonic-gate ** turn calls a bunch of mail servers that do the real work of 700Sstevel@tonic-gate ** delivering the mail. 710Sstevel@tonic-gate ** 720Sstevel@tonic-gate ** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 730Sstevel@tonic-gate ** (read by readcf.c). 740Sstevel@tonic-gate ** 750Sstevel@tonic-gate ** Usage: 760Sstevel@tonic-gate ** /usr/lib/sendmail [flags] addr ... 770Sstevel@tonic-gate ** 780Sstevel@tonic-gate ** See the associated documentation for details. 790Sstevel@tonic-gate ** 800Sstevel@tonic-gate ** Authors: 810Sstevel@tonic-gate ** Eric Allman, UCB/INGRES (until 10/81). 820Sstevel@tonic-gate ** Britton-Lee, Inc., purveyors of fine 830Sstevel@tonic-gate ** database computers (11/81 - 10/88). 840Sstevel@tonic-gate ** International Computer Science Institute 850Sstevel@tonic-gate ** (11/88 - 9/89). 860Sstevel@tonic-gate ** UCB/Mammoth Project (10/89 - 7/95). 870Sstevel@tonic-gate ** InReference, Inc. (8/95 - 1/97). 880Sstevel@tonic-gate ** Sendmail, Inc. (1/98 - present). 890Sstevel@tonic-gate ** The support of my employers is gratefully acknowledged. 900Sstevel@tonic-gate ** Few of them (Britton-Lee in particular) have had 910Sstevel@tonic-gate ** anything to gain from my involvement in this project. 920Sstevel@tonic-gate ** 930Sstevel@tonic-gate ** Gregory Neil Shapiro, 940Sstevel@tonic-gate ** Worcester Polytechnic Institute (until 3/98). 950Sstevel@tonic-gate ** Sendmail, Inc. (3/98 - present). 960Sstevel@tonic-gate ** 970Sstevel@tonic-gate ** Claus Assmann, 980Sstevel@tonic-gate ** Sendmail, Inc. (12/98 - present). 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate char *FullName; /* sender's full name */ 1020Sstevel@tonic-gate ENVELOPE BlankEnvelope; /* a "blank" envelope */ 1030Sstevel@tonic-gate static ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 1040Sstevel@tonic-gate ADDRESS NullAddress = /* a null address */ 1050Sstevel@tonic-gate { "", "", NULL, "" }; 1060Sstevel@tonic-gate char *CommandLineArgs; /* command line args for pid file */ 1070Sstevel@tonic-gate bool Warn_Q_option = false; /* warn about Q option use */ 1080Sstevel@tonic-gate static int MissingFds = 0; /* bit map of fds missing on startup */ 1090Sstevel@tonic-gate char *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */ 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate #ifdef NGROUPS_MAX 1120Sstevel@tonic-gate GIDSET_T InitialGidSet[NGROUPS_MAX]; 1130Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate #define MAXCONFIGLEVEL 10 /* highest config version level known */ 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate #if SASL 1180Sstevel@tonic-gate static sasl_callback_t srvcallbacks[] = 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, 1210Sstevel@tonic-gate { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, 1220Sstevel@tonic-gate { SASL_CB_LIST_END, NULL, NULL } 1230Sstevel@tonic-gate }; 1240Sstevel@tonic-gate #endif /* SASL */ 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate unsigned int SubmitMode; 1270Sstevel@tonic-gate int SyslogPrefixLen; /* estimated length of syslog prefix */ 1280Sstevel@tonic-gate #define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 1290Sstevel@tonic-gate #ifndef SL_FUDGE 1300Sstevel@tonic-gate # define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 1310Sstevel@tonic-gate #endif /* ! SL_FUDGE */ 1320Sstevel@tonic-gate #define SLDLL 8 /* est. length of default syslog label */ 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* Some options are dangerous to allow users to use in non-submit mode */ 1360Sstevel@tonic-gate #define CHECK_AGAINST_OPMODE(cmd) \ 1370Sstevel@tonic-gate { \ 1380Sstevel@tonic-gate if (extraprivs && \ 1390Sstevel@tonic-gate OpMode != MD_DELIVER && OpMode != MD_SMTP && \ 1400Sstevel@tonic-gate OpMode != MD_ARPAFTP && \ 1410Sstevel@tonic-gate OpMode != MD_VERIFY && OpMode != MD_TEST) \ 1420Sstevel@tonic-gate { \ 1430Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 1440Sstevel@tonic-gate "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \ 1450Sstevel@tonic-gate (cmd)); \ 1460Sstevel@tonic-gate break; \ 1470Sstevel@tonic-gate } \ 1480Sstevel@tonic-gate if (extraprivs && queuerun) \ 1490Sstevel@tonic-gate { \ 1500Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 1510Sstevel@tonic-gate "WARNING: Ignoring submission mode -%c option with -q\n", \ 1520Sstevel@tonic-gate (cmd)); \ 1530Sstevel@tonic-gate break; \ 1540Sstevel@tonic-gate } \ 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate int 1580Sstevel@tonic-gate main(argc, argv, envp) 1590Sstevel@tonic-gate int argc; 1600Sstevel@tonic-gate char **argv; 1610Sstevel@tonic-gate char **envp; 1620Sstevel@tonic-gate { 1630Sstevel@tonic-gate register char *p; 1640Sstevel@tonic-gate char **av; 1650Sstevel@tonic-gate extern char Version[]; 1660Sstevel@tonic-gate char *ep, *from; 1670Sstevel@tonic-gate STAB *st; 1680Sstevel@tonic-gate register int i; 1690Sstevel@tonic-gate int j; 1700Sstevel@tonic-gate int dp; 1710Sstevel@tonic-gate int fill_errno; 1720Sstevel@tonic-gate int qgrp = NOQGRP; /* queue group to process */ 1730Sstevel@tonic-gate bool safecf = true; 1740Sstevel@tonic-gate BITMAP256 *p_flags = NULL; /* daemon flags */ 1750Sstevel@tonic-gate bool warn_C_flag = false; 1760Sstevel@tonic-gate bool auth = true; /* whether to set e_auth_param */ 1770Sstevel@tonic-gate char warn_f_flag = '\0'; 1780Sstevel@tonic-gate bool run_in_foreground = false; /* -bD mode */ 1790Sstevel@tonic-gate bool queuerun = false, debug = false; 1800Sstevel@tonic-gate struct passwd *pw; 1810Sstevel@tonic-gate struct hostent *hp; 1820Sstevel@tonic-gate char *nullserver = NULL; 1830Sstevel@tonic-gate char *authinfo = NULL; 1840Sstevel@tonic-gate char *sysloglabel = NULL; /* label for syslog */ 1850Sstevel@tonic-gate char *conffile = NULL; /* name of .cf file */ 1860Sstevel@tonic-gate char *queuegroup = NULL; /* queue group to process */ 1870Sstevel@tonic-gate char *quarantining = NULL; /* quarantine queue items? */ 1880Sstevel@tonic-gate bool extraprivs; 1890Sstevel@tonic-gate bool forged, negate; 1900Sstevel@tonic-gate bool queuepersistent = false; /* queue runner process runs forever */ 1910Sstevel@tonic-gate bool foregroundqueue = false; /* queue run in foreground */ 1920Sstevel@tonic-gate bool save_val; /* to save some bool var. */ 1930Sstevel@tonic-gate int cftype; /* which cf file to use? */ 1940Sstevel@tonic-gate SM_FILE_T *smdebug; 1950Sstevel@tonic-gate static time_t starttime = 0; /* when was process started */ 1960Sstevel@tonic-gate struct stat traf_st; /* for TrafficLog FIFO check */ 1970Sstevel@tonic-gate char buf[MAXLINE]; 1980Sstevel@tonic-gate char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 1990Sstevel@tonic-gate static char rnamebuf[MAXNAME]; /* holds RealUserName */ 2000Sstevel@tonic-gate char *emptyenviron[1]; 2010Sstevel@tonic-gate #if STARTTLS 2020Sstevel@tonic-gate bool tls_ok; 2030Sstevel@tonic-gate #endif /* STARTTLS */ 2040Sstevel@tonic-gate QUEUE_CHAR *new; 2050Sstevel@tonic-gate ENVELOPE *e; 2060Sstevel@tonic-gate extern int DtableSize; 2070Sstevel@tonic-gate extern int optind; 2080Sstevel@tonic-gate extern int opterr; 2090Sstevel@tonic-gate extern char *optarg; 2100Sstevel@tonic-gate extern char **environ; 2110Sstevel@tonic-gate #if SASL 2120Sstevel@tonic-gate extern void sm_sasl_init __P((void)); 2130Sstevel@tonic-gate #endif /* SASL */ 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate #if USE_ENVIRON 2160Sstevel@tonic-gate envp = environ; 2170Sstevel@tonic-gate #endif /* USE_ENVIRON */ 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* turn off profiling */ 2200Sstevel@tonic-gate SM_PROF(0); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* install default exception handler */ 2230Sstevel@tonic-gate sm_exc_newthread(fatal_error); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* set the default in/out channel so errors reported to screen */ 2260Sstevel@tonic-gate InChannel = smioin; 2270Sstevel@tonic-gate OutChannel = smioout; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate ** Check to see if we reentered. 2310Sstevel@tonic-gate ** This would normally happen if e_putheader or e_putbody 2320Sstevel@tonic-gate ** were NULL when invoked. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (starttime != 0) 2360Sstevel@tonic-gate { 2370Sstevel@tonic-gate syserr("main: reentered!"); 2380Sstevel@tonic-gate abort(); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate starttime = curtime(); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* avoid null pointer dereferences */ 2430Sstevel@tonic-gate TermEscape.te_rv_on = TermEscape.te_rv_off = ""; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate RealUid = getuid(); 2460Sstevel@tonic-gate RealGid = getgid(); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* Check if sendmail is running with extra privs */ 2490Sstevel@tonic-gate extraprivs = (RealUid != 0 && 2500Sstevel@tonic-gate (geteuid() != getuid() || getegid() != getgid())); 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate CurrentPid = getpid(); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* get whatever .cf file is right for the opmode */ 2550Sstevel@tonic-gate cftype = SM_GET_RIGHT_CF; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 2580Sstevel@tonic-gate DtableSize = getdtsize(); 2590Sstevel@tonic-gate if (DtableSize > 256) 2600Sstevel@tonic-gate DtableSize = 256; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate ** Be sure we have enough file descriptors. 2640Sstevel@tonic-gate ** But also be sure that 0, 1, & 2 are open. 2650Sstevel@tonic-gate */ 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate /* reset errno and fill_errno; the latter is used way down below */ 2680Sstevel@tonic-gate errno = fill_errno = 0; 2690Sstevel@tonic-gate fill_fd(STDIN_FILENO, NULL); 2700Sstevel@tonic-gate if (errno != 0) 2710Sstevel@tonic-gate fill_errno = errno; 2720Sstevel@tonic-gate fill_fd(STDOUT_FILENO, NULL); 2730Sstevel@tonic-gate if (errno != 0) 2740Sstevel@tonic-gate fill_errno = errno; 2750Sstevel@tonic-gate fill_fd(STDERR_FILENO, NULL); 2760Sstevel@tonic-gate if (errno != 0) 2770Sstevel@tonic-gate fill_errno = errno; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate sm_closefrom(STDERR_FILENO + 1, DtableSize); 2800Sstevel@tonic-gate errno = 0; 2810Sstevel@tonic-gate smdebug = NULL; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate #if LOG 2840Sstevel@tonic-gate # ifndef SM_LOG_STR 2850Sstevel@tonic-gate # define SM_LOG_STR "sendmail" 2860Sstevel@tonic-gate # endif /* ! SM_LOG_STR */ 2870Sstevel@tonic-gate # ifdef LOG_MAIL 2880Sstevel@tonic-gate openlog(SM_LOG_STR, LOG_PID, LOG_MAIL); 2890Sstevel@tonic-gate # else /* LOG_MAIL */ 2900Sstevel@tonic-gate openlog(SM_LOG_STR, LOG_PID); 2910Sstevel@tonic-gate # endif /* LOG_MAIL */ 2920Sstevel@tonic-gate #endif /* LOG */ 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate ** Seed the random number generator. 2960Sstevel@tonic-gate ** Used for queue file names, picking a queue directory, and 2970Sstevel@tonic-gate ** MX randomization. 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate seed_random(); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* do machine-dependent initializations */ 3030Sstevel@tonic-gate init_md(argc, argv); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* reset status from syserr() calls for missing file descriptors */ 3090Sstevel@tonic-gate Errors = 0; 3100Sstevel@tonic-gate ExitStat = EX_OK; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate SubmitMode = SUBMIT_UNKNOWN; 3130Sstevel@tonic-gate #if XDEBUG 3140Sstevel@tonic-gate checkfd012("after openlog"); 3150Sstevel@tonic-gate #endif /* XDEBUG */ 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1"); 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate #ifdef NGROUPS_MAX 3200Sstevel@tonic-gate /* save initial group set for future checks */ 3210Sstevel@tonic-gate i = getgroups(NGROUPS_MAX, InitialGidSet); 3220Sstevel@tonic-gate if (i <= 0) 3230Sstevel@tonic-gate { 3240Sstevel@tonic-gate InitialGidSet[0] = (GID_T) -1; 3250Sstevel@tonic-gate i = 0; 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate while (i < NGROUPS_MAX) 3280Sstevel@tonic-gate InitialGidSet[i++] = InitialGidSet[0]; 3290Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* drop group id privileges (RunAsUser not yet set) */ 3320Sstevel@tonic-gate dp = drop_privileges(false); 3330Sstevel@tonic-gate setstat(dp); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate #ifdef SIGUSR1 3360Sstevel@tonic-gate /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 3370Sstevel@tonic-gate if (!extraprivs) 3380Sstevel@tonic-gate { 3390Sstevel@tonic-gate /* arrange to dump state on user-1 signal */ 3400Sstevel@tonic-gate (void) sm_signal(SIGUSR1, sigusr1); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate else 3430Sstevel@tonic-gate { 3440Sstevel@tonic-gate /* ignore user-1 signal */ 3450Sstevel@tonic-gate (void) sm_signal(SIGUSR1, SIG_IGN); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate #endif /* SIGUSR1 */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* initialize for setproctitle */ 3500Sstevel@tonic-gate initsetproctitle(argc, argv, envp); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* Handle any non-getoptable constructions. */ 3530Sstevel@tonic-gate obsolete(argv); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate ** Do a quick prescan of the argument list. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* find initial opMode */ 3610Sstevel@tonic-gate OpMode = MD_DELIVER; 3620Sstevel@tonic-gate av = argv; 3630Sstevel@tonic-gate p = strrchr(*av, '/'); 3640Sstevel@tonic-gate if (p++ == NULL) 3650Sstevel@tonic-gate p = *av; 3660Sstevel@tonic-gate if (strcmp(p, "newaliases") == 0) 3670Sstevel@tonic-gate OpMode = MD_INITALIAS; 3680Sstevel@tonic-gate else if (strcmp(p, "mailq") == 0) 3690Sstevel@tonic-gate OpMode = MD_PRINT; 3700Sstevel@tonic-gate else if (strcmp(p, "smtpd") == 0) 3710Sstevel@tonic-gate OpMode = MD_DAEMON; 3720Sstevel@tonic-gate else if (strcmp(p, "hoststat") == 0) 3730Sstevel@tonic-gate OpMode = MD_HOSTSTAT; 3740Sstevel@tonic-gate else if (strcmp(p, "purgestat") == 0) 3750Sstevel@tonic-gate OpMode = MD_PURGESTAT; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate #if defined(__osf__) || defined(_AIX3) 3780Sstevel@tonic-gate # 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" 3790Sstevel@tonic-gate #endif /* defined(__osf__) || defined(_AIX3) */ 3800Sstevel@tonic-gate #if defined(sony_news) 3810Sstevel@tonic-gate # 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:" 3820Sstevel@tonic-gate #endif /* defined(sony_news) */ 3830Sstevel@tonic-gate #ifndef OPTIONS 3840Sstevel@tonic-gate # define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" 3850Sstevel@tonic-gate #endif /* ! OPTIONS */ 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* Set to 0 to allow -b; need to check optarg before using it! */ 3880Sstevel@tonic-gate opterr = 0; 3890Sstevel@tonic-gate while ((j = getopt(argc, argv, OPTIONS)) != -1) 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate switch (j) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate case 'b': /* operations mode */ 3940Sstevel@tonic-gate j = (optarg == NULL) ? ' ' : *optarg; 3950Sstevel@tonic-gate switch (j) 3960Sstevel@tonic-gate { 3970Sstevel@tonic-gate case MD_DAEMON: 3980Sstevel@tonic-gate case MD_FGDAEMON: 3990Sstevel@tonic-gate case MD_SMTP: 4000Sstevel@tonic-gate case MD_INITALIAS: 4010Sstevel@tonic-gate case MD_DELIVER: 4020Sstevel@tonic-gate case MD_VERIFY: 4030Sstevel@tonic-gate case MD_TEST: 4040Sstevel@tonic-gate case MD_PRINT: 4050Sstevel@tonic-gate case MD_PRINTNQE: 4060Sstevel@tonic-gate case MD_HOSTSTAT: 4070Sstevel@tonic-gate case MD_PURGESTAT: 4080Sstevel@tonic-gate case MD_ARPAFTP: 4090Sstevel@tonic-gate OpMode = j; 4100Sstevel@tonic-gate break; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate case MD_FREEZE: 4130Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4140Sstevel@tonic-gate "Frozen configurations unsupported\n"); 4150Sstevel@tonic-gate return EX_USAGE; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate default: 4180Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4190Sstevel@tonic-gate "Invalid operation mode %c\n", 4200Sstevel@tonic-gate j); 4210Sstevel@tonic-gate return EX_USAGE; 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate break; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate case 'D': 4260Sstevel@tonic-gate if (debug) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate errno = 0; 4290Sstevel@tonic-gate syserr("-D file must be before -d"); 4300Sstevel@tonic-gate ExitStat = EX_USAGE; 4310Sstevel@tonic-gate break; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate dp = drop_privileges(true); 4340Sstevel@tonic-gate setstat(dp); 4350Sstevel@tonic-gate smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 4360Sstevel@tonic-gate optarg, SM_IO_APPEND, NULL); 4370Sstevel@tonic-gate if (smdebug == NULL) 4380Sstevel@tonic-gate { 4390Sstevel@tonic-gate syserr("cannot open %s", optarg); 4400Sstevel@tonic-gate ExitStat = EX_CANTCREAT; 4410Sstevel@tonic-gate break; 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate sm_debug_setfile(smdebug); 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate case 'd': 4470Sstevel@tonic-gate debug = true; 4480Sstevel@tonic-gate tTflag(optarg); 4490Sstevel@tonic-gate (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT, 4500Sstevel@tonic-gate (char *) NULL, SM_IO_NBF, 4510Sstevel@tonic-gate SM_IO_BUFSIZ); 4520Sstevel@tonic-gate break; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate case 'G': /* relay (gateway) submission */ 4550Sstevel@tonic-gate SubmitMode = SUBMIT_MTA; 4560Sstevel@tonic-gate break; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate case 'L': 4590Sstevel@tonic-gate if (optarg == NULL) 4600Sstevel@tonic-gate { 4610Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4620Sstevel@tonic-gate "option requires an argument -- '%c'", 4630Sstevel@tonic-gate (char) j); 4640Sstevel@tonic-gate return EX_USAGE; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate j = SM_MIN(strlen(optarg), 32) + 1; 4670Sstevel@tonic-gate sysloglabel = xalloc(j); 4680Sstevel@tonic-gate (void) sm_strlcpy(sysloglabel, optarg, j); 4690Sstevel@tonic-gate SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + 4700Sstevel@tonic-gate SL_FUDGE + j; 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate case 'Q': 4740Sstevel@tonic-gate case 'q': 4750Sstevel@tonic-gate /* just check if it is there */ 4760Sstevel@tonic-gate queuerun = true; 4770Sstevel@tonic-gate break; 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate opterr = 1; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* Don't leak queue information via debug flags */ 4830Sstevel@tonic-gate if (extraprivs && queuerun && debug) 4840Sstevel@tonic-gate { 4850Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4860Sstevel@tonic-gate "WARNING: Can not use -d with -q. Disabling debugging.\n"); 4870Sstevel@tonic-gate sm_debug_close(); 4880Sstevel@tonic-gate sm_debug_setfile(NULL); 4890Sstevel@tonic-gate (void) memset(tTdvect, '\0', sizeof tTdvect); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate #if LOG 4930Sstevel@tonic-gate if (sysloglabel != NULL) 4940Sstevel@tonic-gate { 4950Sstevel@tonic-gate /* Sanitize the string */ 4960Sstevel@tonic-gate for (p = sysloglabel; *p != '\0'; p++) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate if (!isascii(*p) || !isprint(*p) || *p == '%') 4990Sstevel@tonic-gate *p = '*'; 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate closelog(); 5020Sstevel@tonic-gate # ifdef LOG_MAIL 5030Sstevel@tonic-gate openlog(sysloglabel, LOG_PID, LOG_MAIL); 5040Sstevel@tonic-gate # else /* LOG_MAIL */ 5050Sstevel@tonic-gate openlog(sysloglabel, LOG_PID); 5060Sstevel@tonic-gate # endif /* LOG_MAIL */ 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate #endif /* LOG */ 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* set up the blank envelope */ 5110Sstevel@tonic-gate BlankEnvelope.e_puthdr = putheader; 5120Sstevel@tonic-gate BlankEnvelope.e_putbody = putbody; 5130Sstevel@tonic-gate BlankEnvelope.e_xfp = NULL; 5140Sstevel@tonic-gate STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 5150Sstevel@tonic-gate CurEnv = &BlankEnvelope; 5160Sstevel@tonic-gate STRUCTCOPY(NullAddress, MainEnvelope.e_from); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate ** Set default values for variables. 5200Sstevel@tonic-gate ** These cannot be in initialized data space. 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate setdefaults(&BlankEnvelope); 5240Sstevel@tonic-gate initmacros(&BlankEnvelope); 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* reset macro */ 5270Sstevel@tonic-gate set_op_mode(OpMode); 5282197Sjbeck if (OpMode == MD_DAEMON) 5292197Sjbeck DaemonPid = CurrentPid; /* needed for finis() to work */ 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate pw = sm_getpwuid(RealUid); 5320Sstevel@tonic-gate if (pw != NULL) 5330Sstevel@tonic-gate (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 5340Sstevel@tonic-gate else 5350Sstevel@tonic-gate (void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 5360Sstevel@tonic-gate (int) RealUid); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate RealUserName = rnamebuf; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if (tTd(0, 101)) 5410Sstevel@tonic-gate { 5420Sstevel@tonic-gate sm_dprintf("Version %s\n", Version); 5430Sstevel@tonic-gate finis(false, true, EX_OK); 5440Sstevel@tonic-gate /* NOTREACHED */ 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate ** if running non-set-user-ID binary as non-root, pretend 5490Sstevel@tonic-gate ** we are the RunAsUid 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate if (RealUid != 0 && geteuid() == RealUid) 5530Sstevel@tonic-gate { 5540Sstevel@tonic-gate if (tTd(47, 1)) 5550Sstevel@tonic-gate sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n", 5560Sstevel@tonic-gate (int) RealUid); 5570Sstevel@tonic-gate RunAsUid = RealUid; 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate else if (geteuid() != 0) 5600Sstevel@tonic-gate RunAsUid = geteuid(); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate EffGid = getegid(); 5630Sstevel@tonic-gate if (RealUid != 0 && EffGid == RealGid) 5640Sstevel@tonic-gate RunAsGid = RealGid; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (tTd(47, 5)) 5670Sstevel@tonic-gate { 5680Sstevel@tonic-gate sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 5690Sstevel@tonic-gate (int) geteuid(), (int) getuid(), 5700Sstevel@tonic-gate (int) getegid(), (int) getgid()); 5710Sstevel@tonic-gate sm_dprintf("main: RunAsUser = %d:%d\n", 5720Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* save command line arguments */ 5760Sstevel@tonic-gate j = 0; 5770Sstevel@tonic-gate for (av = argv; *av != NULL; ) 5780Sstevel@tonic-gate j += strlen(*av++) + 1; 5790Sstevel@tonic-gate SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); 5800Sstevel@tonic-gate CommandLineArgs = xalloc(j); 5810Sstevel@tonic-gate p = CommandLineArgs; 5820Sstevel@tonic-gate for (av = argv, i = 0; *av != NULL; ) 5830Sstevel@tonic-gate { 5840Sstevel@tonic-gate int h; 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate SaveArgv[i++] = newstr(*av); 5870Sstevel@tonic-gate if (av != argv) 5880Sstevel@tonic-gate *p++ = ' '; 5890Sstevel@tonic-gate (void) sm_strlcpy(p, *av++, j); 5900Sstevel@tonic-gate h = strlen(p); 5910Sstevel@tonic-gate p += h; 5920Sstevel@tonic-gate j -= h + 1; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate SaveArgv[i] = NULL; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (tTd(0, 1)) 5970Sstevel@tonic-gate { 5980Sstevel@tonic-gate extern char *CompileOptions[]; 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate sm_dprintf("Version %s\n Compiled with:", Version); 6010Sstevel@tonic-gate sm_printoptions(CompileOptions); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate if (tTd(0, 10)) 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate extern char *OsCompileOptions[]; 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate sm_dprintf(" OS Defines:"); 6080Sstevel@tonic-gate sm_printoptions(OsCompileOptions); 6090Sstevel@tonic-gate #ifdef _PATH_UNIX 6100Sstevel@tonic-gate sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 6110Sstevel@tonic-gate #endif /* _PATH_UNIX */ 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (default for MSP)\n", 6140Sstevel@tonic-gate getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF, 6150Sstevel@tonic-gate conffile)); 6160Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (default for MTA)\n", 6170Sstevel@tonic-gate getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF, 6180Sstevel@tonic-gate conffile)); 6190Sstevel@tonic-gate sm_dprintf(" Pid file:\t%s (default)\n", PidFile); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate if (tTd(0, 12)) 6230Sstevel@tonic-gate { 6240Sstevel@tonic-gate extern char *SmCompileOptions[]; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate sm_dprintf(" libsm Defines:"); 6270Sstevel@tonic-gate sm_printoptions(SmCompileOptions); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if (tTd(0, 13)) 6310Sstevel@tonic-gate { 6320Sstevel@tonic-gate extern char *FFRCompileOptions[]; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate sm_dprintf(" FFR Defines:"); 6350Sstevel@tonic-gate sm_printoptions(FFRCompileOptions); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* clear sendmail's environment */ 6390Sstevel@tonic-gate ExternalEnviron = environ; 6400Sstevel@tonic-gate emptyenviron[0] = NULL; 6410Sstevel@tonic-gate environ = emptyenviron; 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate ** restore any original TZ setting until TimeZoneSpec has been 6450Sstevel@tonic-gate ** determined - or early log messages may get bogus time stamps 6460Sstevel@tonic-gate */ 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate if ((p = getextenv("TZ")) != NULL) 6490Sstevel@tonic-gate { 6500Sstevel@tonic-gate char *tz; 6510Sstevel@tonic-gate int tzlen; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* XXX check for reasonable length? */ 6540Sstevel@tonic-gate tzlen = strlen(p) + 4; 6550Sstevel@tonic-gate tz = xalloc(tzlen); 6560Sstevel@tonic-gate (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* XXX check return code? */ 6590Sstevel@tonic-gate (void) putenv(tz); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* prime the child environment */ 6631658Sjbeck sm_setuserenv("AGENT", "sendmail"); 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate (void) sm_signal(SIGPIPE, SIG_IGN); 6660Sstevel@tonic-gate OldUmask = umask(022); 6670Sstevel@tonic-gate FullName = getextenv("NAME"); 6680Sstevel@tonic-gate if (FullName != NULL) 6690Sstevel@tonic-gate FullName = newstr(FullName); 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate ** Initialize name server if it is going to be used. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate #if NAMED_BIND 6760Sstevel@tonic-gate if (!bitset(RES_INIT, _res.options)) 6770Sstevel@tonic-gate (void) res_init(); 6780Sstevel@tonic-gate if (tTd(8, 8)) 6790Sstevel@tonic-gate _res.options |= RES_DEBUG; 6800Sstevel@tonic-gate else 6810Sstevel@tonic-gate _res.options &= ~RES_DEBUG; 6820Sstevel@tonic-gate # ifdef RES_NOALIASES 6830Sstevel@tonic-gate _res.options |= RES_NOALIASES; 6840Sstevel@tonic-gate # endif /* RES_NOALIASES */ 6850Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 6860Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 6870Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 6880Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 6890Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 6900Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 6910Sstevel@tonic-gate #endif /* NAMED_BIND */ 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate errno = 0; 6940Sstevel@tonic-gate from = NULL; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* initialize some macros, etc. */ 6970Sstevel@tonic-gate init_vendor_macros(&BlankEnvelope); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate /* version */ 7000Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* hostname */ 7030Sstevel@tonic-gate hp = myhostname(jbuf, sizeof jbuf); 7040Sstevel@tonic-gate if (jbuf[0] != '\0') 7050Sstevel@tonic-gate { 7060Sstevel@tonic-gate struct utsname utsname; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate if (tTd(0, 4)) 7090Sstevel@tonic-gate sm_dprintf("Canonical name: %s\n", jbuf); 7100Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf); 7110Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf); 7120Sstevel@tonic-gate setclass('w', jbuf); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate p = strchr(jbuf, '.'); 7150Sstevel@tonic-gate if (p != NULL && p[1] != '\0') 7160Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate if (uname(&utsname) >= 0) 7190Sstevel@tonic-gate p = utsname.nodename; 7200Sstevel@tonic-gate else 7210Sstevel@tonic-gate { 7220Sstevel@tonic-gate if (tTd(0, 22)) 7230Sstevel@tonic-gate sm_dprintf("uname failed (%s)\n", 7240Sstevel@tonic-gate sm_errstring(errno)); 7250Sstevel@tonic-gate makelower(jbuf); 7260Sstevel@tonic-gate p = jbuf; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate if (tTd(0, 4)) 7290Sstevel@tonic-gate sm_dprintf(" UUCP nodename: %s\n", p); 7300Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p); 7310Sstevel@tonic-gate setclass('k', p); 7320Sstevel@tonic-gate setclass('w', p); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate if (hp != NULL) 7350Sstevel@tonic-gate { 7360Sstevel@tonic-gate for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 7370Sstevel@tonic-gate { 7380Sstevel@tonic-gate if (tTd(0, 4)) 7390Sstevel@tonic-gate sm_dprintf("\ta.k.a.: %s\n", *av); 7400Sstevel@tonic-gate setclass('w', *av); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate #if NETINET || NETINET6 7430Sstevel@tonic-gate for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++) 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate # if NETINET6 7460Sstevel@tonic-gate char *addr; 7470Sstevel@tonic-gate char buf6[INET6_ADDRSTRLEN]; 7480Sstevel@tonic-gate struct in6_addr ia6; 7490Sstevel@tonic-gate # endif /* NETINET6 */ 7500Sstevel@tonic-gate # if NETINET 7510Sstevel@tonic-gate struct in_addr ia; 7520Sstevel@tonic-gate # endif /* NETINET */ 7530Sstevel@tonic-gate char ipbuf[103]; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate ipbuf[0] = '\0'; 7560Sstevel@tonic-gate switch (hp->h_addrtype) 7570Sstevel@tonic-gate { 7580Sstevel@tonic-gate # if NETINET 7590Sstevel@tonic-gate case AF_INET: 7600Sstevel@tonic-gate if (hp->h_length != INADDRSZ) 7610Sstevel@tonic-gate break; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate memmove(&ia, hp->h_addr_list[i], INADDRSZ); 7640Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, 7650Sstevel@tonic-gate "[%.100s]", inet_ntoa(ia)); 7660Sstevel@tonic-gate break; 7670Sstevel@tonic-gate # endif /* NETINET */ 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate # if NETINET6 7700Sstevel@tonic-gate case AF_INET6: 7710Sstevel@tonic-gate if (hp->h_length != IN6ADDRSZ) 7720Sstevel@tonic-gate break; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 7750Sstevel@tonic-gate addr = anynet_ntop(&ia6, buf6, sizeof buf6); 7760Sstevel@tonic-gate if (addr != NULL) 7770Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, 7780Sstevel@tonic-gate "[%.100s]", addr); 7790Sstevel@tonic-gate break; 7800Sstevel@tonic-gate # endif /* NETINET6 */ 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate if (ipbuf[0] == '\0') 7830Sstevel@tonic-gate break; 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate if (tTd(0, 4)) 7860Sstevel@tonic-gate sm_dprintf("\ta.k.a.: %s\n", ipbuf); 7870Sstevel@tonic-gate setclass('w', ipbuf); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 7900Sstevel@tonic-gate #if NETINET6 7910Sstevel@tonic-gate freehostent(hp); 7920Sstevel@tonic-gate hp = NULL; 7930Sstevel@tonic-gate #endif /* NETINET6 */ 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* current time */ 7970Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL)); 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* current load average */ 8000Sstevel@tonic-gate sm_getla(); 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate QueueLimitRecipient = (QUEUE_CHAR *) NULL; 8030Sstevel@tonic-gate QueueLimitSender = (QUEUE_CHAR *) NULL; 8040Sstevel@tonic-gate QueueLimitId = (QUEUE_CHAR *) NULL; 8050Sstevel@tonic-gate QueueLimitQuarantine = (QUEUE_CHAR *) NULL; 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* 8080Sstevel@tonic-gate ** Crack argv. 8090Sstevel@tonic-gate */ 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate optind = 1; 8120Sstevel@tonic-gate while ((j = getopt(argc, argv, OPTIONS)) != -1) 8130Sstevel@tonic-gate { 8140Sstevel@tonic-gate switch (j) 8150Sstevel@tonic-gate { 8160Sstevel@tonic-gate case 'b': /* operations mode */ 8170Sstevel@tonic-gate /* already done */ 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate case 'A': /* use Alternate sendmail/submit.cf */ 8210Sstevel@tonic-gate cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF 8220Sstevel@tonic-gate : SM_GET_SENDMAIL_CF; 8230Sstevel@tonic-gate break; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate case 'B': /* body type */ 8260Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8270Sstevel@tonic-gate BlankEnvelope.e_bodytype = newstr(optarg); 8280Sstevel@tonic-gate break; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate case 'C': /* select configuration file (already done) */ 8310Sstevel@tonic-gate if (RealUid != 0) 8320Sstevel@tonic-gate warn_C_flag = true; 8330Sstevel@tonic-gate conffile = newstr(optarg); 8340Sstevel@tonic-gate dp = drop_privileges(true); 8350Sstevel@tonic-gate setstat(dp); 8360Sstevel@tonic-gate safecf = false; 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate case 'D': 8400Sstevel@tonic-gate case 'd': /* debugging */ 8410Sstevel@tonic-gate /* already done */ 8420Sstevel@tonic-gate break; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate case 'f': /* from address */ 8450Sstevel@tonic-gate case 'r': /* obsolete -f flag */ 8460Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8470Sstevel@tonic-gate if (from != NULL) 8480Sstevel@tonic-gate { 8490Sstevel@tonic-gate usrerr("More than one \"from\" person"); 8500Sstevel@tonic-gate ExitStat = EX_USAGE; 8510Sstevel@tonic-gate break; 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate if (optarg[0] == '\0') 8540Sstevel@tonic-gate from = newstr("<>"); 8550Sstevel@tonic-gate else 8560Sstevel@tonic-gate from = newstr(denlstring(optarg, true, true)); 8570Sstevel@tonic-gate if (strcmp(RealUserName, from) != 0) 8580Sstevel@tonic-gate warn_f_flag = j; 8590Sstevel@tonic-gate break; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate case 'F': /* set full name */ 8620Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8630Sstevel@tonic-gate FullName = newstr(optarg); 8640Sstevel@tonic-gate break; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate case 'G': /* relay (gateway) submission */ 8670Sstevel@tonic-gate /* already set */ 8680Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8690Sstevel@tonic-gate break; 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate case 'h': /* hop count */ 8720Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8730Sstevel@tonic-gate BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep, 8740Sstevel@tonic-gate 10); 8750Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%d", 8760Sstevel@tonic-gate BlankEnvelope.e_hopcount); 8770Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf); 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate if (*ep) 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate usrerr("Bad hop count (%s)", optarg); 8820Sstevel@tonic-gate ExitStat = EX_USAGE; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate break; 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate case 'L': /* program label */ 8870Sstevel@tonic-gate /* already set */ 8880Sstevel@tonic-gate break; 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate case 'n': /* don't alias */ 8910Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8920Sstevel@tonic-gate NoAlias = true; 8930Sstevel@tonic-gate break; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate case 'N': /* delivery status notifications */ 8960Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 8970Sstevel@tonic-gate DefaultNotify |= QHASNOTIFY; 8980Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 8990Sstevel@tonic-gate macid("{dsn_notify}"), optarg); 9000Sstevel@tonic-gate if (sm_strcasecmp(optarg, "never") == 0) 9010Sstevel@tonic-gate break; 9020Sstevel@tonic-gate for (p = optarg; p != NULL; optarg = p) 9030Sstevel@tonic-gate { 9040Sstevel@tonic-gate p = strchr(p, ','); 9050Sstevel@tonic-gate if (p != NULL) 9060Sstevel@tonic-gate *p++ = '\0'; 9070Sstevel@tonic-gate if (sm_strcasecmp(optarg, "success") == 0) 9080Sstevel@tonic-gate DefaultNotify |= QPINGONSUCCESS; 9090Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "failure") == 0) 9100Sstevel@tonic-gate DefaultNotify |= QPINGONFAILURE; 9110Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "delay") == 0) 9120Sstevel@tonic-gate DefaultNotify |= QPINGONDELAY; 9130Sstevel@tonic-gate else 9140Sstevel@tonic-gate { 9150Sstevel@tonic-gate usrerr("Invalid -N argument"); 9160Sstevel@tonic-gate ExitStat = EX_USAGE; 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate break; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate case 'o': /* set option */ 9220Sstevel@tonic-gate setoption(*optarg, optarg + 1, false, true, 9230Sstevel@tonic-gate &BlankEnvelope); 9240Sstevel@tonic-gate break; 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate case 'O': /* set option (long form) */ 9270Sstevel@tonic-gate setoption(' ', optarg, false, true, &BlankEnvelope); 9280Sstevel@tonic-gate break; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate case 'p': /* set protocol */ 9310Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 9320Sstevel@tonic-gate p = strchr(optarg, ':'); 9330Sstevel@tonic-gate if (p != NULL) 9340Sstevel@tonic-gate { 9350Sstevel@tonic-gate *p++ = '\0'; 9360Sstevel@tonic-gate if (*p != '\0') 9370Sstevel@tonic-gate { 9380Sstevel@tonic-gate i = strlen(p) + 1; 9390Sstevel@tonic-gate ep = sm_malloc_x(i); 9400Sstevel@tonic-gate cleanstrcpy(ep, p, i); 9410Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 9420Sstevel@tonic-gate A_HEAP, 's', ep); 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate if (*optarg != '\0') 9460Sstevel@tonic-gate { 9470Sstevel@tonic-gate i = strlen(optarg) + 1; 9480Sstevel@tonic-gate ep = sm_malloc_x(i); 9490Sstevel@tonic-gate cleanstrcpy(ep, optarg, i); 9500Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_HEAP, 9510Sstevel@tonic-gate 'r', ep); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate break; 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate case 'Q': /* change quarantining on queued items */ 9560Sstevel@tonic-gate /* sanity check */ 9570Sstevel@tonic-gate if (OpMode != MD_DELIVER && 9580Sstevel@tonic-gate OpMode != MD_QUEUERUN) 9590Sstevel@tonic-gate { 9600Sstevel@tonic-gate usrerr("Can not use -Q with -b%c", OpMode); 9610Sstevel@tonic-gate ExitStat = EX_USAGE; 9620Sstevel@tonic-gate break; 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate if (OpMode == MD_DELIVER) 9660Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate FullName = NULL; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate quarantining = newstr(optarg); 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate case 'q': /* run queue files at intervals */ 9740Sstevel@tonic-gate /* sanity check */ 9750Sstevel@tonic-gate if (OpMode != MD_DELIVER && 9760Sstevel@tonic-gate OpMode != MD_DAEMON && 9770Sstevel@tonic-gate OpMode != MD_FGDAEMON && 9780Sstevel@tonic-gate OpMode != MD_PRINT && 9790Sstevel@tonic-gate OpMode != MD_PRINTNQE && 9800Sstevel@tonic-gate OpMode != MD_QUEUERUN) 9810Sstevel@tonic-gate { 9820Sstevel@tonic-gate usrerr("Can not use -q with -b%c", OpMode); 9830Sstevel@tonic-gate ExitStat = EX_USAGE; 9840Sstevel@tonic-gate break; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate /* don't override -bd, -bD or -bp */ 9880Sstevel@tonic-gate if (OpMode == MD_DELIVER) 9890Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate FullName = NULL; 9920Sstevel@tonic-gate negate = optarg[0] == '!'; 9930Sstevel@tonic-gate if (negate) 9940Sstevel@tonic-gate { 9950Sstevel@tonic-gate /* negate meaning of pattern match */ 9960Sstevel@tonic-gate optarg++; /* skip '!' for next switch */ 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate switch (optarg[0]) 10000Sstevel@tonic-gate { 10010Sstevel@tonic-gate case 'G': /* Limit by queue group name */ 10020Sstevel@tonic-gate if (negate) 10030Sstevel@tonic-gate { 10040Sstevel@tonic-gate usrerr("Can not use -q!G"); 10050Sstevel@tonic-gate ExitStat = EX_USAGE; 10060Sstevel@tonic-gate break; 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate if (queuegroup != NULL) 10090Sstevel@tonic-gate { 10100Sstevel@tonic-gate usrerr("Can not use multiple -qG options"); 10110Sstevel@tonic-gate ExitStat = EX_USAGE; 10120Sstevel@tonic-gate break; 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate queuegroup = newstr(&optarg[1]); 10150Sstevel@tonic-gate break; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate case 'I': /* Limit by ID */ 10180Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 10190Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 10200Sstevel@tonic-gate new->queue_negate = negate; 10210Sstevel@tonic-gate new->queue_next = QueueLimitId; 10220Sstevel@tonic-gate QueueLimitId = new; 10230Sstevel@tonic-gate break; 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate case 'R': /* Limit by recipient */ 10260Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 10270Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 10280Sstevel@tonic-gate new->queue_negate = negate; 10290Sstevel@tonic-gate new->queue_next = QueueLimitRecipient; 10300Sstevel@tonic-gate QueueLimitRecipient = new; 10310Sstevel@tonic-gate break; 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate case 'S': /* Limit by sender */ 10340Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 10350Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 10360Sstevel@tonic-gate new->queue_negate = negate; 10370Sstevel@tonic-gate new->queue_next = QueueLimitSender; 10380Sstevel@tonic-gate QueueLimitSender = new; 10390Sstevel@tonic-gate break; 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate case 'f': /* foreground queue run */ 10420Sstevel@tonic-gate foregroundqueue = true; 10430Sstevel@tonic-gate break; 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate case 'Q': /* Limit by quarantine message */ 10460Sstevel@tonic-gate if (optarg[1] != '\0') 10470Sstevel@tonic-gate { 10480Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 10490Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 10500Sstevel@tonic-gate new->queue_negate = negate; 10510Sstevel@tonic-gate new->queue_next = QueueLimitQuarantine; 10520Sstevel@tonic-gate QueueLimitQuarantine = new; 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate QueueMode = QM_QUARANTINE; 10550Sstevel@tonic-gate break; 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate case 'L': /* act on lost items */ 10580Sstevel@tonic-gate QueueMode = QM_LOST; 10590Sstevel@tonic-gate break; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate case 'p': /* Persistent queue */ 10620Sstevel@tonic-gate queuepersistent = true; 10630Sstevel@tonic-gate if (QueueIntvl == 0) 10640Sstevel@tonic-gate QueueIntvl = 1; 10650Sstevel@tonic-gate if (optarg[1] == '\0') 10660Sstevel@tonic-gate break; 10670Sstevel@tonic-gate ++optarg; 10680Sstevel@tonic-gate /* FALLTHROUGH */ 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate default: 10710Sstevel@tonic-gate i = Errors; 10720Sstevel@tonic-gate QueueIntvl = convtime(optarg, 'm'); 10730Sstevel@tonic-gate if (QueueIntvl < 0) 10740Sstevel@tonic-gate { 10750Sstevel@tonic-gate usrerr("Invalid -q value"); 10760Sstevel@tonic-gate ExitStat = EX_USAGE; 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* check for bad conversion */ 10800Sstevel@tonic-gate if (i < Errors) 10810Sstevel@tonic-gate ExitStat = EX_USAGE; 10820Sstevel@tonic-gate break; 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate break; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate case 'R': /* DSN RET: what to return */ 10870Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 10880Sstevel@tonic-gate if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags)) 10890Sstevel@tonic-gate { 10900Sstevel@tonic-gate usrerr("Duplicate -R flag"); 10910Sstevel@tonic-gate ExitStat = EX_USAGE; 10920Sstevel@tonic-gate break; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_RET_PARAM; 10950Sstevel@tonic-gate if (sm_strcasecmp(optarg, "hdrs") == 0) 10960Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_NO_BODY_RETN; 10970Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "full") != 0) 10980Sstevel@tonic-gate { 10990Sstevel@tonic-gate usrerr("Invalid -R value"); 11000Sstevel@tonic-gate ExitStat = EX_USAGE; 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 11030Sstevel@tonic-gate macid("{dsn_ret}"), optarg); 11040Sstevel@tonic-gate break; 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate case 't': /* read recipients from message */ 11070Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 11080Sstevel@tonic-gate GrabTo = true; 11090Sstevel@tonic-gate break; 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate case 'V': /* DSN ENVID: set "original" envelope id */ 11120Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 11130Sstevel@tonic-gate if (!xtextok(optarg)) 11140Sstevel@tonic-gate { 11150Sstevel@tonic-gate usrerr("Invalid syntax in -V flag"); 11160Sstevel@tonic-gate ExitStat = EX_USAGE; 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate else 11190Sstevel@tonic-gate { 11200Sstevel@tonic-gate BlankEnvelope.e_envid = newstr(optarg); 11210Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 11220Sstevel@tonic-gate macid("{dsn_envid}"), optarg); 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate break; 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate case 'X': /* traffic log file */ 11270Sstevel@tonic-gate dp = drop_privileges(true); 11280Sstevel@tonic-gate setstat(dp); 11290Sstevel@tonic-gate if (stat(optarg, &traf_st) == 0 && 11300Sstevel@tonic-gate S_ISFIFO(traf_st.st_mode)) 11310Sstevel@tonic-gate TrafficLogFile = sm_io_open(SmFtStdio, 11320Sstevel@tonic-gate SM_TIME_DEFAULT, 11330Sstevel@tonic-gate optarg, 11340Sstevel@tonic-gate SM_IO_WRONLY, NULL); 11350Sstevel@tonic-gate else 11360Sstevel@tonic-gate TrafficLogFile = sm_io_open(SmFtStdio, 11370Sstevel@tonic-gate SM_TIME_DEFAULT, 11380Sstevel@tonic-gate optarg, 11390Sstevel@tonic-gate SM_IO_APPEND, NULL); 11400Sstevel@tonic-gate if (TrafficLogFile == NULL) 11410Sstevel@tonic-gate { 11420Sstevel@tonic-gate syserr("cannot open %s", optarg); 11430Sstevel@tonic-gate ExitStat = EX_CANTCREAT; 11440Sstevel@tonic-gate break; 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT, 11470Sstevel@tonic-gate NULL, SM_IO_LBF, 0); 11480Sstevel@tonic-gate break; 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate /* compatibility flags */ 11510Sstevel@tonic-gate case 'c': /* connect to non-local mailers */ 11520Sstevel@tonic-gate case 'i': /* don't let dot stop me */ 11530Sstevel@tonic-gate case 'm': /* send to me too */ 11540Sstevel@tonic-gate case 'T': /* set timeout interval */ 11550Sstevel@tonic-gate case 'v': /* give blow-by-blow description */ 11560Sstevel@tonic-gate setoption(j, "T", false, true, &BlankEnvelope); 11570Sstevel@tonic-gate break; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate case 'e': /* error message disposition */ 11600Sstevel@tonic-gate case 'M': /* define macro */ 11610Sstevel@tonic-gate setoption(j, optarg, false, true, &BlankEnvelope); 11620Sstevel@tonic-gate break; 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate case 's': /* save From lines in headers */ 11650Sstevel@tonic-gate setoption('f', "T", false, true, &BlankEnvelope); 11660Sstevel@tonic-gate break; 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate #ifdef DBM 11690Sstevel@tonic-gate case 'I': /* initialize alias DBM file */ 11700Sstevel@tonic-gate set_op_mode(MD_INITALIAS); 11710Sstevel@tonic-gate break; 11720Sstevel@tonic-gate #endif /* DBM */ 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate #if defined(__osf__) || defined(_AIX3) 11750Sstevel@tonic-gate case 'x': /* random flag that OSF/1 & AIX mailx passes */ 11760Sstevel@tonic-gate break; 11770Sstevel@tonic-gate #endif /* defined(__osf__) || defined(_AIX3) */ 11780Sstevel@tonic-gate #if defined(sony_news) 11790Sstevel@tonic-gate case 'E': 11800Sstevel@tonic-gate case 'J': /* ignore flags for Japanese code conversion 11810Sstevel@tonic-gate implemented on Sony NEWS */ 11820Sstevel@tonic-gate break; 11830Sstevel@tonic-gate #endif /* defined(sony_news) */ 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate default: 11860Sstevel@tonic-gate finis(true, true, EX_USAGE); 11870Sstevel@tonic-gate /* NOTREACHED */ 11880Sstevel@tonic-gate break; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate /* if we've had errors so far, exit now */ 11930Sstevel@tonic-gate if ((ExitStat != EX_OK && OpMode != MD_TEST) || 11940Sstevel@tonic-gate ExitStat == EX_OSERR) 11950Sstevel@tonic-gate { 11960Sstevel@tonic-gate finis(false, true, ExitStat); 11970Sstevel@tonic-gate /* NOTREACHED */ 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate if (bitset(SUBMIT_MTA, SubmitMode)) 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate /* If set daemon_flags on command line, don't reset it */ 12030Sstevel@tonic-gate if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 12040Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 12050Sstevel@tonic-gate macid("{daemon_flags}"), "CC f"); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate else if (OpMode == MD_DELIVER || OpMode == MD_SMTP) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate SubmitMode = SUBMIT_MSA; 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate /* If set daemon_flags on command line, don't reset it */ 12120Sstevel@tonic-gate if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 12130Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 12140Sstevel@tonic-gate macid("{daemon_flags}"), "c u"); 12150Sstevel@tonic-gate } 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate ** Do basic initialization. 12190Sstevel@tonic-gate ** Read system control file. 12200Sstevel@tonic-gate ** Extract special fields for local use. 12210Sstevel@tonic-gate */ 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate #if XDEBUG 12240Sstevel@tonic-gate checkfd012("before readcf"); 12250Sstevel@tonic-gate #endif /* XDEBUG */ 12260Sstevel@tonic-gate vendor_pre_defaults(&BlankEnvelope); 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate readcf(getcfname(OpMode, SubmitMode, cftype, conffile), 12290Sstevel@tonic-gate safecf, &BlankEnvelope); 12300Sstevel@tonic-gate #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 12310Sstevel@tonic-gate ConfigFileRead = true; 12320Sstevel@tonic-gate #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 12330Sstevel@tonic-gate vendor_post_defaults(&BlankEnvelope); 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate /* now we can complain about missing fds */ 12360Sstevel@tonic-gate if (MissingFds != 0 && LogLevel > 8) 12370Sstevel@tonic-gate { 12380Sstevel@tonic-gate char mbuf[MAXLINE]; 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate mbuf[0] = '\0'; 12410Sstevel@tonic-gate if (bitset(1 << STDIN_FILENO, MissingFds)) 12420Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stdin", sizeof mbuf); 12430Sstevel@tonic-gate if (bitset(1 << STDOUT_FILENO, MissingFds)) 12440Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stdout", sizeof mbuf); 12450Sstevel@tonic-gate if (bitset(1 << STDERR_FILENO, MissingFds)) 12460Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stderr", sizeof mbuf); 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate /* Notice: fill_errno is from high above: fill_fd() */ 12490Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 12500Sstevel@tonic-gate "File descriptors missing on startup: %s; %s", 12510Sstevel@tonic-gate &mbuf[2], sm_errstring(fill_errno)); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate /* Remove the ability for a normal user to send signals */ 12550Sstevel@tonic-gate if (RealUid != 0 && RealUid != geteuid()) 12560Sstevel@tonic-gate { 12570Sstevel@tonic-gate uid_t new_uid = geteuid(); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate #if HASSETREUID 12600Sstevel@tonic-gate /* 12610Sstevel@tonic-gate ** Since we can differentiate between uid and euid, 12620Sstevel@tonic-gate ** make the uid a different user so the real user 12630Sstevel@tonic-gate ** can't send signals. However, it doesn't need to be 12640Sstevel@tonic-gate ** root (euid has root). 12650Sstevel@tonic-gate */ 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate if (new_uid == 0) 12680Sstevel@tonic-gate new_uid = DefUid; 12690Sstevel@tonic-gate if (tTd(47, 5)) 12700Sstevel@tonic-gate sm_dprintf("Changing real uid to %d\n", (int) new_uid); 12710Sstevel@tonic-gate if (setreuid(new_uid, geteuid()) < 0) 12720Sstevel@tonic-gate { 12730Sstevel@tonic-gate syserr("main: setreuid(%d, %d) failed", 12740Sstevel@tonic-gate (int) new_uid, (int) geteuid()); 12750Sstevel@tonic-gate finis(false, true, EX_OSERR); 12760Sstevel@tonic-gate /* NOTREACHED */ 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate if (tTd(47, 10)) 12790Sstevel@tonic-gate sm_dprintf("Now running as e/ruid %d:%d\n", 12800Sstevel@tonic-gate (int) geteuid(), (int) getuid()); 12810Sstevel@tonic-gate #else /* HASSETREUID */ 12820Sstevel@tonic-gate /* 12830Sstevel@tonic-gate ** Have to change both effective and real so need to 12840Sstevel@tonic-gate ** change them both to effective to keep privs. 12850Sstevel@tonic-gate */ 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate if (tTd(47, 5)) 12880Sstevel@tonic-gate sm_dprintf("Changing uid to %d\n", (int) new_uid); 12890Sstevel@tonic-gate if (setuid(new_uid) < 0) 12900Sstevel@tonic-gate { 12910Sstevel@tonic-gate syserr("main: setuid(%d) failed", (int) new_uid); 12920Sstevel@tonic-gate finis(false, true, EX_OSERR); 12930Sstevel@tonic-gate /* NOTREACHED */ 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate if (tTd(47, 10)) 12960Sstevel@tonic-gate sm_dprintf("Now running as e/ruid %d:%d\n", 12970Sstevel@tonic-gate (int) geteuid(), (int) getuid()); 12980Sstevel@tonic-gate #endif /* HASSETREUID */ 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate #if NAMED_BIND 13020Sstevel@tonic-gate if (FallbackMX != NULL) 13030Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX); 13040Sstevel@tonic-gate #endif /* NAMED_BIND */ 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER) 13070Sstevel@tonic-gate { 13080Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 13090Sstevel@tonic-gate "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n"); 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)) 13130Sstevel@tonic-gate { 13140Sstevel@tonic-gate usrerr("Mail submission program cannot be used as daemon"); 13150Sstevel@tonic-gate finis(false, true, EX_USAGE); 13160Sstevel@tonic-gate } 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate if (OpMode == MD_DELIVER || OpMode == MD_SMTP || 13190Sstevel@tonic-gate OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP || 13200Sstevel@tonic-gate OpMode == MD_DAEMON || OpMode == MD_FGDAEMON) 13210Sstevel@tonic-gate makeworkgroups(); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* set up the basic signal handlers */ 13240Sstevel@tonic-gate if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN) 13250Sstevel@tonic-gate (void) sm_signal(SIGINT, intsig); 13260Sstevel@tonic-gate (void) sm_signal(SIGTERM, intsig); 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate /* Enforce use of local time (null string overrides this) */ 13290Sstevel@tonic-gate if (TimeZoneSpec == NULL) 13300Sstevel@tonic-gate unsetenv("TZ"); 13310Sstevel@tonic-gate else if (TimeZoneSpec[0] != '\0') 13321658Sjbeck sm_setuserenv("TZ", TimeZoneSpec); 13330Sstevel@tonic-gate else 13341658Sjbeck sm_setuserenv("TZ", NULL); 13350Sstevel@tonic-gate tzset(); 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate /* initialize mailbox database */ 13380Sstevel@tonic-gate i = sm_mbdb_initialize(Mbdb); 13390Sstevel@tonic-gate if (i != EX_OK) 13400Sstevel@tonic-gate { 13410Sstevel@tonic-gate usrerr("Can't initialize mailbox database \"%s\": %s", 13420Sstevel@tonic-gate Mbdb, sm_strexit(i)); 13430Sstevel@tonic-gate ExitStat = i; 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate /* avoid denial-of-service attacks */ 13470Sstevel@tonic-gate resetlimits(); 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate if (OpMode == MD_TEST) 13500Sstevel@tonic-gate { 13510Sstevel@tonic-gate /* can't be done after readcf if RunAs* is used */ 13520Sstevel@tonic-gate dp = drop_privileges(true); 13530Sstevel@tonic-gate if (dp != EX_OK) 13540Sstevel@tonic-gate { 13550Sstevel@tonic-gate finis(false, true, dp); 13560Sstevel@tonic-gate /* NOTREACHED */ 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 13600Sstevel@tonic-gate { 13610Sstevel@tonic-gate /* drop privileges -- daemon mode done after socket/bind */ 13620Sstevel@tonic-gate dp = drop_privileges(false); 13630Sstevel@tonic-gate setstat(dp); 13640Sstevel@tonic-gate if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0)) 13650Sstevel@tonic-gate { 13660Sstevel@tonic-gate usrerr("Mail submission program must have RunAsUser set to non root user"); 13670Sstevel@tonic-gate finis(false, true, EX_CONFIG); 13680Sstevel@tonic-gate /* NOTREACHED */ 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate #if NAMED_BIND 13730Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 13740Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 13750Sstevel@tonic-gate #endif /* NAMED_BIND */ 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate ** Find our real host name for future logging. 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate authinfo = getauthinfo(STDIN_FILENO, &forged); 13820Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate /* suppress error printing if errors mailed back or whatever */ 13850Sstevel@tonic-gate if (BlankEnvelope.e_errormode != EM_PRINT) 13860Sstevel@tonic-gate HoldErrs = true; 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate /* set up the $=m class now, after .cf has a chance to redefine $m */ 13890Sstevel@tonic-gate expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope); 13900Sstevel@tonic-gate if (jbuf[0] != '\0') 13910Sstevel@tonic-gate setclass('m', jbuf); 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate /* probe interfaces and locate any additional names */ 13940Sstevel@tonic-gate if (DontProbeInterfaces != DPI_PROBENONE) 13950Sstevel@tonic-gate load_if_names(); 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate if (tTd(0, 10)) 13980Sstevel@tonic-gate { 13990Sstevel@tonic-gate char pidpath[MAXPATHLEN]; 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate /* Now we know which .cf file we use */ 14020Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (selected)\n", 14030Sstevel@tonic-gate getcfname(OpMode, SubmitMode, cftype, conffile)); 14040Sstevel@tonic-gate expand(PidFile, pidpath, sizeof pidpath, &BlankEnvelope); 14050Sstevel@tonic-gate sm_dprintf(" Pid file:\t%s (selected)\n", pidpath); 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate if (tTd(0, 1)) 14090Sstevel@tonic-gate { 14100Sstevel@tonic-gate sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 14110Sstevel@tonic-gate sm_dprintf("\n (short domain name) $w = "); 14120Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('w', &BlankEnvelope)); 14130Sstevel@tonic-gate sm_dprintf("\n (canonical domain name) $j = "); 14140Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('j', &BlankEnvelope)); 14150Sstevel@tonic-gate sm_dprintf("\n (subdomain name) $m = "); 14160Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('m', &BlankEnvelope)); 14170Sstevel@tonic-gate sm_dprintf("\n (node name) $k = "); 14180Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('k', &BlankEnvelope)); 14190Sstevel@tonic-gate sm_dprintf("\n========================================================\n\n"); 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate /* 14230Sstevel@tonic-gate ** Do more command line checking -- these are things that 14240Sstevel@tonic-gate ** have to modify the results of reading the config file. 14250Sstevel@tonic-gate */ 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate /* process authorization warnings from command line */ 14280Sstevel@tonic-gate if (warn_C_flag) 14290Sstevel@tonic-gate auth_warning(&BlankEnvelope, "Processed by %s with -C %s", 14300Sstevel@tonic-gate RealUserName, conffile); 14310Sstevel@tonic-gate if (Warn_Q_option && !wordinclass(RealUserName, 't')) 14320Sstevel@tonic-gate auth_warning(&BlankEnvelope, "Processed from queue %s", 14330Sstevel@tonic-gate QueueDir); 14340Sstevel@tonic-gate if (sysloglabel != NULL && !wordinclass(RealUserName, 't') && 14350Sstevel@tonic-gate RealUid != 0 && RealUid != TrustedUid && LogLevel > 1) 14360Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label", 14370Sstevel@tonic-gate (int) RealUid); 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate /* check body type for legality */ 14400Sstevel@tonic-gate i = check_bodytype(BlankEnvelope.e_bodytype); 14410Sstevel@tonic-gate if (i == BODYTYPE_ILLEGAL) 14420Sstevel@tonic-gate { 14430Sstevel@tonic-gate usrerr("Illegal body type %s", BlankEnvelope.e_bodytype); 14440Sstevel@tonic-gate BlankEnvelope.e_bodytype = NULL; 14450Sstevel@tonic-gate } 14460Sstevel@tonic-gate else if (i != BODYTYPE_NONE) 14470Sstevel@tonic-gate SevenBitInput = (i == BODYTYPE_7BIT); 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate /* tweak default DSN notifications */ 14500Sstevel@tonic-gate if (DefaultNotify == 0) 14510Sstevel@tonic-gate DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* check for sane configuration level */ 14540Sstevel@tonic-gate if (ConfigLevel > MAXCONFIGLEVEL) 14550Sstevel@tonic-gate { 14560Sstevel@tonic-gate syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 14570Sstevel@tonic-gate ConfigLevel, Version, MAXCONFIGLEVEL); 14580Sstevel@tonic-gate } 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate /* need MCI cache to have persistence */ 14610Sstevel@tonic-gate if (HostStatDir != NULL && MaxMciCache == 0) 14620Sstevel@tonic-gate { 14630Sstevel@tonic-gate HostStatDir = NULL; 14640Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 14650Sstevel@tonic-gate "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate /* need HostStatusDir in order to have SingleThreadDelivery */ 14690Sstevel@tonic-gate if (SingleThreadDelivery && HostStatDir == NULL) 14700Sstevel@tonic-gate { 14710Sstevel@tonic-gate SingleThreadDelivery = false; 14720Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 14730Sstevel@tonic-gate "Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 14740Sstevel@tonic-gate } 14750Sstevel@tonic-gate 14761658Sjbeck #if _FFR_MEMSTAT 14771658Sjbeck j = sm_memstat_open(); 14781658Sjbeck if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4) 14791658Sjbeck { 14801658Sjbeck sm_syslog(LOG_WARNING, NOQID, 14811658Sjbeck "cannot get memory statistics, settings ignored, error=%d" 14821658Sjbeck , j); 14831658Sjbeck } 14841658Sjbeck #endif /* _FFR_MEMSTAT */ 14851658Sjbeck 14860Sstevel@tonic-gate /* check for permissions */ 14870Sstevel@tonic-gate if (RealUid != 0 && 14880Sstevel@tonic-gate RealUid != TrustedUid) 14890Sstevel@tonic-gate { 14900Sstevel@tonic-gate char *action = NULL; 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate switch (OpMode) 14930Sstevel@tonic-gate { 14940Sstevel@tonic-gate case MD_QUEUERUN: 14950Sstevel@tonic-gate if (quarantining != NULL) 14960Sstevel@tonic-gate action = "quarantine jobs"; 14970Sstevel@tonic-gate else 14980Sstevel@tonic-gate { 14990Sstevel@tonic-gate /* Normal users can do a single queue run */ 15000Sstevel@tonic-gate if (QueueIntvl == 0) 15010Sstevel@tonic-gate break; 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate /* but not persistent queue runners */ 15050Sstevel@tonic-gate if (action == NULL) 15060Sstevel@tonic-gate action = "start a queue runner daemon"; 15070Sstevel@tonic-gate /* FALLTHROUGH */ 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate case MD_PURGESTAT: 15100Sstevel@tonic-gate if (action == NULL) 15110Sstevel@tonic-gate action = "purge host status"; 15120Sstevel@tonic-gate /* FALLTHROUGH */ 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate case MD_DAEMON: 15150Sstevel@tonic-gate case MD_FGDAEMON: 15160Sstevel@tonic-gate if (action == NULL) 15170Sstevel@tonic-gate action = "run daemon"; 15180Sstevel@tonic-gate 15190Sstevel@tonic-gate if (tTd(65, 1)) 15200Sstevel@tonic-gate sm_dprintf("Deny user %d attempt to %s\n", 15210Sstevel@tonic-gate (int) RealUid, action); 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate if (LogLevel > 1) 15240Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 15250Sstevel@tonic-gate "user %d attempted to %s", 15260Sstevel@tonic-gate (int) RealUid, action); 15270Sstevel@tonic-gate HoldErrs = false; 15280Sstevel@tonic-gate usrerr("Permission denied (real uid not trusted)"); 15290Sstevel@tonic-gate finis(false, true, EX_USAGE); 15300Sstevel@tonic-gate /* NOTREACHED */ 15310Sstevel@tonic-gate break; 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate case MD_VERIFY: 15340Sstevel@tonic-gate if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags)) 15350Sstevel@tonic-gate { 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate ** If -bv and RestrictExpand, 15380Sstevel@tonic-gate ** drop privs to prevent normal 15390Sstevel@tonic-gate ** users from reading private 15400Sstevel@tonic-gate ** aliases/forwards/:include:s 15410Sstevel@tonic-gate */ 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate if (tTd(65, 1)) 15440Sstevel@tonic-gate sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n", 15450Sstevel@tonic-gate (int) RealUid); 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate dp = drop_privileges(true); 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate /* Fake address safety */ 15500Sstevel@tonic-gate if (tTd(65, 1)) 15510Sstevel@tonic-gate sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n"); 15520Sstevel@tonic-gate setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail); 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate if (dp != EX_OK) 15550Sstevel@tonic-gate { 15560Sstevel@tonic-gate if (tTd(65, 1)) 15570Sstevel@tonic-gate sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n", 15580Sstevel@tonic-gate (int) RealUid); 15590Sstevel@tonic-gate CurEnv->e_id = NULL; 15600Sstevel@tonic-gate finis(true, true, dp); 15610Sstevel@tonic-gate /* NOTREACHED */ 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate break; 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate case MD_TEST: 15670Sstevel@tonic-gate case MD_PRINT: 15680Sstevel@tonic-gate case MD_PRINTNQE: 15690Sstevel@tonic-gate case MD_FREEZE: 15700Sstevel@tonic-gate case MD_HOSTSTAT: 15710Sstevel@tonic-gate /* Nothing special to check */ 15720Sstevel@tonic-gate break; 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate case MD_INITALIAS: 15750Sstevel@tonic-gate if (!wordinclass(RealUserName, 't')) 15760Sstevel@tonic-gate { 15770Sstevel@tonic-gate if (tTd(65, 1)) 15780Sstevel@tonic-gate sm_dprintf("Deny user %d attempt to rebuild the alias map\n", 15790Sstevel@tonic-gate (int) RealUid); 15800Sstevel@tonic-gate if (LogLevel > 1) 15810Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 15820Sstevel@tonic-gate "user %d attempted to rebuild the alias map", 15830Sstevel@tonic-gate (int) RealUid); 15840Sstevel@tonic-gate HoldErrs = false; 15850Sstevel@tonic-gate usrerr("Permission denied (real uid not trusted)"); 15860Sstevel@tonic-gate finis(false, true, EX_USAGE); 15870Sstevel@tonic-gate /* NOTREACHED */ 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate if (UseMSP) 15900Sstevel@tonic-gate { 15910Sstevel@tonic-gate HoldErrs = false; 15920Sstevel@tonic-gate usrerr("User %d cannot rebuild aliases in mail submission program", 15930Sstevel@tonic-gate (int) RealUid); 15940Sstevel@tonic-gate finis(false, true, EX_USAGE); 15950Sstevel@tonic-gate /* NOTREACHED */ 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate /* FALLTHROUGH */ 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate default: 16000Sstevel@tonic-gate if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) && 16010Sstevel@tonic-gate Verbose != 0) 16020Sstevel@tonic-gate { 16030Sstevel@tonic-gate /* 16040Sstevel@tonic-gate ** If -v and RestrictExpand, reset 16050Sstevel@tonic-gate ** Verbose to prevent normal users 16060Sstevel@tonic-gate ** from seeing the expansion of 16070Sstevel@tonic-gate ** aliases/forwards/:include:s 16080Sstevel@tonic-gate */ 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate if (tTd(65, 1)) 16110Sstevel@tonic-gate sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n", 16120Sstevel@tonic-gate (int) RealUid); 16130Sstevel@tonic-gate Verbose = 0; 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate break; 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate } 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate if (MeToo) 16200Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_METOO; 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate switch (OpMode) 16230Sstevel@tonic-gate { 16240Sstevel@tonic-gate case MD_TEST: 16250Sstevel@tonic-gate /* don't have persistent host status in test mode */ 16260Sstevel@tonic-gate HostStatDir = NULL; 16270Sstevel@tonic-gate if (Verbose == 0) 16280Sstevel@tonic-gate Verbose = 2; 16290Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 16300Sstevel@tonic-gate HoldErrs = false; 16310Sstevel@tonic-gate break; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate case MD_VERIFY: 16340Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 16350Sstevel@tonic-gate HoldErrs = false; 16360Sstevel@tonic-gate /* arrange to exit cleanly on hangup signal */ 16370Sstevel@tonic-gate if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 16380Sstevel@tonic-gate (void) sm_signal(SIGHUP, intsig); 16390Sstevel@tonic-gate if (geteuid() != 0) 16400Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 16410Sstevel@tonic-gate "Notice: -bv may give misleading output for non-privileged user\n"); 16420Sstevel@tonic-gate break; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate case MD_FGDAEMON: 16450Sstevel@tonic-gate run_in_foreground = true; 16460Sstevel@tonic-gate set_op_mode(MD_DAEMON); 16470Sstevel@tonic-gate /* FALLTHROUGH */ 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate case MD_DAEMON: 16500Sstevel@tonic-gate vendor_daemon_setup(&BlankEnvelope); 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate /* remove things that don't make sense in daemon mode */ 16530Sstevel@tonic-gate FullName = NULL; 16540Sstevel@tonic-gate GrabTo = false; 16550Sstevel@tonic-gate 16560Sstevel@tonic-gate /* arrange to restart on hangup signal */ 16570Sstevel@tonic-gate if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 16580Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 16590Sstevel@tonic-gate "daemon invoked without full pathname; kill -1 won't work"); 16600Sstevel@tonic-gate break; 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate case MD_INITALIAS: 16630Sstevel@tonic-gate Verbose = 2; 16640Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 16650Sstevel@tonic-gate HoldErrs = false; 16660Sstevel@tonic-gate /* FALLTHROUGH */ 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate default: 16690Sstevel@tonic-gate /* arrange to exit cleanly on hangup signal */ 16700Sstevel@tonic-gate if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 16710Sstevel@tonic-gate (void) sm_signal(SIGHUP, intsig); 16720Sstevel@tonic-gate break; 16730Sstevel@tonic-gate } 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate /* special considerations for FullName */ 16760Sstevel@tonic-gate if (FullName != NULL) 16770Sstevel@tonic-gate { 16780Sstevel@tonic-gate char *full = NULL; 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate /* full names can't have newlines */ 16810Sstevel@tonic-gate if (strchr(FullName, '\n') != NULL) 16820Sstevel@tonic-gate { 16830Sstevel@tonic-gate full = newstr(denlstring(FullName, true, true)); 16840Sstevel@tonic-gate FullName = full; 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* check for characters that may have to be quoted */ 16880Sstevel@tonic-gate if (!rfc822_string(FullName)) 16890Sstevel@tonic-gate { 16900Sstevel@tonic-gate /* 16910Sstevel@tonic-gate ** Quote a full name with special characters 16920Sstevel@tonic-gate ** as a comment so crackaddr() doesn't destroy 16930Sstevel@tonic-gate ** the name portion of the address. 16940Sstevel@tonic-gate */ 16950Sstevel@tonic-gate 16960Sstevel@tonic-gate FullName = addquotes(FullName, NULL); 16970Sstevel@tonic-gate if (full != NULL) 16980Sstevel@tonic-gate sm_free(full); /* XXX */ 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate } 17010Sstevel@tonic-gate 17020Sstevel@tonic-gate /* do heuristic mode adjustment */ 17030Sstevel@tonic-gate if (Verbose) 17040Sstevel@tonic-gate { 17050Sstevel@tonic-gate /* turn off noconnect option */ 17060Sstevel@tonic-gate setoption('c', "F", true, false, &BlankEnvelope); 17070Sstevel@tonic-gate 17080Sstevel@tonic-gate /* turn on interactive delivery */ 17090Sstevel@tonic-gate setoption('d', "", true, false, &BlankEnvelope); 17100Sstevel@tonic-gate } 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate #ifdef VENDOR_CODE 17130Sstevel@tonic-gate /* check for vendor mismatch */ 17140Sstevel@tonic-gate if (VendorCode != VENDOR_CODE) 17150Sstevel@tonic-gate { 17160Sstevel@tonic-gate message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 17170Sstevel@tonic-gate getvendor(VENDOR_CODE), getvendor(VendorCode)); 17180Sstevel@tonic-gate } 17190Sstevel@tonic-gate #endif /* VENDOR_CODE */ 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate /* check for out of date configuration level */ 17220Sstevel@tonic-gate if (ConfigLevel < MAXCONFIGLEVEL) 17230Sstevel@tonic-gate { 17240Sstevel@tonic-gate message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 17250Sstevel@tonic-gate Version, MAXCONFIGLEVEL, ConfigLevel); 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate if (ConfigLevel < 3) 17290Sstevel@tonic-gate UseErrorsTo = true; 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate /* set options that were previous macros */ 17320Sstevel@tonic-gate if (SmtpGreeting == NULL) 17330Sstevel@tonic-gate { 17340Sstevel@tonic-gate if (ConfigLevel < 7 && 17350Sstevel@tonic-gate (p = macvalue('e', &BlankEnvelope)) != NULL) 17360Sstevel@tonic-gate SmtpGreeting = newstr(p); 17370Sstevel@tonic-gate else 17380Sstevel@tonic-gate SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 17390Sstevel@tonic-gate } 17400Sstevel@tonic-gate if (UnixFromLine == NULL) 17410Sstevel@tonic-gate { 17420Sstevel@tonic-gate if (ConfigLevel < 7 && 17430Sstevel@tonic-gate (p = macvalue('l', &BlankEnvelope)) != NULL) 17440Sstevel@tonic-gate UnixFromLine = newstr(p); 17450Sstevel@tonic-gate else 17460Sstevel@tonic-gate UnixFromLine = "From \201g \201d"; 17470Sstevel@tonic-gate } 17480Sstevel@tonic-gate SmtpError[0] = '\0'; 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate /* our name for SMTP codes */ 17510Sstevel@tonic-gate expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope); 17520Sstevel@tonic-gate if (jbuf[0] == '\0') 17530Sstevel@tonic-gate PSTRSET(MyHostName, "localhost"); 17540Sstevel@tonic-gate else 17550Sstevel@tonic-gate PSTRSET(MyHostName, jbuf); 17560Sstevel@tonic-gate if (strchr(MyHostName, '.') == NULL) 17570Sstevel@tonic-gate message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?", 17580Sstevel@tonic-gate MyHostName); 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate /* make certain that this name is part of the $=w class */ 17610Sstevel@tonic-gate setclass('w', MyHostName); 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate /* fill in the structure of the *default* queue */ 17640Sstevel@tonic-gate st = stab("mqueue", ST_QUEUE, ST_FIND); 17650Sstevel@tonic-gate if (st == NULL) 17660Sstevel@tonic-gate syserr("No default queue (mqueue) defined"); 17670Sstevel@tonic-gate else 17680Sstevel@tonic-gate set_def_queueval(st->s_quegrp, true); 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate /* the indices of built-in mailers */ 17710Sstevel@tonic-gate st = stab("local", ST_MAILER, ST_FIND); 17720Sstevel@tonic-gate if (st != NULL) 17730Sstevel@tonic-gate LocalMailer = st->s_mailer; 17740Sstevel@tonic-gate else if (OpMode != MD_TEST || !warn_C_flag) 17750Sstevel@tonic-gate syserr("No local mailer defined"); 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate st = stab("prog", ST_MAILER, ST_FIND); 17780Sstevel@tonic-gate if (st == NULL) 17790Sstevel@tonic-gate syserr("No prog mailer defined"); 17800Sstevel@tonic-gate else 17810Sstevel@tonic-gate { 17820Sstevel@tonic-gate ProgMailer = st->s_mailer; 17830Sstevel@tonic-gate clrbitn(M_MUSER, ProgMailer->m_flags); 17840Sstevel@tonic-gate } 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate st = stab("*file*", ST_MAILER, ST_FIND); 17870Sstevel@tonic-gate if (st == NULL) 17880Sstevel@tonic-gate syserr("No *file* mailer defined"); 17890Sstevel@tonic-gate else 17900Sstevel@tonic-gate { 17910Sstevel@tonic-gate FileMailer = st->s_mailer; 17920Sstevel@tonic-gate clrbitn(M_MUSER, FileMailer->m_flags); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate st = stab("*include*", ST_MAILER, ST_FIND); 17960Sstevel@tonic-gate if (st == NULL) 17970Sstevel@tonic-gate syserr("No *include* mailer defined"); 17980Sstevel@tonic-gate else 17990Sstevel@tonic-gate InclMailer = st->s_mailer; 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate if (ConfigLevel < 6) 18020Sstevel@tonic-gate { 18030Sstevel@tonic-gate /* heuristic tweaking of local mailer for back compat */ 18040Sstevel@tonic-gate if (LocalMailer != NULL) 18050Sstevel@tonic-gate { 18060Sstevel@tonic-gate setbitn(M_ALIASABLE, LocalMailer->m_flags); 18070Sstevel@tonic-gate setbitn(M_HASPWENT, LocalMailer->m_flags); 18080Sstevel@tonic-gate setbitn(M_TRYRULESET5, LocalMailer->m_flags); 18090Sstevel@tonic-gate setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 18100Sstevel@tonic-gate setbitn(M_CHECKPROG, LocalMailer->m_flags); 18110Sstevel@tonic-gate setbitn(M_CHECKFILE, LocalMailer->m_flags); 18120Sstevel@tonic-gate setbitn(M_CHECKUDB, LocalMailer->m_flags); 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate if (ProgMailer != NULL) 18150Sstevel@tonic-gate setbitn(M_RUNASRCPT, ProgMailer->m_flags); 18160Sstevel@tonic-gate if (FileMailer != NULL) 18170Sstevel@tonic-gate setbitn(M_RUNASRCPT, FileMailer->m_flags); 18180Sstevel@tonic-gate } 18190Sstevel@tonic-gate if (ConfigLevel < 7) 18200Sstevel@tonic-gate { 18210Sstevel@tonic-gate if (LocalMailer != NULL) 18220Sstevel@tonic-gate setbitn(M_VRFY250, LocalMailer->m_flags); 18230Sstevel@tonic-gate if (ProgMailer != NULL) 18240Sstevel@tonic-gate setbitn(M_VRFY250, ProgMailer->m_flags); 18250Sstevel@tonic-gate if (FileMailer != NULL) 18260Sstevel@tonic-gate setbitn(M_VRFY250, FileMailer->m_flags); 18270Sstevel@tonic-gate } 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate /* MIME Content-Types that cannot be transfer encoded */ 18300Sstevel@tonic-gate setclass('n', "multipart/signed"); 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate /* MIME message/xxx subtypes that can be treated as messages */ 18330Sstevel@tonic-gate setclass('s', "rfc822"); 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate /* MIME Content-Transfer-Encodings that can be encoded */ 18360Sstevel@tonic-gate setclass('e', "7bit"); 18370Sstevel@tonic-gate setclass('e', "8bit"); 18380Sstevel@tonic-gate setclass('e', "binary"); 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate #ifdef USE_B_CLASS 18410Sstevel@tonic-gate /* MIME Content-Types that should be treated as binary */ 18420Sstevel@tonic-gate setclass('b', "image"); 18430Sstevel@tonic-gate setclass('b', "audio"); 18440Sstevel@tonic-gate setclass('b', "video"); 18450Sstevel@tonic-gate setclass('b', "application/octet-stream"); 18460Sstevel@tonic-gate #endif /* USE_B_CLASS */ 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate /* MIME headers which have fields to check for overflow */ 18490Sstevel@tonic-gate setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition"); 18500Sstevel@tonic-gate setclass(macid("{checkMIMEFieldHeaders}"), "content-type"); 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate /* MIME headers to check for length overflow */ 18530Sstevel@tonic-gate setclass(macid("{checkMIMETextHeaders}"), "content-description"); 18540Sstevel@tonic-gate 18550Sstevel@tonic-gate /* MIME headers to check for overflow and rebalance */ 18560Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-disposition"); 18570Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-id"); 18580Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding"); 18590Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-type"); 18600Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "mime-version"); 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate /* Macros to save in the queue file -- don't remove any */ 18630Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "r"); 18640Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "s"); 18650Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "_"); 18660Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "{if_addr}"); 18670Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "{daemon_flags}"); 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate /* operate in queue directory */ 18700Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0') 18710Sstevel@tonic-gate { 18720Sstevel@tonic-gate if (OpMode != MD_TEST) 18730Sstevel@tonic-gate { 18740Sstevel@tonic-gate syserr("QueueDirectory (Q) option must be set"); 18750Sstevel@tonic-gate ExitStat = EX_CONFIG; 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate else 18790Sstevel@tonic-gate { 18800Sstevel@tonic-gate if (OpMode != MD_TEST) 18810Sstevel@tonic-gate setup_queues(OpMode == MD_DAEMON); 18820Sstevel@tonic-gate } 18830Sstevel@tonic-gate 18840Sstevel@tonic-gate /* check host status directory for validity */ 18850Sstevel@tonic-gate if (HostStatDir != NULL && !path_is_dir(HostStatDir, false)) 18860Sstevel@tonic-gate { 18870Sstevel@tonic-gate /* cannot use this value */ 18880Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 18890Sstevel@tonic-gate "Warning: Cannot use HostStatusDirectory = %s: %s\n", 18900Sstevel@tonic-gate HostStatDir, sm_errstring(errno)); 18910Sstevel@tonic-gate HostStatDir = NULL; 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate if (OpMode == MD_QUEUERUN && 18950Sstevel@tonic-gate RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 18960Sstevel@tonic-gate { 18970Sstevel@tonic-gate struct stat stbuf; 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate /* check to see if we own the queue directory */ 19000Sstevel@tonic-gate if (stat(".", &stbuf) < 0) 19010Sstevel@tonic-gate syserr("main: cannot stat %s", QueueDir); 19020Sstevel@tonic-gate if (stbuf.st_uid != RealUid) 19030Sstevel@tonic-gate { 19040Sstevel@tonic-gate /* nope, really a botch */ 19050Sstevel@tonic-gate HoldErrs = false; 19060Sstevel@tonic-gate usrerr("You do not have permission to process the queue"); 19070Sstevel@tonic-gate finis(false, true, EX_NOPERM); 19080Sstevel@tonic-gate /* NOTREACHED */ 19090Sstevel@tonic-gate } 19100Sstevel@tonic-gate } 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate #if MILTER 19130Sstevel@tonic-gate /* sanity checks on milter filters */ 19140Sstevel@tonic-gate if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 19150Sstevel@tonic-gate { 19160Sstevel@tonic-gate milter_config(InputFilterList, InputFilters, MAXFILTERS); 19170Sstevel@tonic-gate setup_daemon_milters(); 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate #endif /* MILTER */ 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate /* Convert queuegroup string to qgrp number */ 19220Sstevel@tonic-gate if (queuegroup != NULL) 19230Sstevel@tonic-gate { 19240Sstevel@tonic-gate qgrp = name2qid(queuegroup); 19250Sstevel@tonic-gate if (qgrp == NOQGRP) 19260Sstevel@tonic-gate { 19270Sstevel@tonic-gate HoldErrs = false; 19280Sstevel@tonic-gate usrerr("Queue group %s unknown", queuegroup); 19290Sstevel@tonic-gate finis(false, true, ExitStat); 19300Sstevel@tonic-gate /* NOTREACHED */ 19310Sstevel@tonic-gate } 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate /* if we've had errors so far, exit now */ 19350Sstevel@tonic-gate if (ExitStat != EX_OK && OpMode != MD_TEST) 19360Sstevel@tonic-gate { 19370Sstevel@tonic-gate finis(false, true, ExitStat); 19380Sstevel@tonic-gate /* NOTREACHED */ 19390Sstevel@tonic-gate } 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate #if SASL 19420Sstevel@tonic-gate /* sendmail specific SASL initialization */ 19430Sstevel@tonic-gate sm_sasl_init(); 19440Sstevel@tonic-gate #endif /* SASL */ 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate #if XDEBUG 19470Sstevel@tonic-gate checkfd012("before main() initmaps"); 19480Sstevel@tonic-gate #endif /* XDEBUG */ 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate ** Do operation-mode-dependent initialization. 19520Sstevel@tonic-gate */ 19530Sstevel@tonic-gate 19540Sstevel@tonic-gate switch (OpMode) 19550Sstevel@tonic-gate { 19560Sstevel@tonic-gate case MD_PRINT: 19570Sstevel@tonic-gate /* print the queue */ 19580Sstevel@tonic-gate HoldErrs = false; 19590Sstevel@tonic-gate dropenvelope(&BlankEnvelope, true, false); 19600Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 19610Sstevel@tonic-gate if (qgrp != NOQGRP) 19620Sstevel@tonic-gate { 19630Sstevel@tonic-gate int j; 19640Sstevel@tonic-gate 19650Sstevel@tonic-gate /* Selecting a particular queue group to run */ 19660Sstevel@tonic-gate for (j = 0; j < Queue[qgrp]->qg_numqueues; j++) 19670Sstevel@tonic-gate { 19680Sstevel@tonic-gate if (StopRequest) 19690Sstevel@tonic-gate stop_sendmail(); 19700Sstevel@tonic-gate (void) print_single_queue(qgrp, j); 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate finis(false, true, EX_OK); 19730Sstevel@tonic-gate /* NOTREACHED */ 19740Sstevel@tonic-gate } 19750Sstevel@tonic-gate printqueue(); 19760Sstevel@tonic-gate finis(false, true, EX_OK); 19770Sstevel@tonic-gate /* NOTREACHED */ 19780Sstevel@tonic-gate break; 19790Sstevel@tonic-gate 19800Sstevel@tonic-gate case MD_PRINTNQE: 19810Sstevel@tonic-gate /* print number of entries in queue */ 19820Sstevel@tonic-gate dropenvelope(&BlankEnvelope, true, false); 19830Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 19840Sstevel@tonic-gate printnqe(smioout, NULL); 19850Sstevel@tonic-gate finis(false, true, EX_OK); 19860Sstevel@tonic-gate /* NOTREACHED */ 19870Sstevel@tonic-gate break; 19880Sstevel@tonic-gate 19890Sstevel@tonic-gate case MD_QUEUERUN: 19900Sstevel@tonic-gate /* only handle quarantining here */ 19910Sstevel@tonic-gate if (quarantining == NULL) 19920Sstevel@tonic-gate break; 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE && 19950Sstevel@tonic-gate QueueMode != QM_NORMAL) 19960Sstevel@tonic-gate { 19970Sstevel@tonic-gate HoldErrs = false; 19980Sstevel@tonic-gate usrerr("Can not use -Q with -q%c", QueueMode); 19990Sstevel@tonic-gate ExitStat = EX_USAGE; 20000Sstevel@tonic-gate finis(false, true, ExitStat); 20010Sstevel@tonic-gate /* NOTREACHED */ 20020Sstevel@tonic-gate } 20030Sstevel@tonic-gate quarantine_queue(quarantining, qgrp); 20040Sstevel@tonic-gate finis(false, true, EX_OK); 20050Sstevel@tonic-gate break; 20060Sstevel@tonic-gate 20070Sstevel@tonic-gate case MD_HOSTSTAT: 20080Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 20090Sstevel@tonic-gate (void) mci_traverse_persistent(mci_print_persistent, NULL); 20100Sstevel@tonic-gate finis(false, true, EX_OK); 20110Sstevel@tonic-gate /* NOTREACHED */ 20120Sstevel@tonic-gate break; 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate case MD_PURGESTAT: 20150Sstevel@tonic-gate (void) mci_traverse_persistent(mci_purge_persistent, NULL); 20160Sstevel@tonic-gate finis(false, true, EX_OK); 20170Sstevel@tonic-gate /* NOTREACHED */ 20180Sstevel@tonic-gate break; 20190Sstevel@tonic-gate 20200Sstevel@tonic-gate case MD_INITALIAS: 20210Sstevel@tonic-gate /* initialize maps */ 20220Sstevel@tonic-gate initmaps(); 20230Sstevel@tonic-gate finis(false, true, ExitStat); 20240Sstevel@tonic-gate /* NOTREACHED */ 20250Sstevel@tonic-gate break; 20260Sstevel@tonic-gate 20270Sstevel@tonic-gate case MD_SMTP: 20280Sstevel@tonic-gate case MD_DAEMON: 20290Sstevel@tonic-gate /* reset DSN parameters */ 20300Sstevel@tonic-gate DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 20310Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 20320Sstevel@tonic-gate macid("{dsn_notify}"), NULL); 20330Sstevel@tonic-gate BlankEnvelope.e_envid = NULL; 20340Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 20350Sstevel@tonic-gate macid("{dsn_envid}"), NULL); 20360Sstevel@tonic-gate BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 20370Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 20380Sstevel@tonic-gate macid("{dsn_ret}"), NULL); 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate /* don't open maps for daemon -- done below in child */ 20410Sstevel@tonic-gate break; 20420Sstevel@tonic-gate } 20430Sstevel@tonic-gate 20440Sstevel@tonic-gate if (tTd(0, 15)) 20450Sstevel@tonic-gate { 20460Sstevel@tonic-gate /* print configuration table (or at least part of it) */ 20470Sstevel@tonic-gate if (tTd(0, 90)) 20480Sstevel@tonic-gate printrules(); 20490Sstevel@tonic-gate for (i = 0; i < MAXMAILERS; i++) 20500Sstevel@tonic-gate { 20510Sstevel@tonic-gate if (Mailer[i] != NULL) 20520Sstevel@tonic-gate printmailer(sm_debug_file(), Mailer[i]); 20530Sstevel@tonic-gate } 20540Sstevel@tonic-gate } 20550Sstevel@tonic-gate 20560Sstevel@tonic-gate /* 20570Sstevel@tonic-gate ** Switch to the main envelope. 20580Sstevel@tonic-gate */ 20590Sstevel@tonic-gate 20600Sstevel@tonic-gate CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope, 20610Sstevel@tonic-gate sm_rpool_new_x(NULL)); 20620Sstevel@tonic-gate MainEnvelope.e_flags = BlankEnvelope.e_flags; 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate /* 20650Sstevel@tonic-gate ** If test mode, read addresses from stdin and process. 20660Sstevel@tonic-gate */ 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate if (OpMode == MD_TEST) 20690Sstevel@tonic-gate { 20700Sstevel@tonic-gate if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL))) 20710Sstevel@tonic-gate Verbose = 2; 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate if (Verbose) 20740Sstevel@tonic-gate { 20750Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 20760Sstevel@tonic-gate "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 20770Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 20780Sstevel@tonic-gate "Enter <ruleset> <address>\n"); 20790Sstevel@tonic-gate } 20800Sstevel@tonic-gate macdefine(&(MainEnvelope.e_macro), A_PERM, 20810Sstevel@tonic-gate macid("{addr_type}"), "e r"); 20820Sstevel@tonic-gate for (;;) 20830Sstevel@tonic-gate { 20840Sstevel@tonic-gate SM_TRY 20850Sstevel@tonic-gate { 20860Sstevel@tonic-gate (void) sm_signal(SIGINT, intindebug); 20870Sstevel@tonic-gate (void) sm_releasesignal(SIGINT); 20880Sstevel@tonic-gate if (Verbose == 2) 20890Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 20900Sstevel@tonic-gate SM_TIME_DEFAULT, 20910Sstevel@tonic-gate "> "); 20920Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 20930Sstevel@tonic-gate if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, 20940Sstevel@tonic-gate sizeof buf) == NULL) 20950Sstevel@tonic-gate testmodeline("/quit", &MainEnvelope); 20960Sstevel@tonic-gate p = strchr(buf, '\n'); 20970Sstevel@tonic-gate if (p != NULL) 20980Sstevel@tonic-gate *p = '\0'; 20990Sstevel@tonic-gate if (Verbose < 2) 21000Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 21010Sstevel@tonic-gate SM_TIME_DEFAULT, 21020Sstevel@tonic-gate "> %s\n", buf); 21030Sstevel@tonic-gate testmodeline(buf, &MainEnvelope); 21040Sstevel@tonic-gate } 21050Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 21060Sstevel@tonic-gate { 21070Sstevel@tonic-gate /* 21080Sstevel@tonic-gate ** 8.10 just prints \n on interrupt. 21090Sstevel@tonic-gate ** I'm printing the exception here in case 21100Sstevel@tonic-gate ** sendmail is extended to raise additional 21110Sstevel@tonic-gate ** exceptions in this context. 21120Sstevel@tonic-gate */ 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 21150Sstevel@tonic-gate "\n"); 21160Sstevel@tonic-gate sm_exc_print(exc, smioout); 21170Sstevel@tonic-gate } 21180Sstevel@tonic-gate SM_END_TRY 21190Sstevel@tonic-gate } 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate #if STARTTLS 21230Sstevel@tonic-gate tls_ok = true; 21240Sstevel@tonic-gate if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER) 21250Sstevel@tonic-gate { 21260Sstevel@tonic-gate /* check whether STARTTLS is turned off for the client */ 21270Sstevel@tonic-gate if (chkclientmodifiers(D_NOTLS)) 21280Sstevel@tonic-gate tls_ok = false; 21290Sstevel@tonic-gate } 21300Sstevel@tonic-gate else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON || 21310Sstevel@tonic-gate OpMode == MD_SMTP) 21320Sstevel@tonic-gate { 21330Sstevel@tonic-gate /* check whether STARTTLS is turned off for the server */ 21340Sstevel@tonic-gate if (chkdaemonmodifiers(D_NOTLS)) 21350Sstevel@tonic-gate tls_ok = false; 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate else /* other modes don't need STARTTLS */ 21380Sstevel@tonic-gate tls_ok = false; 21390Sstevel@tonic-gate 21400Sstevel@tonic-gate if (tls_ok) 21410Sstevel@tonic-gate { 21420Sstevel@tonic-gate /* basic TLS initialization */ 21430Sstevel@tonic-gate tls_ok = init_tls_library(); 21440Sstevel@tonic-gate } 21450Sstevel@tonic-gate 21460Sstevel@tonic-gate if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)) 21470Sstevel@tonic-gate { 21480Sstevel@tonic-gate /* disable TLS for client */ 21490Sstevel@tonic-gate setclttls(false); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate #endif /* STARTTLS */ 21520Sstevel@tonic-gate 21530Sstevel@tonic-gate /* 21540Sstevel@tonic-gate ** If collecting stuff from the queue, go start doing that. 21550Sstevel@tonic-gate */ 21560Sstevel@tonic-gate 21570Sstevel@tonic-gate if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 21580Sstevel@tonic-gate { 21590Sstevel@tonic-gate pid_t pid = -1; 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate #if STARTTLS 21620Sstevel@tonic-gate /* init TLS for client, ignore result for now */ 21630Sstevel@tonic-gate (void) initclttls(tls_ok); 21640Sstevel@tonic-gate #endif /* STARTTLS */ 21650Sstevel@tonic-gate 21660Sstevel@tonic-gate /* 21670Sstevel@tonic-gate ** The parent process of the caller of runqueue() needs 21680Sstevel@tonic-gate ** to stay around for a possible SIGTERM. The SIGTERM will 21690Sstevel@tonic-gate ** tell this process that all of the queue runners children 21700Sstevel@tonic-gate ** need to be sent SIGTERM as well. At the same time, we 21710Sstevel@tonic-gate ** want to return control to the command line. So we do an 21720Sstevel@tonic-gate ** extra fork(). 21730Sstevel@tonic-gate */ 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate if (Verbose || foregroundqueue || (pid = fork()) <= 0) 21760Sstevel@tonic-gate { 21770Sstevel@tonic-gate /* 21780Sstevel@tonic-gate ** If the fork() failed we should still try to do 21790Sstevel@tonic-gate ** the queue run. If it succeeded then the child 21800Sstevel@tonic-gate ** is going to start the run and wait for all 21810Sstevel@tonic-gate ** of the children to finish. 21820Sstevel@tonic-gate */ 21830Sstevel@tonic-gate 21840Sstevel@tonic-gate if (pid == 0) 21850Sstevel@tonic-gate { 21860Sstevel@tonic-gate /* Reset global flags */ 21870Sstevel@tonic-gate RestartRequest = NULL; 21880Sstevel@tonic-gate ShutdownRequest = NULL; 21890Sstevel@tonic-gate PendingSignal = 0; 21900Sstevel@tonic-gate 21910Sstevel@tonic-gate /* disconnect from terminal */ 21920Sstevel@tonic-gate disconnect(2, CurEnv); 21930Sstevel@tonic-gate } 21940Sstevel@tonic-gate 21950Sstevel@tonic-gate CurrentPid = getpid(); 21960Sstevel@tonic-gate if (qgrp != NOQGRP) 21970Sstevel@tonic-gate { 21980Sstevel@tonic-gate int rwgflags = RWG_NONE; 21990Sstevel@tonic-gate 22000Sstevel@tonic-gate /* 22010Sstevel@tonic-gate ** To run a specific queue group mark it to 22020Sstevel@tonic-gate ** be run, select the work group it's in and 22030Sstevel@tonic-gate ** increment the work counter. 22040Sstevel@tonic-gate */ 22050Sstevel@tonic-gate 22060Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; 22070Sstevel@tonic-gate i++) 22080Sstevel@tonic-gate Queue[i]->qg_nextrun = (time_t) -1; 22090Sstevel@tonic-gate Queue[qgrp]->qg_nextrun = 0; 22100Sstevel@tonic-gate if (Verbose) 22110Sstevel@tonic-gate rwgflags |= RWG_VERBOSE; 22120Sstevel@tonic-gate if (queuepersistent) 22130Sstevel@tonic-gate rwgflags |= RWG_PERSISTENT; 22140Sstevel@tonic-gate rwgflags |= RWG_FORCE; 22150Sstevel@tonic-gate (void) run_work_group(Queue[qgrp]->qg_wgrp, 22160Sstevel@tonic-gate rwgflags); 22170Sstevel@tonic-gate } 22180Sstevel@tonic-gate else 22190Sstevel@tonic-gate (void) runqueue(false, Verbose, 22200Sstevel@tonic-gate queuepersistent, true); 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate /* set the title to make it easier to find */ 22230Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "Queue control"); 22240Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 22250Sstevel@tonic-gate while (CurChildren > 0) 22260Sstevel@tonic-gate { 22270Sstevel@tonic-gate int status; 22280Sstevel@tonic-gate pid_t ret; 22290Sstevel@tonic-gate 22300Sstevel@tonic-gate errno = 0; 22310Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 22320Sstevel@tonic-gate { 22330Sstevel@tonic-gate if (errno == ECHILD) 22340Sstevel@tonic-gate { 22350Sstevel@tonic-gate /* 22360Sstevel@tonic-gate ** Oops... something got messed 22370Sstevel@tonic-gate ** up really bad. Waiting for 22380Sstevel@tonic-gate ** non-existent children 22390Sstevel@tonic-gate ** shouldn't happen. Let's get 22400Sstevel@tonic-gate ** out of here. 22410Sstevel@tonic-gate */ 22420Sstevel@tonic-gate 22430Sstevel@tonic-gate CurChildren = 0; 22440Sstevel@tonic-gate break; 22450Sstevel@tonic-gate } 22460Sstevel@tonic-gate continue; 22470Sstevel@tonic-gate } 22480Sstevel@tonic-gate 22490Sstevel@tonic-gate /* something is really really wrong */ 22500Sstevel@tonic-gate if (errno == ECHILD) 22510Sstevel@tonic-gate { 22520Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 22530Sstevel@tonic-gate "queue control process: lost all children: wait returned ECHILD"); 22540Sstevel@tonic-gate break; 22550Sstevel@tonic-gate } 22560Sstevel@tonic-gate 22570Sstevel@tonic-gate /* Only drop when a child gives status */ 22580Sstevel@tonic-gate if (WIFSTOPPED(status)) 22590Sstevel@tonic-gate continue; 22600Sstevel@tonic-gate 22610Sstevel@tonic-gate proc_list_drop(ret, status, NULL); 22620Sstevel@tonic-gate } 22630Sstevel@tonic-gate } 22640Sstevel@tonic-gate finis(true, true, ExitStat); 22650Sstevel@tonic-gate /* NOTREACHED */ 22660Sstevel@tonic-gate } 22670Sstevel@tonic-gate 22680Sstevel@tonic-gate # if SASL 22690Sstevel@tonic-gate if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 22700Sstevel@tonic-gate { 22710Sstevel@tonic-gate /* check whether AUTH is turned off for the server */ 22720Sstevel@tonic-gate if (!chkdaemonmodifiers(D_NOAUTH) && 22730Sstevel@tonic-gate (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 22740Sstevel@tonic-gate syserr("!sasl_server_init failed! [%s]", 22750Sstevel@tonic-gate sasl_errstring(i, NULL, NULL)); 22760Sstevel@tonic-gate } 22770Sstevel@tonic-gate # endif /* SASL */ 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate if (OpMode == MD_SMTP) 22800Sstevel@tonic-gate { 22810Sstevel@tonic-gate proc_list_add(CurrentPid, "Sendmail SMTP Agent", 22820Sstevel@tonic-gate PROC_DAEMON, 0, -1, NULL); 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate /* clean up background delivery children */ 22850Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 22860Sstevel@tonic-gate } 22870Sstevel@tonic-gate 22880Sstevel@tonic-gate /* 22890Sstevel@tonic-gate ** If a daemon, wait for a request. 22900Sstevel@tonic-gate ** getrequests will always return in a child. 22910Sstevel@tonic-gate ** If we should also be processing the queue, start 22920Sstevel@tonic-gate ** doing it in background. 22930Sstevel@tonic-gate ** We check for any errors that might have happened 22940Sstevel@tonic-gate ** during startup. 22950Sstevel@tonic-gate */ 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate if (OpMode == MD_DAEMON || QueueIntvl > 0) 22980Sstevel@tonic-gate { 22990Sstevel@tonic-gate char dtype[200]; 23000Sstevel@tonic-gate 2301*2526Sjbeck /* avoid cleanup in finis(), DaemonPid will be set below */ 2302*2526Sjbeck DaemonPid = 0; 23030Sstevel@tonic-gate if (!run_in_foreground && !tTd(99, 100)) 23040Sstevel@tonic-gate { 23050Sstevel@tonic-gate /* put us in background */ 23060Sstevel@tonic-gate i = fork(); 23070Sstevel@tonic-gate if (i < 0) 23080Sstevel@tonic-gate syserr("daemon: cannot fork"); 23090Sstevel@tonic-gate if (i != 0) 23100Sstevel@tonic-gate { 23110Sstevel@tonic-gate finis(false, true, EX_OK); 23120Sstevel@tonic-gate /* NOTREACHED */ 23130Sstevel@tonic-gate } 23140Sstevel@tonic-gate 23150Sstevel@tonic-gate /* 23160Sstevel@tonic-gate ** Initialize exception stack and default exception 23170Sstevel@tonic-gate ** handler for child process. 23180Sstevel@tonic-gate */ 23190Sstevel@tonic-gate 23200Sstevel@tonic-gate /* Reset global flags */ 23210Sstevel@tonic-gate RestartRequest = NULL; 23220Sstevel@tonic-gate RestartWorkGroup = false; 23230Sstevel@tonic-gate ShutdownRequest = NULL; 23240Sstevel@tonic-gate PendingSignal = 0; 23250Sstevel@tonic-gate CurrentPid = getpid(); 23260Sstevel@tonic-gate 23270Sstevel@tonic-gate sm_exc_newthread(fatal_error); 23280Sstevel@tonic-gate 23290Sstevel@tonic-gate /* disconnect from our controlling tty */ 23300Sstevel@tonic-gate disconnect(2, &MainEnvelope); 23310Sstevel@tonic-gate } 23320Sstevel@tonic-gate 23330Sstevel@tonic-gate dtype[0] = '\0'; 23340Sstevel@tonic-gate if (OpMode == MD_DAEMON) 2335*2526Sjbeck { 23360Sstevel@tonic-gate (void) sm_strlcat(dtype, "+SMTP", sizeof dtype); 2337*2526Sjbeck DaemonPid = CurrentPid; 2338*2526Sjbeck } 23390Sstevel@tonic-gate if (QueueIntvl > 0) 23400Sstevel@tonic-gate { 23410Sstevel@tonic-gate (void) sm_strlcat2(dtype, 23420Sstevel@tonic-gate queuepersistent 23430Sstevel@tonic-gate ? "+persistent-queueing@" 23440Sstevel@tonic-gate : "+queueing@", 23450Sstevel@tonic-gate pintvl(QueueIntvl, true), 23460Sstevel@tonic-gate sizeof dtype); 23470Sstevel@tonic-gate } 23480Sstevel@tonic-gate if (tTd(0, 1)) 23490Sstevel@tonic-gate (void) sm_strlcat(dtype, "+debugging", sizeof dtype); 23500Sstevel@tonic-gate 23510Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 23520Sstevel@tonic-gate "starting daemon (%s): %s", Version, dtype + 1); 23530Sstevel@tonic-gate #if XLA 23540Sstevel@tonic-gate xla_create_file(); 23550Sstevel@tonic-gate #endif /* XLA */ 23560Sstevel@tonic-gate 23570Sstevel@tonic-gate /* save daemon type in a macro for possible PidFile use */ 23580Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 23590Sstevel@tonic-gate macid("{daemon_info}"), dtype + 1); 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate /* save queue interval in a macro for possible PidFile use */ 23620Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_TEMP, 23630Sstevel@tonic-gate macid("{queue_interval}"), pintvl(QueueIntvl, true)); 23640Sstevel@tonic-gate 23650Sstevel@tonic-gate /* workaround: can't seem to release the signal in the parent */ 23660Sstevel@tonic-gate (void) sm_signal(SIGHUP, sighup); 23670Sstevel@tonic-gate (void) sm_releasesignal(SIGHUP); 23680Sstevel@tonic-gate (void) sm_signal(SIGTERM, sigterm); 23690Sstevel@tonic-gate 23700Sstevel@tonic-gate if (QueueIntvl > 0) 23710Sstevel@tonic-gate { 23720Sstevel@tonic-gate (void) runqueue(true, false, queuepersistent, true); 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate /* 23750Sstevel@tonic-gate ** If queuepersistent but not in daemon mode then 23760Sstevel@tonic-gate ** we're going to do the queue runner monitoring here. 23770Sstevel@tonic-gate ** If in daemon mode then the monitoring will happen 23780Sstevel@tonic-gate ** elsewhere. 23790Sstevel@tonic-gate */ 23800Sstevel@tonic-gate 23810Sstevel@tonic-gate if (OpMode != MD_DAEMON && queuepersistent) 23820Sstevel@tonic-gate { 23830Sstevel@tonic-gate /* 23840Sstevel@tonic-gate ** Write the pid to file 23850Sstevel@tonic-gate ** XXX Overwrites sendmail.pid 23860Sstevel@tonic-gate */ 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate log_sendmail_pid(&MainEnvelope); 23890Sstevel@tonic-gate 23900Sstevel@tonic-gate /* set the title to make it easier to find */ 23910Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "Queue control"); 23920Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 23930Sstevel@tonic-gate while (CurChildren > 0) 23940Sstevel@tonic-gate { 23950Sstevel@tonic-gate int status; 23960Sstevel@tonic-gate pid_t ret; 23970Sstevel@tonic-gate int group; 23980Sstevel@tonic-gate 23990Sstevel@tonic-gate CHECK_RESTART; 24000Sstevel@tonic-gate errno = 0; 24010Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 24020Sstevel@tonic-gate { 24030Sstevel@tonic-gate /* 24040Sstevel@tonic-gate ** Waiting for non-existent 24050Sstevel@tonic-gate ** children shouldn't happen. 24060Sstevel@tonic-gate ** Let's get out of here if 24070Sstevel@tonic-gate ** it occurs. 24080Sstevel@tonic-gate */ 24090Sstevel@tonic-gate 24100Sstevel@tonic-gate if (errno == ECHILD) 24110Sstevel@tonic-gate { 24120Sstevel@tonic-gate CurChildren = 0; 24130Sstevel@tonic-gate break; 24140Sstevel@tonic-gate } 24150Sstevel@tonic-gate continue; 24160Sstevel@tonic-gate } 24170Sstevel@tonic-gate 24180Sstevel@tonic-gate /* something is really really wrong */ 24190Sstevel@tonic-gate if (errno == ECHILD) 24200Sstevel@tonic-gate { 24210Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 24220Sstevel@tonic-gate "persistent queue runner control process: lost all children: wait returned ECHILD"); 24230Sstevel@tonic-gate break; 24240Sstevel@tonic-gate } 24250Sstevel@tonic-gate 24260Sstevel@tonic-gate if (WIFSTOPPED(status)) 24270Sstevel@tonic-gate continue; 24280Sstevel@tonic-gate 24290Sstevel@tonic-gate /* Probe only on a child status */ 24300Sstevel@tonic-gate proc_list_drop(ret, status, &group); 24310Sstevel@tonic-gate 24320Sstevel@tonic-gate if (WIFSIGNALED(status)) 24330Sstevel@tonic-gate { 24340Sstevel@tonic-gate if (WCOREDUMP(status)) 24350Sstevel@tonic-gate { 24360Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 24370Sstevel@tonic-gate "persistent queue runner=%d core dumped, signal=%d", 24380Sstevel@tonic-gate group, WTERMSIG(status)); 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate /* don't restart this */ 24410Sstevel@tonic-gate mark_work_group_restart( 24420Sstevel@tonic-gate group, -1); 24430Sstevel@tonic-gate continue; 24440Sstevel@tonic-gate } 24450Sstevel@tonic-gate 24460Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 24470Sstevel@tonic-gate "persistent queue runner=%d died, signal=%d", 24480Sstevel@tonic-gate group, WTERMSIG(status)); 24490Sstevel@tonic-gate } 24500Sstevel@tonic-gate 24510Sstevel@tonic-gate /* 24520Sstevel@tonic-gate ** When debugging active, don't 24530Sstevel@tonic-gate ** restart the persistent queues. 24540Sstevel@tonic-gate ** But do log this as info. 24550Sstevel@tonic-gate */ 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate if (sm_debug_active(&DebugNoPRestart, 24580Sstevel@tonic-gate 1)) 24590Sstevel@tonic-gate { 24600Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 24610Sstevel@tonic-gate "persistent queue runner=%d, exited", 24620Sstevel@tonic-gate group); 24630Sstevel@tonic-gate mark_work_group_restart(group, 24640Sstevel@tonic-gate -1); 24650Sstevel@tonic-gate } 24660Sstevel@tonic-gate } 24670Sstevel@tonic-gate finis(true, true, ExitStat); 24680Sstevel@tonic-gate /* NOTREACHED */ 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate 24710Sstevel@tonic-gate if (OpMode != MD_DAEMON) 24720Sstevel@tonic-gate { 24730Sstevel@tonic-gate char qtype[200]; 24740Sstevel@tonic-gate 24750Sstevel@tonic-gate /* 24760Sstevel@tonic-gate ** Write the pid to file 24770Sstevel@tonic-gate ** XXX Overwrites sendmail.pid 24780Sstevel@tonic-gate */ 24790Sstevel@tonic-gate 24800Sstevel@tonic-gate log_sendmail_pid(&MainEnvelope); 24810Sstevel@tonic-gate 24820Sstevel@tonic-gate /* set the title to make it easier to find */ 24830Sstevel@tonic-gate qtype[0] = '\0'; 24840Sstevel@tonic-gate (void) sm_strlcpyn(qtype, sizeof qtype, 4, 24850Sstevel@tonic-gate "Queue runner@", 24860Sstevel@tonic-gate pintvl(QueueIntvl, true), 24870Sstevel@tonic-gate " for ", 24880Sstevel@tonic-gate QueueDir); 24890Sstevel@tonic-gate sm_setproctitle(true, CurEnv, qtype); 24900Sstevel@tonic-gate for (;;) 24910Sstevel@tonic-gate { 24920Sstevel@tonic-gate (void) pause(); 24930Sstevel@tonic-gate 24940Sstevel@tonic-gate CHECK_RESTART; 24950Sstevel@tonic-gate 24960Sstevel@tonic-gate if (doqueuerun()) 24970Sstevel@tonic-gate (void) runqueue(true, false, 24980Sstevel@tonic-gate false, false); 24990Sstevel@tonic-gate } 25000Sstevel@tonic-gate } 25010Sstevel@tonic-gate } 25020Sstevel@tonic-gate dropenvelope(&MainEnvelope, true, false); 25030Sstevel@tonic-gate 25040Sstevel@tonic-gate #if STARTTLS 25050Sstevel@tonic-gate /* init TLS for server, ignore result for now */ 25060Sstevel@tonic-gate (void) initsrvtls(tls_ok); 25070Sstevel@tonic-gate #endif /* STARTTLS */ 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate nextreq: 25100Sstevel@tonic-gate p_flags = getrequests(&MainEnvelope); 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate /* drop privileges */ 25130Sstevel@tonic-gate (void) drop_privileges(false); 25140Sstevel@tonic-gate 25150Sstevel@tonic-gate /* 25160Sstevel@tonic-gate ** Get authentication data 25170Sstevel@tonic-gate ** Set _ macro in BlankEnvelope before calling newenvelope(). 25180Sstevel@tonic-gate */ 25190Sstevel@tonic-gate 25200Sstevel@tonic-gate authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 25210Sstevel@tonic-gate NULL), &forged); 25220Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 25230Sstevel@tonic-gate 25240Sstevel@tonic-gate /* at this point we are in a child: reset state */ 25250Sstevel@tonic-gate sm_rpool_free(MainEnvelope.e_rpool); 25260Sstevel@tonic-gate (void) newenvelope(&MainEnvelope, &MainEnvelope, 25270Sstevel@tonic-gate sm_rpool_new_x(NULL)); 25280Sstevel@tonic-gate } 25290Sstevel@tonic-gate 25300Sstevel@tonic-gate if (LogLevel > 9) 25310Sstevel@tonic-gate { 25320Sstevel@tonic-gate /* log connection information */ 25330Sstevel@tonic-gate sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo); 25340Sstevel@tonic-gate } 25350Sstevel@tonic-gate 25360Sstevel@tonic-gate /* 25370Sstevel@tonic-gate ** If running SMTP protocol, start collecting and executing 25380Sstevel@tonic-gate ** commands. This will never return. 25390Sstevel@tonic-gate */ 25400Sstevel@tonic-gate 25410Sstevel@tonic-gate if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 25420Sstevel@tonic-gate { 25430Sstevel@tonic-gate char pbuf[20]; 25440Sstevel@tonic-gate 25450Sstevel@tonic-gate /* 25460Sstevel@tonic-gate ** Save some macros for check_* rulesets. 25470Sstevel@tonic-gate */ 25480Sstevel@tonic-gate 25490Sstevel@tonic-gate if (forged) 25500Sstevel@tonic-gate { 25510Sstevel@tonic-gate char ipbuf[103]; 25520Sstevel@tonic-gate 25530Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 25540Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 25550Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 25560Sstevel@tonic-gate macid("{client_name}"), ipbuf); 25570Sstevel@tonic-gate } 25580Sstevel@tonic-gate else 25590Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 25600Sstevel@tonic-gate macid("{client_name}"), RealHostName); 25610Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 25620Sstevel@tonic-gate macid("{client_ptr}"), RealHostName); 25630Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 25640Sstevel@tonic-gate macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 25650Sstevel@tonic-gate sm_getla(); 25660Sstevel@tonic-gate 25670Sstevel@tonic-gate switch (RealHostAddr.sa.sa_family) 25680Sstevel@tonic-gate { 25690Sstevel@tonic-gate #if NETINET 25700Sstevel@tonic-gate case AF_INET: 25710Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 25720Sstevel@tonic-gate RealHostAddr.sin.sin_port); 25730Sstevel@tonic-gate break; 25740Sstevel@tonic-gate #endif /* NETINET */ 25750Sstevel@tonic-gate #if NETINET6 25760Sstevel@tonic-gate case AF_INET6: 25770Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 25780Sstevel@tonic-gate RealHostAddr.sin6.sin6_port); 25790Sstevel@tonic-gate break; 25800Sstevel@tonic-gate #endif /* NETINET6 */ 25810Sstevel@tonic-gate default: 25820Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "0"); 25830Sstevel@tonic-gate break; 25840Sstevel@tonic-gate } 25850Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 25860Sstevel@tonic-gate macid("{client_port}"), pbuf); 25870Sstevel@tonic-gate 25880Sstevel@tonic-gate if (OpMode == MD_DAEMON) 25890Sstevel@tonic-gate { 25900Sstevel@tonic-gate /* validate the connection */ 25910Sstevel@tonic-gate HoldErrs = true; 25920Sstevel@tonic-gate nullserver = validate_connection(&RealHostAddr, 25930Sstevel@tonic-gate macvalue(macid("{client_name}"), 25940Sstevel@tonic-gate &MainEnvelope), 25950Sstevel@tonic-gate &MainEnvelope); 25960Sstevel@tonic-gate HoldErrs = false; 25970Sstevel@tonic-gate } 25980Sstevel@tonic-gate else if (p_flags == NULL) 25990Sstevel@tonic-gate { 26000Sstevel@tonic-gate p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); 26010Sstevel@tonic-gate clrbitmap(p_flags); 26020Sstevel@tonic-gate } 26030Sstevel@tonic-gate #if STARTTLS 26040Sstevel@tonic-gate if (OpMode == MD_SMTP) 26050Sstevel@tonic-gate (void) initsrvtls(tls_ok); 26060Sstevel@tonic-gate #endif /* STARTTLS */ 26070Sstevel@tonic-gate 26080Sstevel@tonic-gate /* turn off profiling */ 26090Sstevel@tonic-gate SM_PROF(1); 26100Sstevel@tonic-gate smtp(nullserver, *p_flags, &MainEnvelope); 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate if (tTd(93, 100)) 26130Sstevel@tonic-gate { 26140Sstevel@tonic-gate /* turn off profiling */ 26150Sstevel@tonic-gate SM_PROF(0); 26160Sstevel@tonic-gate if (OpMode == MD_DAEMON) 26170Sstevel@tonic-gate goto nextreq; 26180Sstevel@tonic-gate } 26190Sstevel@tonic-gate } 26200Sstevel@tonic-gate 26210Sstevel@tonic-gate sm_rpool_free(MainEnvelope.e_rpool); 26220Sstevel@tonic-gate clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 26230Sstevel@tonic-gate if (OpMode == MD_VERIFY) 26240Sstevel@tonic-gate { 26250Sstevel@tonic-gate set_delivery_mode(SM_VERIFY, &MainEnvelope); 26260Sstevel@tonic-gate PostMasterCopy = NULL; 26270Sstevel@tonic-gate } 26280Sstevel@tonic-gate else 26290Sstevel@tonic-gate { 26300Sstevel@tonic-gate /* interactive -- all errors are global */ 26310Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 26320Sstevel@tonic-gate } 26330Sstevel@tonic-gate 26340Sstevel@tonic-gate /* 26350Sstevel@tonic-gate ** Do basic system initialization and set the sender 26360Sstevel@tonic-gate */ 26370Sstevel@tonic-gate 26380Sstevel@tonic-gate initsys(&MainEnvelope); 26390Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 26400Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 26410Sstevel@tonic-gate setsender(from, &MainEnvelope, NULL, '\0', false); 26420Sstevel@tonic-gate if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 26430Sstevel@tonic-gate (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 26440Sstevel@tonic-gate strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 26450Sstevel@tonic-gate { 26460Sstevel@tonic-gate auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 26470Sstevel@tonic-gate RealUserName, from, warn_f_flag); 26480Sstevel@tonic-gate #if SASL 26490Sstevel@tonic-gate auth = false; 26500Sstevel@tonic-gate #endif /* SASL */ 26510Sstevel@tonic-gate } 26520Sstevel@tonic-gate if (auth) 26530Sstevel@tonic-gate { 26540Sstevel@tonic-gate char *fv; 26550Sstevel@tonic-gate 26560Sstevel@tonic-gate /* set the initial sender for AUTH= to $f@$j */ 26570Sstevel@tonic-gate fv = macvalue('f', &MainEnvelope); 26580Sstevel@tonic-gate if (fv == NULL || *fv == '\0') 26590Sstevel@tonic-gate MainEnvelope.e_auth_param = NULL; 26600Sstevel@tonic-gate else 26610Sstevel@tonic-gate { 26620Sstevel@tonic-gate if (strchr(fv, '@') == NULL) 26630Sstevel@tonic-gate { 26640Sstevel@tonic-gate i = strlen(fv) + strlen(macvalue('j', 26650Sstevel@tonic-gate &MainEnvelope)) + 2; 26660Sstevel@tonic-gate p = sm_malloc_x(i); 26670Sstevel@tonic-gate (void) sm_strlcpyn(p, i, 3, fv, "@", 26680Sstevel@tonic-gate macvalue('j', 26690Sstevel@tonic-gate &MainEnvelope)); 26700Sstevel@tonic-gate } 26710Sstevel@tonic-gate else 26720Sstevel@tonic-gate p = sm_strdup_x(fv); 26730Sstevel@tonic-gate MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 26740Sstevel@tonic-gate xtextify(p, "=")); 26750Sstevel@tonic-gate sm_free(p); /* XXX */ 26760Sstevel@tonic-gate } 26770Sstevel@tonic-gate } 26780Sstevel@tonic-gate if (macvalue('s', &MainEnvelope) == NULL) 26790Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 26800Sstevel@tonic-gate 26810Sstevel@tonic-gate av = argv + optind; 26820Sstevel@tonic-gate if (*av == NULL && !GrabTo) 26830Sstevel@tonic-gate { 26840Sstevel@tonic-gate MainEnvelope.e_to = NULL; 26850Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS; 26860Sstevel@tonic-gate HoldErrs = false; 26870Sstevel@tonic-gate SuperSafe = SAFE_NO; 26880Sstevel@tonic-gate usrerr("Recipient names must be specified"); 26890Sstevel@tonic-gate 26900Sstevel@tonic-gate /* collect body for UUCP return */ 26910Sstevel@tonic-gate if (OpMode != MD_VERIFY) 26920Sstevel@tonic-gate collect(InChannel, false, NULL, &MainEnvelope, true); 26930Sstevel@tonic-gate finis(true, true, EX_USAGE); 26940Sstevel@tonic-gate /* NOTREACHED */ 26950Sstevel@tonic-gate } 26960Sstevel@tonic-gate 26970Sstevel@tonic-gate /* 26980Sstevel@tonic-gate ** Scan argv and deliver the message to everyone. 26990Sstevel@tonic-gate */ 27000Sstevel@tonic-gate 27010Sstevel@tonic-gate save_val = LogUsrErrs; 27020Sstevel@tonic-gate LogUsrErrs = true; 27030Sstevel@tonic-gate sendtoargv(av, &MainEnvelope); 27040Sstevel@tonic-gate LogUsrErrs = save_val; 27050Sstevel@tonic-gate 27060Sstevel@tonic-gate /* if we have had errors sofar, arrange a meaningful exit stat */ 27070Sstevel@tonic-gate if (Errors > 0 && ExitStat == EX_OK) 27080Sstevel@tonic-gate ExitStat = EX_USAGE; 27090Sstevel@tonic-gate 27100Sstevel@tonic-gate #if _FFR_FIX_DASHT 27110Sstevel@tonic-gate /* 27120Sstevel@tonic-gate ** If using -t, force not sending to argv recipients, even 27130Sstevel@tonic-gate ** if they are mentioned in the headers. 27140Sstevel@tonic-gate */ 27150Sstevel@tonic-gate 27160Sstevel@tonic-gate if (GrabTo) 27170Sstevel@tonic-gate { 27180Sstevel@tonic-gate ADDRESS *q; 27190Sstevel@tonic-gate 27200Sstevel@tonic-gate for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 27210Sstevel@tonic-gate q->q_state = QS_REMOVED; 27220Sstevel@tonic-gate } 27230Sstevel@tonic-gate #endif /* _FFR_FIX_DASHT */ 27240Sstevel@tonic-gate 27250Sstevel@tonic-gate /* 27260Sstevel@tonic-gate ** Read the input mail. 27270Sstevel@tonic-gate */ 27280Sstevel@tonic-gate 27290Sstevel@tonic-gate MainEnvelope.e_to = NULL; 27300Sstevel@tonic-gate if (OpMode != MD_VERIFY || GrabTo) 27310Sstevel@tonic-gate { 27320Sstevel@tonic-gate int savederrors; 27330Sstevel@tonic-gate unsigned long savedflags; 27340Sstevel@tonic-gate 27350Sstevel@tonic-gate /* 27360Sstevel@tonic-gate ** workaround for compiler warning on Irix: 27370Sstevel@tonic-gate ** do not initialize variable in the definition, but 27380Sstevel@tonic-gate ** later on: 27390Sstevel@tonic-gate ** warning(1548): transfer of control bypasses 27400Sstevel@tonic-gate ** initialization of: 27410Sstevel@tonic-gate ** variable "savederrors" (declared at line 2570) 27420Sstevel@tonic-gate ** variable "savedflags" (declared at line 2571) 27430Sstevel@tonic-gate ** goto giveup; 27440Sstevel@tonic-gate */ 27450Sstevel@tonic-gate 27460Sstevel@tonic-gate savederrors = Errors; 27470Sstevel@tonic-gate savedflags = MainEnvelope.e_flags & EF_FATALERRS; 27480Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS; 27490Sstevel@tonic-gate MainEnvelope.e_flags &= ~EF_FATALERRS; 27500Sstevel@tonic-gate Errors = 0; 27510Sstevel@tonic-gate buffer_errors(); 27520Sstevel@tonic-gate collect(InChannel, false, NULL, &MainEnvelope, true); 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate /* header checks failed */ 27550Sstevel@tonic-gate if (Errors > 0) 27560Sstevel@tonic-gate { 27570Sstevel@tonic-gate giveup: 27580Sstevel@tonic-gate if (!GrabTo) 27590Sstevel@tonic-gate { 27600Sstevel@tonic-gate /* Log who the mail would have gone to */ 27610Sstevel@tonic-gate logundelrcpts(&MainEnvelope, 27620Sstevel@tonic-gate MainEnvelope.e_message, 27630Sstevel@tonic-gate 8, false); 27640Sstevel@tonic-gate } 27650Sstevel@tonic-gate flush_errors(true); 27660Sstevel@tonic-gate finis(true, true, ExitStat); 27670Sstevel@tonic-gate /* NOTREACHED */ 27680Sstevel@tonic-gate return -1; 27690Sstevel@tonic-gate } 27700Sstevel@tonic-gate 27710Sstevel@tonic-gate /* bail out if message too large */ 27720Sstevel@tonic-gate if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 27730Sstevel@tonic-gate { 27740Sstevel@tonic-gate finis(true, true, ExitStat != EX_OK ? ExitStat 27750Sstevel@tonic-gate : EX_DATAERR); 27760Sstevel@tonic-gate /* NOTREACHED */ 27770Sstevel@tonic-gate return -1; 27780Sstevel@tonic-gate } 27790Sstevel@tonic-gate 27800Sstevel@tonic-gate /* set message size */ 27810Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%ld", 27820Sstevel@tonic-gate MainEnvelope.e_msgsize); 27830Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_TEMP, 27840Sstevel@tonic-gate macid("{msg_size}"), buf); 27850Sstevel@tonic-gate 27860Sstevel@tonic-gate Errors = savederrors; 27870Sstevel@tonic-gate MainEnvelope.e_flags |= savedflags; 27880Sstevel@tonic-gate } 27890Sstevel@tonic-gate errno = 0; 27900Sstevel@tonic-gate 27910Sstevel@tonic-gate if (tTd(1, 1)) 27920Sstevel@tonic-gate sm_dprintf("From person = \"%s\"\n", 27930Sstevel@tonic-gate MainEnvelope.e_from.q_paddr); 27940Sstevel@tonic-gate 27950Sstevel@tonic-gate /* Check if quarantining stats should be updated */ 27960Sstevel@tonic-gate if (MainEnvelope.e_quarmsg != NULL) 27970Sstevel@tonic-gate markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 27980Sstevel@tonic-gate 27990Sstevel@tonic-gate /* 28000Sstevel@tonic-gate ** Actually send everything. 28010Sstevel@tonic-gate ** If verifying, just ack. 28020Sstevel@tonic-gate */ 28030Sstevel@tonic-gate 28040Sstevel@tonic-gate if (Errors == 0) 28050Sstevel@tonic-gate { 28060Sstevel@tonic-gate if (!split_by_recipient(&MainEnvelope) && 28070Sstevel@tonic-gate bitset(EF_FATALERRS, MainEnvelope.e_flags)) 28080Sstevel@tonic-gate goto giveup; 28090Sstevel@tonic-gate } 28100Sstevel@tonic-gate 28110Sstevel@tonic-gate /* make sure we deliver at least the first envelope */ 28120Sstevel@tonic-gate i = FastSplit > 0 ? 0 : -1; 28130Sstevel@tonic-gate for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 28140Sstevel@tonic-gate { 28150Sstevel@tonic-gate ENVELOPE *next; 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate e->e_from.q_state = QS_SENDER; 28180Sstevel@tonic-gate if (tTd(1, 5)) 28190Sstevel@tonic-gate { 28200Sstevel@tonic-gate sm_dprintf("main[%d]: QS_SENDER ", i); 28210Sstevel@tonic-gate printaddr(sm_debug_file(), &e->e_from, false); 28220Sstevel@tonic-gate } 28230Sstevel@tonic-gate e->e_to = NULL; 28240Sstevel@tonic-gate sm_getla(); 28250Sstevel@tonic-gate GrabTo = false; 28260Sstevel@tonic-gate #if NAMED_BIND 28270Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 28280Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 28290Sstevel@tonic-gate #endif /* NAMED_BIND */ 28300Sstevel@tonic-gate next = e->e_sibling; 28310Sstevel@tonic-gate e->e_sibling = NULL; 28320Sstevel@tonic-gate 28330Sstevel@tonic-gate /* after FastSplit envelopes: queue up */ 28340Sstevel@tonic-gate sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 28350Sstevel@tonic-gate e->e_sibling = next; 28360Sstevel@tonic-gate } 28370Sstevel@tonic-gate 28380Sstevel@tonic-gate /* 28390Sstevel@tonic-gate ** All done. 28400Sstevel@tonic-gate ** Don't send return error message if in VERIFY mode. 28410Sstevel@tonic-gate */ 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate finis(true, true, ExitStat); 28440Sstevel@tonic-gate /* NOTREACHED */ 28450Sstevel@tonic-gate return ExitStat; 28460Sstevel@tonic-gate } 28470Sstevel@tonic-gate /* 28480Sstevel@tonic-gate ** STOP_SENDMAIL -- Stop the running program 28490Sstevel@tonic-gate ** 28500Sstevel@tonic-gate ** Parameters: 28510Sstevel@tonic-gate ** none. 28520Sstevel@tonic-gate ** 28530Sstevel@tonic-gate ** Returns: 28540Sstevel@tonic-gate ** none. 28550Sstevel@tonic-gate ** 28560Sstevel@tonic-gate ** Side Effects: 28570Sstevel@tonic-gate ** exits. 28580Sstevel@tonic-gate */ 28590Sstevel@tonic-gate 28600Sstevel@tonic-gate void 28610Sstevel@tonic-gate stop_sendmail() 28620Sstevel@tonic-gate { 28630Sstevel@tonic-gate /* reset uid for process accounting */ 28640Sstevel@tonic-gate endpwent(); 28650Sstevel@tonic-gate (void) setuid(RealUid); 28660Sstevel@tonic-gate exit(EX_OK); 28670Sstevel@tonic-gate } 28680Sstevel@tonic-gate /* 28690Sstevel@tonic-gate ** FINIS -- Clean up and exit. 28700Sstevel@tonic-gate ** 28710Sstevel@tonic-gate ** Parameters: 28720Sstevel@tonic-gate ** drop -- whether or not to drop CurEnv envelope 28730Sstevel@tonic-gate ** cleanup -- call exit() or _exit()? 28740Sstevel@tonic-gate ** exitstat -- exit status to use for exit() call 28750Sstevel@tonic-gate ** 28760Sstevel@tonic-gate ** Returns: 28770Sstevel@tonic-gate ** never 28780Sstevel@tonic-gate ** 28790Sstevel@tonic-gate ** Side Effects: 28800Sstevel@tonic-gate ** exits sendmail 28810Sstevel@tonic-gate */ 28820Sstevel@tonic-gate 28830Sstevel@tonic-gate void 28840Sstevel@tonic-gate finis(drop, cleanup, exitstat) 28850Sstevel@tonic-gate bool drop; 28860Sstevel@tonic-gate bool cleanup; 28870Sstevel@tonic-gate volatile int exitstat; 28880Sstevel@tonic-gate { 28890Sstevel@tonic-gate char pidpath[MAXPATHLEN]; 28902197Sjbeck pid_t pid; 28910Sstevel@tonic-gate 28920Sstevel@tonic-gate /* Still want to process new timeouts added below */ 28930Sstevel@tonic-gate sm_clear_events(); 28940Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM); 28950Sstevel@tonic-gate 28960Sstevel@tonic-gate if (tTd(2, 1)) 28970Sstevel@tonic-gate { 28980Sstevel@tonic-gate sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 28990Sstevel@tonic-gate exitstat, 29000Sstevel@tonic-gate CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 29010Sstevel@tonic-gate printenvflags(CurEnv); 29020Sstevel@tonic-gate } 29030Sstevel@tonic-gate if (tTd(2, 9)) 29040Sstevel@tonic-gate printopenfds(false); 29050Sstevel@tonic-gate 29060Sstevel@tonic-gate SM_TRY 29070Sstevel@tonic-gate /* 29080Sstevel@tonic-gate ** Clean up. This might raise E:mta.quickabort 29090Sstevel@tonic-gate */ 29100Sstevel@tonic-gate 29110Sstevel@tonic-gate /* clean up temp files */ 29120Sstevel@tonic-gate CurEnv->e_to = NULL; 29130Sstevel@tonic-gate if (drop) 29140Sstevel@tonic-gate { 29150Sstevel@tonic-gate if (CurEnv->e_id != NULL) 29160Sstevel@tonic-gate { 29170Sstevel@tonic-gate dropenvelope(CurEnv, true, false); 29180Sstevel@tonic-gate sm_rpool_free(CurEnv->e_rpool); 29190Sstevel@tonic-gate CurEnv->e_rpool = NULL; 2920*2526Sjbeck 2921*2526Sjbeck /* this may have pointed to the rpool */ 2922*2526Sjbeck CurEnv->e_to = NULL; 29230Sstevel@tonic-gate } 29240Sstevel@tonic-gate else 29250Sstevel@tonic-gate poststats(StatFile); 29260Sstevel@tonic-gate } 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate /* flush any cached connections */ 29290Sstevel@tonic-gate mci_flush(true, NULL); 29300Sstevel@tonic-gate 29310Sstevel@tonic-gate /* close maps belonging to this pid */ 29320Sstevel@tonic-gate closemaps(false); 29330Sstevel@tonic-gate 29340Sstevel@tonic-gate #if USERDB 29350Sstevel@tonic-gate /* close UserDatabase */ 29360Sstevel@tonic-gate _udbx_close(); 29370Sstevel@tonic-gate #endif /* USERDB */ 29380Sstevel@tonic-gate 29390Sstevel@tonic-gate #if SASL 29400Sstevel@tonic-gate stop_sasl_client(); 29410Sstevel@tonic-gate #endif /* SASL */ 29420Sstevel@tonic-gate 29430Sstevel@tonic-gate #if XLA 29440Sstevel@tonic-gate /* clean up extended load average stuff */ 29450Sstevel@tonic-gate xla_all_end(); 29460Sstevel@tonic-gate #endif /* XLA */ 29470Sstevel@tonic-gate 29480Sstevel@tonic-gate SM_FINALLY 29490Sstevel@tonic-gate /* 29500Sstevel@tonic-gate ** And exit. 29510Sstevel@tonic-gate */ 29520Sstevel@tonic-gate 29530Sstevel@tonic-gate if (LogLevel > 78) 29540Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 29550Sstevel@tonic-gate (int) CurrentPid); 29560Sstevel@tonic-gate if (exitstat == EX_TEMPFAIL || 29570Sstevel@tonic-gate CurEnv->e_errormode == EM_BERKNET) 29580Sstevel@tonic-gate exitstat = EX_OK; 29590Sstevel@tonic-gate 29600Sstevel@tonic-gate /* XXX clean up queues and related data structures */ 29610Sstevel@tonic-gate cleanup_queues(); 29622197Sjbeck pid = getpid(); 29630Sstevel@tonic-gate #if SM_CONF_SHM 29642197Sjbeck cleanup_shm(DaemonPid == pid); 29650Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 29660Sstevel@tonic-gate 29670Sstevel@tonic-gate /* close locked pid file */ 29680Sstevel@tonic-gate close_sendmail_pid(); 29690Sstevel@tonic-gate 29702197Sjbeck if (DaemonPid == pid || PidFilePid == pid) 29710Sstevel@tonic-gate { 29720Sstevel@tonic-gate /* blow away the pid file */ 29730Sstevel@tonic-gate expand(PidFile, pidpath, sizeof pidpath, CurEnv); 29740Sstevel@tonic-gate (void) unlink(pidpath); 29750Sstevel@tonic-gate } 29760Sstevel@tonic-gate 29770Sstevel@tonic-gate /* reset uid for process accounting */ 29780Sstevel@tonic-gate endpwent(); 29790Sstevel@tonic-gate sm_mbdb_terminate(); 29801658Sjbeck #if _FFR_MEMSTAT 29811658Sjbeck (void) sm_memstat_close(); 29821658Sjbeck #endif /* _FFR_MEMSTAT */ 29830Sstevel@tonic-gate (void) setuid(RealUid); 29840Sstevel@tonic-gate #if SM_HEAP_CHECK 29850Sstevel@tonic-gate /* dump the heap, if we are checking for memory leaks */ 29860Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2)) 29870Sstevel@tonic-gate sm_heap_report(smioout, 29880Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1); 29890Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 29900Sstevel@tonic-gate if (sm_debug_active(&SmXtrapReport, 1)) 29910Sstevel@tonic-gate sm_dprintf("xtrap count = %d\n", SmXtrapCount); 29920Sstevel@tonic-gate if (cleanup) 29930Sstevel@tonic-gate exit(exitstat); 29940Sstevel@tonic-gate else 29950Sstevel@tonic-gate _exit(exitstat); 29960Sstevel@tonic-gate SM_END_TRY 29970Sstevel@tonic-gate } 29980Sstevel@tonic-gate /* 29990Sstevel@tonic-gate ** INTINDEBUG -- signal handler for SIGINT in -bt mode 30000Sstevel@tonic-gate ** 30010Sstevel@tonic-gate ** Parameters: 30020Sstevel@tonic-gate ** sig -- incoming signal. 30030Sstevel@tonic-gate ** 30040Sstevel@tonic-gate ** Returns: 30050Sstevel@tonic-gate ** none. 30060Sstevel@tonic-gate ** 30070Sstevel@tonic-gate ** Side Effects: 30080Sstevel@tonic-gate ** longjmps back to test mode loop. 30090Sstevel@tonic-gate ** 30100Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 30110Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 30120Sstevel@tonic-gate ** DOING. 30130Sstevel@tonic-gate */ 30140Sstevel@tonic-gate 30150Sstevel@tonic-gate /* Type of an exception generated on SIGINT during address test mode. */ 30160Sstevel@tonic-gate static const SM_EXC_TYPE_T EtypeInterrupt = 30170Sstevel@tonic-gate { 30180Sstevel@tonic-gate SmExcTypeMagic, 30190Sstevel@tonic-gate "S:mta.interrupt", 30200Sstevel@tonic-gate "", 30210Sstevel@tonic-gate sm_etype_printf, 30220Sstevel@tonic-gate "interrupt", 30230Sstevel@tonic-gate }; 30240Sstevel@tonic-gate 30250Sstevel@tonic-gate /* ARGSUSED */ 30260Sstevel@tonic-gate static SIGFUNC_DECL 30270Sstevel@tonic-gate intindebug(sig) 30280Sstevel@tonic-gate int sig; 30290Sstevel@tonic-gate { 30300Sstevel@tonic-gate int save_errno = errno; 30310Sstevel@tonic-gate 30320Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, intindebug); 30330Sstevel@tonic-gate errno = save_errno; 30340Sstevel@tonic-gate CHECK_CRITICAL(sig); 30350Sstevel@tonic-gate errno = save_errno; 30360Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeInterrupt); 30370Sstevel@tonic-gate errno = save_errno; 30380Sstevel@tonic-gate return SIGFUNC_RETURN; 30390Sstevel@tonic-gate } 30400Sstevel@tonic-gate /* 30410Sstevel@tonic-gate ** SIGTERM -- SIGTERM handler for the daemon 30420Sstevel@tonic-gate ** 30430Sstevel@tonic-gate ** Parameters: 30440Sstevel@tonic-gate ** sig -- signal number. 30450Sstevel@tonic-gate ** 30460Sstevel@tonic-gate ** Returns: 30470Sstevel@tonic-gate ** none. 30480Sstevel@tonic-gate ** 30490Sstevel@tonic-gate ** Side Effects: 30500Sstevel@tonic-gate ** Sets ShutdownRequest which will hopefully trigger 30510Sstevel@tonic-gate ** the daemon to exit. 30520Sstevel@tonic-gate ** 30530Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 30540Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 30550Sstevel@tonic-gate ** DOING. 30560Sstevel@tonic-gate */ 30570Sstevel@tonic-gate 30580Sstevel@tonic-gate /* ARGSUSED */ 30590Sstevel@tonic-gate static SIGFUNC_DECL 30600Sstevel@tonic-gate sigterm(sig) 30610Sstevel@tonic-gate int sig; 30620Sstevel@tonic-gate { 30630Sstevel@tonic-gate int save_errno = errno; 30640Sstevel@tonic-gate 30650Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigterm); 30660Sstevel@tonic-gate ShutdownRequest = "signal"; 30670Sstevel@tonic-gate errno = save_errno; 30680Sstevel@tonic-gate return SIGFUNC_RETURN; 30690Sstevel@tonic-gate } 30700Sstevel@tonic-gate /* 30710Sstevel@tonic-gate ** SIGHUP -- handle a SIGHUP signal 30720Sstevel@tonic-gate ** 30730Sstevel@tonic-gate ** Parameters: 30740Sstevel@tonic-gate ** sig -- incoming signal. 30750Sstevel@tonic-gate ** 30760Sstevel@tonic-gate ** Returns: 30770Sstevel@tonic-gate ** none. 30780Sstevel@tonic-gate ** 30790Sstevel@tonic-gate ** Side Effects: 30800Sstevel@tonic-gate ** Sets RestartRequest which should cause the daemon 30810Sstevel@tonic-gate ** to restart. 30820Sstevel@tonic-gate ** 30830Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 30840Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 30850Sstevel@tonic-gate ** DOING. 30860Sstevel@tonic-gate */ 30870Sstevel@tonic-gate 30880Sstevel@tonic-gate /* ARGSUSED */ 30890Sstevel@tonic-gate static SIGFUNC_DECL 30900Sstevel@tonic-gate sighup(sig) 30910Sstevel@tonic-gate int sig; 30920Sstevel@tonic-gate { 30930Sstevel@tonic-gate int save_errno = errno; 30940Sstevel@tonic-gate 30950Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sighup); 30960Sstevel@tonic-gate RestartRequest = "signal"; 30970Sstevel@tonic-gate errno = save_errno; 30980Sstevel@tonic-gate return SIGFUNC_RETURN; 30990Sstevel@tonic-gate } 31000Sstevel@tonic-gate /* 31010Sstevel@tonic-gate ** SIGPIPE -- signal handler for SIGPIPE 31020Sstevel@tonic-gate ** 31030Sstevel@tonic-gate ** Parameters: 31040Sstevel@tonic-gate ** sig -- incoming signal. 31050Sstevel@tonic-gate ** 31060Sstevel@tonic-gate ** Returns: 31070Sstevel@tonic-gate ** none. 31080Sstevel@tonic-gate ** 31090Sstevel@tonic-gate ** Side Effects: 31100Sstevel@tonic-gate ** Sets StopRequest which should cause the mailq/hoststatus 31110Sstevel@tonic-gate ** display to stop. 31120Sstevel@tonic-gate ** 31130Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 31140Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 31150Sstevel@tonic-gate ** DOING. 31160Sstevel@tonic-gate */ 31170Sstevel@tonic-gate 31180Sstevel@tonic-gate /* ARGSUSED */ 31190Sstevel@tonic-gate static SIGFUNC_DECL 31200Sstevel@tonic-gate sigpipe(sig) 31210Sstevel@tonic-gate int sig; 31220Sstevel@tonic-gate { 31230Sstevel@tonic-gate int save_errno = errno; 31240Sstevel@tonic-gate 31250Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigpipe); 31260Sstevel@tonic-gate StopRequest = true; 31270Sstevel@tonic-gate errno = save_errno; 31280Sstevel@tonic-gate return SIGFUNC_RETURN; 31290Sstevel@tonic-gate } 31300Sstevel@tonic-gate /* 31310Sstevel@tonic-gate ** INTSIG -- clean up on interrupt 31320Sstevel@tonic-gate ** 31330Sstevel@tonic-gate ** This just arranges to exit. It pessimizes in that it 31340Sstevel@tonic-gate ** may resend a message. 31350Sstevel@tonic-gate ** 31360Sstevel@tonic-gate ** Parameters: 31370Sstevel@tonic-gate ** none. 31380Sstevel@tonic-gate ** 31390Sstevel@tonic-gate ** Returns: 31400Sstevel@tonic-gate ** none. 31410Sstevel@tonic-gate ** 31420Sstevel@tonic-gate ** Side Effects: 31430Sstevel@tonic-gate ** Unlocks the current job. 31440Sstevel@tonic-gate ** 31450Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 31460Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 31470Sstevel@tonic-gate ** DOING. 31480Sstevel@tonic-gate ** 31490Sstevel@tonic-gate ** XXX: More work is needed for this signal handler. 31500Sstevel@tonic-gate */ 31510Sstevel@tonic-gate 31520Sstevel@tonic-gate /* ARGSUSED */ 31530Sstevel@tonic-gate SIGFUNC_DECL 31540Sstevel@tonic-gate intsig(sig) 31550Sstevel@tonic-gate int sig; 31560Sstevel@tonic-gate { 31570Sstevel@tonic-gate bool drop = false; 31580Sstevel@tonic-gate int save_errno = errno; 31590Sstevel@tonic-gate 31600Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, intsig); 31610Sstevel@tonic-gate errno = save_errno; 31620Sstevel@tonic-gate CHECK_CRITICAL(sig); 31630Sstevel@tonic-gate sm_allsignals(true); 31640Sstevel@tonic-gate 31650Sstevel@tonic-gate if (sig != 0 && LogLevel > 79) 31660Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 31670Sstevel@tonic-gate FileName = NULL; 31680Sstevel@tonic-gate 31690Sstevel@tonic-gate /* Clean-up on aborted stdin message submission */ 31700Sstevel@tonic-gate if (CurEnv->e_id != NULL && 31710Sstevel@tonic-gate (OpMode == MD_SMTP || 31720Sstevel@tonic-gate OpMode == MD_DELIVER || 31730Sstevel@tonic-gate OpMode == MD_ARPAFTP)) 31740Sstevel@tonic-gate { 31750Sstevel@tonic-gate register ADDRESS *q; 31760Sstevel@tonic-gate 31770Sstevel@tonic-gate /* don't return an error indication */ 31780Sstevel@tonic-gate CurEnv->e_to = NULL; 31790Sstevel@tonic-gate CurEnv->e_flags &= ~EF_FATALERRS; 31800Sstevel@tonic-gate CurEnv->e_flags |= EF_CLRQUEUE; 31810Sstevel@tonic-gate 31820Sstevel@tonic-gate /* 31830Sstevel@tonic-gate ** Spin through the addresses and 31840Sstevel@tonic-gate ** mark them dead to prevent bounces 31850Sstevel@tonic-gate */ 31860Sstevel@tonic-gate 31870Sstevel@tonic-gate for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 31880Sstevel@tonic-gate q->q_state = QS_DONTSEND; 31890Sstevel@tonic-gate 31900Sstevel@tonic-gate drop = true; 31910Sstevel@tonic-gate } 31920Sstevel@tonic-gate else if (OpMode != MD_TEST) 31930Sstevel@tonic-gate { 31940Sstevel@tonic-gate unlockqueue(CurEnv); 31950Sstevel@tonic-gate } 31960Sstevel@tonic-gate 31970Sstevel@tonic-gate finis(drop, false, EX_OK); 31980Sstevel@tonic-gate /* NOTREACHED */ 31990Sstevel@tonic-gate } 32000Sstevel@tonic-gate /* 32010Sstevel@tonic-gate ** DISCONNECT -- remove our connection with any foreground process 32020Sstevel@tonic-gate ** 32030Sstevel@tonic-gate ** Parameters: 32040Sstevel@tonic-gate ** droplev -- how "deeply" we should drop the line. 32050Sstevel@tonic-gate ** 0 -- ignore signals, mail back errors, make sure 32060Sstevel@tonic-gate ** output goes to stdout. 32070Sstevel@tonic-gate ** 1 -- also, make stdout go to /dev/null. 32080Sstevel@tonic-gate ** 2 -- also, disconnect from controlling terminal 32090Sstevel@tonic-gate ** (only for daemon mode). 32100Sstevel@tonic-gate ** e -- the current envelope. 32110Sstevel@tonic-gate ** 32120Sstevel@tonic-gate ** Returns: 32130Sstevel@tonic-gate ** none 32140Sstevel@tonic-gate ** 32150Sstevel@tonic-gate ** Side Effects: 32160Sstevel@tonic-gate ** Trys to insure that we are immune to vagaries of 32170Sstevel@tonic-gate ** the controlling tty. 32180Sstevel@tonic-gate */ 32190Sstevel@tonic-gate 32200Sstevel@tonic-gate void 32210Sstevel@tonic-gate disconnect(droplev, e) 32220Sstevel@tonic-gate int droplev; 32230Sstevel@tonic-gate register ENVELOPE *e; 32240Sstevel@tonic-gate { 32250Sstevel@tonic-gate int fd; 32260Sstevel@tonic-gate 32270Sstevel@tonic-gate if (tTd(52, 1)) 32280Sstevel@tonic-gate sm_dprintf("disconnect: In %d Out %d, e=%p\n", 32290Sstevel@tonic-gate sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 32300Sstevel@tonic-gate sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e); 32310Sstevel@tonic-gate if (tTd(52, 100)) 32320Sstevel@tonic-gate { 32330Sstevel@tonic-gate sm_dprintf("don't\n"); 32340Sstevel@tonic-gate return; 32350Sstevel@tonic-gate } 32360Sstevel@tonic-gate if (LogLevel > 93) 32370Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 32380Sstevel@tonic-gate "disconnect level %d", 32390Sstevel@tonic-gate droplev); 32400Sstevel@tonic-gate 32410Sstevel@tonic-gate /* be sure we don't get nasty signals */ 32420Sstevel@tonic-gate (void) sm_signal(SIGINT, SIG_IGN); 32430Sstevel@tonic-gate (void) sm_signal(SIGQUIT, SIG_IGN); 32440Sstevel@tonic-gate 32450Sstevel@tonic-gate /* we can't communicate with our caller, so.... */ 32460Sstevel@tonic-gate HoldErrs = true; 32470Sstevel@tonic-gate CurEnv->e_errormode = EM_MAIL; 32480Sstevel@tonic-gate Verbose = 0; 32490Sstevel@tonic-gate DisConnected = true; 32500Sstevel@tonic-gate 32510Sstevel@tonic-gate /* all input from /dev/null */ 32520Sstevel@tonic-gate if (InChannel != smioin) 32530Sstevel@tonic-gate { 32540Sstevel@tonic-gate (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 32550Sstevel@tonic-gate InChannel = smioin; 32560Sstevel@tonic-gate } 32570Sstevel@tonic-gate if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 32580Sstevel@tonic-gate SM_IO_RDONLY, NULL, smioin) == NULL) 32590Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 32600Sstevel@tonic-gate "disconnect: sm_io_reopen(\"%s\") failed: %s", 32610Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 32620Sstevel@tonic-gate 32630Sstevel@tonic-gate /* 32640Sstevel@tonic-gate ** output to the transcript 32650Sstevel@tonic-gate ** We also compare the fd numbers here since OutChannel 32660Sstevel@tonic-gate ** might be a layer on top of smioout due to encryption 32670Sstevel@tonic-gate ** (see sfsasl.c). 32680Sstevel@tonic-gate */ 32690Sstevel@tonic-gate 32700Sstevel@tonic-gate if (OutChannel != smioout && 32710Sstevel@tonic-gate sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 32720Sstevel@tonic-gate sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 32730Sstevel@tonic-gate { 32740Sstevel@tonic-gate (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 32750Sstevel@tonic-gate OutChannel = smioout; 32760Sstevel@tonic-gate 32770Sstevel@tonic-gate #if 0 32780Sstevel@tonic-gate /* 32790Sstevel@tonic-gate ** Has smioout been closed? Reopen it. 32800Sstevel@tonic-gate ** This shouldn't happen anymore, the code is here 32810Sstevel@tonic-gate ** just as a reminder. 32820Sstevel@tonic-gate */ 32830Sstevel@tonic-gate 32840Sstevel@tonic-gate if (smioout->sm_magic == NULL && 32850Sstevel@tonic-gate sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 32860Sstevel@tonic-gate SM_IO_WRONLY, NULL, smioout) == NULL) 32870Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 32880Sstevel@tonic-gate "disconnect: sm_io_reopen(\"%s\") failed: %s", 32890Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 32900Sstevel@tonic-gate #endif /* 0 */ 32910Sstevel@tonic-gate } 32920Sstevel@tonic-gate if (droplev > 0) 32930Sstevel@tonic-gate { 32940Sstevel@tonic-gate fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 32950Sstevel@tonic-gate if (fd == -1) 32962197Sjbeck { 32970Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 32980Sstevel@tonic-gate "disconnect: open(\"%s\") failed: %s", 32990Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 33002197Sjbeck } 33010Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 33022197Sjbeck if (fd >= 0) 33032197Sjbeck { 33042197Sjbeck (void) dup2(fd, STDOUT_FILENO); 33052197Sjbeck (void) dup2(fd, STDERR_FILENO); 33062197Sjbeck (void) close(fd); 33072197Sjbeck } 33080Sstevel@tonic-gate } 33090Sstevel@tonic-gate 33100Sstevel@tonic-gate /* drop our controlling TTY completely if possible */ 33110Sstevel@tonic-gate if (droplev > 1) 33120Sstevel@tonic-gate { 33130Sstevel@tonic-gate (void) setsid(); 33140Sstevel@tonic-gate errno = 0; 33150Sstevel@tonic-gate } 33160Sstevel@tonic-gate 33170Sstevel@tonic-gate #if XDEBUG 33180Sstevel@tonic-gate checkfd012("disconnect"); 33190Sstevel@tonic-gate #endif /* XDEBUG */ 33200Sstevel@tonic-gate 33210Sstevel@tonic-gate if (LogLevel > 71) 33220Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 33230Sstevel@tonic-gate (int) CurrentPid); 33240Sstevel@tonic-gate 33250Sstevel@tonic-gate errno = 0; 33260Sstevel@tonic-gate } 33270Sstevel@tonic-gate 33280Sstevel@tonic-gate static void 33290Sstevel@tonic-gate obsolete(argv) 33300Sstevel@tonic-gate char *argv[]; 33310Sstevel@tonic-gate { 33320Sstevel@tonic-gate register char *ap; 33330Sstevel@tonic-gate register char *op; 33340Sstevel@tonic-gate 33350Sstevel@tonic-gate while ((ap = *++argv) != NULL) 33360Sstevel@tonic-gate { 33370Sstevel@tonic-gate /* Return if "--" or not an option of any form. */ 33380Sstevel@tonic-gate if (ap[0] != '-' || ap[1] == '-') 33390Sstevel@tonic-gate return; 33400Sstevel@tonic-gate 33410Sstevel@tonic-gate /* Don't allow users to use "-Q." or "-Q ." */ 33420Sstevel@tonic-gate if ((ap[1] == 'Q' && ap[2] == '.') || 33430Sstevel@tonic-gate (ap[1] == 'Q' && argv[1] != NULL && 33440Sstevel@tonic-gate argv[1][0] == '.' && argv[1][1] == '\0')) 33450Sstevel@tonic-gate { 33460Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 33470Sstevel@tonic-gate "Can not use -Q.\n"); 33480Sstevel@tonic-gate exit(EX_USAGE); 33490Sstevel@tonic-gate } 33500Sstevel@tonic-gate 33510Sstevel@tonic-gate /* skip over options that do have a value */ 33520Sstevel@tonic-gate op = strchr(OPTIONS, ap[1]); 33530Sstevel@tonic-gate if (op != NULL && *++op == ':' && ap[2] == '\0' && 33540Sstevel@tonic-gate ap[1] != 'd' && 33550Sstevel@tonic-gate #if defined(sony_news) 33560Sstevel@tonic-gate ap[1] != 'E' && ap[1] != 'J' && 33570Sstevel@tonic-gate #endif /* defined(sony_news) */ 33580Sstevel@tonic-gate argv[1] != NULL && argv[1][0] != '-') 33590Sstevel@tonic-gate { 33600Sstevel@tonic-gate argv++; 33610Sstevel@tonic-gate continue; 33620Sstevel@tonic-gate } 33630Sstevel@tonic-gate 33640Sstevel@tonic-gate /* If -C doesn't have an argument, use sendmail.cf. */ 33650Sstevel@tonic-gate #define __DEFPATH "sendmail.cf" 33660Sstevel@tonic-gate if (ap[1] == 'C' && ap[2] == '\0') 33670Sstevel@tonic-gate { 33680Sstevel@tonic-gate *argv = xalloc(sizeof(__DEFPATH) + 2); 33690Sstevel@tonic-gate (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 33700Sstevel@tonic-gate "-C", __DEFPATH); 33710Sstevel@tonic-gate } 33720Sstevel@tonic-gate 33730Sstevel@tonic-gate /* If -q doesn't have an argument, run it once. */ 33740Sstevel@tonic-gate if (ap[1] == 'q' && ap[2] == '\0') 33750Sstevel@tonic-gate *argv = "-q0"; 33760Sstevel@tonic-gate 33770Sstevel@tonic-gate /* If -Q doesn't have an argument, disable quarantining */ 33780Sstevel@tonic-gate if (ap[1] == 'Q' && ap[2] == '\0') 33790Sstevel@tonic-gate *argv = "-Q."; 33800Sstevel@tonic-gate 33810Sstevel@tonic-gate /* if -d doesn't have an argument, use 0-99.1 */ 33820Sstevel@tonic-gate if (ap[1] == 'd' && ap[2] == '\0') 33830Sstevel@tonic-gate *argv = "-d0-99.1"; 33840Sstevel@tonic-gate 33850Sstevel@tonic-gate #if defined(sony_news) 33860Sstevel@tonic-gate /* if -E doesn't have an argument, use -EC */ 33870Sstevel@tonic-gate if (ap[1] == 'E' && ap[2] == '\0') 33880Sstevel@tonic-gate *argv = "-EC"; 33890Sstevel@tonic-gate 33900Sstevel@tonic-gate /* if -J doesn't have an argument, use -JJ */ 33910Sstevel@tonic-gate if (ap[1] == 'J' && ap[2] == '\0') 33920Sstevel@tonic-gate *argv = "-JJ"; 33930Sstevel@tonic-gate #endif /* defined(sony_news) */ 33940Sstevel@tonic-gate } 33950Sstevel@tonic-gate } 33960Sstevel@tonic-gate /* 33970Sstevel@tonic-gate ** AUTH_WARNING -- specify authorization warning 33980Sstevel@tonic-gate ** 33990Sstevel@tonic-gate ** Parameters: 34000Sstevel@tonic-gate ** e -- the current envelope. 34010Sstevel@tonic-gate ** msg -- the text of the message. 34020Sstevel@tonic-gate ** args -- arguments to the message. 34030Sstevel@tonic-gate ** 34040Sstevel@tonic-gate ** Returns: 34050Sstevel@tonic-gate ** none. 34060Sstevel@tonic-gate */ 34070Sstevel@tonic-gate 34080Sstevel@tonic-gate void 34090Sstevel@tonic-gate #ifdef __STDC__ 34100Sstevel@tonic-gate auth_warning(register ENVELOPE *e, const char *msg, ...) 34110Sstevel@tonic-gate #else /* __STDC__ */ 34120Sstevel@tonic-gate auth_warning(e, msg, va_alist) 34130Sstevel@tonic-gate register ENVELOPE *e; 34140Sstevel@tonic-gate const char *msg; 34150Sstevel@tonic-gate va_dcl 34160Sstevel@tonic-gate #endif /* __STDC__ */ 34170Sstevel@tonic-gate { 34180Sstevel@tonic-gate char buf[MAXLINE]; 34190Sstevel@tonic-gate SM_VA_LOCAL_DECL 34200Sstevel@tonic-gate 34210Sstevel@tonic-gate if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 34220Sstevel@tonic-gate { 34230Sstevel@tonic-gate register char *p; 34240Sstevel@tonic-gate static char hostbuf[48]; 34250Sstevel@tonic-gate 34260Sstevel@tonic-gate if (hostbuf[0] == '\0') 34270Sstevel@tonic-gate { 34280Sstevel@tonic-gate struct hostent *hp; 34290Sstevel@tonic-gate 34300Sstevel@tonic-gate hp = myhostname(hostbuf, sizeof hostbuf); 34310Sstevel@tonic-gate #if NETINET6 34320Sstevel@tonic-gate if (hp != NULL) 34330Sstevel@tonic-gate { 34340Sstevel@tonic-gate freehostent(hp); 34350Sstevel@tonic-gate hp = NULL; 34360Sstevel@tonic-gate } 34370Sstevel@tonic-gate #endif /* NETINET6 */ 34380Sstevel@tonic-gate } 34390Sstevel@tonic-gate 34400Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": "); 34410Sstevel@tonic-gate p = &buf[strlen(buf)]; 34420Sstevel@tonic-gate SM_VA_START(ap, msg); 34430Sstevel@tonic-gate (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 34440Sstevel@tonic-gate SM_VA_END(ap); 34450Sstevel@tonic-gate addheader("X-Authentication-Warning", buf, 0, e); 34460Sstevel@tonic-gate if (LogLevel > 3) 34470Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 34480Sstevel@tonic-gate "Authentication-Warning: %.400s", 34490Sstevel@tonic-gate buf); 34500Sstevel@tonic-gate } 34510Sstevel@tonic-gate } 34520Sstevel@tonic-gate /* 34530Sstevel@tonic-gate ** GETEXTENV -- get from external environment 34540Sstevel@tonic-gate ** 34550Sstevel@tonic-gate ** Parameters: 34560Sstevel@tonic-gate ** envar -- the name of the variable to retrieve 34570Sstevel@tonic-gate ** 34580Sstevel@tonic-gate ** Returns: 34590Sstevel@tonic-gate ** The value, if any. 34600Sstevel@tonic-gate */ 34610Sstevel@tonic-gate 34620Sstevel@tonic-gate static char * 34630Sstevel@tonic-gate getextenv(envar) 34640Sstevel@tonic-gate const char *envar; 34650Sstevel@tonic-gate { 34660Sstevel@tonic-gate char **envp; 34670Sstevel@tonic-gate int l; 34680Sstevel@tonic-gate 34690Sstevel@tonic-gate l = strlen(envar); 34700Sstevel@tonic-gate for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++) 34710Sstevel@tonic-gate { 34720Sstevel@tonic-gate if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 34730Sstevel@tonic-gate return &(*envp)[l + 1]; 34740Sstevel@tonic-gate } 34750Sstevel@tonic-gate return NULL; 34760Sstevel@tonic-gate } 34770Sstevel@tonic-gate /* 34781658Sjbeck ** SM_SETUSERENV -- set an environment variable in the propagated environment 34790Sstevel@tonic-gate ** 34800Sstevel@tonic-gate ** Parameters: 34810Sstevel@tonic-gate ** envar -- the name of the environment variable. 34820Sstevel@tonic-gate ** value -- the value to which it should be set. If 34830Sstevel@tonic-gate ** null, this is extracted from the incoming 34840Sstevel@tonic-gate ** environment. If that is not set, the call 34851658Sjbeck ** to sm_setuserenv is ignored. 34860Sstevel@tonic-gate ** 34870Sstevel@tonic-gate ** Returns: 34880Sstevel@tonic-gate ** none. 34890Sstevel@tonic-gate */ 34900Sstevel@tonic-gate 34910Sstevel@tonic-gate void 34921658Sjbeck sm_setuserenv(envar, value) 34930Sstevel@tonic-gate const char *envar; 34940Sstevel@tonic-gate const char *value; 34950Sstevel@tonic-gate { 34960Sstevel@tonic-gate int i, l; 34970Sstevel@tonic-gate char **evp = UserEnviron; 34980Sstevel@tonic-gate char *p; 34990Sstevel@tonic-gate 35000Sstevel@tonic-gate if (value == NULL) 35010Sstevel@tonic-gate { 35020Sstevel@tonic-gate value = getextenv(envar); 35030Sstevel@tonic-gate if (value == NULL) 35040Sstevel@tonic-gate return; 35050Sstevel@tonic-gate } 35060Sstevel@tonic-gate 35070Sstevel@tonic-gate /* XXX enforce reasonable size? */ 35080Sstevel@tonic-gate i = strlen(envar) + 1; 35090Sstevel@tonic-gate l = strlen(value) + i + 1; 35100Sstevel@tonic-gate p = (char *) xalloc(l); 35110Sstevel@tonic-gate (void) sm_strlcpyn(p, l, 3, envar, "=", value); 35120Sstevel@tonic-gate 35130Sstevel@tonic-gate while (*evp != NULL && strncmp(*evp, p, i) != 0) 35140Sstevel@tonic-gate evp++; 35150Sstevel@tonic-gate if (*evp != NULL) 35160Sstevel@tonic-gate { 35170Sstevel@tonic-gate *evp++ = p; 35180Sstevel@tonic-gate } 35190Sstevel@tonic-gate else if (evp < &UserEnviron[MAXUSERENVIRON]) 35200Sstevel@tonic-gate { 35210Sstevel@tonic-gate *evp++ = p; 35220Sstevel@tonic-gate *evp = NULL; 35230Sstevel@tonic-gate } 35240Sstevel@tonic-gate 35250Sstevel@tonic-gate /* make sure it is in our environment as well */ 35260Sstevel@tonic-gate if (putenv(p) < 0) 35271658Sjbeck syserr("sm_setuserenv: putenv(%s) failed", p); 35280Sstevel@tonic-gate } 35290Sstevel@tonic-gate /* 35300Sstevel@tonic-gate ** DUMPSTATE -- dump state 35310Sstevel@tonic-gate ** 35320Sstevel@tonic-gate ** For debugging. 35330Sstevel@tonic-gate */ 35340Sstevel@tonic-gate 35350Sstevel@tonic-gate void 35360Sstevel@tonic-gate dumpstate(when) 35370Sstevel@tonic-gate char *when; 35380Sstevel@tonic-gate { 35390Sstevel@tonic-gate register char *j = macvalue('j', CurEnv); 35400Sstevel@tonic-gate int rs; 35410Sstevel@tonic-gate extern int NextMacroId; 35420Sstevel@tonic-gate 35430Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 35440Sstevel@tonic-gate "--- dumping state on %s: $j = %s ---", 35450Sstevel@tonic-gate when, 35460Sstevel@tonic-gate j == NULL ? "<NULL>" : j); 35470Sstevel@tonic-gate if (j != NULL) 35480Sstevel@tonic-gate { 35490Sstevel@tonic-gate if (!wordinclass(j, 'w')) 35500Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 35510Sstevel@tonic-gate "*** $j not in $=w ***"); 35520Sstevel@tonic-gate } 35530Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 35540Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 35550Sstevel@tonic-gate NextMacroId, MAXMACROID); 35560Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 35570Sstevel@tonic-gate printopenfds(true); 35580Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 35590Sstevel@tonic-gate mci_dump_all(smioout, true); 35600Sstevel@tonic-gate rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 35610Sstevel@tonic-gate if (rs > 0) 35620Sstevel@tonic-gate { 35630Sstevel@tonic-gate int status; 35640Sstevel@tonic-gate register char **pvp; 35650Sstevel@tonic-gate char *pv[MAXATOM + 1]; 35660Sstevel@tonic-gate 35670Sstevel@tonic-gate pv[0] = NULL; 35680Sstevel@tonic-gate status = REWRITE(pv, rs, CurEnv); 35690Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 35700Sstevel@tonic-gate "--- ruleset debug_dumpstate returns stat %d, pv: ---", 35710Sstevel@tonic-gate status); 35720Sstevel@tonic-gate for (pvp = pv; *pvp != NULL; pvp++) 35730Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 35740Sstevel@tonic-gate } 35750Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 35760Sstevel@tonic-gate } 35770Sstevel@tonic-gate 35780Sstevel@tonic-gate #ifdef SIGUSR1 35790Sstevel@tonic-gate /* 35800Sstevel@tonic-gate ** SIGUSR1 -- Signal a request to dump state. 35810Sstevel@tonic-gate ** 35820Sstevel@tonic-gate ** Parameters: 35830Sstevel@tonic-gate ** sig -- calling signal. 35840Sstevel@tonic-gate ** 35850Sstevel@tonic-gate ** Returns: 35860Sstevel@tonic-gate ** none. 35870Sstevel@tonic-gate ** 35880Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 35890Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 35900Sstevel@tonic-gate ** DOING. 35910Sstevel@tonic-gate ** 35920Sstevel@tonic-gate ** XXX: More work is needed for this signal handler. 35930Sstevel@tonic-gate */ 35940Sstevel@tonic-gate 35950Sstevel@tonic-gate /* ARGSUSED */ 35960Sstevel@tonic-gate static SIGFUNC_DECL 35970Sstevel@tonic-gate sigusr1(sig) 35980Sstevel@tonic-gate int sig; 35990Sstevel@tonic-gate { 36000Sstevel@tonic-gate int save_errno = errno; 36010Sstevel@tonic-gate # if SM_HEAP_CHECK 36020Sstevel@tonic-gate extern void dumpstab __P((void)); 36030Sstevel@tonic-gate # endif /* SM_HEAP_CHECK */ 36040Sstevel@tonic-gate 36050Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigusr1); 36060Sstevel@tonic-gate errno = save_errno; 36070Sstevel@tonic-gate CHECK_CRITICAL(sig); 36080Sstevel@tonic-gate dumpstate("user signal"); 36090Sstevel@tonic-gate # if SM_HEAP_CHECK 36100Sstevel@tonic-gate dumpstab(); 36110Sstevel@tonic-gate # endif /* SM_HEAP_CHECK */ 36120Sstevel@tonic-gate errno = save_errno; 36130Sstevel@tonic-gate return SIGFUNC_RETURN; 36140Sstevel@tonic-gate } 36150Sstevel@tonic-gate #endif /* SIGUSR1 */ 36160Sstevel@tonic-gate 36170Sstevel@tonic-gate /* 36180Sstevel@tonic-gate ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 36190Sstevel@tonic-gate ** 36200Sstevel@tonic-gate ** Parameters: 36210Sstevel@tonic-gate ** to_real_uid -- if set, drop to the real uid instead 36220Sstevel@tonic-gate ** of the RunAsUser. 36230Sstevel@tonic-gate ** 36240Sstevel@tonic-gate ** Returns: 36250Sstevel@tonic-gate ** EX_OSERR if the setuid failed. 36260Sstevel@tonic-gate ** EX_OK otherwise. 36270Sstevel@tonic-gate */ 36280Sstevel@tonic-gate 36290Sstevel@tonic-gate int 36300Sstevel@tonic-gate drop_privileges(to_real_uid) 36310Sstevel@tonic-gate bool to_real_uid; 36320Sstevel@tonic-gate { 36330Sstevel@tonic-gate int rval = EX_OK; 36340Sstevel@tonic-gate GIDSET_T emptygidset[1]; 36350Sstevel@tonic-gate 36360Sstevel@tonic-gate if (tTd(47, 1)) 36370Sstevel@tonic-gate sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n", 36380Sstevel@tonic-gate (int) to_real_uid, 36390Sstevel@tonic-gate (int) RealUid, (int) RealGid, 36400Sstevel@tonic-gate (int) getuid(), (int) getgid(), 36410Sstevel@tonic-gate (int) geteuid(), (int) getegid(), 36420Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 36430Sstevel@tonic-gate 36440Sstevel@tonic-gate if (to_real_uid) 36450Sstevel@tonic-gate { 36460Sstevel@tonic-gate RunAsUserName = RealUserName; 36470Sstevel@tonic-gate RunAsUid = RealUid; 36480Sstevel@tonic-gate RunAsGid = RealGid; 36490Sstevel@tonic-gate EffGid = RunAsGid; 36500Sstevel@tonic-gate } 36510Sstevel@tonic-gate 36520Sstevel@tonic-gate /* make sure no one can grab open descriptors for secret files */ 36530Sstevel@tonic-gate endpwent(); 36540Sstevel@tonic-gate sm_mbdb_terminate(); 36550Sstevel@tonic-gate 36560Sstevel@tonic-gate /* reset group permissions; these can be set later */ 36570Sstevel@tonic-gate emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 36580Sstevel@tonic-gate 36590Sstevel@tonic-gate /* 36600Sstevel@tonic-gate ** Notice: on some OS (Linux...) the setgroups() call causes 36610Sstevel@tonic-gate ** a logfile entry if sendmail is not run by root. 36620Sstevel@tonic-gate ** However, it is unclear (no POSIX standard) whether 36630Sstevel@tonic-gate ** setgroups() can only succeed if executed by root. 36640Sstevel@tonic-gate ** So for now we keep it as it is; if you want to change it, use 36650Sstevel@tonic-gate ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 36660Sstevel@tonic-gate */ 36670Sstevel@tonic-gate 36680Sstevel@tonic-gate if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 36690Sstevel@tonic-gate { 36700Sstevel@tonic-gate syserr("drop_privileges: setgroups(1, %d) failed", 36710Sstevel@tonic-gate (int) emptygidset[0]); 36720Sstevel@tonic-gate rval = EX_OSERR; 36730Sstevel@tonic-gate } 36740Sstevel@tonic-gate 36750Sstevel@tonic-gate /* reset primary group id */ 36760Sstevel@tonic-gate if (to_real_uid) 36770Sstevel@tonic-gate { 36780Sstevel@tonic-gate /* 36790Sstevel@tonic-gate ** Drop gid to real gid. 36800Sstevel@tonic-gate ** On some OS we must reset the effective[/real[/saved]] gid, 36810Sstevel@tonic-gate ** and then use setgid() to finally drop all group privileges. 36820Sstevel@tonic-gate ** Later on we check whether we can get back the 36830Sstevel@tonic-gate ** effective gid. 36840Sstevel@tonic-gate */ 36850Sstevel@tonic-gate 36860Sstevel@tonic-gate #if HASSETEGID 36870Sstevel@tonic-gate if (setegid(RunAsGid) < 0) 36880Sstevel@tonic-gate { 36890Sstevel@tonic-gate syserr("drop_privileges: setegid(%d) failed", 36900Sstevel@tonic-gate (int) RunAsGid); 36910Sstevel@tonic-gate rval = EX_OSERR; 36920Sstevel@tonic-gate } 36930Sstevel@tonic-gate #else /* HASSETEGID */ 36940Sstevel@tonic-gate # if HASSETREGID 36950Sstevel@tonic-gate if (setregid(RunAsGid, RunAsGid) < 0) 36960Sstevel@tonic-gate { 36970Sstevel@tonic-gate syserr("drop_privileges: setregid(%d, %d) failed", 36980Sstevel@tonic-gate (int) RunAsGid, (int) RunAsGid); 36990Sstevel@tonic-gate rval = EX_OSERR; 37000Sstevel@tonic-gate } 37010Sstevel@tonic-gate # else /* HASSETREGID */ 37020Sstevel@tonic-gate # if HASSETRESGID 37030Sstevel@tonic-gate if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 37040Sstevel@tonic-gate { 37050Sstevel@tonic-gate syserr("drop_privileges: setresgid(%d, %d, %d) failed", 37060Sstevel@tonic-gate (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 37070Sstevel@tonic-gate rval = EX_OSERR; 37080Sstevel@tonic-gate } 37090Sstevel@tonic-gate # endif /* HASSETRESGID */ 37100Sstevel@tonic-gate # endif /* HASSETREGID */ 37110Sstevel@tonic-gate #endif /* HASSETEGID */ 37120Sstevel@tonic-gate } 37130Sstevel@tonic-gate if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 37140Sstevel@tonic-gate { 37150Sstevel@tonic-gate if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 37160Sstevel@tonic-gate { 37170Sstevel@tonic-gate syserr("drop_privileges: setgid(%d) failed", 37180Sstevel@tonic-gate (int) RunAsGid); 37190Sstevel@tonic-gate rval = EX_OSERR; 37200Sstevel@tonic-gate } 37210Sstevel@tonic-gate errno = 0; 37220Sstevel@tonic-gate if (rval == EX_OK && getegid() != RunAsGid) 37230Sstevel@tonic-gate { 37240Sstevel@tonic-gate syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", 37250Sstevel@tonic-gate (int) getegid(), (int) RunAsGid); 37260Sstevel@tonic-gate rval = EX_OSERR; 37270Sstevel@tonic-gate } 37280Sstevel@tonic-gate } 37290Sstevel@tonic-gate 37300Sstevel@tonic-gate /* fiddle with uid */ 37310Sstevel@tonic-gate if (to_real_uid || RunAsUid != 0) 37320Sstevel@tonic-gate { 37330Sstevel@tonic-gate uid_t euid; 37340Sstevel@tonic-gate 37350Sstevel@tonic-gate /* 37360Sstevel@tonic-gate ** Try to setuid(RunAsUid). 37370Sstevel@tonic-gate ** euid must be RunAsUid, 37380Sstevel@tonic-gate ** ruid must be RunAsUid unless (e|r)uid wasn't 0 37390Sstevel@tonic-gate ** and we didn't have to drop privileges to the real uid. 37400Sstevel@tonic-gate */ 37410Sstevel@tonic-gate 37420Sstevel@tonic-gate if (setuid(RunAsUid) < 0 || 37430Sstevel@tonic-gate geteuid() != RunAsUid || 37440Sstevel@tonic-gate (getuid() != RunAsUid && 37450Sstevel@tonic-gate (to_real_uid || geteuid() == 0 || getuid() == 0))) 37460Sstevel@tonic-gate { 37470Sstevel@tonic-gate #if HASSETREUID 37480Sstevel@tonic-gate /* 37490Sstevel@tonic-gate ** if ruid != RunAsUid, euid == RunAsUid, then 37500Sstevel@tonic-gate ** try resetting just the real uid, then using 37510Sstevel@tonic-gate ** setuid() to drop the saved-uid as well. 37520Sstevel@tonic-gate */ 37530Sstevel@tonic-gate 37540Sstevel@tonic-gate if (geteuid() == RunAsUid) 37550Sstevel@tonic-gate { 37560Sstevel@tonic-gate if (setreuid(RunAsUid, -1) < 0) 37570Sstevel@tonic-gate { 37580Sstevel@tonic-gate syserr("drop_privileges: setreuid(%d, -1) failed", 37590Sstevel@tonic-gate (int) RunAsUid); 37600Sstevel@tonic-gate rval = EX_OSERR; 37610Sstevel@tonic-gate } 37620Sstevel@tonic-gate if (setuid(RunAsUid) < 0) 37630Sstevel@tonic-gate { 37640Sstevel@tonic-gate syserr("drop_privileges: second setuid(%d) attempt failed", 37650Sstevel@tonic-gate (int) RunAsUid); 37660Sstevel@tonic-gate rval = EX_OSERR; 37670Sstevel@tonic-gate } 37680Sstevel@tonic-gate } 37690Sstevel@tonic-gate else 37700Sstevel@tonic-gate #endif /* HASSETREUID */ 37710Sstevel@tonic-gate { 37720Sstevel@tonic-gate syserr("drop_privileges: setuid(%d) failed", 37730Sstevel@tonic-gate (int) RunAsUid); 37740Sstevel@tonic-gate rval = EX_OSERR; 37750Sstevel@tonic-gate } 37760Sstevel@tonic-gate } 37770Sstevel@tonic-gate euid = geteuid(); 37780Sstevel@tonic-gate if (RunAsUid != 0 && setuid(0) == 0) 37790Sstevel@tonic-gate { 37800Sstevel@tonic-gate /* 37810Sstevel@tonic-gate ** Believe it or not, the Linux capability model 37820Sstevel@tonic-gate ** allows a non-root process to override setuid() 37830Sstevel@tonic-gate ** on a process running as root and prevent that 37840Sstevel@tonic-gate ** process from dropping privileges. 37850Sstevel@tonic-gate */ 37860Sstevel@tonic-gate 37870Sstevel@tonic-gate syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 37880Sstevel@tonic-gate rval = EX_OSERR; 37890Sstevel@tonic-gate } 37900Sstevel@tonic-gate else if (RunAsUid != euid && setuid(euid) == 0) 37910Sstevel@tonic-gate { 37920Sstevel@tonic-gate /* 37930Sstevel@tonic-gate ** Some operating systems will keep the saved-uid 37940Sstevel@tonic-gate ** if a non-root effective-uid calls setuid(real-uid) 37950Sstevel@tonic-gate ** making it possible to set it back again later. 37960Sstevel@tonic-gate */ 37970Sstevel@tonic-gate 37980Sstevel@tonic-gate syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 37990Sstevel@tonic-gate rval = EX_OSERR; 38000Sstevel@tonic-gate } 38010Sstevel@tonic-gate } 38020Sstevel@tonic-gate 38030Sstevel@tonic-gate if ((to_real_uid || RunAsGid != 0) && 38040Sstevel@tonic-gate rval == EX_OK && RunAsGid != EffGid && 38050Sstevel@tonic-gate getuid() != 0 && geteuid() != 0) 38060Sstevel@tonic-gate { 38070Sstevel@tonic-gate errno = 0; 38080Sstevel@tonic-gate if (setgid(EffGid) == 0) 38090Sstevel@tonic-gate { 38100Sstevel@tonic-gate syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 38110Sstevel@tonic-gate (int) EffGid); 38120Sstevel@tonic-gate rval = EX_OSERR; 38130Sstevel@tonic-gate } 38140Sstevel@tonic-gate } 38150Sstevel@tonic-gate 38160Sstevel@tonic-gate if (tTd(47, 5)) 38170Sstevel@tonic-gate { 38180Sstevel@tonic-gate sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 38190Sstevel@tonic-gate (int) geteuid(), (int) getuid(), 38200Sstevel@tonic-gate (int) getegid(), (int) getgid()); 38210Sstevel@tonic-gate sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 38220Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 38230Sstevel@tonic-gate if (tTd(47, 10)) 38240Sstevel@tonic-gate sm_dprintf("drop_privileges: rval = %d\n", rval); 38250Sstevel@tonic-gate } 38260Sstevel@tonic-gate return rval; 38270Sstevel@tonic-gate } 38280Sstevel@tonic-gate /* 38290Sstevel@tonic-gate ** FILL_FD -- make sure a file descriptor has been properly allocated 38300Sstevel@tonic-gate ** 38310Sstevel@tonic-gate ** Used to make sure that stdin/out/err are allocated on startup 38320Sstevel@tonic-gate ** 38330Sstevel@tonic-gate ** Parameters: 38340Sstevel@tonic-gate ** fd -- the file descriptor to be filled. 38350Sstevel@tonic-gate ** where -- a string used for logging. If NULL, this is 38360Sstevel@tonic-gate ** being called on startup, and logging should 38370Sstevel@tonic-gate ** not be done. 38380Sstevel@tonic-gate ** 38390Sstevel@tonic-gate ** Returns: 38400Sstevel@tonic-gate ** none 38410Sstevel@tonic-gate ** 38420Sstevel@tonic-gate ** Side Effects: 38430Sstevel@tonic-gate ** possibly changes MissingFds 38440Sstevel@tonic-gate */ 38450Sstevel@tonic-gate 38460Sstevel@tonic-gate void 38470Sstevel@tonic-gate fill_fd(fd, where) 38480Sstevel@tonic-gate int fd; 38490Sstevel@tonic-gate char *where; 38500Sstevel@tonic-gate { 38510Sstevel@tonic-gate int i; 38520Sstevel@tonic-gate struct stat stbuf; 38530Sstevel@tonic-gate 38540Sstevel@tonic-gate if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 38550Sstevel@tonic-gate return; 38560Sstevel@tonic-gate 38570Sstevel@tonic-gate if (where != NULL) 38580Sstevel@tonic-gate syserr("fill_fd: %s: fd %d not open", where, fd); 38590Sstevel@tonic-gate else 38600Sstevel@tonic-gate MissingFds |= 1 << fd; 38610Sstevel@tonic-gate i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 38620Sstevel@tonic-gate if (i < 0) 38630Sstevel@tonic-gate { 38640Sstevel@tonic-gate syserr("!fill_fd: %s: cannot open %s", 38650Sstevel@tonic-gate where == NULL ? "startup" : where, SM_PATH_DEVNULL); 38660Sstevel@tonic-gate } 38670Sstevel@tonic-gate if (fd != i) 38680Sstevel@tonic-gate { 38690Sstevel@tonic-gate (void) dup2(i, fd); 38700Sstevel@tonic-gate (void) close(i); 38710Sstevel@tonic-gate } 38720Sstevel@tonic-gate } 38730Sstevel@tonic-gate /* 38740Sstevel@tonic-gate ** SM_PRINTOPTIONS -- print options 38750Sstevel@tonic-gate ** 38760Sstevel@tonic-gate ** Parameters: 38770Sstevel@tonic-gate ** options -- array of options. 38780Sstevel@tonic-gate ** 38790Sstevel@tonic-gate ** Returns: 38800Sstevel@tonic-gate ** none. 38810Sstevel@tonic-gate */ 38820Sstevel@tonic-gate 38830Sstevel@tonic-gate static void 38840Sstevel@tonic-gate sm_printoptions(options) 38850Sstevel@tonic-gate char **options; 38860Sstevel@tonic-gate { 38870Sstevel@tonic-gate int ll; 38880Sstevel@tonic-gate char **av; 38890Sstevel@tonic-gate 38900Sstevel@tonic-gate av = options; 38910Sstevel@tonic-gate ll = 7; 38920Sstevel@tonic-gate while (*av != NULL) 38930Sstevel@tonic-gate { 38940Sstevel@tonic-gate if (ll + strlen(*av) > 63) 38950Sstevel@tonic-gate { 38960Sstevel@tonic-gate sm_dprintf("\n"); 38970Sstevel@tonic-gate ll = 0; 38980Sstevel@tonic-gate } 38990Sstevel@tonic-gate if (ll == 0) 39000Sstevel@tonic-gate sm_dprintf("\t\t"); 39010Sstevel@tonic-gate else 39020Sstevel@tonic-gate sm_dprintf(" "); 39030Sstevel@tonic-gate sm_dprintf("%s", *av); 39040Sstevel@tonic-gate ll += strlen(*av++) + 1; 39050Sstevel@tonic-gate } 39060Sstevel@tonic-gate sm_dprintf("\n"); 39070Sstevel@tonic-gate } 39080Sstevel@tonic-gate /* 39090Sstevel@tonic-gate ** TESTMODELINE -- process a test mode input line 39100Sstevel@tonic-gate ** 39110Sstevel@tonic-gate ** Parameters: 39120Sstevel@tonic-gate ** line -- the input line. 39130Sstevel@tonic-gate ** e -- the current environment. 39140Sstevel@tonic-gate ** Syntax: 39150Sstevel@tonic-gate ** # a comment 39160Sstevel@tonic-gate ** .X process X as a configuration line 39170Sstevel@tonic-gate ** =X dump a configuration item (such as mailers) 39180Sstevel@tonic-gate ** $X dump a macro or class 39190Sstevel@tonic-gate ** /X try an activity 39200Sstevel@tonic-gate ** X normal process through rule set X 39210Sstevel@tonic-gate */ 39220Sstevel@tonic-gate 39230Sstevel@tonic-gate static void 39240Sstevel@tonic-gate testmodeline(line, e) 39250Sstevel@tonic-gate char *line; 39260Sstevel@tonic-gate ENVELOPE *e; 39270Sstevel@tonic-gate { 39280Sstevel@tonic-gate register char *p; 39290Sstevel@tonic-gate char *q; 39300Sstevel@tonic-gate auto char *delimptr; 39310Sstevel@tonic-gate int mid; 39320Sstevel@tonic-gate int i, rs; 39330Sstevel@tonic-gate STAB *map; 39340Sstevel@tonic-gate char **s; 39350Sstevel@tonic-gate struct rewrite *rw; 39360Sstevel@tonic-gate ADDRESS a; 39370Sstevel@tonic-gate static int tryflags = RF_COPYNONE; 39380Sstevel@tonic-gate char exbuf[MAXLINE]; 39390Sstevel@tonic-gate extern unsigned char TokTypeNoC[]; 39400Sstevel@tonic-gate 39410Sstevel@tonic-gate /* skip leading spaces */ 39420Sstevel@tonic-gate while (*line == ' ') 39430Sstevel@tonic-gate line++; 39440Sstevel@tonic-gate 39450Sstevel@tonic-gate switch (line[0]) 39460Sstevel@tonic-gate { 39470Sstevel@tonic-gate case '#': 39480Sstevel@tonic-gate case '\0': 39490Sstevel@tonic-gate return; 39500Sstevel@tonic-gate 39510Sstevel@tonic-gate case '?': 39520Sstevel@tonic-gate help("-bt", e); 39530Sstevel@tonic-gate return; 39540Sstevel@tonic-gate 39550Sstevel@tonic-gate case '.': /* config-style settings */ 39560Sstevel@tonic-gate switch (line[1]) 39570Sstevel@tonic-gate { 39580Sstevel@tonic-gate case 'D': 39590Sstevel@tonic-gate mid = macid_parse(&line[2], &delimptr); 39600Sstevel@tonic-gate if (mid == 0) 39610Sstevel@tonic-gate return; 39620Sstevel@tonic-gate translate_dollars(delimptr); 39630Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, mid, delimptr); 39640Sstevel@tonic-gate break; 39650Sstevel@tonic-gate 39660Sstevel@tonic-gate case 'C': 39670Sstevel@tonic-gate if (line[2] == '\0') /* not to call syserr() */ 39680Sstevel@tonic-gate return; 39690Sstevel@tonic-gate 39700Sstevel@tonic-gate mid = macid_parse(&line[2], &delimptr); 39710Sstevel@tonic-gate if (mid == 0) 39720Sstevel@tonic-gate return; 39730Sstevel@tonic-gate translate_dollars(delimptr); 39740Sstevel@tonic-gate expand(delimptr, exbuf, sizeof exbuf, e); 39750Sstevel@tonic-gate p = exbuf; 39760Sstevel@tonic-gate while (*p != '\0') 39770Sstevel@tonic-gate { 39780Sstevel@tonic-gate register char *wd; 39790Sstevel@tonic-gate char delim; 39800Sstevel@tonic-gate 39810Sstevel@tonic-gate while (*p != '\0' && isascii(*p) && isspace(*p)) 39820Sstevel@tonic-gate p++; 39830Sstevel@tonic-gate wd = p; 39840Sstevel@tonic-gate while (*p != '\0' && !(isascii(*p) && isspace(*p))) 39850Sstevel@tonic-gate p++; 39860Sstevel@tonic-gate delim = *p; 39870Sstevel@tonic-gate *p = '\0'; 39880Sstevel@tonic-gate if (wd[0] != '\0') 39890Sstevel@tonic-gate setclass(mid, wd); 39900Sstevel@tonic-gate *p = delim; 39910Sstevel@tonic-gate } 39920Sstevel@tonic-gate break; 39930Sstevel@tonic-gate 39940Sstevel@tonic-gate case '\0': 39950Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 39960Sstevel@tonic-gate "Usage: .[DC]macro value(s)\n"); 39970Sstevel@tonic-gate break; 39980Sstevel@tonic-gate 39990Sstevel@tonic-gate default: 40000Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40010Sstevel@tonic-gate "Unknown \".\" command %s\n", line); 40020Sstevel@tonic-gate break; 40030Sstevel@tonic-gate } 40040Sstevel@tonic-gate return; 40050Sstevel@tonic-gate 40060Sstevel@tonic-gate case '=': /* config-style settings */ 40070Sstevel@tonic-gate switch (line[1]) 40080Sstevel@tonic-gate { 40090Sstevel@tonic-gate case 'S': /* dump rule set */ 40100Sstevel@tonic-gate rs = strtorwset(&line[2], NULL, ST_FIND); 40110Sstevel@tonic-gate if (rs < 0) 40120Sstevel@tonic-gate { 40130Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40140Sstevel@tonic-gate "Undefined ruleset %s\n", &line[2]); 40150Sstevel@tonic-gate return; 40160Sstevel@tonic-gate } 40170Sstevel@tonic-gate rw = RewriteRules[rs]; 40180Sstevel@tonic-gate if (rw == NULL) 40190Sstevel@tonic-gate return; 40200Sstevel@tonic-gate do 40210Sstevel@tonic-gate { 40220Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 40230Sstevel@tonic-gate 'R'); 40240Sstevel@tonic-gate s = rw->r_lhs; 40250Sstevel@tonic-gate while (*s != NULL) 40260Sstevel@tonic-gate { 40270Sstevel@tonic-gate xputs(smioout, *s++); 40280Sstevel@tonic-gate (void) sm_io_putc(smioout, 40290Sstevel@tonic-gate SM_TIME_DEFAULT, ' '); 40300Sstevel@tonic-gate } 40310Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 40320Sstevel@tonic-gate '\t'); 40330Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 40340Sstevel@tonic-gate '\t'); 40350Sstevel@tonic-gate s = rw->r_rhs; 40360Sstevel@tonic-gate while (*s != NULL) 40370Sstevel@tonic-gate { 40380Sstevel@tonic-gate xputs(smioout, *s++); 40390Sstevel@tonic-gate (void) sm_io_putc(smioout, 40400Sstevel@tonic-gate SM_TIME_DEFAULT, ' '); 40410Sstevel@tonic-gate } 40420Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 40430Sstevel@tonic-gate '\n'); 40440Sstevel@tonic-gate } while ((rw = rw->r_next) != NULL); 40450Sstevel@tonic-gate break; 40460Sstevel@tonic-gate 40470Sstevel@tonic-gate case 'M': 40480Sstevel@tonic-gate for (i = 0; i < MAXMAILERS; i++) 40490Sstevel@tonic-gate { 40500Sstevel@tonic-gate if (Mailer[i] != NULL) 40510Sstevel@tonic-gate printmailer(smioout, Mailer[i]); 40520Sstevel@tonic-gate } 40530Sstevel@tonic-gate break; 40540Sstevel@tonic-gate 40550Sstevel@tonic-gate case '\0': 40560Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40570Sstevel@tonic-gate "Usage: =Sruleset or =M\n"); 40580Sstevel@tonic-gate break; 40590Sstevel@tonic-gate 40600Sstevel@tonic-gate default: 40610Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40620Sstevel@tonic-gate "Unknown \"=\" command %s\n", line); 40630Sstevel@tonic-gate break; 40640Sstevel@tonic-gate } 40650Sstevel@tonic-gate return; 40660Sstevel@tonic-gate 40670Sstevel@tonic-gate case '-': /* set command-line-like opts */ 40680Sstevel@tonic-gate switch (line[1]) 40690Sstevel@tonic-gate { 40700Sstevel@tonic-gate case 'd': 40710Sstevel@tonic-gate tTflag(&line[2]); 40720Sstevel@tonic-gate break; 40730Sstevel@tonic-gate 40740Sstevel@tonic-gate case '\0': 40750Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40760Sstevel@tonic-gate "Usage: -d{debug arguments}\n"); 40770Sstevel@tonic-gate break; 40780Sstevel@tonic-gate 40790Sstevel@tonic-gate default: 40800Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 40810Sstevel@tonic-gate "Unknown \"-\" command %s\n", line); 40820Sstevel@tonic-gate break; 40830Sstevel@tonic-gate } 40840Sstevel@tonic-gate return; 40850Sstevel@tonic-gate 40860Sstevel@tonic-gate case '$': 40870Sstevel@tonic-gate if (line[1] == '=') 40880Sstevel@tonic-gate { 40890Sstevel@tonic-gate mid = macid(&line[2]); 40900Sstevel@tonic-gate if (mid != 0) 40910Sstevel@tonic-gate stabapply(dump_class, mid); 40920Sstevel@tonic-gate return; 40930Sstevel@tonic-gate } 40940Sstevel@tonic-gate mid = macid(&line[1]); 40950Sstevel@tonic-gate if (mid == 0) 40960Sstevel@tonic-gate return; 40970Sstevel@tonic-gate p = macvalue(mid, e); 40980Sstevel@tonic-gate if (p == NULL) 40990Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41000Sstevel@tonic-gate "Undefined\n"); 41010Sstevel@tonic-gate else 41020Sstevel@tonic-gate { 41030Sstevel@tonic-gate xputs(smioout, p); 41040Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41050Sstevel@tonic-gate "\n"); 41060Sstevel@tonic-gate } 41070Sstevel@tonic-gate return; 41080Sstevel@tonic-gate 41090Sstevel@tonic-gate case '/': /* miscellaneous commands */ 41100Sstevel@tonic-gate p = &line[strlen(line)]; 41110Sstevel@tonic-gate while (--p >= line && isascii(*p) && isspace(*p)) 41120Sstevel@tonic-gate *p = '\0'; 41130Sstevel@tonic-gate p = strpbrk(line, " \t"); 41140Sstevel@tonic-gate if (p != NULL) 41150Sstevel@tonic-gate { 41160Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 41170Sstevel@tonic-gate *p++ = '\0'; 41180Sstevel@tonic-gate } 41190Sstevel@tonic-gate else 41200Sstevel@tonic-gate p = ""; 41210Sstevel@tonic-gate if (line[1] == '\0') 41220Sstevel@tonic-gate { 41230Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41240Sstevel@tonic-gate "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 41250Sstevel@tonic-gate return; 41260Sstevel@tonic-gate } 41270Sstevel@tonic-gate if (sm_strcasecmp(&line[1], "quit") == 0) 41280Sstevel@tonic-gate { 41290Sstevel@tonic-gate CurEnv->e_id = NULL; 41300Sstevel@tonic-gate finis(true, true, ExitStat); 41310Sstevel@tonic-gate /* NOTREACHED */ 41320Sstevel@tonic-gate } 41330Sstevel@tonic-gate if (sm_strcasecmp(&line[1], "mx") == 0) 41340Sstevel@tonic-gate { 41350Sstevel@tonic-gate #if NAMED_BIND 41360Sstevel@tonic-gate /* look up MX records */ 41370Sstevel@tonic-gate int nmx; 41380Sstevel@tonic-gate auto int rcode; 41390Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 41400Sstevel@tonic-gate 41410Sstevel@tonic-gate if (*p == '\0') 41420Sstevel@tonic-gate { 41430Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41440Sstevel@tonic-gate "Usage: /mx address\n"); 41450Sstevel@tonic-gate return; 41460Sstevel@tonic-gate } 41470Sstevel@tonic-gate nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true, 41480Sstevel@tonic-gate NULL); 41490Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41500Sstevel@tonic-gate "getmxrr(%s) returns %d value(s):\n", 41510Sstevel@tonic-gate p, nmx); 41520Sstevel@tonic-gate for (i = 0; i < nmx; i++) 41530Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41540Sstevel@tonic-gate "\t%s\n", mxhosts[i]); 41550Sstevel@tonic-gate #else /* NAMED_BIND */ 41560Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41570Sstevel@tonic-gate "No MX code compiled in\n"); 41580Sstevel@tonic-gate #endif /* NAMED_BIND */ 41590Sstevel@tonic-gate } 41600Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "canon") == 0) 41610Sstevel@tonic-gate { 41620Sstevel@tonic-gate char host[MAXHOSTNAMELEN]; 41630Sstevel@tonic-gate 41640Sstevel@tonic-gate if (*p == '\0') 41650Sstevel@tonic-gate { 41660Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41670Sstevel@tonic-gate "Usage: /canon address\n"); 41680Sstevel@tonic-gate return; 41690Sstevel@tonic-gate } 41700Sstevel@tonic-gate else if (sm_strlcpy(host, p, sizeof host) >= sizeof host) 41710Sstevel@tonic-gate { 41720Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41730Sstevel@tonic-gate "Name too long\n"); 41740Sstevel@tonic-gate return; 41750Sstevel@tonic-gate } 41760Sstevel@tonic-gate (void) getcanonname(host, sizeof host, !HasWildcardMX, 41770Sstevel@tonic-gate NULL); 41780Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41790Sstevel@tonic-gate "getcanonname(%s) returns %s\n", 41800Sstevel@tonic-gate p, host); 41810Sstevel@tonic-gate } 41820Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "map") == 0) 41830Sstevel@tonic-gate { 41840Sstevel@tonic-gate auto int rcode = EX_OK; 41850Sstevel@tonic-gate char *av[2]; 41860Sstevel@tonic-gate 41870Sstevel@tonic-gate if (*p == '\0') 41880Sstevel@tonic-gate { 41890Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41900Sstevel@tonic-gate "Usage: /map mapname key\n"); 41910Sstevel@tonic-gate return; 41920Sstevel@tonic-gate } 41930Sstevel@tonic-gate for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 41940Sstevel@tonic-gate continue; 41950Sstevel@tonic-gate if (*q == '\0') 41960Sstevel@tonic-gate { 41970Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 41980Sstevel@tonic-gate "No key specified\n"); 41990Sstevel@tonic-gate return; 42000Sstevel@tonic-gate } 42010Sstevel@tonic-gate *q++ = '\0'; 42020Sstevel@tonic-gate map = stab(p, ST_MAP, ST_FIND); 42030Sstevel@tonic-gate if (map == NULL) 42040Sstevel@tonic-gate { 42050Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42060Sstevel@tonic-gate "Map named \"%s\" not found\n", p); 42070Sstevel@tonic-gate return; 42080Sstevel@tonic-gate } 42090Sstevel@tonic-gate if (!bitset(MF_OPEN, map->s_map.map_mflags) && 42100Sstevel@tonic-gate !openmap(&(map->s_map))) 42110Sstevel@tonic-gate { 42120Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42130Sstevel@tonic-gate "Map named \"%s\" not open\n", p); 42140Sstevel@tonic-gate return; 42150Sstevel@tonic-gate } 42160Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42170Sstevel@tonic-gate "map_lookup: %s (%s) ", p, q); 42180Sstevel@tonic-gate av[0] = q; 42190Sstevel@tonic-gate av[1] = NULL; 42200Sstevel@tonic-gate p = (*map->s_map.map_class->map_lookup) 42210Sstevel@tonic-gate (&map->s_map, q, av, &rcode); 42220Sstevel@tonic-gate if (p == NULL) 42230Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42240Sstevel@tonic-gate "no match (%d)\n", 42250Sstevel@tonic-gate rcode); 42260Sstevel@tonic-gate else 42270Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42280Sstevel@tonic-gate "returns %s (%d)\n", p, 42290Sstevel@tonic-gate rcode); 42300Sstevel@tonic-gate } 42310Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "try") == 0) 42320Sstevel@tonic-gate { 42330Sstevel@tonic-gate MAILER *m; 42340Sstevel@tonic-gate STAB *st; 42350Sstevel@tonic-gate auto int rcode = EX_OK; 42360Sstevel@tonic-gate 42370Sstevel@tonic-gate q = strpbrk(p, " \t"); 42380Sstevel@tonic-gate if (q != NULL) 42390Sstevel@tonic-gate { 42400Sstevel@tonic-gate while (isascii(*q) && isspace(*q)) 42410Sstevel@tonic-gate *q++ = '\0'; 42420Sstevel@tonic-gate } 42430Sstevel@tonic-gate if (q == NULL || *q == '\0') 42440Sstevel@tonic-gate { 42450Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42460Sstevel@tonic-gate "Usage: /try mailer address\n"); 42470Sstevel@tonic-gate return; 42480Sstevel@tonic-gate } 42490Sstevel@tonic-gate st = stab(p, ST_MAILER, ST_FIND); 42500Sstevel@tonic-gate if (st == NULL) 42510Sstevel@tonic-gate { 42520Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42530Sstevel@tonic-gate "Unknown mailer %s\n", p); 42540Sstevel@tonic-gate return; 42550Sstevel@tonic-gate } 42560Sstevel@tonic-gate m = st->s_mailer; 42570Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42580Sstevel@tonic-gate "Trying %s %s address %s for mailer %s\n", 42590Sstevel@tonic-gate bitset(RF_HEADERADDR, tryflags) ? "header" 42600Sstevel@tonic-gate : "envelope", 42610Sstevel@tonic-gate bitset(RF_SENDERADDR, tryflags) ? "sender" 42620Sstevel@tonic-gate : "recipient", q, p); 42630Sstevel@tonic-gate p = remotename(q, m, tryflags, &rcode, CurEnv); 42640Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42650Sstevel@tonic-gate "Rcode = %d, addr = %s\n", 42660Sstevel@tonic-gate rcode, p == NULL ? "<NULL>" : p); 42670Sstevel@tonic-gate e->e_to = NULL; 42680Sstevel@tonic-gate } 42690Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "tryflags") == 0) 42700Sstevel@tonic-gate { 42710Sstevel@tonic-gate if (*p == '\0') 42720Sstevel@tonic-gate { 42730Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 42740Sstevel@tonic-gate "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 42750Sstevel@tonic-gate return; 42760Sstevel@tonic-gate } 42770Sstevel@tonic-gate for (; *p != '\0'; p++) 42780Sstevel@tonic-gate { 42790Sstevel@tonic-gate switch (*p) 42800Sstevel@tonic-gate { 42810Sstevel@tonic-gate case 'H': 42820Sstevel@tonic-gate case 'h': 42830Sstevel@tonic-gate tryflags |= RF_HEADERADDR; 42840Sstevel@tonic-gate break; 42850Sstevel@tonic-gate 42860Sstevel@tonic-gate case 'E': 42870Sstevel@tonic-gate case 'e': 42880Sstevel@tonic-gate tryflags &= ~RF_HEADERADDR; 42890Sstevel@tonic-gate break; 42900Sstevel@tonic-gate 42910Sstevel@tonic-gate case 'S': 42920Sstevel@tonic-gate case 's': 42930Sstevel@tonic-gate tryflags |= RF_SENDERADDR; 42940Sstevel@tonic-gate break; 42950Sstevel@tonic-gate 42960Sstevel@tonic-gate case 'R': 42970Sstevel@tonic-gate case 'r': 42980Sstevel@tonic-gate tryflags &= ~RF_SENDERADDR; 42990Sstevel@tonic-gate break; 43000Sstevel@tonic-gate } 43010Sstevel@tonic-gate } 43020Sstevel@tonic-gate exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 43030Sstevel@tonic-gate exbuf[1] = ' '; 43040Sstevel@tonic-gate exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 43050Sstevel@tonic-gate exbuf[3] = '\0'; 43060Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 43070Sstevel@tonic-gate macid("{addr_type}"), exbuf); 43080Sstevel@tonic-gate } 43090Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "parse") == 0) 43100Sstevel@tonic-gate { 43110Sstevel@tonic-gate if (*p == '\0') 43120Sstevel@tonic-gate { 43130Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43140Sstevel@tonic-gate "Usage: /parse address\n"); 43150Sstevel@tonic-gate return; 43160Sstevel@tonic-gate } 43170Sstevel@tonic-gate q = crackaddr(p, e); 43180Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43190Sstevel@tonic-gate "Cracked address = "); 43200Sstevel@tonic-gate xputs(smioout, q); 43210Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43220Sstevel@tonic-gate "\nParsing %s %s address\n", 43230Sstevel@tonic-gate bitset(RF_HEADERADDR, tryflags) ? 43240Sstevel@tonic-gate "header" : "envelope", 43250Sstevel@tonic-gate bitset(RF_SENDERADDR, tryflags) ? 43260Sstevel@tonic-gate "sender" : "recipient"); 43270Sstevel@tonic-gate if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 43280Sstevel@tonic-gate == NULL) 43290Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43300Sstevel@tonic-gate "Cannot parse\n"); 43310Sstevel@tonic-gate else if (a.q_host != NULL && a.q_host[0] != '\0') 43320Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43330Sstevel@tonic-gate "mailer %s, host %s, user %s\n", 43340Sstevel@tonic-gate a.q_mailer->m_name, 43350Sstevel@tonic-gate a.q_host, 43360Sstevel@tonic-gate a.q_user); 43370Sstevel@tonic-gate else 43380Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43390Sstevel@tonic-gate "mailer %s, user %s\n", 43400Sstevel@tonic-gate a.q_mailer->m_name, 43410Sstevel@tonic-gate a.q_user); 43420Sstevel@tonic-gate e->e_to = NULL; 43430Sstevel@tonic-gate } 43440Sstevel@tonic-gate else 43450Sstevel@tonic-gate { 43460Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43470Sstevel@tonic-gate "Unknown \"/\" command %s\n", 43480Sstevel@tonic-gate line); 43490Sstevel@tonic-gate } 43500Sstevel@tonic-gate return; 43510Sstevel@tonic-gate } 43520Sstevel@tonic-gate 43530Sstevel@tonic-gate for (p = line; isascii(*p) && isspace(*p); p++) 43540Sstevel@tonic-gate continue; 43550Sstevel@tonic-gate q = p; 43560Sstevel@tonic-gate while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43570Sstevel@tonic-gate p++; 43580Sstevel@tonic-gate if (*p == '\0') 43590Sstevel@tonic-gate { 43600Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43610Sstevel@tonic-gate "No address!\n"); 43620Sstevel@tonic-gate return; 43630Sstevel@tonic-gate } 43640Sstevel@tonic-gate *p = '\0'; 43650Sstevel@tonic-gate if (invalidaddr(p + 1, NULL, true)) 43660Sstevel@tonic-gate return; 43670Sstevel@tonic-gate do 43680Sstevel@tonic-gate { 43690Sstevel@tonic-gate register char **pvp; 43700Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 43710Sstevel@tonic-gate 43720Sstevel@tonic-gate pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, &delimptr, 43730Sstevel@tonic-gate ConfigLevel >= 9 ? TokTypeNoC : NULL, false); 43740Sstevel@tonic-gate if (pvp == NULL) 43750Sstevel@tonic-gate continue; 43760Sstevel@tonic-gate p = q; 43770Sstevel@tonic-gate while (*p != '\0') 43780Sstevel@tonic-gate { 43790Sstevel@tonic-gate int status; 43800Sstevel@tonic-gate 43810Sstevel@tonic-gate rs = strtorwset(p, NULL, ST_FIND); 43820Sstevel@tonic-gate if (rs < 0) 43830Sstevel@tonic-gate { 43840Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43850Sstevel@tonic-gate "Undefined ruleset %s\n", 43860Sstevel@tonic-gate p); 43870Sstevel@tonic-gate break; 43880Sstevel@tonic-gate } 43890Sstevel@tonic-gate status = REWRITE(pvp, rs, e); 43900Sstevel@tonic-gate if (status != EX_OK) 43910Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 43920Sstevel@tonic-gate "== Ruleset %s (%d) status %d\n", 43930Sstevel@tonic-gate p, rs, status); 43940Sstevel@tonic-gate while (*p != '\0' && *p++ != ',') 43950Sstevel@tonic-gate continue; 43960Sstevel@tonic-gate } 43970Sstevel@tonic-gate } while (*(p = delimptr) != '\0'); 43980Sstevel@tonic-gate } 43990Sstevel@tonic-gate 44000Sstevel@tonic-gate static void 44010Sstevel@tonic-gate dump_class(s, id) 44020Sstevel@tonic-gate register STAB *s; 44030Sstevel@tonic-gate int id; 44040Sstevel@tonic-gate { 44050Sstevel@tonic-gate if (s->s_symtype != ST_CLASS) 44060Sstevel@tonic-gate return; 44070Sstevel@tonic-gate if (bitnset(bitidx(id), s->s_class)) 44080Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 44090Sstevel@tonic-gate "%s\n", s->s_name); 44100Sstevel@tonic-gate } 44110Sstevel@tonic-gate 44120Sstevel@tonic-gate /* 44130Sstevel@tonic-gate ** An exception type used to create QuickAbort exceptions. 44140Sstevel@tonic-gate ** This is my first cut at converting QuickAbort from longjmp to exceptions. 44150Sstevel@tonic-gate ** These exceptions have a single integer argument, which is the argument 44160Sstevel@tonic-gate ** to longjmp in the original code (either 1 or 2). I don't know the 44170Sstevel@tonic-gate ** significance of 1 vs 2: the calls to setjmp don't care. 44180Sstevel@tonic-gate */ 44190Sstevel@tonic-gate 44200Sstevel@tonic-gate const SM_EXC_TYPE_T EtypeQuickAbort = 44210Sstevel@tonic-gate { 44220Sstevel@tonic-gate SmExcTypeMagic, 44230Sstevel@tonic-gate "E:mta.quickabort", 44240Sstevel@tonic-gate "i", 44250Sstevel@tonic-gate sm_etype_printf, 44260Sstevel@tonic-gate "quick abort %0", 44270Sstevel@tonic-gate }; 4428