1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 6*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 9*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 10*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate /* 15*7c478bd9Sstevel@tonic-gate * Copyright 1996-2004 Sun Microsystems, Inc. All rights reserved. 16*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 17*7c478bd9Sstevel@tonic-gate */ 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate #define _DEFINE 20*7c478bd9Sstevel@tonic-gate #include <sendmail.h> 21*7c478bd9Sstevel@tonic-gate #include <sm/xtrap.h> 22*7c478bd9Sstevel@tonic-gate #include <sm/signal.h> 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate #ifndef lint 25*7c478bd9Sstevel@tonic-gate SM_UNUSED(static char copyright[]) = 26*7c478bd9Sstevel@tonic-gate "@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\ 27*7c478bd9Sstevel@tonic-gate @(#) All rights reserved.\n\ 28*7c478bd9Sstevel@tonic-gate @(#) Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 29*7c478bd9Sstevel@tonic-gate @(#) Copyright (c) 1988, 1993\n\ 30*7c478bd9Sstevel@tonic-gate @(#) The Regents of the University of California. All rights reserved.\n\ 31*7c478bd9Sstevel@tonic-gate @(#) Copyright 1996-2004 Sun Microsystems, Inc. All rights reserved.\n\ 32*7c478bd9Sstevel@tonic-gate @(#) Use is subject to license terms.\n"; 33*7c478bd9Sstevel@tonic-gate #endif /* ! lint */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: main.c,v 8.939 2004/06/17 16:39:21 ca Exp $") 38*7c478bd9Sstevel@tonic-gate SM_IDSTR(i2, "%W% (Sun) %G%") 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #if NETINET || NETINET6 41*7c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 42*7c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* for getcfname() */ 45*7c478bd9Sstevel@tonic-gate #include <sendmail/pathnames.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static SM_DEBUG_T 48*7c478bd9Sstevel@tonic-gate DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart", 49*7c478bd9Sstevel@tonic-gate "@(#)$Debug: no_persistent_restart - don't restart, log only $"); 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate static void dump_class __P((STAB *, int)); 52*7c478bd9Sstevel@tonic-gate static void obsolete __P((char **)); 53*7c478bd9Sstevel@tonic-gate static void testmodeline __P((char *, ENVELOPE *)); 54*7c478bd9Sstevel@tonic-gate static char *getextenv __P((const char *)); 55*7c478bd9Sstevel@tonic-gate static void sm_printoptions __P((char **)); 56*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL intindebug __P((int)); 57*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL sighup __P((int)); 58*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL sigpipe __P((int)); 59*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL sigterm __P((int)); 60*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1 61*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL sigusr1 __P((int)); 62*7c478bd9Sstevel@tonic-gate #endif /* SIGUSR1 */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate ** SENDMAIL -- Post mail to a set of destinations. 66*7c478bd9Sstevel@tonic-gate ** 67*7c478bd9Sstevel@tonic-gate ** This is the basic mail router. All user mail programs should 68*7c478bd9Sstevel@tonic-gate ** call this routine to actually deliver mail. Sendmail in 69*7c478bd9Sstevel@tonic-gate ** turn calls a bunch of mail servers that do the real work of 70*7c478bd9Sstevel@tonic-gate ** delivering the mail. 71*7c478bd9Sstevel@tonic-gate ** 72*7c478bd9Sstevel@tonic-gate ** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 73*7c478bd9Sstevel@tonic-gate ** (read by readcf.c). 74*7c478bd9Sstevel@tonic-gate ** 75*7c478bd9Sstevel@tonic-gate ** Usage: 76*7c478bd9Sstevel@tonic-gate ** /usr/lib/sendmail [flags] addr ... 77*7c478bd9Sstevel@tonic-gate ** 78*7c478bd9Sstevel@tonic-gate ** See the associated documentation for details. 79*7c478bd9Sstevel@tonic-gate ** 80*7c478bd9Sstevel@tonic-gate ** Authors: 81*7c478bd9Sstevel@tonic-gate ** Eric Allman, UCB/INGRES (until 10/81). 82*7c478bd9Sstevel@tonic-gate ** Britton-Lee, Inc., purveyors of fine 83*7c478bd9Sstevel@tonic-gate ** database computers (11/81 - 10/88). 84*7c478bd9Sstevel@tonic-gate ** International Computer Science Institute 85*7c478bd9Sstevel@tonic-gate ** (11/88 - 9/89). 86*7c478bd9Sstevel@tonic-gate ** UCB/Mammoth Project (10/89 - 7/95). 87*7c478bd9Sstevel@tonic-gate ** InReference, Inc. (8/95 - 1/97). 88*7c478bd9Sstevel@tonic-gate ** Sendmail, Inc. (1/98 - present). 89*7c478bd9Sstevel@tonic-gate ** The support of my employers is gratefully acknowledged. 90*7c478bd9Sstevel@tonic-gate ** Few of them (Britton-Lee in particular) have had 91*7c478bd9Sstevel@tonic-gate ** anything to gain from my involvement in this project. 92*7c478bd9Sstevel@tonic-gate ** 93*7c478bd9Sstevel@tonic-gate ** Gregory Neil Shapiro, 94*7c478bd9Sstevel@tonic-gate ** Worcester Polytechnic Institute (until 3/98). 95*7c478bd9Sstevel@tonic-gate ** Sendmail, Inc. (3/98 - present). 96*7c478bd9Sstevel@tonic-gate ** 97*7c478bd9Sstevel@tonic-gate ** Claus Assmann, 98*7c478bd9Sstevel@tonic-gate ** Sendmail, Inc. (12/98 - present). 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate char *FullName; /* sender's full name */ 102*7c478bd9Sstevel@tonic-gate ENVELOPE BlankEnvelope; /* a "blank" envelope */ 103*7c478bd9Sstevel@tonic-gate static ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 104*7c478bd9Sstevel@tonic-gate ADDRESS NullAddress = /* a null address */ 105*7c478bd9Sstevel@tonic-gate { "", "", NULL, "" }; 106*7c478bd9Sstevel@tonic-gate char *CommandLineArgs; /* command line args for pid file */ 107*7c478bd9Sstevel@tonic-gate bool Warn_Q_option = false; /* warn about Q option use */ 108*7c478bd9Sstevel@tonic-gate static int MissingFds = 0; /* bit map of fds missing on startup */ 109*7c478bd9Sstevel@tonic-gate char *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */ 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 112*7c478bd9Sstevel@tonic-gate GIDSET_T InitialGidSet[NGROUPS_MAX]; 113*7c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate #define MAXCONFIGLEVEL 10 /* highest config version level known */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate #if SASL 118*7c478bd9Sstevel@tonic-gate static sasl_callback_t srvcallbacks[] = 119*7c478bd9Sstevel@tonic-gate { 120*7c478bd9Sstevel@tonic-gate { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, 121*7c478bd9Sstevel@tonic-gate { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, 122*7c478bd9Sstevel@tonic-gate { SASL_CB_LIST_END, NULL, NULL } 123*7c478bd9Sstevel@tonic-gate }; 124*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate unsigned int SubmitMode; 127*7c478bd9Sstevel@tonic-gate int SyslogPrefixLen; /* estimated length of syslog prefix */ 128*7c478bd9Sstevel@tonic-gate #define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 129*7c478bd9Sstevel@tonic-gate #ifndef SL_FUDGE 130*7c478bd9Sstevel@tonic-gate # define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 131*7c478bd9Sstevel@tonic-gate #endif /* ! SL_FUDGE */ 132*7c478bd9Sstevel@tonic-gate #define SLDLL 8 /* est. length of default syslog label */ 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* Some options are dangerous to allow users to use in non-submit mode */ 136*7c478bd9Sstevel@tonic-gate #define CHECK_AGAINST_OPMODE(cmd) \ 137*7c478bd9Sstevel@tonic-gate { \ 138*7c478bd9Sstevel@tonic-gate if (extraprivs && \ 139*7c478bd9Sstevel@tonic-gate OpMode != MD_DELIVER && OpMode != MD_SMTP && \ 140*7c478bd9Sstevel@tonic-gate OpMode != MD_ARPAFTP && \ 141*7c478bd9Sstevel@tonic-gate OpMode != MD_VERIFY && OpMode != MD_TEST) \ 142*7c478bd9Sstevel@tonic-gate { \ 143*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 144*7c478bd9Sstevel@tonic-gate "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \ 145*7c478bd9Sstevel@tonic-gate (cmd)); \ 146*7c478bd9Sstevel@tonic-gate break; \ 147*7c478bd9Sstevel@tonic-gate } \ 148*7c478bd9Sstevel@tonic-gate if (extraprivs && queuerun) \ 149*7c478bd9Sstevel@tonic-gate { \ 150*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \ 151*7c478bd9Sstevel@tonic-gate "WARNING: Ignoring submission mode -%c option with -q\n", \ 152*7c478bd9Sstevel@tonic-gate (cmd)); \ 153*7c478bd9Sstevel@tonic-gate break; \ 154*7c478bd9Sstevel@tonic-gate } \ 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate int 158*7c478bd9Sstevel@tonic-gate main(argc, argv, envp) 159*7c478bd9Sstevel@tonic-gate int argc; 160*7c478bd9Sstevel@tonic-gate char **argv; 161*7c478bd9Sstevel@tonic-gate char **envp; 162*7c478bd9Sstevel@tonic-gate { 163*7c478bd9Sstevel@tonic-gate register char *p; 164*7c478bd9Sstevel@tonic-gate char **av; 165*7c478bd9Sstevel@tonic-gate extern char Version[]; 166*7c478bd9Sstevel@tonic-gate char *ep, *from; 167*7c478bd9Sstevel@tonic-gate STAB *st; 168*7c478bd9Sstevel@tonic-gate register int i; 169*7c478bd9Sstevel@tonic-gate int j; 170*7c478bd9Sstevel@tonic-gate int dp; 171*7c478bd9Sstevel@tonic-gate int fill_errno; 172*7c478bd9Sstevel@tonic-gate int qgrp = NOQGRP; /* queue group to process */ 173*7c478bd9Sstevel@tonic-gate bool safecf = true; 174*7c478bd9Sstevel@tonic-gate BITMAP256 *p_flags = NULL; /* daemon flags */ 175*7c478bd9Sstevel@tonic-gate bool warn_C_flag = false; 176*7c478bd9Sstevel@tonic-gate bool auth = true; /* whether to set e_auth_param */ 177*7c478bd9Sstevel@tonic-gate char warn_f_flag = '\0'; 178*7c478bd9Sstevel@tonic-gate bool run_in_foreground = false; /* -bD mode */ 179*7c478bd9Sstevel@tonic-gate bool queuerun = false, debug = false; 180*7c478bd9Sstevel@tonic-gate struct passwd *pw; 181*7c478bd9Sstevel@tonic-gate struct hostent *hp; 182*7c478bd9Sstevel@tonic-gate char *nullserver = NULL; 183*7c478bd9Sstevel@tonic-gate char *authinfo = NULL; 184*7c478bd9Sstevel@tonic-gate char *sysloglabel = NULL; /* label for syslog */ 185*7c478bd9Sstevel@tonic-gate char *conffile = NULL; /* name of .cf file */ 186*7c478bd9Sstevel@tonic-gate char *queuegroup = NULL; /* queue group to process */ 187*7c478bd9Sstevel@tonic-gate char *quarantining = NULL; /* quarantine queue items? */ 188*7c478bd9Sstevel@tonic-gate bool extraprivs; 189*7c478bd9Sstevel@tonic-gate bool forged, negate; 190*7c478bd9Sstevel@tonic-gate bool queuepersistent = false; /* queue runner process runs forever */ 191*7c478bd9Sstevel@tonic-gate bool foregroundqueue = false; /* queue run in foreground */ 192*7c478bd9Sstevel@tonic-gate bool save_val; /* to save some bool var. */ 193*7c478bd9Sstevel@tonic-gate int cftype; /* which cf file to use? */ 194*7c478bd9Sstevel@tonic-gate SM_FILE_T *smdebug; 195*7c478bd9Sstevel@tonic-gate static time_t starttime = 0; /* when was process started */ 196*7c478bd9Sstevel@tonic-gate struct stat traf_st; /* for TrafficLog FIFO check */ 197*7c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 198*7c478bd9Sstevel@tonic-gate char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 199*7c478bd9Sstevel@tonic-gate static char rnamebuf[MAXNAME]; /* holds RealUserName */ 200*7c478bd9Sstevel@tonic-gate char *emptyenviron[1]; 201*7c478bd9Sstevel@tonic-gate #if STARTTLS 202*7c478bd9Sstevel@tonic-gate bool tls_ok; 203*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 204*7c478bd9Sstevel@tonic-gate QUEUE_CHAR *new; 205*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 206*7c478bd9Sstevel@tonic-gate extern int DtableSize; 207*7c478bd9Sstevel@tonic-gate extern int optind; 208*7c478bd9Sstevel@tonic-gate extern int opterr; 209*7c478bd9Sstevel@tonic-gate extern char *optarg; 210*7c478bd9Sstevel@tonic-gate extern char **environ; 211*7c478bd9Sstevel@tonic-gate #if SASL 212*7c478bd9Sstevel@tonic-gate extern void sm_sasl_init __P((void)); 213*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate #if USE_ENVIRON 216*7c478bd9Sstevel@tonic-gate envp = environ; 217*7c478bd9Sstevel@tonic-gate #endif /* USE_ENVIRON */ 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* turn off profiling */ 220*7c478bd9Sstevel@tonic-gate SM_PROF(0); 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate /* install default exception handler */ 223*7c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* set the default in/out channel so errors reported to screen */ 226*7c478bd9Sstevel@tonic-gate InChannel = smioin; 227*7c478bd9Sstevel@tonic-gate OutChannel = smioout; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate ** Check to see if we reentered. 231*7c478bd9Sstevel@tonic-gate ** This would normally happen if e_putheader or e_putbody 232*7c478bd9Sstevel@tonic-gate ** were NULL when invoked. 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate if (starttime != 0) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate syserr("main: reentered!"); 238*7c478bd9Sstevel@tonic-gate abort(); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate starttime = curtime(); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* avoid null pointer dereferences */ 243*7c478bd9Sstevel@tonic-gate TermEscape.te_rv_on = TermEscape.te_rv_off = ""; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate RealUid = getuid(); 246*7c478bd9Sstevel@tonic-gate RealGid = getgid(); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate /* Check if sendmail is running with extra privs */ 249*7c478bd9Sstevel@tonic-gate extraprivs = (RealUid != 0 && 250*7c478bd9Sstevel@tonic-gate (geteuid() != getuid() || getegid() != getgid())); 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* get whatever .cf file is right for the opmode */ 255*7c478bd9Sstevel@tonic-gate cftype = SM_GET_RIGHT_CF; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 258*7c478bd9Sstevel@tonic-gate DtableSize = getdtsize(); 259*7c478bd9Sstevel@tonic-gate if (DtableSize > 256) 260*7c478bd9Sstevel@tonic-gate DtableSize = 256; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate ** Be sure we have enough file descriptors. 264*7c478bd9Sstevel@tonic-gate ** But also be sure that 0, 1, & 2 are open. 265*7c478bd9Sstevel@tonic-gate */ 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate /* reset errno and fill_errno; the latter is used way down below */ 268*7c478bd9Sstevel@tonic-gate errno = fill_errno = 0; 269*7c478bd9Sstevel@tonic-gate fill_fd(STDIN_FILENO, NULL); 270*7c478bd9Sstevel@tonic-gate if (errno != 0) 271*7c478bd9Sstevel@tonic-gate fill_errno = errno; 272*7c478bd9Sstevel@tonic-gate fill_fd(STDOUT_FILENO, NULL); 273*7c478bd9Sstevel@tonic-gate if (errno != 0) 274*7c478bd9Sstevel@tonic-gate fill_errno = errno; 275*7c478bd9Sstevel@tonic-gate fill_fd(STDERR_FILENO, NULL); 276*7c478bd9Sstevel@tonic-gate if (errno != 0) 277*7c478bd9Sstevel@tonic-gate fill_errno = errno; 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate sm_closefrom(STDERR_FILENO + 1, DtableSize); 280*7c478bd9Sstevel@tonic-gate errno = 0; 281*7c478bd9Sstevel@tonic-gate smdebug = NULL; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate #if LOG 284*7c478bd9Sstevel@tonic-gate # ifndef SM_LOG_STR 285*7c478bd9Sstevel@tonic-gate # define SM_LOG_STR "sendmail" 286*7c478bd9Sstevel@tonic-gate # endif /* ! SM_LOG_STR */ 287*7c478bd9Sstevel@tonic-gate # ifdef LOG_MAIL 288*7c478bd9Sstevel@tonic-gate openlog(SM_LOG_STR, LOG_PID, LOG_MAIL); 289*7c478bd9Sstevel@tonic-gate # else /* LOG_MAIL */ 290*7c478bd9Sstevel@tonic-gate openlog(SM_LOG_STR, LOG_PID); 291*7c478bd9Sstevel@tonic-gate # endif /* LOG_MAIL */ 292*7c478bd9Sstevel@tonic-gate #endif /* LOG */ 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate /* 295*7c478bd9Sstevel@tonic-gate ** Seed the random number generator. 296*7c478bd9Sstevel@tonic-gate ** Used for queue file names, picking a queue directory, and 297*7c478bd9Sstevel@tonic-gate ** MX randomization. 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate seed_random(); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* do machine-dependent initializations */ 303*7c478bd9Sstevel@tonic-gate init_md(argc, argv); 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* reset status from syserr() calls for missing file descriptors */ 309*7c478bd9Sstevel@tonic-gate Errors = 0; 310*7c478bd9Sstevel@tonic-gate ExitStat = EX_OK; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate SubmitMode = SUBMIT_UNKNOWN; 313*7c478bd9Sstevel@tonic-gate #if XDEBUG 314*7c478bd9Sstevel@tonic-gate checkfd012("after openlog"); 315*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1"); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate #ifdef NGROUPS_MAX 320*7c478bd9Sstevel@tonic-gate /* save initial group set for future checks */ 321*7c478bd9Sstevel@tonic-gate i = getgroups(NGROUPS_MAX, InitialGidSet); 322*7c478bd9Sstevel@tonic-gate if (i <= 0) 323*7c478bd9Sstevel@tonic-gate { 324*7c478bd9Sstevel@tonic-gate InitialGidSet[0] = (GID_T) -1; 325*7c478bd9Sstevel@tonic-gate i = 0; 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate while (i < NGROUPS_MAX) 328*7c478bd9Sstevel@tonic-gate InitialGidSet[i++] = InitialGidSet[0]; 329*7c478bd9Sstevel@tonic-gate #endif /* NGROUPS_MAX */ 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* drop group id privileges (RunAsUser not yet set) */ 332*7c478bd9Sstevel@tonic-gate dp = drop_privileges(false); 333*7c478bd9Sstevel@tonic-gate setstat(dp); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1 336*7c478bd9Sstevel@tonic-gate /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 337*7c478bd9Sstevel@tonic-gate if (!extraprivs) 338*7c478bd9Sstevel@tonic-gate { 339*7c478bd9Sstevel@tonic-gate /* arrange to dump state on user-1 signal */ 340*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGUSR1, sigusr1); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate else 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate /* ignore user-1 signal */ 345*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGUSR1, SIG_IGN); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate #endif /* SIGUSR1 */ 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* initialize for setproctitle */ 350*7c478bd9Sstevel@tonic-gate initsetproctitle(argc, argv, envp); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate /* Handle any non-getoptable constructions. */ 353*7c478bd9Sstevel@tonic-gate obsolete(argv); 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate ** Do a quick prescan of the argument list. 357*7c478bd9Sstevel@tonic-gate */ 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* find initial opMode */ 361*7c478bd9Sstevel@tonic-gate OpMode = MD_DELIVER; 362*7c478bd9Sstevel@tonic-gate av = argv; 363*7c478bd9Sstevel@tonic-gate p = strrchr(*av, '/'); 364*7c478bd9Sstevel@tonic-gate if (p++ == NULL) 365*7c478bd9Sstevel@tonic-gate p = *av; 366*7c478bd9Sstevel@tonic-gate if (strcmp(p, "newaliases") == 0) 367*7c478bd9Sstevel@tonic-gate OpMode = MD_INITALIAS; 368*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "mailq") == 0) 369*7c478bd9Sstevel@tonic-gate OpMode = MD_PRINT; 370*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "smtpd") == 0) 371*7c478bd9Sstevel@tonic-gate OpMode = MD_DAEMON; 372*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "hoststat") == 0) 373*7c478bd9Sstevel@tonic-gate OpMode = MD_HOSTSTAT; 374*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "purgestat") == 0) 375*7c478bd9Sstevel@tonic-gate OpMode = MD_PURGESTAT; 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate #if defined(__osf__) || defined(_AIX3) 378*7c478bd9Sstevel@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" 379*7c478bd9Sstevel@tonic-gate #endif /* defined(__osf__) || defined(_AIX3) */ 380*7c478bd9Sstevel@tonic-gate #if defined(sony_news) 381*7c478bd9Sstevel@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:" 382*7c478bd9Sstevel@tonic-gate #endif /* defined(sony_news) */ 383*7c478bd9Sstevel@tonic-gate #ifndef OPTIONS 384*7c478bd9Sstevel@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:" 385*7c478bd9Sstevel@tonic-gate #endif /* ! OPTIONS */ 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate /* Set to 0 to allow -b; need to check optarg before using it! */ 388*7c478bd9Sstevel@tonic-gate opterr = 0; 389*7c478bd9Sstevel@tonic-gate while ((j = getopt(argc, argv, OPTIONS)) != -1) 390*7c478bd9Sstevel@tonic-gate { 391*7c478bd9Sstevel@tonic-gate switch (j) 392*7c478bd9Sstevel@tonic-gate { 393*7c478bd9Sstevel@tonic-gate case 'b': /* operations mode */ 394*7c478bd9Sstevel@tonic-gate j = (optarg == NULL) ? ' ' : *optarg; 395*7c478bd9Sstevel@tonic-gate switch (j) 396*7c478bd9Sstevel@tonic-gate { 397*7c478bd9Sstevel@tonic-gate case MD_DAEMON: 398*7c478bd9Sstevel@tonic-gate case MD_FGDAEMON: 399*7c478bd9Sstevel@tonic-gate case MD_SMTP: 400*7c478bd9Sstevel@tonic-gate case MD_INITALIAS: 401*7c478bd9Sstevel@tonic-gate case MD_DELIVER: 402*7c478bd9Sstevel@tonic-gate case MD_VERIFY: 403*7c478bd9Sstevel@tonic-gate case MD_TEST: 404*7c478bd9Sstevel@tonic-gate case MD_PRINT: 405*7c478bd9Sstevel@tonic-gate case MD_PRINTNQE: 406*7c478bd9Sstevel@tonic-gate case MD_HOSTSTAT: 407*7c478bd9Sstevel@tonic-gate case MD_PURGESTAT: 408*7c478bd9Sstevel@tonic-gate case MD_ARPAFTP: 409*7c478bd9Sstevel@tonic-gate OpMode = j; 410*7c478bd9Sstevel@tonic-gate break; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate case MD_FREEZE: 413*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 414*7c478bd9Sstevel@tonic-gate "Frozen configurations unsupported\n"); 415*7c478bd9Sstevel@tonic-gate return EX_USAGE; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate default: 418*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 419*7c478bd9Sstevel@tonic-gate "Invalid operation mode %c\n", 420*7c478bd9Sstevel@tonic-gate j); 421*7c478bd9Sstevel@tonic-gate return EX_USAGE; 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate break; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate case 'D': 426*7c478bd9Sstevel@tonic-gate if (debug) 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate errno = 0; 429*7c478bd9Sstevel@tonic-gate syserr("-D file must be before -d"); 430*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 431*7c478bd9Sstevel@tonic-gate break; 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate dp = drop_privileges(true); 434*7c478bd9Sstevel@tonic-gate setstat(dp); 435*7c478bd9Sstevel@tonic-gate smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 436*7c478bd9Sstevel@tonic-gate optarg, SM_IO_APPEND, NULL); 437*7c478bd9Sstevel@tonic-gate if (smdebug == NULL) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate syserr("cannot open %s", optarg); 440*7c478bd9Sstevel@tonic-gate ExitStat = EX_CANTCREAT; 441*7c478bd9Sstevel@tonic-gate break; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate sm_debug_setfile(smdebug); 444*7c478bd9Sstevel@tonic-gate break; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate case 'd': 447*7c478bd9Sstevel@tonic-gate debug = true; 448*7c478bd9Sstevel@tonic-gate tTflag(optarg); 449*7c478bd9Sstevel@tonic-gate (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT, 450*7c478bd9Sstevel@tonic-gate (char *) NULL, SM_IO_NBF, 451*7c478bd9Sstevel@tonic-gate SM_IO_BUFSIZ); 452*7c478bd9Sstevel@tonic-gate break; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate case 'G': /* relay (gateway) submission */ 455*7c478bd9Sstevel@tonic-gate SubmitMode = SUBMIT_MTA; 456*7c478bd9Sstevel@tonic-gate break; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate case 'L': 459*7c478bd9Sstevel@tonic-gate if (optarg == NULL) 460*7c478bd9Sstevel@tonic-gate { 461*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 462*7c478bd9Sstevel@tonic-gate "option requires an argument -- '%c'", 463*7c478bd9Sstevel@tonic-gate (char) j); 464*7c478bd9Sstevel@tonic-gate return EX_USAGE; 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate j = SM_MIN(strlen(optarg), 32) + 1; 467*7c478bd9Sstevel@tonic-gate sysloglabel = xalloc(j); 468*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(sysloglabel, optarg, j); 469*7c478bd9Sstevel@tonic-gate SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + 470*7c478bd9Sstevel@tonic-gate SL_FUDGE + j; 471*7c478bd9Sstevel@tonic-gate break; 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate case 'Q': 474*7c478bd9Sstevel@tonic-gate case 'q': 475*7c478bd9Sstevel@tonic-gate /* just check if it is there */ 476*7c478bd9Sstevel@tonic-gate queuerun = true; 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate opterr = 1; 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate /* Don't leak queue information via debug flags */ 483*7c478bd9Sstevel@tonic-gate if (extraprivs && queuerun && debug) 484*7c478bd9Sstevel@tonic-gate { 485*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 486*7c478bd9Sstevel@tonic-gate "WARNING: Can not use -d with -q. Disabling debugging.\n"); 487*7c478bd9Sstevel@tonic-gate sm_debug_close(); 488*7c478bd9Sstevel@tonic-gate sm_debug_setfile(NULL); 489*7c478bd9Sstevel@tonic-gate (void) memset(tTdvect, '\0', sizeof tTdvect); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate #if LOG 493*7c478bd9Sstevel@tonic-gate if (sysloglabel != NULL) 494*7c478bd9Sstevel@tonic-gate { 495*7c478bd9Sstevel@tonic-gate /* Sanitize the string */ 496*7c478bd9Sstevel@tonic-gate for (p = sysloglabel; *p != '\0'; p++) 497*7c478bd9Sstevel@tonic-gate { 498*7c478bd9Sstevel@tonic-gate if (!isascii(*p) || !isprint(*p) || *p == '%') 499*7c478bd9Sstevel@tonic-gate *p = '*'; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate closelog(); 502*7c478bd9Sstevel@tonic-gate # ifdef LOG_MAIL 503*7c478bd9Sstevel@tonic-gate openlog(sysloglabel, LOG_PID, LOG_MAIL); 504*7c478bd9Sstevel@tonic-gate # else /* LOG_MAIL */ 505*7c478bd9Sstevel@tonic-gate openlog(sysloglabel, LOG_PID); 506*7c478bd9Sstevel@tonic-gate # endif /* LOG_MAIL */ 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate #endif /* LOG */ 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate /* set up the blank envelope */ 511*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_puthdr = putheader; 512*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_putbody = putbody; 513*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_xfp = NULL; 514*7c478bd9Sstevel@tonic-gate STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 515*7c478bd9Sstevel@tonic-gate CurEnv = &BlankEnvelope; 516*7c478bd9Sstevel@tonic-gate STRUCTCOPY(NullAddress, MainEnvelope.e_from); 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate ** Set default values for variables. 520*7c478bd9Sstevel@tonic-gate ** These cannot be in initialized data space. 521*7c478bd9Sstevel@tonic-gate */ 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate setdefaults(&BlankEnvelope); 524*7c478bd9Sstevel@tonic-gate initmacros(&BlankEnvelope); 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* reset macro */ 527*7c478bd9Sstevel@tonic-gate set_op_mode(OpMode); 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate pw = sm_getpwuid(RealUid); 530*7c478bd9Sstevel@tonic-gate if (pw != NULL) 531*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); 532*7c478bd9Sstevel@tonic-gate else 533*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 534*7c478bd9Sstevel@tonic-gate (int) RealUid); 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate RealUserName = rnamebuf; 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate if (tTd(0, 101)) 539*7c478bd9Sstevel@tonic-gate { 540*7c478bd9Sstevel@tonic-gate sm_dprintf("Version %s\n", Version); 541*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 542*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate ** if running non-set-user-ID binary as non-root, pretend 547*7c478bd9Sstevel@tonic-gate ** we are the RunAsUid 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (RealUid != 0 && geteuid() == RealUid) 551*7c478bd9Sstevel@tonic-gate { 552*7c478bd9Sstevel@tonic-gate if (tTd(47, 1)) 553*7c478bd9Sstevel@tonic-gate sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n", 554*7c478bd9Sstevel@tonic-gate (int) RealUid); 555*7c478bd9Sstevel@tonic-gate RunAsUid = RealUid; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate else if (geteuid() != 0) 558*7c478bd9Sstevel@tonic-gate RunAsUid = geteuid(); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate EffGid = getegid(); 561*7c478bd9Sstevel@tonic-gate if (RealUid != 0 && EffGid == RealGid) 562*7c478bd9Sstevel@tonic-gate RunAsGid = RealGid; 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate if (tTd(47, 5)) 565*7c478bd9Sstevel@tonic-gate { 566*7c478bd9Sstevel@tonic-gate sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 567*7c478bd9Sstevel@tonic-gate (int) geteuid(), (int) getuid(), 568*7c478bd9Sstevel@tonic-gate (int) getegid(), (int) getgid()); 569*7c478bd9Sstevel@tonic-gate sm_dprintf("main: RunAsUser = %d:%d\n", 570*7c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* save command line arguments */ 574*7c478bd9Sstevel@tonic-gate j = 0; 575*7c478bd9Sstevel@tonic-gate for (av = argv; *av != NULL; ) 576*7c478bd9Sstevel@tonic-gate j += strlen(*av++) + 1; 577*7c478bd9Sstevel@tonic-gate SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); 578*7c478bd9Sstevel@tonic-gate CommandLineArgs = xalloc(j); 579*7c478bd9Sstevel@tonic-gate p = CommandLineArgs; 580*7c478bd9Sstevel@tonic-gate for (av = argv, i = 0; *av != NULL; ) 581*7c478bd9Sstevel@tonic-gate { 582*7c478bd9Sstevel@tonic-gate int h; 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate SaveArgv[i++] = newstr(*av); 585*7c478bd9Sstevel@tonic-gate if (av != argv) 586*7c478bd9Sstevel@tonic-gate *p++ = ' '; 587*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(p, *av++, j); 588*7c478bd9Sstevel@tonic-gate h = strlen(p); 589*7c478bd9Sstevel@tonic-gate p += h; 590*7c478bd9Sstevel@tonic-gate j -= h + 1; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate SaveArgv[i] = NULL; 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate if (tTd(0, 1)) 595*7c478bd9Sstevel@tonic-gate { 596*7c478bd9Sstevel@tonic-gate extern char *CompileOptions[]; 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate sm_dprintf("Version %s\n Compiled with:", Version); 599*7c478bd9Sstevel@tonic-gate sm_printoptions(CompileOptions); 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate if (tTd(0, 10)) 602*7c478bd9Sstevel@tonic-gate { 603*7c478bd9Sstevel@tonic-gate extern char *OsCompileOptions[]; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate sm_dprintf(" OS Defines:"); 606*7c478bd9Sstevel@tonic-gate sm_printoptions(OsCompileOptions); 607*7c478bd9Sstevel@tonic-gate #ifdef _PATH_UNIX 608*7c478bd9Sstevel@tonic-gate sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 609*7c478bd9Sstevel@tonic-gate #endif /* _PATH_UNIX */ 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (default for MSP)\n", 612*7c478bd9Sstevel@tonic-gate getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF, 613*7c478bd9Sstevel@tonic-gate conffile)); 614*7c478bd9Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (default for MTA)\n", 615*7c478bd9Sstevel@tonic-gate getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF, 616*7c478bd9Sstevel@tonic-gate conffile)); 617*7c478bd9Sstevel@tonic-gate sm_dprintf(" Pid file:\t%s (default)\n", PidFile); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate if (tTd(0, 12)) 621*7c478bd9Sstevel@tonic-gate { 622*7c478bd9Sstevel@tonic-gate extern char *SmCompileOptions[]; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate sm_dprintf(" libsm Defines:"); 625*7c478bd9Sstevel@tonic-gate sm_printoptions(SmCompileOptions); 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate if (tTd(0, 13)) 629*7c478bd9Sstevel@tonic-gate { 630*7c478bd9Sstevel@tonic-gate extern char *FFRCompileOptions[]; 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate sm_dprintf(" FFR Defines:"); 633*7c478bd9Sstevel@tonic-gate sm_printoptions(FFRCompileOptions); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* clear sendmail's environment */ 637*7c478bd9Sstevel@tonic-gate ExternalEnviron = environ; 638*7c478bd9Sstevel@tonic-gate emptyenviron[0] = NULL; 639*7c478bd9Sstevel@tonic-gate environ = emptyenviron; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate ** restore any original TZ setting until TimeZoneSpec has been 643*7c478bd9Sstevel@tonic-gate ** determined - or early log messages may get bogus time stamps 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate if ((p = getextenv("TZ")) != NULL) 647*7c478bd9Sstevel@tonic-gate { 648*7c478bd9Sstevel@tonic-gate char *tz; 649*7c478bd9Sstevel@tonic-gate int tzlen; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* XXX check for reasonable length? */ 652*7c478bd9Sstevel@tonic-gate tzlen = strlen(p) + 4; 653*7c478bd9Sstevel@tonic-gate tz = xalloc(tzlen); 654*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p); 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* XXX check return code? */ 657*7c478bd9Sstevel@tonic-gate (void) putenv(tz); 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate /* prime the child environment */ 661*7c478bd9Sstevel@tonic-gate setuserenv("AGENT", "sendmail"); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGPIPE, SIG_IGN); 664*7c478bd9Sstevel@tonic-gate OldUmask = umask(022); 665*7c478bd9Sstevel@tonic-gate FullName = getextenv("NAME"); 666*7c478bd9Sstevel@tonic-gate if (FullName != NULL) 667*7c478bd9Sstevel@tonic-gate FullName = newstr(FullName); 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate /* 670*7c478bd9Sstevel@tonic-gate ** Initialize name server if it is going to be used. 671*7c478bd9Sstevel@tonic-gate */ 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 674*7c478bd9Sstevel@tonic-gate if (!bitset(RES_INIT, _res.options)) 675*7c478bd9Sstevel@tonic-gate (void) res_init(); 676*7c478bd9Sstevel@tonic-gate if (tTd(8, 8)) 677*7c478bd9Sstevel@tonic-gate _res.options |= RES_DEBUG; 678*7c478bd9Sstevel@tonic-gate else 679*7c478bd9Sstevel@tonic-gate _res.options &= ~RES_DEBUG; 680*7c478bd9Sstevel@tonic-gate # ifdef RES_NOALIASES 681*7c478bd9Sstevel@tonic-gate _res.options |= RES_NOALIASES; 682*7c478bd9Sstevel@tonic-gate # endif /* RES_NOALIASES */ 683*7c478bd9Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 684*7c478bd9Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 685*7c478bd9Sstevel@tonic-gate TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 686*7c478bd9Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 687*7c478bd9Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 688*7c478bd9Sstevel@tonic-gate TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 689*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate errno = 0; 692*7c478bd9Sstevel@tonic-gate from = NULL; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* initialize some macros, etc. */ 695*7c478bd9Sstevel@tonic-gate init_vendor_macros(&BlankEnvelope); 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate /* version */ 698*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate /* hostname */ 701*7c478bd9Sstevel@tonic-gate hp = myhostname(jbuf, sizeof jbuf); 702*7c478bd9Sstevel@tonic-gate if (jbuf[0] != '\0') 703*7c478bd9Sstevel@tonic-gate { 704*7c478bd9Sstevel@tonic-gate struct utsname utsname; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate if (tTd(0, 4)) 707*7c478bd9Sstevel@tonic-gate sm_dprintf("Canonical name: %s\n", jbuf); 708*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf); 709*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf); 710*7c478bd9Sstevel@tonic-gate setclass('w', jbuf); 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate p = strchr(jbuf, '.'); 713*7c478bd9Sstevel@tonic-gate if (p != NULL && p[1] != '\0') 714*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]); 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate if (uname(&utsname) >= 0) 717*7c478bd9Sstevel@tonic-gate p = utsname.nodename; 718*7c478bd9Sstevel@tonic-gate else 719*7c478bd9Sstevel@tonic-gate { 720*7c478bd9Sstevel@tonic-gate if (tTd(0, 22)) 721*7c478bd9Sstevel@tonic-gate sm_dprintf("uname failed (%s)\n", 722*7c478bd9Sstevel@tonic-gate sm_errstring(errno)); 723*7c478bd9Sstevel@tonic-gate makelower(jbuf); 724*7c478bd9Sstevel@tonic-gate p = jbuf; 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate if (tTd(0, 4)) 727*7c478bd9Sstevel@tonic-gate sm_dprintf(" UUCP nodename: %s\n", p); 728*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p); 729*7c478bd9Sstevel@tonic-gate setclass('k', p); 730*7c478bd9Sstevel@tonic-gate setclass('w', p); 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate if (hp != NULL) 733*7c478bd9Sstevel@tonic-gate { 734*7c478bd9Sstevel@tonic-gate for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 735*7c478bd9Sstevel@tonic-gate { 736*7c478bd9Sstevel@tonic-gate if (tTd(0, 4)) 737*7c478bd9Sstevel@tonic-gate sm_dprintf("\ta.k.a.: %s\n", *av); 738*7c478bd9Sstevel@tonic-gate setclass('w', *av); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate #if NETINET || NETINET6 741*7c478bd9Sstevel@tonic-gate for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++) 742*7c478bd9Sstevel@tonic-gate { 743*7c478bd9Sstevel@tonic-gate # if NETINET6 744*7c478bd9Sstevel@tonic-gate char *addr; 745*7c478bd9Sstevel@tonic-gate char buf6[INET6_ADDRSTRLEN]; 746*7c478bd9Sstevel@tonic-gate struct in6_addr ia6; 747*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 748*7c478bd9Sstevel@tonic-gate # if NETINET 749*7c478bd9Sstevel@tonic-gate struct in_addr ia; 750*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 751*7c478bd9Sstevel@tonic-gate char ipbuf[103]; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate ipbuf[0] = '\0'; 754*7c478bd9Sstevel@tonic-gate switch (hp->h_addrtype) 755*7c478bd9Sstevel@tonic-gate { 756*7c478bd9Sstevel@tonic-gate # if NETINET 757*7c478bd9Sstevel@tonic-gate case AF_INET: 758*7c478bd9Sstevel@tonic-gate if (hp->h_length != INADDRSZ) 759*7c478bd9Sstevel@tonic-gate break; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate memmove(&ia, hp->h_addr_list[i], INADDRSZ); 762*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, 763*7c478bd9Sstevel@tonic-gate "[%.100s]", inet_ntoa(ia)); 764*7c478bd9Sstevel@tonic-gate break; 765*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate # if NETINET6 768*7c478bd9Sstevel@tonic-gate case AF_INET6: 769*7c478bd9Sstevel@tonic-gate if (hp->h_length != IN6ADDRSZ) 770*7c478bd9Sstevel@tonic-gate break; 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 773*7c478bd9Sstevel@tonic-gate addr = anynet_ntop(&ia6, buf6, sizeof buf6); 774*7c478bd9Sstevel@tonic-gate if (addr != NULL) 775*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, 776*7c478bd9Sstevel@tonic-gate "[%.100s]", addr); 777*7c478bd9Sstevel@tonic-gate break; 778*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate if (ipbuf[0] == '\0') 781*7c478bd9Sstevel@tonic-gate break; 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate if (tTd(0, 4)) 784*7c478bd9Sstevel@tonic-gate sm_dprintf("\ta.k.a.: %s\n", ipbuf); 785*7c478bd9Sstevel@tonic-gate setclass('w', ipbuf); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 788*7c478bd9Sstevel@tonic-gate #if NETINET6 789*7c478bd9Sstevel@tonic-gate freehostent(hp); 790*7c478bd9Sstevel@tonic-gate hp = NULL; 791*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* current time */ 795*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL)); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate /* current load average */ 798*7c478bd9Sstevel@tonic-gate sm_getla(); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate QueueLimitRecipient = (QUEUE_CHAR *) NULL; 801*7c478bd9Sstevel@tonic-gate QueueLimitSender = (QUEUE_CHAR *) NULL; 802*7c478bd9Sstevel@tonic-gate QueueLimitId = (QUEUE_CHAR *) NULL; 803*7c478bd9Sstevel@tonic-gate QueueLimitQuarantine = (QUEUE_CHAR *) NULL; 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* 806*7c478bd9Sstevel@tonic-gate ** Crack argv. 807*7c478bd9Sstevel@tonic-gate */ 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate optind = 1; 810*7c478bd9Sstevel@tonic-gate while ((j = getopt(argc, argv, OPTIONS)) != -1) 811*7c478bd9Sstevel@tonic-gate { 812*7c478bd9Sstevel@tonic-gate switch (j) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate case 'b': /* operations mode */ 815*7c478bd9Sstevel@tonic-gate /* already done */ 816*7c478bd9Sstevel@tonic-gate break; 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate case 'A': /* use Alternate sendmail/submit.cf */ 819*7c478bd9Sstevel@tonic-gate cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF 820*7c478bd9Sstevel@tonic-gate : SM_GET_SENDMAIL_CF; 821*7c478bd9Sstevel@tonic-gate break; 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate case 'B': /* body type */ 824*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 825*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_bodytype = newstr(optarg); 826*7c478bd9Sstevel@tonic-gate break; 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate case 'C': /* select configuration file (already done) */ 829*7c478bd9Sstevel@tonic-gate if (RealUid != 0) 830*7c478bd9Sstevel@tonic-gate warn_C_flag = true; 831*7c478bd9Sstevel@tonic-gate conffile = newstr(optarg); 832*7c478bd9Sstevel@tonic-gate dp = drop_privileges(true); 833*7c478bd9Sstevel@tonic-gate setstat(dp); 834*7c478bd9Sstevel@tonic-gate safecf = false; 835*7c478bd9Sstevel@tonic-gate break; 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate case 'D': 838*7c478bd9Sstevel@tonic-gate case 'd': /* debugging */ 839*7c478bd9Sstevel@tonic-gate /* already done */ 840*7c478bd9Sstevel@tonic-gate break; 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate case 'f': /* from address */ 843*7c478bd9Sstevel@tonic-gate case 'r': /* obsolete -f flag */ 844*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 845*7c478bd9Sstevel@tonic-gate if (from != NULL) 846*7c478bd9Sstevel@tonic-gate { 847*7c478bd9Sstevel@tonic-gate usrerr("More than one \"from\" person"); 848*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 849*7c478bd9Sstevel@tonic-gate break; 850*7c478bd9Sstevel@tonic-gate } 851*7c478bd9Sstevel@tonic-gate if (optarg[0] == '\0') 852*7c478bd9Sstevel@tonic-gate from = newstr("<>"); 853*7c478bd9Sstevel@tonic-gate else 854*7c478bd9Sstevel@tonic-gate from = newstr(denlstring(optarg, true, true)); 855*7c478bd9Sstevel@tonic-gate if (strcmp(RealUserName, from) != 0) 856*7c478bd9Sstevel@tonic-gate warn_f_flag = j; 857*7c478bd9Sstevel@tonic-gate break; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate case 'F': /* set full name */ 860*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 861*7c478bd9Sstevel@tonic-gate FullName = newstr(optarg); 862*7c478bd9Sstevel@tonic-gate break; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate case 'G': /* relay (gateway) submission */ 865*7c478bd9Sstevel@tonic-gate /* already set */ 866*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 867*7c478bd9Sstevel@tonic-gate break; 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate case 'h': /* hop count */ 870*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 871*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep, 872*7c478bd9Sstevel@tonic-gate 10); 873*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%d", 874*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_hopcount); 875*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf); 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate if (*ep) 878*7c478bd9Sstevel@tonic-gate { 879*7c478bd9Sstevel@tonic-gate usrerr("Bad hop count (%s)", optarg); 880*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate break; 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate case 'L': /* program label */ 885*7c478bd9Sstevel@tonic-gate /* already set */ 886*7c478bd9Sstevel@tonic-gate break; 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate case 'n': /* don't alias */ 889*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 890*7c478bd9Sstevel@tonic-gate NoAlias = true; 891*7c478bd9Sstevel@tonic-gate break; 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate case 'N': /* delivery status notifications */ 894*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 895*7c478bd9Sstevel@tonic-gate DefaultNotify |= QHASNOTIFY; 896*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 897*7c478bd9Sstevel@tonic-gate macid("{dsn_notify}"), optarg); 898*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(optarg, "never") == 0) 899*7c478bd9Sstevel@tonic-gate break; 900*7c478bd9Sstevel@tonic-gate for (p = optarg; p != NULL; optarg = p) 901*7c478bd9Sstevel@tonic-gate { 902*7c478bd9Sstevel@tonic-gate p = strchr(p, ','); 903*7c478bd9Sstevel@tonic-gate if (p != NULL) 904*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 905*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(optarg, "success") == 0) 906*7c478bd9Sstevel@tonic-gate DefaultNotify |= QPINGONSUCCESS; 907*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "failure") == 0) 908*7c478bd9Sstevel@tonic-gate DefaultNotify |= QPINGONFAILURE; 909*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "delay") == 0) 910*7c478bd9Sstevel@tonic-gate DefaultNotify |= QPINGONDELAY; 911*7c478bd9Sstevel@tonic-gate else 912*7c478bd9Sstevel@tonic-gate { 913*7c478bd9Sstevel@tonic-gate usrerr("Invalid -N argument"); 914*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 915*7c478bd9Sstevel@tonic-gate } 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate break; 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate case 'o': /* set option */ 920*7c478bd9Sstevel@tonic-gate setoption(*optarg, optarg + 1, false, true, 921*7c478bd9Sstevel@tonic-gate &BlankEnvelope); 922*7c478bd9Sstevel@tonic-gate break; 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate case 'O': /* set option (long form) */ 925*7c478bd9Sstevel@tonic-gate setoption(' ', optarg, false, true, &BlankEnvelope); 926*7c478bd9Sstevel@tonic-gate break; 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate case 'p': /* set protocol */ 929*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 930*7c478bd9Sstevel@tonic-gate p = strchr(optarg, ':'); 931*7c478bd9Sstevel@tonic-gate if (p != NULL) 932*7c478bd9Sstevel@tonic-gate { 933*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 934*7c478bd9Sstevel@tonic-gate if (*p != '\0') 935*7c478bd9Sstevel@tonic-gate { 936*7c478bd9Sstevel@tonic-gate i = strlen(p) + 1; 937*7c478bd9Sstevel@tonic-gate ep = sm_malloc_x(i); 938*7c478bd9Sstevel@tonic-gate cleanstrcpy(ep, p, i); 939*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 940*7c478bd9Sstevel@tonic-gate A_HEAP, 's', ep); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate if (*optarg != '\0') 944*7c478bd9Sstevel@tonic-gate { 945*7c478bd9Sstevel@tonic-gate i = strlen(optarg) + 1; 946*7c478bd9Sstevel@tonic-gate ep = sm_malloc_x(i); 947*7c478bd9Sstevel@tonic-gate cleanstrcpy(ep, optarg, i); 948*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_HEAP, 949*7c478bd9Sstevel@tonic-gate 'r', ep); 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate break; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate case 'Q': /* change quarantining on queued items */ 954*7c478bd9Sstevel@tonic-gate /* sanity check */ 955*7c478bd9Sstevel@tonic-gate if (OpMode != MD_DELIVER && 956*7c478bd9Sstevel@tonic-gate OpMode != MD_QUEUERUN) 957*7c478bd9Sstevel@tonic-gate { 958*7c478bd9Sstevel@tonic-gate usrerr("Can not use -Q with -b%c", OpMode); 959*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 960*7c478bd9Sstevel@tonic-gate break; 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DELIVER) 964*7c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate FullName = NULL; 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate quarantining = newstr(optarg); 969*7c478bd9Sstevel@tonic-gate break; 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate case 'q': /* run queue files at intervals */ 972*7c478bd9Sstevel@tonic-gate /* sanity check */ 973*7c478bd9Sstevel@tonic-gate if (OpMode != MD_DELIVER && 974*7c478bd9Sstevel@tonic-gate OpMode != MD_DAEMON && 975*7c478bd9Sstevel@tonic-gate OpMode != MD_FGDAEMON && 976*7c478bd9Sstevel@tonic-gate OpMode != MD_PRINT && 977*7c478bd9Sstevel@tonic-gate OpMode != MD_PRINTNQE && 978*7c478bd9Sstevel@tonic-gate OpMode != MD_QUEUERUN) 979*7c478bd9Sstevel@tonic-gate { 980*7c478bd9Sstevel@tonic-gate usrerr("Can not use -q with -b%c", OpMode); 981*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 982*7c478bd9Sstevel@tonic-gate break; 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate /* don't override -bd, -bD or -bp */ 986*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DELIVER) 987*7c478bd9Sstevel@tonic-gate set_op_mode(MD_QUEUERUN); 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate FullName = NULL; 990*7c478bd9Sstevel@tonic-gate negate = optarg[0] == '!'; 991*7c478bd9Sstevel@tonic-gate if (negate) 992*7c478bd9Sstevel@tonic-gate { 993*7c478bd9Sstevel@tonic-gate /* negate meaning of pattern match */ 994*7c478bd9Sstevel@tonic-gate optarg++; /* skip '!' for next switch */ 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate switch (optarg[0]) 998*7c478bd9Sstevel@tonic-gate { 999*7c478bd9Sstevel@tonic-gate case 'G': /* Limit by queue group name */ 1000*7c478bd9Sstevel@tonic-gate if (negate) 1001*7c478bd9Sstevel@tonic-gate { 1002*7c478bd9Sstevel@tonic-gate usrerr("Can not use -q!G"); 1003*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1004*7c478bd9Sstevel@tonic-gate break; 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate if (queuegroup != NULL) 1007*7c478bd9Sstevel@tonic-gate { 1008*7c478bd9Sstevel@tonic-gate usrerr("Can not use multiple -qG options"); 1009*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1010*7c478bd9Sstevel@tonic-gate break; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate queuegroup = newstr(&optarg[1]); 1013*7c478bd9Sstevel@tonic-gate break; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate case 'I': /* Limit by ID */ 1016*7c478bd9Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 1017*7c478bd9Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 1018*7c478bd9Sstevel@tonic-gate new->queue_negate = negate; 1019*7c478bd9Sstevel@tonic-gate new->queue_next = QueueLimitId; 1020*7c478bd9Sstevel@tonic-gate QueueLimitId = new; 1021*7c478bd9Sstevel@tonic-gate break; 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate case 'R': /* Limit by recipient */ 1024*7c478bd9Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 1025*7c478bd9Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 1026*7c478bd9Sstevel@tonic-gate new->queue_negate = negate; 1027*7c478bd9Sstevel@tonic-gate new->queue_next = QueueLimitRecipient; 1028*7c478bd9Sstevel@tonic-gate QueueLimitRecipient = new; 1029*7c478bd9Sstevel@tonic-gate break; 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate case 'S': /* Limit by sender */ 1032*7c478bd9Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 1033*7c478bd9Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 1034*7c478bd9Sstevel@tonic-gate new->queue_negate = negate; 1035*7c478bd9Sstevel@tonic-gate new->queue_next = QueueLimitSender; 1036*7c478bd9Sstevel@tonic-gate QueueLimitSender = new; 1037*7c478bd9Sstevel@tonic-gate break; 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate case 'f': /* foreground queue run */ 1040*7c478bd9Sstevel@tonic-gate foregroundqueue = true; 1041*7c478bd9Sstevel@tonic-gate break; 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate case 'Q': /* Limit by quarantine message */ 1044*7c478bd9Sstevel@tonic-gate if (optarg[1] != '\0') 1045*7c478bd9Sstevel@tonic-gate { 1046*7c478bd9Sstevel@tonic-gate new = (QUEUE_CHAR *) xalloc(sizeof *new); 1047*7c478bd9Sstevel@tonic-gate new->queue_match = newstr(&optarg[1]); 1048*7c478bd9Sstevel@tonic-gate new->queue_negate = negate; 1049*7c478bd9Sstevel@tonic-gate new->queue_next = QueueLimitQuarantine; 1050*7c478bd9Sstevel@tonic-gate QueueLimitQuarantine = new; 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate QueueMode = QM_QUARANTINE; 1053*7c478bd9Sstevel@tonic-gate break; 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate case 'L': /* act on lost items */ 1056*7c478bd9Sstevel@tonic-gate QueueMode = QM_LOST; 1057*7c478bd9Sstevel@tonic-gate break; 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate case 'p': /* Persistent queue */ 1060*7c478bd9Sstevel@tonic-gate queuepersistent = true; 1061*7c478bd9Sstevel@tonic-gate if (QueueIntvl == 0) 1062*7c478bd9Sstevel@tonic-gate QueueIntvl = 1; 1063*7c478bd9Sstevel@tonic-gate if (optarg[1] == '\0') 1064*7c478bd9Sstevel@tonic-gate break; 1065*7c478bd9Sstevel@tonic-gate ++optarg; 1066*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate default: 1069*7c478bd9Sstevel@tonic-gate i = Errors; 1070*7c478bd9Sstevel@tonic-gate QueueIntvl = convtime(optarg, 'm'); 1071*7c478bd9Sstevel@tonic-gate if (QueueIntvl < 0) 1072*7c478bd9Sstevel@tonic-gate { 1073*7c478bd9Sstevel@tonic-gate usrerr("Invalid -q value"); 1074*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* check for bad conversion */ 1078*7c478bd9Sstevel@tonic-gate if (i < Errors) 1079*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1080*7c478bd9Sstevel@tonic-gate break; 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate break; 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate case 'R': /* DSN RET: what to return */ 1085*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 1086*7c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags)) 1087*7c478bd9Sstevel@tonic-gate { 1088*7c478bd9Sstevel@tonic-gate usrerr("Duplicate -R flag"); 1089*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1090*7c478bd9Sstevel@tonic-gate break; 1091*7c478bd9Sstevel@tonic-gate } 1092*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_RET_PARAM; 1093*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(optarg, "hdrs") == 0) 1094*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_NO_BODY_RETN; 1095*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(optarg, "full") != 0) 1096*7c478bd9Sstevel@tonic-gate { 1097*7c478bd9Sstevel@tonic-gate usrerr("Invalid -R value"); 1098*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1099*7c478bd9Sstevel@tonic-gate } 1100*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 1101*7c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), optarg); 1102*7c478bd9Sstevel@tonic-gate break; 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate case 't': /* read recipients from message */ 1105*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 1106*7c478bd9Sstevel@tonic-gate GrabTo = true; 1107*7c478bd9Sstevel@tonic-gate break; 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate case 'V': /* DSN ENVID: set "original" envelope id */ 1110*7c478bd9Sstevel@tonic-gate CHECK_AGAINST_OPMODE(j); 1111*7c478bd9Sstevel@tonic-gate if (!xtextok(optarg)) 1112*7c478bd9Sstevel@tonic-gate { 1113*7c478bd9Sstevel@tonic-gate usrerr("Invalid syntax in -V flag"); 1114*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate else 1117*7c478bd9Sstevel@tonic-gate { 1118*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_envid = newstr(optarg); 1119*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 1120*7c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), optarg); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate break; 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate case 'X': /* traffic log file */ 1125*7c478bd9Sstevel@tonic-gate dp = drop_privileges(true); 1126*7c478bd9Sstevel@tonic-gate setstat(dp); 1127*7c478bd9Sstevel@tonic-gate if (stat(optarg, &traf_st) == 0 && 1128*7c478bd9Sstevel@tonic-gate S_ISFIFO(traf_st.st_mode)) 1129*7c478bd9Sstevel@tonic-gate TrafficLogFile = sm_io_open(SmFtStdio, 1130*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 1131*7c478bd9Sstevel@tonic-gate optarg, 1132*7c478bd9Sstevel@tonic-gate SM_IO_WRONLY, NULL); 1133*7c478bd9Sstevel@tonic-gate else 1134*7c478bd9Sstevel@tonic-gate TrafficLogFile = sm_io_open(SmFtStdio, 1135*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 1136*7c478bd9Sstevel@tonic-gate optarg, 1137*7c478bd9Sstevel@tonic-gate SM_IO_APPEND, NULL); 1138*7c478bd9Sstevel@tonic-gate if (TrafficLogFile == NULL) 1139*7c478bd9Sstevel@tonic-gate { 1140*7c478bd9Sstevel@tonic-gate syserr("cannot open %s", optarg); 1141*7c478bd9Sstevel@tonic-gate ExitStat = EX_CANTCREAT; 1142*7c478bd9Sstevel@tonic-gate break; 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT, 1145*7c478bd9Sstevel@tonic-gate NULL, SM_IO_LBF, 0); 1146*7c478bd9Sstevel@tonic-gate break; 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate /* compatibility flags */ 1149*7c478bd9Sstevel@tonic-gate case 'c': /* connect to non-local mailers */ 1150*7c478bd9Sstevel@tonic-gate case 'i': /* don't let dot stop me */ 1151*7c478bd9Sstevel@tonic-gate case 'm': /* send to me too */ 1152*7c478bd9Sstevel@tonic-gate case 'T': /* set timeout interval */ 1153*7c478bd9Sstevel@tonic-gate case 'v': /* give blow-by-blow description */ 1154*7c478bd9Sstevel@tonic-gate setoption(j, "T", false, true, &BlankEnvelope); 1155*7c478bd9Sstevel@tonic-gate break; 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate case 'e': /* error message disposition */ 1158*7c478bd9Sstevel@tonic-gate case 'M': /* define macro */ 1159*7c478bd9Sstevel@tonic-gate setoption(j, optarg, false, true, &BlankEnvelope); 1160*7c478bd9Sstevel@tonic-gate break; 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate case 's': /* save From lines in headers */ 1163*7c478bd9Sstevel@tonic-gate setoption('f', "T", false, true, &BlankEnvelope); 1164*7c478bd9Sstevel@tonic-gate break; 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate #ifdef DBM 1167*7c478bd9Sstevel@tonic-gate case 'I': /* initialize alias DBM file */ 1168*7c478bd9Sstevel@tonic-gate set_op_mode(MD_INITALIAS); 1169*7c478bd9Sstevel@tonic-gate break; 1170*7c478bd9Sstevel@tonic-gate #endif /* DBM */ 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate #if defined(__osf__) || defined(_AIX3) 1173*7c478bd9Sstevel@tonic-gate case 'x': /* random flag that OSF/1 & AIX mailx passes */ 1174*7c478bd9Sstevel@tonic-gate break; 1175*7c478bd9Sstevel@tonic-gate #endif /* defined(__osf__) || defined(_AIX3) */ 1176*7c478bd9Sstevel@tonic-gate #if defined(sony_news) 1177*7c478bd9Sstevel@tonic-gate case 'E': 1178*7c478bd9Sstevel@tonic-gate case 'J': /* ignore flags for Japanese code conversion 1179*7c478bd9Sstevel@tonic-gate implemented on Sony NEWS */ 1180*7c478bd9Sstevel@tonic-gate break; 1181*7c478bd9Sstevel@tonic-gate #endif /* defined(sony_news) */ 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate default: 1184*7c478bd9Sstevel@tonic-gate finis(true, true, EX_USAGE); 1185*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1186*7c478bd9Sstevel@tonic-gate break; 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate } 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate /* if we've had errors so far, exit now */ 1191*7c478bd9Sstevel@tonic-gate if ((ExitStat != EX_OK && OpMode != MD_TEST) || 1192*7c478bd9Sstevel@tonic-gate ExitStat == EX_OSERR) 1193*7c478bd9Sstevel@tonic-gate { 1194*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 1195*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1196*7c478bd9Sstevel@tonic-gate } 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate if (bitset(SUBMIT_MTA, SubmitMode)) 1199*7c478bd9Sstevel@tonic-gate { 1200*7c478bd9Sstevel@tonic-gate /* If set daemon_flags on command line, don't reset it */ 1201*7c478bd9Sstevel@tonic-gate if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 1202*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 1203*7c478bd9Sstevel@tonic-gate macid("{daemon_flags}"), "CC f"); 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate else if (OpMode == MD_DELIVER || OpMode == MD_SMTP) 1206*7c478bd9Sstevel@tonic-gate { 1207*7c478bd9Sstevel@tonic-gate SubmitMode = SUBMIT_MSA; 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate /* If set daemon_flags on command line, don't reset it */ 1210*7c478bd9Sstevel@tonic-gate if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL) 1211*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 1212*7c478bd9Sstevel@tonic-gate macid("{daemon_flags}"), "c u"); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* 1216*7c478bd9Sstevel@tonic-gate ** Do basic initialization. 1217*7c478bd9Sstevel@tonic-gate ** Read system control file. 1218*7c478bd9Sstevel@tonic-gate ** Extract special fields for local use. 1219*7c478bd9Sstevel@tonic-gate */ 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate #if XDEBUG 1222*7c478bd9Sstevel@tonic-gate checkfd012("before readcf"); 1223*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 1224*7c478bd9Sstevel@tonic-gate vendor_pre_defaults(&BlankEnvelope); 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate readcf(getcfname(OpMode, SubmitMode, cftype, conffile), 1227*7c478bd9Sstevel@tonic-gate safecf, &BlankEnvelope); 1228*7c478bd9Sstevel@tonic-gate #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 1229*7c478bd9Sstevel@tonic-gate ConfigFileRead = true; 1230*7c478bd9Sstevel@tonic-gate #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 1231*7c478bd9Sstevel@tonic-gate vendor_post_defaults(&BlankEnvelope); 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* now we can complain about missing fds */ 1234*7c478bd9Sstevel@tonic-gate if (MissingFds != 0 && LogLevel > 8) 1235*7c478bd9Sstevel@tonic-gate { 1236*7c478bd9Sstevel@tonic-gate char mbuf[MAXLINE]; 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate mbuf[0] = '\0'; 1239*7c478bd9Sstevel@tonic-gate if (bitset(1 << STDIN_FILENO, MissingFds)) 1240*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stdin", sizeof mbuf); 1241*7c478bd9Sstevel@tonic-gate if (bitset(1 << STDOUT_FILENO, MissingFds)) 1242*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stdout", sizeof mbuf); 1243*7c478bd9Sstevel@tonic-gate if (bitset(1 << STDERR_FILENO, MissingFds)) 1244*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(mbuf, ", stderr", sizeof mbuf); 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate /* Notice: fill_errno is from high above: fill_fd() */ 1247*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 1248*7c478bd9Sstevel@tonic-gate "File descriptors missing on startup: %s; %s", 1249*7c478bd9Sstevel@tonic-gate &mbuf[2], sm_errstring(fill_errno)); 1250*7c478bd9Sstevel@tonic-gate } 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* Remove the ability for a normal user to send signals */ 1253*7c478bd9Sstevel@tonic-gate if (RealUid != 0 && RealUid != geteuid()) 1254*7c478bd9Sstevel@tonic-gate { 1255*7c478bd9Sstevel@tonic-gate uid_t new_uid = geteuid(); 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate #if HASSETREUID 1258*7c478bd9Sstevel@tonic-gate /* 1259*7c478bd9Sstevel@tonic-gate ** Since we can differentiate between uid and euid, 1260*7c478bd9Sstevel@tonic-gate ** make the uid a different user so the real user 1261*7c478bd9Sstevel@tonic-gate ** can't send signals. However, it doesn't need to be 1262*7c478bd9Sstevel@tonic-gate ** root (euid has root). 1263*7c478bd9Sstevel@tonic-gate */ 1264*7c478bd9Sstevel@tonic-gate 1265*7c478bd9Sstevel@tonic-gate if (new_uid == 0) 1266*7c478bd9Sstevel@tonic-gate new_uid = DefUid; 1267*7c478bd9Sstevel@tonic-gate if (tTd(47, 5)) 1268*7c478bd9Sstevel@tonic-gate sm_dprintf("Changing real uid to %d\n", (int) new_uid); 1269*7c478bd9Sstevel@tonic-gate if (setreuid(new_uid, geteuid()) < 0) 1270*7c478bd9Sstevel@tonic-gate { 1271*7c478bd9Sstevel@tonic-gate syserr("main: setreuid(%d, %d) failed", 1272*7c478bd9Sstevel@tonic-gate (int) new_uid, (int) geteuid()); 1273*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OSERR); 1274*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1275*7c478bd9Sstevel@tonic-gate } 1276*7c478bd9Sstevel@tonic-gate if (tTd(47, 10)) 1277*7c478bd9Sstevel@tonic-gate sm_dprintf("Now running as e/ruid %d:%d\n", 1278*7c478bd9Sstevel@tonic-gate (int) geteuid(), (int) getuid()); 1279*7c478bd9Sstevel@tonic-gate #else /* HASSETREUID */ 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate ** Have to change both effective and real so need to 1282*7c478bd9Sstevel@tonic-gate ** change them both to effective to keep privs. 1283*7c478bd9Sstevel@tonic-gate */ 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate if (tTd(47, 5)) 1286*7c478bd9Sstevel@tonic-gate sm_dprintf("Changing uid to %d\n", (int) new_uid); 1287*7c478bd9Sstevel@tonic-gate if (setuid(new_uid) < 0) 1288*7c478bd9Sstevel@tonic-gate { 1289*7c478bd9Sstevel@tonic-gate syserr("main: setuid(%d) failed", (int) new_uid); 1290*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OSERR); 1291*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate if (tTd(47, 10)) 1294*7c478bd9Sstevel@tonic-gate sm_dprintf("Now running as e/ruid %d:%d\n", 1295*7c478bd9Sstevel@tonic-gate (int) geteuid(), (int) getuid()); 1296*7c478bd9Sstevel@tonic-gate #endif /* HASSETREUID */ 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 1300*7c478bd9Sstevel@tonic-gate if (FallbackMX != NULL) 1301*7c478bd9Sstevel@tonic-gate (void) getfallbackmxrr(FallbackMX); 1302*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER) 1305*7c478bd9Sstevel@tonic-gate { 1306*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1307*7c478bd9Sstevel@tonic-gate "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n"); 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate 1310*7c478bd9Sstevel@tonic-gate if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)) 1311*7c478bd9Sstevel@tonic-gate { 1312*7c478bd9Sstevel@tonic-gate usrerr("Mail submission program cannot be used as daemon"); 1313*7c478bd9Sstevel@tonic-gate finis(false, true, EX_USAGE); 1314*7c478bd9Sstevel@tonic-gate } 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DELIVER || OpMode == MD_SMTP || 1317*7c478bd9Sstevel@tonic-gate OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP || 1318*7c478bd9Sstevel@tonic-gate OpMode == MD_DAEMON || OpMode == MD_FGDAEMON) 1319*7c478bd9Sstevel@tonic-gate makeworkgroups(); 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate /* set up the basic signal handlers */ 1322*7c478bd9Sstevel@tonic-gate if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN) 1323*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, intsig); 1324*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, intsig); 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate /* Enforce use of local time (null string overrides this) */ 1327*7c478bd9Sstevel@tonic-gate if (TimeZoneSpec == NULL) 1328*7c478bd9Sstevel@tonic-gate unsetenv("TZ"); 1329*7c478bd9Sstevel@tonic-gate else if (TimeZoneSpec[0] != '\0') 1330*7c478bd9Sstevel@tonic-gate setuserenv("TZ", TimeZoneSpec); 1331*7c478bd9Sstevel@tonic-gate else 1332*7c478bd9Sstevel@tonic-gate setuserenv("TZ", NULL); 1333*7c478bd9Sstevel@tonic-gate tzset(); 1334*7c478bd9Sstevel@tonic-gate 1335*7c478bd9Sstevel@tonic-gate /* initialize mailbox database */ 1336*7c478bd9Sstevel@tonic-gate i = sm_mbdb_initialize(Mbdb); 1337*7c478bd9Sstevel@tonic-gate if (i != EX_OK) 1338*7c478bd9Sstevel@tonic-gate { 1339*7c478bd9Sstevel@tonic-gate usrerr("Can't initialize mailbox database \"%s\": %s", 1340*7c478bd9Sstevel@tonic-gate Mbdb, sm_strexit(i)); 1341*7c478bd9Sstevel@tonic-gate ExitStat = i; 1342*7c478bd9Sstevel@tonic-gate } 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate /* avoid denial-of-service attacks */ 1345*7c478bd9Sstevel@tonic-gate resetlimits(); 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate if (OpMode == MD_TEST) 1348*7c478bd9Sstevel@tonic-gate { 1349*7c478bd9Sstevel@tonic-gate /* can't be done after readcf if RunAs* is used */ 1350*7c478bd9Sstevel@tonic-gate dp = drop_privileges(true); 1351*7c478bd9Sstevel@tonic-gate if (dp != EX_OK) 1352*7c478bd9Sstevel@tonic-gate { 1353*7c478bd9Sstevel@tonic-gate finis(false, true, dp); 1354*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate } 1357*7c478bd9Sstevel@tonic-gate else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate /* drop privileges -- daemon mode done after socket/bind */ 1360*7c478bd9Sstevel@tonic-gate dp = drop_privileges(false); 1361*7c478bd9Sstevel@tonic-gate setstat(dp); 1362*7c478bd9Sstevel@tonic-gate if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0)) 1363*7c478bd9Sstevel@tonic-gate { 1364*7c478bd9Sstevel@tonic-gate usrerr("Mail submission program must have RunAsUser set to non root user"); 1365*7c478bd9Sstevel@tonic-gate finis(false, true, EX_CONFIG); 1366*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 1371*7c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 1372*7c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 1373*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 1374*7c478bd9Sstevel@tonic-gate 1375*7c478bd9Sstevel@tonic-gate /* 1376*7c478bd9Sstevel@tonic-gate ** Find our real host name for future logging. 1377*7c478bd9Sstevel@tonic-gate */ 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate authinfo = getauthinfo(STDIN_FILENO, &forged); 1380*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate /* suppress error printing if errors mailed back or whatever */ 1383*7c478bd9Sstevel@tonic-gate if (BlankEnvelope.e_errormode != EM_PRINT) 1384*7c478bd9Sstevel@tonic-gate HoldErrs = true; 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate /* set up the $=m class now, after .cf has a chance to redefine $m */ 1387*7c478bd9Sstevel@tonic-gate expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope); 1388*7c478bd9Sstevel@tonic-gate if (jbuf[0] != '\0') 1389*7c478bd9Sstevel@tonic-gate setclass('m', jbuf); 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate /* probe interfaces and locate any additional names */ 1392*7c478bd9Sstevel@tonic-gate if (DontProbeInterfaces != DPI_PROBENONE) 1393*7c478bd9Sstevel@tonic-gate load_if_names(); 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate if (tTd(0, 10)) 1396*7c478bd9Sstevel@tonic-gate { 1397*7c478bd9Sstevel@tonic-gate char pidpath[MAXPATHLEN]; 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate /* Now we know which .cf file we use */ 1400*7c478bd9Sstevel@tonic-gate sm_dprintf(" Conf file:\t%s (selected)\n", 1401*7c478bd9Sstevel@tonic-gate getcfname(OpMode, SubmitMode, cftype, conffile)); 1402*7c478bd9Sstevel@tonic-gate expand(PidFile, pidpath, sizeof pidpath, &BlankEnvelope); 1403*7c478bd9Sstevel@tonic-gate sm_dprintf(" Pid file:\t%s (selected)\n", pidpath); 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate if (tTd(0, 1)) 1407*7c478bd9Sstevel@tonic-gate { 1408*7c478bd9Sstevel@tonic-gate sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 1409*7c478bd9Sstevel@tonic-gate sm_dprintf("\n (short domain name) $w = "); 1410*7c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('w', &BlankEnvelope)); 1411*7c478bd9Sstevel@tonic-gate sm_dprintf("\n (canonical domain name) $j = "); 1412*7c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('j', &BlankEnvelope)); 1413*7c478bd9Sstevel@tonic-gate sm_dprintf("\n (subdomain name) $m = "); 1414*7c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('m', &BlankEnvelope)); 1415*7c478bd9Sstevel@tonic-gate sm_dprintf("\n (node name) $k = "); 1416*7c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), macvalue('k', &BlankEnvelope)); 1417*7c478bd9Sstevel@tonic-gate sm_dprintf("\n========================================================\n\n"); 1418*7c478bd9Sstevel@tonic-gate } 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate /* 1421*7c478bd9Sstevel@tonic-gate ** Do more command line checking -- these are things that 1422*7c478bd9Sstevel@tonic-gate ** have to modify the results of reading the config file. 1423*7c478bd9Sstevel@tonic-gate */ 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate /* process authorization warnings from command line */ 1426*7c478bd9Sstevel@tonic-gate if (warn_C_flag) 1427*7c478bd9Sstevel@tonic-gate auth_warning(&BlankEnvelope, "Processed by %s with -C %s", 1428*7c478bd9Sstevel@tonic-gate RealUserName, conffile); 1429*7c478bd9Sstevel@tonic-gate if (Warn_Q_option && !wordinclass(RealUserName, 't')) 1430*7c478bd9Sstevel@tonic-gate auth_warning(&BlankEnvelope, "Processed from queue %s", 1431*7c478bd9Sstevel@tonic-gate QueueDir); 1432*7c478bd9Sstevel@tonic-gate if (sysloglabel != NULL && !wordinclass(RealUserName, 't') && 1433*7c478bd9Sstevel@tonic-gate RealUid != 0 && RealUid != TrustedUid && LogLevel > 1) 1434*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label", 1435*7c478bd9Sstevel@tonic-gate (int) RealUid); 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate /* check body type for legality */ 1438*7c478bd9Sstevel@tonic-gate i = check_bodytype(BlankEnvelope.e_bodytype); 1439*7c478bd9Sstevel@tonic-gate if (i == BODYTYPE_ILLEGAL) 1440*7c478bd9Sstevel@tonic-gate { 1441*7c478bd9Sstevel@tonic-gate usrerr("Illegal body type %s", BlankEnvelope.e_bodytype); 1442*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_bodytype = NULL; 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate else if (i != BODYTYPE_NONE) 1445*7c478bd9Sstevel@tonic-gate SevenBitInput = (i == BODYTYPE_7BIT); 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate /* tweak default DSN notifications */ 1448*7c478bd9Sstevel@tonic-gate if (DefaultNotify == 0) 1449*7c478bd9Sstevel@tonic-gate DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate /* check for sane configuration level */ 1452*7c478bd9Sstevel@tonic-gate if (ConfigLevel > MAXCONFIGLEVEL) 1453*7c478bd9Sstevel@tonic-gate { 1454*7c478bd9Sstevel@tonic-gate syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 1455*7c478bd9Sstevel@tonic-gate ConfigLevel, Version, MAXCONFIGLEVEL); 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate /* need MCI cache to have persistence */ 1459*7c478bd9Sstevel@tonic-gate if (HostStatDir != NULL && MaxMciCache == 0) 1460*7c478bd9Sstevel@tonic-gate { 1461*7c478bd9Sstevel@tonic-gate HostStatDir = NULL; 1462*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1463*7c478bd9Sstevel@tonic-gate "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate /* need HostStatusDir in order to have SingleThreadDelivery */ 1467*7c478bd9Sstevel@tonic-gate if (SingleThreadDelivery && HostStatDir == NULL) 1468*7c478bd9Sstevel@tonic-gate { 1469*7c478bd9Sstevel@tonic-gate SingleThreadDelivery = false; 1470*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1471*7c478bd9Sstevel@tonic-gate "Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 1472*7c478bd9Sstevel@tonic-gate } 1473*7c478bd9Sstevel@tonic-gate 1474*7c478bd9Sstevel@tonic-gate /* check for permissions */ 1475*7c478bd9Sstevel@tonic-gate if (RealUid != 0 && 1476*7c478bd9Sstevel@tonic-gate RealUid != TrustedUid) 1477*7c478bd9Sstevel@tonic-gate { 1478*7c478bd9Sstevel@tonic-gate char *action = NULL; 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate switch (OpMode) 1481*7c478bd9Sstevel@tonic-gate { 1482*7c478bd9Sstevel@tonic-gate case MD_QUEUERUN: 1483*7c478bd9Sstevel@tonic-gate if (quarantining != NULL) 1484*7c478bd9Sstevel@tonic-gate action = "quarantine jobs"; 1485*7c478bd9Sstevel@tonic-gate else 1486*7c478bd9Sstevel@tonic-gate { 1487*7c478bd9Sstevel@tonic-gate /* Normal users can do a single queue run */ 1488*7c478bd9Sstevel@tonic-gate if (QueueIntvl == 0) 1489*7c478bd9Sstevel@tonic-gate break; 1490*7c478bd9Sstevel@tonic-gate } 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate /* but not persistent queue runners */ 1493*7c478bd9Sstevel@tonic-gate if (action == NULL) 1494*7c478bd9Sstevel@tonic-gate action = "start a queue runner daemon"; 1495*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate case MD_PURGESTAT: 1498*7c478bd9Sstevel@tonic-gate if (action == NULL) 1499*7c478bd9Sstevel@tonic-gate action = "purge host status"; 1500*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate case MD_DAEMON: 1503*7c478bd9Sstevel@tonic-gate case MD_FGDAEMON: 1504*7c478bd9Sstevel@tonic-gate if (action == NULL) 1505*7c478bd9Sstevel@tonic-gate action = "run daemon"; 1506*7c478bd9Sstevel@tonic-gate 1507*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1508*7c478bd9Sstevel@tonic-gate sm_dprintf("Deny user %d attempt to %s\n", 1509*7c478bd9Sstevel@tonic-gate (int) RealUid, action); 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate if (LogLevel > 1) 1512*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 1513*7c478bd9Sstevel@tonic-gate "user %d attempted to %s", 1514*7c478bd9Sstevel@tonic-gate (int) RealUid, action); 1515*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1516*7c478bd9Sstevel@tonic-gate usrerr("Permission denied (real uid not trusted)"); 1517*7c478bd9Sstevel@tonic-gate finis(false, true, EX_USAGE); 1518*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1519*7c478bd9Sstevel@tonic-gate break; 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate case MD_VERIFY: 1522*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags)) 1523*7c478bd9Sstevel@tonic-gate { 1524*7c478bd9Sstevel@tonic-gate /* 1525*7c478bd9Sstevel@tonic-gate ** If -bv and RestrictExpand, 1526*7c478bd9Sstevel@tonic-gate ** drop privs to prevent normal 1527*7c478bd9Sstevel@tonic-gate ** users from reading private 1528*7c478bd9Sstevel@tonic-gate ** aliases/forwards/:include:s 1529*7c478bd9Sstevel@tonic-gate */ 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1532*7c478bd9Sstevel@tonic-gate sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n", 1533*7c478bd9Sstevel@tonic-gate (int) RealUid); 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate dp = drop_privileges(true); 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate /* Fake address safety */ 1538*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1539*7c478bd9Sstevel@tonic-gate sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n"); 1540*7c478bd9Sstevel@tonic-gate setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail); 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate if (dp != EX_OK) 1543*7c478bd9Sstevel@tonic-gate { 1544*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1545*7c478bd9Sstevel@tonic-gate sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n", 1546*7c478bd9Sstevel@tonic-gate (int) RealUid); 1547*7c478bd9Sstevel@tonic-gate CurEnv->e_id = NULL; 1548*7c478bd9Sstevel@tonic-gate finis(true, true, dp); 1549*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate } 1552*7c478bd9Sstevel@tonic-gate break; 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate case MD_TEST: 1555*7c478bd9Sstevel@tonic-gate case MD_PRINT: 1556*7c478bd9Sstevel@tonic-gate case MD_PRINTNQE: 1557*7c478bd9Sstevel@tonic-gate case MD_FREEZE: 1558*7c478bd9Sstevel@tonic-gate case MD_HOSTSTAT: 1559*7c478bd9Sstevel@tonic-gate /* Nothing special to check */ 1560*7c478bd9Sstevel@tonic-gate break; 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate case MD_INITALIAS: 1563*7c478bd9Sstevel@tonic-gate if (!wordinclass(RealUserName, 't')) 1564*7c478bd9Sstevel@tonic-gate { 1565*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1566*7c478bd9Sstevel@tonic-gate sm_dprintf("Deny user %d attempt to rebuild the alias map\n", 1567*7c478bd9Sstevel@tonic-gate (int) RealUid); 1568*7c478bd9Sstevel@tonic-gate if (LogLevel > 1) 1569*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, NOQID, 1570*7c478bd9Sstevel@tonic-gate "user %d attempted to rebuild the alias map", 1571*7c478bd9Sstevel@tonic-gate (int) RealUid); 1572*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1573*7c478bd9Sstevel@tonic-gate usrerr("Permission denied (real uid not trusted)"); 1574*7c478bd9Sstevel@tonic-gate finis(false, true, EX_USAGE); 1575*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1576*7c478bd9Sstevel@tonic-gate } 1577*7c478bd9Sstevel@tonic-gate if (UseMSP) 1578*7c478bd9Sstevel@tonic-gate { 1579*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1580*7c478bd9Sstevel@tonic-gate usrerr("User %d cannot rebuild aliases in mail submission program", 1581*7c478bd9Sstevel@tonic-gate (int) RealUid); 1582*7c478bd9Sstevel@tonic-gate finis(false, true, EX_USAGE); 1583*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1584*7c478bd9Sstevel@tonic-gate } 1585*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate default: 1588*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) && 1589*7c478bd9Sstevel@tonic-gate Verbose != 0) 1590*7c478bd9Sstevel@tonic-gate { 1591*7c478bd9Sstevel@tonic-gate /* 1592*7c478bd9Sstevel@tonic-gate ** If -v and RestrictExpand, reset 1593*7c478bd9Sstevel@tonic-gate ** Verbose to prevent normal users 1594*7c478bd9Sstevel@tonic-gate ** from seeing the expansion of 1595*7c478bd9Sstevel@tonic-gate ** aliases/forwards/:include:s 1596*7c478bd9Sstevel@tonic-gate */ 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate if (tTd(65, 1)) 1599*7c478bd9Sstevel@tonic-gate sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n", 1600*7c478bd9Sstevel@tonic-gate (int) RealUid); 1601*7c478bd9Sstevel@tonic-gate Verbose = 0; 1602*7c478bd9Sstevel@tonic-gate } 1603*7c478bd9Sstevel@tonic-gate break; 1604*7c478bd9Sstevel@tonic-gate } 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate if (MeToo) 1608*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_flags |= EF_METOO; 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate switch (OpMode) 1611*7c478bd9Sstevel@tonic-gate { 1612*7c478bd9Sstevel@tonic-gate case MD_TEST: 1613*7c478bd9Sstevel@tonic-gate /* don't have persistent host status in test mode */ 1614*7c478bd9Sstevel@tonic-gate HostStatDir = NULL; 1615*7c478bd9Sstevel@tonic-gate if (Verbose == 0) 1616*7c478bd9Sstevel@tonic-gate Verbose = 2; 1617*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 1618*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1619*7c478bd9Sstevel@tonic-gate break; 1620*7c478bd9Sstevel@tonic-gate 1621*7c478bd9Sstevel@tonic-gate case MD_VERIFY: 1622*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 1623*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1624*7c478bd9Sstevel@tonic-gate /* arrange to exit cleanly on hangup signal */ 1625*7c478bd9Sstevel@tonic-gate if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1626*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, intsig); 1627*7c478bd9Sstevel@tonic-gate if (geteuid() != 0) 1628*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1629*7c478bd9Sstevel@tonic-gate "Notice: -bv may give misleading output for non-privileged user\n"); 1630*7c478bd9Sstevel@tonic-gate break; 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate case MD_FGDAEMON: 1633*7c478bd9Sstevel@tonic-gate run_in_foreground = true; 1634*7c478bd9Sstevel@tonic-gate set_op_mode(MD_DAEMON); 1635*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate case MD_DAEMON: 1638*7c478bd9Sstevel@tonic-gate vendor_daemon_setup(&BlankEnvelope); 1639*7c478bd9Sstevel@tonic-gate 1640*7c478bd9Sstevel@tonic-gate /* remove things that don't make sense in daemon mode */ 1641*7c478bd9Sstevel@tonic-gate FullName = NULL; 1642*7c478bd9Sstevel@tonic-gate GrabTo = false; 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate /* arrange to restart on hangup signal */ 1645*7c478bd9Sstevel@tonic-gate if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 1646*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 1647*7c478bd9Sstevel@tonic-gate "daemon invoked without full pathname; kill -1 won't work"); 1648*7c478bd9Sstevel@tonic-gate break; 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate case MD_INITALIAS: 1651*7c478bd9Sstevel@tonic-gate Verbose = 2; 1652*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_errormode = EM_PRINT; 1653*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1654*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate default: 1657*7c478bd9Sstevel@tonic-gate /* arrange to exit cleanly on hangup signal */ 1658*7c478bd9Sstevel@tonic-gate if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1659*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, intsig); 1660*7c478bd9Sstevel@tonic-gate break; 1661*7c478bd9Sstevel@tonic-gate } 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate /* special considerations for FullName */ 1664*7c478bd9Sstevel@tonic-gate if (FullName != NULL) 1665*7c478bd9Sstevel@tonic-gate { 1666*7c478bd9Sstevel@tonic-gate char *full = NULL; 1667*7c478bd9Sstevel@tonic-gate 1668*7c478bd9Sstevel@tonic-gate /* full names can't have newlines */ 1669*7c478bd9Sstevel@tonic-gate if (strchr(FullName, '\n') != NULL) 1670*7c478bd9Sstevel@tonic-gate { 1671*7c478bd9Sstevel@tonic-gate full = newstr(denlstring(FullName, true, true)); 1672*7c478bd9Sstevel@tonic-gate FullName = full; 1673*7c478bd9Sstevel@tonic-gate } 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate /* check for characters that may have to be quoted */ 1676*7c478bd9Sstevel@tonic-gate if (!rfc822_string(FullName)) 1677*7c478bd9Sstevel@tonic-gate { 1678*7c478bd9Sstevel@tonic-gate /* 1679*7c478bd9Sstevel@tonic-gate ** Quote a full name with special characters 1680*7c478bd9Sstevel@tonic-gate ** as a comment so crackaddr() doesn't destroy 1681*7c478bd9Sstevel@tonic-gate ** the name portion of the address. 1682*7c478bd9Sstevel@tonic-gate */ 1683*7c478bd9Sstevel@tonic-gate 1684*7c478bd9Sstevel@tonic-gate FullName = addquotes(FullName, NULL); 1685*7c478bd9Sstevel@tonic-gate if (full != NULL) 1686*7c478bd9Sstevel@tonic-gate sm_free(full); /* XXX */ 1687*7c478bd9Sstevel@tonic-gate } 1688*7c478bd9Sstevel@tonic-gate } 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate /* do heuristic mode adjustment */ 1691*7c478bd9Sstevel@tonic-gate if (Verbose) 1692*7c478bd9Sstevel@tonic-gate { 1693*7c478bd9Sstevel@tonic-gate /* turn off noconnect option */ 1694*7c478bd9Sstevel@tonic-gate setoption('c', "F", true, false, &BlankEnvelope); 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate /* turn on interactive delivery */ 1697*7c478bd9Sstevel@tonic-gate setoption('d', "", true, false, &BlankEnvelope); 1698*7c478bd9Sstevel@tonic-gate } 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate #ifdef VENDOR_CODE 1701*7c478bd9Sstevel@tonic-gate /* check for vendor mismatch */ 1702*7c478bd9Sstevel@tonic-gate if (VendorCode != VENDOR_CODE) 1703*7c478bd9Sstevel@tonic-gate { 1704*7c478bd9Sstevel@tonic-gate message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 1705*7c478bd9Sstevel@tonic-gate getvendor(VENDOR_CODE), getvendor(VendorCode)); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate #endif /* VENDOR_CODE */ 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate /* check for out of date configuration level */ 1710*7c478bd9Sstevel@tonic-gate if (ConfigLevel < MAXCONFIGLEVEL) 1711*7c478bd9Sstevel@tonic-gate { 1712*7c478bd9Sstevel@tonic-gate message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 1713*7c478bd9Sstevel@tonic-gate Version, MAXCONFIGLEVEL, ConfigLevel); 1714*7c478bd9Sstevel@tonic-gate } 1715*7c478bd9Sstevel@tonic-gate 1716*7c478bd9Sstevel@tonic-gate if (ConfigLevel < 3) 1717*7c478bd9Sstevel@tonic-gate UseErrorsTo = true; 1718*7c478bd9Sstevel@tonic-gate 1719*7c478bd9Sstevel@tonic-gate /* set options that were previous macros */ 1720*7c478bd9Sstevel@tonic-gate if (SmtpGreeting == NULL) 1721*7c478bd9Sstevel@tonic-gate { 1722*7c478bd9Sstevel@tonic-gate if (ConfigLevel < 7 && 1723*7c478bd9Sstevel@tonic-gate (p = macvalue('e', &BlankEnvelope)) != NULL) 1724*7c478bd9Sstevel@tonic-gate SmtpGreeting = newstr(p); 1725*7c478bd9Sstevel@tonic-gate else 1726*7c478bd9Sstevel@tonic-gate SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 1727*7c478bd9Sstevel@tonic-gate } 1728*7c478bd9Sstevel@tonic-gate if (UnixFromLine == NULL) 1729*7c478bd9Sstevel@tonic-gate { 1730*7c478bd9Sstevel@tonic-gate if (ConfigLevel < 7 && 1731*7c478bd9Sstevel@tonic-gate (p = macvalue('l', &BlankEnvelope)) != NULL) 1732*7c478bd9Sstevel@tonic-gate UnixFromLine = newstr(p); 1733*7c478bd9Sstevel@tonic-gate else 1734*7c478bd9Sstevel@tonic-gate UnixFromLine = "From \201g \201d"; 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate SmtpError[0] = '\0'; 1737*7c478bd9Sstevel@tonic-gate 1738*7c478bd9Sstevel@tonic-gate /* our name for SMTP codes */ 1739*7c478bd9Sstevel@tonic-gate expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope); 1740*7c478bd9Sstevel@tonic-gate if (jbuf[0] == '\0') 1741*7c478bd9Sstevel@tonic-gate PSTRSET(MyHostName, "localhost"); 1742*7c478bd9Sstevel@tonic-gate else 1743*7c478bd9Sstevel@tonic-gate PSTRSET(MyHostName, jbuf); 1744*7c478bd9Sstevel@tonic-gate if (strchr(MyHostName, '.') == NULL) 1745*7c478bd9Sstevel@tonic-gate message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?", 1746*7c478bd9Sstevel@tonic-gate MyHostName); 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate /* make certain that this name is part of the $=w class */ 1749*7c478bd9Sstevel@tonic-gate setclass('w', MyHostName); 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate /* fill in the structure of the *default* queue */ 1752*7c478bd9Sstevel@tonic-gate st = stab("mqueue", ST_QUEUE, ST_FIND); 1753*7c478bd9Sstevel@tonic-gate if (st == NULL) 1754*7c478bd9Sstevel@tonic-gate syserr("No default queue (mqueue) defined"); 1755*7c478bd9Sstevel@tonic-gate else 1756*7c478bd9Sstevel@tonic-gate set_def_queueval(st->s_quegrp, true); 1757*7c478bd9Sstevel@tonic-gate 1758*7c478bd9Sstevel@tonic-gate /* the indices of built-in mailers */ 1759*7c478bd9Sstevel@tonic-gate st = stab("local", ST_MAILER, ST_FIND); 1760*7c478bd9Sstevel@tonic-gate if (st != NULL) 1761*7c478bd9Sstevel@tonic-gate LocalMailer = st->s_mailer; 1762*7c478bd9Sstevel@tonic-gate else if (OpMode != MD_TEST || !warn_C_flag) 1763*7c478bd9Sstevel@tonic-gate syserr("No local mailer defined"); 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate st = stab("prog", ST_MAILER, ST_FIND); 1766*7c478bd9Sstevel@tonic-gate if (st == NULL) 1767*7c478bd9Sstevel@tonic-gate syserr("No prog mailer defined"); 1768*7c478bd9Sstevel@tonic-gate else 1769*7c478bd9Sstevel@tonic-gate { 1770*7c478bd9Sstevel@tonic-gate ProgMailer = st->s_mailer; 1771*7c478bd9Sstevel@tonic-gate clrbitn(M_MUSER, ProgMailer->m_flags); 1772*7c478bd9Sstevel@tonic-gate } 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate st = stab("*file*", ST_MAILER, ST_FIND); 1775*7c478bd9Sstevel@tonic-gate if (st == NULL) 1776*7c478bd9Sstevel@tonic-gate syserr("No *file* mailer defined"); 1777*7c478bd9Sstevel@tonic-gate else 1778*7c478bd9Sstevel@tonic-gate { 1779*7c478bd9Sstevel@tonic-gate FileMailer = st->s_mailer; 1780*7c478bd9Sstevel@tonic-gate clrbitn(M_MUSER, FileMailer->m_flags); 1781*7c478bd9Sstevel@tonic-gate } 1782*7c478bd9Sstevel@tonic-gate 1783*7c478bd9Sstevel@tonic-gate st = stab("*include*", ST_MAILER, ST_FIND); 1784*7c478bd9Sstevel@tonic-gate if (st == NULL) 1785*7c478bd9Sstevel@tonic-gate syserr("No *include* mailer defined"); 1786*7c478bd9Sstevel@tonic-gate else 1787*7c478bd9Sstevel@tonic-gate InclMailer = st->s_mailer; 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate if (ConfigLevel < 6) 1790*7c478bd9Sstevel@tonic-gate { 1791*7c478bd9Sstevel@tonic-gate /* heuristic tweaking of local mailer for back compat */ 1792*7c478bd9Sstevel@tonic-gate if (LocalMailer != NULL) 1793*7c478bd9Sstevel@tonic-gate { 1794*7c478bd9Sstevel@tonic-gate setbitn(M_ALIASABLE, LocalMailer->m_flags); 1795*7c478bd9Sstevel@tonic-gate setbitn(M_HASPWENT, LocalMailer->m_flags); 1796*7c478bd9Sstevel@tonic-gate setbitn(M_TRYRULESET5, LocalMailer->m_flags); 1797*7c478bd9Sstevel@tonic-gate setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 1798*7c478bd9Sstevel@tonic-gate setbitn(M_CHECKPROG, LocalMailer->m_flags); 1799*7c478bd9Sstevel@tonic-gate setbitn(M_CHECKFILE, LocalMailer->m_flags); 1800*7c478bd9Sstevel@tonic-gate setbitn(M_CHECKUDB, LocalMailer->m_flags); 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate if (ProgMailer != NULL) 1803*7c478bd9Sstevel@tonic-gate setbitn(M_RUNASRCPT, ProgMailer->m_flags); 1804*7c478bd9Sstevel@tonic-gate if (FileMailer != NULL) 1805*7c478bd9Sstevel@tonic-gate setbitn(M_RUNASRCPT, FileMailer->m_flags); 1806*7c478bd9Sstevel@tonic-gate } 1807*7c478bd9Sstevel@tonic-gate if (ConfigLevel < 7) 1808*7c478bd9Sstevel@tonic-gate { 1809*7c478bd9Sstevel@tonic-gate if (LocalMailer != NULL) 1810*7c478bd9Sstevel@tonic-gate setbitn(M_VRFY250, LocalMailer->m_flags); 1811*7c478bd9Sstevel@tonic-gate if (ProgMailer != NULL) 1812*7c478bd9Sstevel@tonic-gate setbitn(M_VRFY250, ProgMailer->m_flags); 1813*7c478bd9Sstevel@tonic-gate if (FileMailer != NULL) 1814*7c478bd9Sstevel@tonic-gate setbitn(M_VRFY250, FileMailer->m_flags); 1815*7c478bd9Sstevel@tonic-gate } 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate /* MIME Content-Types that cannot be transfer encoded */ 1818*7c478bd9Sstevel@tonic-gate setclass('n', "multipart/signed"); 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate /* MIME message/xxx subtypes that can be treated as messages */ 1821*7c478bd9Sstevel@tonic-gate setclass('s', "rfc822"); 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate /* MIME Content-Transfer-Encodings that can be encoded */ 1824*7c478bd9Sstevel@tonic-gate setclass('e', "7bit"); 1825*7c478bd9Sstevel@tonic-gate setclass('e', "8bit"); 1826*7c478bd9Sstevel@tonic-gate setclass('e', "binary"); 1827*7c478bd9Sstevel@tonic-gate 1828*7c478bd9Sstevel@tonic-gate #ifdef USE_B_CLASS 1829*7c478bd9Sstevel@tonic-gate /* MIME Content-Types that should be treated as binary */ 1830*7c478bd9Sstevel@tonic-gate setclass('b', "image"); 1831*7c478bd9Sstevel@tonic-gate setclass('b', "audio"); 1832*7c478bd9Sstevel@tonic-gate setclass('b', "video"); 1833*7c478bd9Sstevel@tonic-gate setclass('b', "application/octet-stream"); 1834*7c478bd9Sstevel@tonic-gate #endif /* USE_B_CLASS */ 1835*7c478bd9Sstevel@tonic-gate 1836*7c478bd9Sstevel@tonic-gate /* MIME headers which have fields to check for overflow */ 1837*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition"); 1838*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEFieldHeaders}"), "content-type"); 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate /* MIME headers to check for length overflow */ 1841*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMETextHeaders}"), "content-description"); 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate /* MIME headers to check for overflow and rebalance */ 1844*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-disposition"); 1845*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-id"); 1846*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding"); 1847*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "content-type"); 1848*7c478bd9Sstevel@tonic-gate setclass(macid("{checkMIMEHeaders}"), "mime-version"); 1849*7c478bd9Sstevel@tonic-gate 1850*7c478bd9Sstevel@tonic-gate /* Macros to save in the queue file -- don't remove any */ 1851*7c478bd9Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "r"); 1852*7c478bd9Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "s"); 1853*7c478bd9Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "_"); 1854*7c478bd9Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "{if_addr}"); 1855*7c478bd9Sstevel@tonic-gate setclass(macid("{persistentMacros}"), "{daemon_flags}"); 1856*7c478bd9Sstevel@tonic-gate 1857*7c478bd9Sstevel@tonic-gate /* operate in queue directory */ 1858*7c478bd9Sstevel@tonic-gate if (QueueDir == NULL || *QueueDir == '\0') 1859*7c478bd9Sstevel@tonic-gate { 1860*7c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST) 1861*7c478bd9Sstevel@tonic-gate { 1862*7c478bd9Sstevel@tonic-gate syserr("QueueDirectory (Q) option must be set"); 1863*7c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 1864*7c478bd9Sstevel@tonic-gate } 1865*7c478bd9Sstevel@tonic-gate } 1866*7c478bd9Sstevel@tonic-gate else 1867*7c478bd9Sstevel@tonic-gate { 1868*7c478bd9Sstevel@tonic-gate if (OpMode != MD_TEST) 1869*7c478bd9Sstevel@tonic-gate setup_queues(OpMode == MD_DAEMON); 1870*7c478bd9Sstevel@tonic-gate } 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate /* check host status directory for validity */ 1873*7c478bd9Sstevel@tonic-gate if (HostStatDir != NULL && !path_is_dir(HostStatDir, false)) 1874*7c478bd9Sstevel@tonic-gate { 1875*7c478bd9Sstevel@tonic-gate /* cannot use this value */ 1876*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1877*7c478bd9Sstevel@tonic-gate "Warning: Cannot use HostStatusDirectory = %s: %s\n", 1878*7c478bd9Sstevel@tonic-gate HostStatDir, sm_errstring(errno)); 1879*7c478bd9Sstevel@tonic-gate HostStatDir = NULL; 1880*7c478bd9Sstevel@tonic-gate } 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate if (OpMode == MD_QUEUERUN && 1883*7c478bd9Sstevel@tonic-gate RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 1884*7c478bd9Sstevel@tonic-gate { 1885*7c478bd9Sstevel@tonic-gate struct stat stbuf; 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate /* check to see if we own the queue directory */ 1888*7c478bd9Sstevel@tonic-gate if (stat(".", &stbuf) < 0) 1889*7c478bd9Sstevel@tonic-gate syserr("main: cannot stat %s", QueueDir); 1890*7c478bd9Sstevel@tonic-gate if (stbuf.st_uid != RealUid) 1891*7c478bd9Sstevel@tonic-gate { 1892*7c478bd9Sstevel@tonic-gate /* nope, really a botch */ 1893*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1894*7c478bd9Sstevel@tonic-gate usrerr("You do not have permission to process the queue"); 1895*7c478bd9Sstevel@tonic-gate finis(false, true, EX_NOPERM); 1896*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1897*7c478bd9Sstevel@tonic-gate } 1898*7c478bd9Sstevel@tonic-gate } 1899*7c478bd9Sstevel@tonic-gate 1900*7c478bd9Sstevel@tonic-gate #if MILTER 1901*7c478bd9Sstevel@tonic-gate /* sanity checks on milter filters */ 1902*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 1903*7c478bd9Sstevel@tonic-gate { 1904*7c478bd9Sstevel@tonic-gate milter_config(InputFilterList, InputFilters, MAXFILTERS); 1905*7c478bd9Sstevel@tonic-gate setup_daemon_milters(); 1906*7c478bd9Sstevel@tonic-gate } 1907*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 1908*7c478bd9Sstevel@tonic-gate 1909*7c478bd9Sstevel@tonic-gate /* Convert queuegroup string to qgrp number */ 1910*7c478bd9Sstevel@tonic-gate if (queuegroup != NULL) 1911*7c478bd9Sstevel@tonic-gate { 1912*7c478bd9Sstevel@tonic-gate qgrp = name2qid(queuegroup); 1913*7c478bd9Sstevel@tonic-gate if (qgrp == NOQGRP) 1914*7c478bd9Sstevel@tonic-gate { 1915*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1916*7c478bd9Sstevel@tonic-gate usrerr("Queue group %s unknown", queuegroup); 1917*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 1918*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1919*7c478bd9Sstevel@tonic-gate } 1920*7c478bd9Sstevel@tonic-gate } 1921*7c478bd9Sstevel@tonic-gate 1922*7c478bd9Sstevel@tonic-gate /* if we've had errors so far, exit now */ 1923*7c478bd9Sstevel@tonic-gate if (ExitStat != EX_OK && OpMode != MD_TEST) 1924*7c478bd9Sstevel@tonic-gate { 1925*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 1926*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1927*7c478bd9Sstevel@tonic-gate } 1928*7c478bd9Sstevel@tonic-gate 1929*7c478bd9Sstevel@tonic-gate #if SASL 1930*7c478bd9Sstevel@tonic-gate /* sendmail specific SASL initialization */ 1931*7c478bd9Sstevel@tonic-gate sm_sasl_init(); 1932*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 1933*7c478bd9Sstevel@tonic-gate 1934*7c478bd9Sstevel@tonic-gate #if XDEBUG 1935*7c478bd9Sstevel@tonic-gate checkfd012("before main() initmaps"); 1936*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 1937*7c478bd9Sstevel@tonic-gate 1938*7c478bd9Sstevel@tonic-gate /* 1939*7c478bd9Sstevel@tonic-gate ** Do operation-mode-dependent initialization. 1940*7c478bd9Sstevel@tonic-gate */ 1941*7c478bd9Sstevel@tonic-gate 1942*7c478bd9Sstevel@tonic-gate switch (OpMode) 1943*7c478bd9Sstevel@tonic-gate { 1944*7c478bd9Sstevel@tonic-gate case MD_PRINT: 1945*7c478bd9Sstevel@tonic-gate /* print the queue */ 1946*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1947*7c478bd9Sstevel@tonic-gate dropenvelope(&BlankEnvelope, true, false); 1948*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 1949*7c478bd9Sstevel@tonic-gate if (qgrp != NOQGRP) 1950*7c478bd9Sstevel@tonic-gate { 1951*7c478bd9Sstevel@tonic-gate int j; 1952*7c478bd9Sstevel@tonic-gate 1953*7c478bd9Sstevel@tonic-gate /* Selecting a particular queue group to run */ 1954*7c478bd9Sstevel@tonic-gate for (j = 0; j < Queue[qgrp]->qg_numqueues; j++) 1955*7c478bd9Sstevel@tonic-gate { 1956*7c478bd9Sstevel@tonic-gate if (StopRequest) 1957*7c478bd9Sstevel@tonic-gate stop_sendmail(); 1958*7c478bd9Sstevel@tonic-gate (void) print_single_queue(qgrp, j); 1959*7c478bd9Sstevel@tonic-gate } 1960*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 1961*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1962*7c478bd9Sstevel@tonic-gate } 1963*7c478bd9Sstevel@tonic-gate printqueue(); 1964*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 1965*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1966*7c478bd9Sstevel@tonic-gate break; 1967*7c478bd9Sstevel@tonic-gate 1968*7c478bd9Sstevel@tonic-gate case MD_PRINTNQE: 1969*7c478bd9Sstevel@tonic-gate /* print number of entries in queue */ 1970*7c478bd9Sstevel@tonic-gate dropenvelope(&BlankEnvelope, true, false); 1971*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 1972*7c478bd9Sstevel@tonic-gate printnqe(smioout, NULL); 1973*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 1974*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1975*7c478bd9Sstevel@tonic-gate break; 1976*7c478bd9Sstevel@tonic-gate 1977*7c478bd9Sstevel@tonic-gate case MD_QUEUERUN: 1978*7c478bd9Sstevel@tonic-gate /* only handle quarantining here */ 1979*7c478bd9Sstevel@tonic-gate if (quarantining == NULL) 1980*7c478bd9Sstevel@tonic-gate break; 1981*7c478bd9Sstevel@tonic-gate 1982*7c478bd9Sstevel@tonic-gate if (QueueMode != QM_QUARANTINE && 1983*7c478bd9Sstevel@tonic-gate QueueMode != QM_NORMAL) 1984*7c478bd9Sstevel@tonic-gate { 1985*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1986*7c478bd9Sstevel@tonic-gate usrerr("Can not use -Q with -q%c", QueueMode); 1987*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 1988*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 1989*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1990*7c478bd9Sstevel@tonic-gate } 1991*7c478bd9Sstevel@tonic-gate quarantine_queue(quarantining, qgrp); 1992*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 1993*7c478bd9Sstevel@tonic-gate break; 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate case MD_HOSTSTAT: 1996*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGPIPE, sigpipe); 1997*7c478bd9Sstevel@tonic-gate (void) mci_traverse_persistent(mci_print_persistent, NULL); 1998*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 1999*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2000*7c478bd9Sstevel@tonic-gate break; 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate case MD_PURGESTAT: 2003*7c478bd9Sstevel@tonic-gate (void) mci_traverse_persistent(mci_purge_persistent, NULL); 2004*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 2005*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2006*7c478bd9Sstevel@tonic-gate break; 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate case MD_INITALIAS: 2009*7c478bd9Sstevel@tonic-gate /* initialize maps */ 2010*7c478bd9Sstevel@tonic-gate initmaps(); 2011*7c478bd9Sstevel@tonic-gate finis(false, true, ExitStat); 2012*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2013*7c478bd9Sstevel@tonic-gate break; 2014*7c478bd9Sstevel@tonic-gate 2015*7c478bd9Sstevel@tonic-gate case MD_SMTP: 2016*7c478bd9Sstevel@tonic-gate case MD_DAEMON: 2017*7c478bd9Sstevel@tonic-gate /* reset DSN parameters */ 2018*7c478bd9Sstevel@tonic-gate DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 2019*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 2020*7c478bd9Sstevel@tonic-gate macid("{dsn_notify}"), NULL); 2021*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_envid = NULL; 2022*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 2023*7c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), NULL); 2024*7c478bd9Sstevel@tonic-gate BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 2025*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 2026*7c478bd9Sstevel@tonic-gate macid("{dsn_ret}"), NULL); 2027*7c478bd9Sstevel@tonic-gate 2028*7c478bd9Sstevel@tonic-gate /* don't open maps for daemon -- done below in child */ 2029*7c478bd9Sstevel@tonic-gate break; 2030*7c478bd9Sstevel@tonic-gate } 2031*7c478bd9Sstevel@tonic-gate 2032*7c478bd9Sstevel@tonic-gate if (tTd(0, 15)) 2033*7c478bd9Sstevel@tonic-gate { 2034*7c478bd9Sstevel@tonic-gate /* print configuration table (or at least part of it) */ 2035*7c478bd9Sstevel@tonic-gate if (tTd(0, 90)) 2036*7c478bd9Sstevel@tonic-gate printrules(); 2037*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXMAILERS; i++) 2038*7c478bd9Sstevel@tonic-gate { 2039*7c478bd9Sstevel@tonic-gate if (Mailer[i] != NULL) 2040*7c478bd9Sstevel@tonic-gate printmailer(sm_debug_file(), Mailer[i]); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate } 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate /* 2045*7c478bd9Sstevel@tonic-gate ** Switch to the main envelope. 2046*7c478bd9Sstevel@tonic-gate */ 2047*7c478bd9Sstevel@tonic-gate 2048*7c478bd9Sstevel@tonic-gate CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope, 2049*7c478bd9Sstevel@tonic-gate sm_rpool_new_x(NULL)); 2050*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags = BlankEnvelope.e_flags; 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate /* 2053*7c478bd9Sstevel@tonic-gate ** If test mode, read addresses from stdin and process. 2054*7c478bd9Sstevel@tonic-gate */ 2055*7c478bd9Sstevel@tonic-gate 2056*7c478bd9Sstevel@tonic-gate if (OpMode == MD_TEST) 2057*7c478bd9Sstevel@tonic-gate { 2058*7c478bd9Sstevel@tonic-gate if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL))) 2059*7c478bd9Sstevel@tonic-gate Verbose = 2; 2060*7c478bd9Sstevel@tonic-gate 2061*7c478bd9Sstevel@tonic-gate if (Verbose) 2062*7c478bd9Sstevel@tonic-gate { 2063*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2064*7c478bd9Sstevel@tonic-gate "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 2065*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2066*7c478bd9Sstevel@tonic-gate "Enter <ruleset> <address>\n"); 2067*7c478bd9Sstevel@tonic-gate } 2068*7c478bd9Sstevel@tonic-gate macdefine(&(MainEnvelope.e_macro), A_PERM, 2069*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), "e r"); 2070*7c478bd9Sstevel@tonic-gate for (;;) 2071*7c478bd9Sstevel@tonic-gate { 2072*7c478bd9Sstevel@tonic-gate SM_TRY 2073*7c478bd9Sstevel@tonic-gate { 2074*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, intindebug); 2075*7c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGINT); 2076*7c478bd9Sstevel@tonic-gate if (Verbose == 2) 2077*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 2078*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 2079*7c478bd9Sstevel@tonic-gate "> "); 2080*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 2081*7c478bd9Sstevel@tonic-gate if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, 2082*7c478bd9Sstevel@tonic-gate sizeof buf) == NULL) 2083*7c478bd9Sstevel@tonic-gate testmodeline("/quit", &MainEnvelope); 2084*7c478bd9Sstevel@tonic-gate p = strchr(buf, '\n'); 2085*7c478bd9Sstevel@tonic-gate if (p != NULL) 2086*7c478bd9Sstevel@tonic-gate *p = '\0'; 2087*7c478bd9Sstevel@tonic-gate if (Verbose < 2) 2088*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, 2089*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 2090*7c478bd9Sstevel@tonic-gate "> %s\n", buf); 2091*7c478bd9Sstevel@tonic-gate testmodeline(buf, &MainEnvelope); 2092*7c478bd9Sstevel@tonic-gate } 2093*7c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 2094*7c478bd9Sstevel@tonic-gate { 2095*7c478bd9Sstevel@tonic-gate /* 2096*7c478bd9Sstevel@tonic-gate ** 8.10 just prints \n on interrupt. 2097*7c478bd9Sstevel@tonic-gate ** I'm printing the exception here in case 2098*7c478bd9Sstevel@tonic-gate ** sendmail is extended to raise additional 2099*7c478bd9Sstevel@tonic-gate ** exceptions in this context. 2100*7c478bd9Sstevel@tonic-gate */ 2101*7c478bd9Sstevel@tonic-gate 2102*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2103*7c478bd9Sstevel@tonic-gate "\n"); 2104*7c478bd9Sstevel@tonic-gate sm_exc_print(exc, smioout); 2105*7c478bd9Sstevel@tonic-gate } 2106*7c478bd9Sstevel@tonic-gate SM_END_TRY 2107*7c478bd9Sstevel@tonic-gate } 2108*7c478bd9Sstevel@tonic-gate } 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate #if STARTTLS 2111*7c478bd9Sstevel@tonic-gate tls_ok = true; 2112*7c478bd9Sstevel@tonic-gate if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER) 2113*7c478bd9Sstevel@tonic-gate { 2114*7c478bd9Sstevel@tonic-gate /* check whether STARTTLS is turned off for the client */ 2115*7c478bd9Sstevel@tonic-gate if (chkclientmodifiers(D_NOTLS)) 2116*7c478bd9Sstevel@tonic-gate tls_ok = false; 2117*7c478bd9Sstevel@tonic-gate } 2118*7c478bd9Sstevel@tonic-gate else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON || 2119*7c478bd9Sstevel@tonic-gate OpMode == MD_SMTP) 2120*7c478bd9Sstevel@tonic-gate { 2121*7c478bd9Sstevel@tonic-gate /* check whether STARTTLS is turned off for the server */ 2122*7c478bd9Sstevel@tonic-gate if (chkdaemonmodifiers(D_NOTLS)) 2123*7c478bd9Sstevel@tonic-gate tls_ok = false; 2124*7c478bd9Sstevel@tonic-gate } 2125*7c478bd9Sstevel@tonic-gate else /* other modes don't need STARTTLS */ 2126*7c478bd9Sstevel@tonic-gate tls_ok = false; 2127*7c478bd9Sstevel@tonic-gate 2128*7c478bd9Sstevel@tonic-gate if (tls_ok) 2129*7c478bd9Sstevel@tonic-gate { 2130*7c478bd9Sstevel@tonic-gate /* basic TLS initialization */ 2131*7c478bd9Sstevel@tonic-gate tls_ok = init_tls_library(); 2132*7c478bd9Sstevel@tonic-gate } 2133*7c478bd9Sstevel@tonic-gate 2134*7c478bd9Sstevel@tonic-gate if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)) 2135*7c478bd9Sstevel@tonic-gate { 2136*7c478bd9Sstevel@tonic-gate /* disable TLS for client */ 2137*7c478bd9Sstevel@tonic-gate setclttls(false); 2138*7c478bd9Sstevel@tonic-gate } 2139*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2140*7c478bd9Sstevel@tonic-gate 2141*7c478bd9Sstevel@tonic-gate /* 2142*7c478bd9Sstevel@tonic-gate ** If collecting stuff from the queue, go start doing that. 2143*7c478bd9Sstevel@tonic-gate */ 2144*7c478bd9Sstevel@tonic-gate 2145*7c478bd9Sstevel@tonic-gate if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 2146*7c478bd9Sstevel@tonic-gate { 2147*7c478bd9Sstevel@tonic-gate pid_t pid = -1; 2148*7c478bd9Sstevel@tonic-gate 2149*7c478bd9Sstevel@tonic-gate #if STARTTLS 2150*7c478bd9Sstevel@tonic-gate /* init TLS for client, ignore result for now */ 2151*7c478bd9Sstevel@tonic-gate (void) initclttls(tls_ok); 2152*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate /* 2155*7c478bd9Sstevel@tonic-gate ** The parent process of the caller of runqueue() needs 2156*7c478bd9Sstevel@tonic-gate ** to stay around for a possible SIGTERM. The SIGTERM will 2157*7c478bd9Sstevel@tonic-gate ** tell this process that all of the queue runners children 2158*7c478bd9Sstevel@tonic-gate ** need to be sent SIGTERM as well. At the same time, we 2159*7c478bd9Sstevel@tonic-gate ** want to return control to the command line. So we do an 2160*7c478bd9Sstevel@tonic-gate ** extra fork(). 2161*7c478bd9Sstevel@tonic-gate */ 2162*7c478bd9Sstevel@tonic-gate 2163*7c478bd9Sstevel@tonic-gate if (Verbose || foregroundqueue || (pid = fork()) <= 0) 2164*7c478bd9Sstevel@tonic-gate { 2165*7c478bd9Sstevel@tonic-gate /* 2166*7c478bd9Sstevel@tonic-gate ** If the fork() failed we should still try to do 2167*7c478bd9Sstevel@tonic-gate ** the queue run. If it succeeded then the child 2168*7c478bd9Sstevel@tonic-gate ** is going to start the run and wait for all 2169*7c478bd9Sstevel@tonic-gate ** of the children to finish. 2170*7c478bd9Sstevel@tonic-gate */ 2171*7c478bd9Sstevel@tonic-gate 2172*7c478bd9Sstevel@tonic-gate if (pid == 0) 2173*7c478bd9Sstevel@tonic-gate { 2174*7c478bd9Sstevel@tonic-gate /* Reset global flags */ 2175*7c478bd9Sstevel@tonic-gate RestartRequest = NULL; 2176*7c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 2177*7c478bd9Sstevel@tonic-gate PendingSignal = 0; 2178*7c478bd9Sstevel@tonic-gate 2179*7c478bd9Sstevel@tonic-gate /* disconnect from terminal */ 2180*7c478bd9Sstevel@tonic-gate disconnect(2, CurEnv); 2181*7c478bd9Sstevel@tonic-gate } 2182*7c478bd9Sstevel@tonic-gate 2183*7c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 2184*7c478bd9Sstevel@tonic-gate if (qgrp != NOQGRP) 2185*7c478bd9Sstevel@tonic-gate { 2186*7c478bd9Sstevel@tonic-gate int rwgflags = RWG_NONE; 2187*7c478bd9Sstevel@tonic-gate 2188*7c478bd9Sstevel@tonic-gate /* 2189*7c478bd9Sstevel@tonic-gate ** To run a specific queue group mark it to 2190*7c478bd9Sstevel@tonic-gate ** be run, select the work group it's in and 2191*7c478bd9Sstevel@tonic-gate ** increment the work counter. 2192*7c478bd9Sstevel@tonic-gate */ 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; 2195*7c478bd9Sstevel@tonic-gate i++) 2196*7c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = (time_t) -1; 2197*7c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun = 0; 2198*7c478bd9Sstevel@tonic-gate if (Verbose) 2199*7c478bd9Sstevel@tonic-gate rwgflags |= RWG_VERBOSE; 2200*7c478bd9Sstevel@tonic-gate if (queuepersistent) 2201*7c478bd9Sstevel@tonic-gate rwgflags |= RWG_PERSISTENT; 2202*7c478bd9Sstevel@tonic-gate rwgflags |= RWG_FORCE; 2203*7c478bd9Sstevel@tonic-gate (void) run_work_group(Queue[qgrp]->qg_wgrp, 2204*7c478bd9Sstevel@tonic-gate rwgflags); 2205*7c478bd9Sstevel@tonic-gate } 2206*7c478bd9Sstevel@tonic-gate else 2207*7c478bd9Sstevel@tonic-gate (void) runqueue(false, Verbose, 2208*7c478bd9Sstevel@tonic-gate queuepersistent, true); 2209*7c478bd9Sstevel@tonic-gate 2210*7c478bd9Sstevel@tonic-gate /* set the title to make it easier to find */ 2211*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "Queue control"); 2212*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 2213*7c478bd9Sstevel@tonic-gate while (CurChildren > 0) 2214*7c478bd9Sstevel@tonic-gate { 2215*7c478bd9Sstevel@tonic-gate int status; 2216*7c478bd9Sstevel@tonic-gate pid_t ret; 2217*7c478bd9Sstevel@tonic-gate 2218*7c478bd9Sstevel@tonic-gate errno = 0; 2219*7c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 2220*7c478bd9Sstevel@tonic-gate { 2221*7c478bd9Sstevel@tonic-gate if (errno == ECHILD) 2222*7c478bd9Sstevel@tonic-gate { 2223*7c478bd9Sstevel@tonic-gate /* 2224*7c478bd9Sstevel@tonic-gate ** Oops... something got messed 2225*7c478bd9Sstevel@tonic-gate ** up really bad. Waiting for 2226*7c478bd9Sstevel@tonic-gate ** non-existent children 2227*7c478bd9Sstevel@tonic-gate ** shouldn't happen. Let's get 2228*7c478bd9Sstevel@tonic-gate ** out of here. 2229*7c478bd9Sstevel@tonic-gate */ 2230*7c478bd9Sstevel@tonic-gate 2231*7c478bd9Sstevel@tonic-gate CurChildren = 0; 2232*7c478bd9Sstevel@tonic-gate break; 2233*7c478bd9Sstevel@tonic-gate } 2234*7c478bd9Sstevel@tonic-gate continue; 2235*7c478bd9Sstevel@tonic-gate } 2236*7c478bd9Sstevel@tonic-gate 2237*7c478bd9Sstevel@tonic-gate /* something is really really wrong */ 2238*7c478bd9Sstevel@tonic-gate if (errno == ECHILD) 2239*7c478bd9Sstevel@tonic-gate { 2240*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 2241*7c478bd9Sstevel@tonic-gate "queue control process: lost all children: wait returned ECHILD"); 2242*7c478bd9Sstevel@tonic-gate break; 2243*7c478bd9Sstevel@tonic-gate } 2244*7c478bd9Sstevel@tonic-gate 2245*7c478bd9Sstevel@tonic-gate /* Only drop when a child gives status */ 2246*7c478bd9Sstevel@tonic-gate if (WIFSTOPPED(status)) 2247*7c478bd9Sstevel@tonic-gate continue; 2248*7c478bd9Sstevel@tonic-gate 2249*7c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, NULL); 2250*7c478bd9Sstevel@tonic-gate } 2251*7c478bd9Sstevel@tonic-gate } 2252*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 2253*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2254*7c478bd9Sstevel@tonic-gate } 2255*7c478bd9Sstevel@tonic-gate 2256*7c478bd9Sstevel@tonic-gate # if SASL 2257*7c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 2258*7c478bd9Sstevel@tonic-gate { 2259*7c478bd9Sstevel@tonic-gate /* check whether AUTH is turned off for the server */ 2260*7c478bd9Sstevel@tonic-gate if (!chkdaemonmodifiers(D_NOAUTH) && 2261*7c478bd9Sstevel@tonic-gate (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 2262*7c478bd9Sstevel@tonic-gate syserr("!sasl_server_init failed! [%s]", 2263*7c478bd9Sstevel@tonic-gate sasl_errstring(i, NULL, NULL)); 2264*7c478bd9Sstevel@tonic-gate } 2265*7c478bd9Sstevel@tonic-gate # endif /* SASL */ 2266*7c478bd9Sstevel@tonic-gate 2267*7c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP) 2268*7c478bd9Sstevel@tonic-gate { 2269*7c478bd9Sstevel@tonic-gate proc_list_add(CurrentPid, "Sendmail SMTP Agent", 2270*7c478bd9Sstevel@tonic-gate PROC_DAEMON, 0, -1, NULL); 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate /* clean up background delivery children */ 2273*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, reapchild); 2274*7c478bd9Sstevel@tonic-gate } 2275*7c478bd9Sstevel@tonic-gate 2276*7c478bd9Sstevel@tonic-gate /* 2277*7c478bd9Sstevel@tonic-gate ** If a daemon, wait for a request. 2278*7c478bd9Sstevel@tonic-gate ** getrequests will always return in a child. 2279*7c478bd9Sstevel@tonic-gate ** If we should also be processing the queue, start 2280*7c478bd9Sstevel@tonic-gate ** doing it in background. 2281*7c478bd9Sstevel@tonic-gate ** We check for any errors that might have happened 2282*7c478bd9Sstevel@tonic-gate ** during startup. 2283*7c478bd9Sstevel@tonic-gate */ 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON || QueueIntvl > 0) 2286*7c478bd9Sstevel@tonic-gate { 2287*7c478bd9Sstevel@tonic-gate char dtype[200]; 2288*7c478bd9Sstevel@tonic-gate 2289*7c478bd9Sstevel@tonic-gate if (!run_in_foreground && !tTd(99, 100)) 2290*7c478bd9Sstevel@tonic-gate { 2291*7c478bd9Sstevel@tonic-gate /* put us in background */ 2292*7c478bd9Sstevel@tonic-gate i = fork(); 2293*7c478bd9Sstevel@tonic-gate if (i < 0) 2294*7c478bd9Sstevel@tonic-gate syserr("daemon: cannot fork"); 2295*7c478bd9Sstevel@tonic-gate if (i != 0) 2296*7c478bd9Sstevel@tonic-gate { 2297*7c478bd9Sstevel@tonic-gate finis(false, true, EX_OK); 2298*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2299*7c478bd9Sstevel@tonic-gate } 2300*7c478bd9Sstevel@tonic-gate 2301*7c478bd9Sstevel@tonic-gate /* 2302*7c478bd9Sstevel@tonic-gate ** Initialize exception stack and default exception 2303*7c478bd9Sstevel@tonic-gate ** handler for child process. 2304*7c478bd9Sstevel@tonic-gate */ 2305*7c478bd9Sstevel@tonic-gate 2306*7c478bd9Sstevel@tonic-gate /* Reset global flags */ 2307*7c478bd9Sstevel@tonic-gate RestartRequest = NULL; 2308*7c478bd9Sstevel@tonic-gate RestartWorkGroup = false; 2309*7c478bd9Sstevel@tonic-gate ShutdownRequest = NULL; 2310*7c478bd9Sstevel@tonic-gate PendingSignal = 0; 2311*7c478bd9Sstevel@tonic-gate CurrentPid = getpid(); 2312*7c478bd9Sstevel@tonic-gate 2313*7c478bd9Sstevel@tonic-gate sm_exc_newthread(fatal_error); 2314*7c478bd9Sstevel@tonic-gate 2315*7c478bd9Sstevel@tonic-gate /* disconnect from our controlling tty */ 2316*7c478bd9Sstevel@tonic-gate disconnect(2, &MainEnvelope); 2317*7c478bd9Sstevel@tonic-gate } 2318*7c478bd9Sstevel@tonic-gate 2319*7c478bd9Sstevel@tonic-gate dtype[0] = '\0'; 2320*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON) 2321*7c478bd9Sstevel@tonic-gate { 2322*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(dtype, "+SMTP", sizeof dtype); 2323*7c478bd9Sstevel@tonic-gate DaemonPid = CurrentPid; 2324*7c478bd9Sstevel@tonic-gate } 2325*7c478bd9Sstevel@tonic-gate if (QueueIntvl > 0) 2326*7c478bd9Sstevel@tonic-gate { 2327*7c478bd9Sstevel@tonic-gate (void) sm_strlcat2(dtype, 2328*7c478bd9Sstevel@tonic-gate queuepersistent 2329*7c478bd9Sstevel@tonic-gate ? "+persistent-queueing@" 2330*7c478bd9Sstevel@tonic-gate : "+queueing@", 2331*7c478bd9Sstevel@tonic-gate pintvl(QueueIntvl, true), 2332*7c478bd9Sstevel@tonic-gate sizeof dtype); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate if (tTd(0, 1)) 2335*7c478bd9Sstevel@tonic-gate (void) sm_strlcat(dtype, "+debugging", sizeof dtype); 2336*7c478bd9Sstevel@tonic-gate 2337*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 2338*7c478bd9Sstevel@tonic-gate "starting daemon (%s): %s", Version, dtype + 1); 2339*7c478bd9Sstevel@tonic-gate #if XLA 2340*7c478bd9Sstevel@tonic-gate xla_create_file(); 2341*7c478bd9Sstevel@tonic-gate #endif /* XLA */ 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate /* save daemon type in a macro for possible PidFile use */ 2344*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 2345*7c478bd9Sstevel@tonic-gate macid("{daemon_info}"), dtype + 1); 2346*7c478bd9Sstevel@tonic-gate 2347*7c478bd9Sstevel@tonic-gate /* save queue interval in a macro for possible PidFile use */ 2348*7c478bd9Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_TEMP, 2349*7c478bd9Sstevel@tonic-gate macid("{queue_interval}"), pintvl(QueueIntvl, true)); 2350*7c478bd9Sstevel@tonic-gate 2351*7c478bd9Sstevel@tonic-gate /* workaround: can't seem to release the signal in the parent */ 2352*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGHUP, sighup); 2353*7c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGHUP); 2354*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTERM, sigterm); 2355*7c478bd9Sstevel@tonic-gate 2356*7c478bd9Sstevel@tonic-gate if (QueueIntvl > 0) 2357*7c478bd9Sstevel@tonic-gate { 2358*7c478bd9Sstevel@tonic-gate (void) runqueue(true, false, queuepersistent, true); 2359*7c478bd9Sstevel@tonic-gate 2360*7c478bd9Sstevel@tonic-gate /* 2361*7c478bd9Sstevel@tonic-gate ** If queuepersistent but not in daemon mode then 2362*7c478bd9Sstevel@tonic-gate ** we're going to do the queue runner monitoring here. 2363*7c478bd9Sstevel@tonic-gate ** If in daemon mode then the monitoring will happen 2364*7c478bd9Sstevel@tonic-gate ** elsewhere. 2365*7c478bd9Sstevel@tonic-gate */ 2366*7c478bd9Sstevel@tonic-gate 2367*7c478bd9Sstevel@tonic-gate if (OpMode != MD_DAEMON && queuepersistent) 2368*7c478bd9Sstevel@tonic-gate { 2369*7c478bd9Sstevel@tonic-gate /* 2370*7c478bd9Sstevel@tonic-gate ** Write the pid to file 2371*7c478bd9Sstevel@tonic-gate ** XXX Overwrites sendmail.pid 2372*7c478bd9Sstevel@tonic-gate */ 2373*7c478bd9Sstevel@tonic-gate 2374*7c478bd9Sstevel@tonic-gate log_sendmail_pid(&MainEnvelope); 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate /* set the title to make it easier to find */ 2377*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, "Queue control"); 2378*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGCHLD, SIG_DFL); 2379*7c478bd9Sstevel@tonic-gate while (CurChildren > 0) 2380*7c478bd9Sstevel@tonic-gate { 2381*7c478bd9Sstevel@tonic-gate int status; 2382*7c478bd9Sstevel@tonic-gate pid_t ret; 2383*7c478bd9Sstevel@tonic-gate int group; 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate CHECK_RESTART; 2386*7c478bd9Sstevel@tonic-gate errno = 0; 2387*7c478bd9Sstevel@tonic-gate while ((ret = sm_wait(&status)) <= 0) 2388*7c478bd9Sstevel@tonic-gate { 2389*7c478bd9Sstevel@tonic-gate /* 2390*7c478bd9Sstevel@tonic-gate ** Waiting for non-existent 2391*7c478bd9Sstevel@tonic-gate ** children shouldn't happen. 2392*7c478bd9Sstevel@tonic-gate ** Let's get out of here if 2393*7c478bd9Sstevel@tonic-gate ** it occurs. 2394*7c478bd9Sstevel@tonic-gate */ 2395*7c478bd9Sstevel@tonic-gate 2396*7c478bd9Sstevel@tonic-gate if (errno == ECHILD) 2397*7c478bd9Sstevel@tonic-gate { 2398*7c478bd9Sstevel@tonic-gate CurChildren = 0; 2399*7c478bd9Sstevel@tonic-gate break; 2400*7c478bd9Sstevel@tonic-gate } 2401*7c478bd9Sstevel@tonic-gate continue; 2402*7c478bd9Sstevel@tonic-gate } 2403*7c478bd9Sstevel@tonic-gate 2404*7c478bd9Sstevel@tonic-gate /* something is really really wrong */ 2405*7c478bd9Sstevel@tonic-gate if (errno == ECHILD) 2406*7c478bd9Sstevel@tonic-gate { 2407*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 2408*7c478bd9Sstevel@tonic-gate "persistent queue runner control process: lost all children: wait returned ECHILD"); 2409*7c478bd9Sstevel@tonic-gate break; 2410*7c478bd9Sstevel@tonic-gate } 2411*7c478bd9Sstevel@tonic-gate 2412*7c478bd9Sstevel@tonic-gate if (WIFSTOPPED(status)) 2413*7c478bd9Sstevel@tonic-gate continue; 2414*7c478bd9Sstevel@tonic-gate 2415*7c478bd9Sstevel@tonic-gate /* Probe only on a child status */ 2416*7c478bd9Sstevel@tonic-gate proc_list_drop(ret, status, &group); 2417*7c478bd9Sstevel@tonic-gate 2418*7c478bd9Sstevel@tonic-gate if (WIFSIGNALED(status)) 2419*7c478bd9Sstevel@tonic-gate { 2420*7c478bd9Sstevel@tonic-gate if (WCOREDUMP(status)) 2421*7c478bd9Sstevel@tonic-gate { 2422*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 2423*7c478bd9Sstevel@tonic-gate "persistent queue runner=%d core dumped, signal=%d", 2424*7c478bd9Sstevel@tonic-gate group, WTERMSIG(status)); 2425*7c478bd9Sstevel@tonic-gate 2426*7c478bd9Sstevel@tonic-gate /* don't restart this */ 2427*7c478bd9Sstevel@tonic-gate mark_work_group_restart( 2428*7c478bd9Sstevel@tonic-gate group, -1); 2429*7c478bd9Sstevel@tonic-gate continue; 2430*7c478bd9Sstevel@tonic-gate } 2431*7c478bd9Sstevel@tonic-gate 2432*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 2433*7c478bd9Sstevel@tonic-gate "persistent queue runner=%d died, signal=%d", 2434*7c478bd9Sstevel@tonic-gate group, WTERMSIG(status)); 2435*7c478bd9Sstevel@tonic-gate } 2436*7c478bd9Sstevel@tonic-gate 2437*7c478bd9Sstevel@tonic-gate /* 2438*7c478bd9Sstevel@tonic-gate ** When debugging active, don't 2439*7c478bd9Sstevel@tonic-gate ** restart the persistent queues. 2440*7c478bd9Sstevel@tonic-gate ** But do log this as info. 2441*7c478bd9Sstevel@tonic-gate */ 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugNoPRestart, 2444*7c478bd9Sstevel@tonic-gate 1)) 2445*7c478bd9Sstevel@tonic-gate { 2446*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, NOQID, 2447*7c478bd9Sstevel@tonic-gate "persistent queue runner=%d, exited", 2448*7c478bd9Sstevel@tonic-gate group); 2449*7c478bd9Sstevel@tonic-gate mark_work_group_restart(group, 2450*7c478bd9Sstevel@tonic-gate -1); 2451*7c478bd9Sstevel@tonic-gate } 2452*7c478bd9Sstevel@tonic-gate } 2453*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 2454*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2455*7c478bd9Sstevel@tonic-gate } 2456*7c478bd9Sstevel@tonic-gate 2457*7c478bd9Sstevel@tonic-gate if (OpMode != MD_DAEMON) 2458*7c478bd9Sstevel@tonic-gate { 2459*7c478bd9Sstevel@tonic-gate char qtype[200]; 2460*7c478bd9Sstevel@tonic-gate 2461*7c478bd9Sstevel@tonic-gate /* 2462*7c478bd9Sstevel@tonic-gate ** Write the pid to file 2463*7c478bd9Sstevel@tonic-gate ** XXX Overwrites sendmail.pid 2464*7c478bd9Sstevel@tonic-gate */ 2465*7c478bd9Sstevel@tonic-gate 2466*7c478bd9Sstevel@tonic-gate log_sendmail_pid(&MainEnvelope); 2467*7c478bd9Sstevel@tonic-gate 2468*7c478bd9Sstevel@tonic-gate /* set the title to make it easier to find */ 2469*7c478bd9Sstevel@tonic-gate qtype[0] = '\0'; 2470*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(qtype, sizeof qtype, 4, 2471*7c478bd9Sstevel@tonic-gate "Queue runner@", 2472*7c478bd9Sstevel@tonic-gate pintvl(QueueIntvl, true), 2473*7c478bd9Sstevel@tonic-gate " for ", 2474*7c478bd9Sstevel@tonic-gate QueueDir); 2475*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, CurEnv, qtype); 2476*7c478bd9Sstevel@tonic-gate for (;;) 2477*7c478bd9Sstevel@tonic-gate { 2478*7c478bd9Sstevel@tonic-gate (void) pause(); 2479*7c478bd9Sstevel@tonic-gate 2480*7c478bd9Sstevel@tonic-gate CHECK_RESTART; 2481*7c478bd9Sstevel@tonic-gate 2482*7c478bd9Sstevel@tonic-gate if (doqueuerun()) 2483*7c478bd9Sstevel@tonic-gate (void) runqueue(true, false, 2484*7c478bd9Sstevel@tonic-gate false, false); 2485*7c478bd9Sstevel@tonic-gate } 2486*7c478bd9Sstevel@tonic-gate } 2487*7c478bd9Sstevel@tonic-gate } 2488*7c478bd9Sstevel@tonic-gate dropenvelope(&MainEnvelope, true, false); 2489*7c478bd9Sstevel@tonic-gate 2490*7c478bd9Sstevel@tonic-gate #if STARTTLS 2491*7c478bd9Sstevel@tonic-gate /* init TLS for server, ignore result for now */ 2492*7c478bd9Sstevel@tonic-gate (void) initsrvtls(tls_ok); 2493*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2494*7c478bd9Sstevel@tonic-gate 2495*7c478bd9Sstevel@tonic-gate nextreq: 2496*7c478bd9Sstevel@tonic-gate p_flags = getrequests(&MainEnvelope); 2497*7c478bd9Sstevel@tonic-gate 2498*7c478bd9Sstevel@tonic-gate /* drop privileges */ 2499*7c478bd9Sstevel@tonic-gate (void) drop_privileges(false); 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate /* 2502*7c478bd9Sstevel@tonic-gate ** Get authentication data 2503*7c478bd9Sstevel@tonic-gate ** Set _ macro in BlankEnvelope before calling newenvelope(). 2504*7c478bd9Sstevel@tonic-gate */ 2505*7c478bd9Sstevel@tonic-gate 2506*7c478bd9Sstevel@tonic-gate authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 2507*7c478bd9Sstevel@tonic-gate NULL), &forged); 2508*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 2509*7c478bd9Sstevel@tonic-gate 2510*7c478bd9Sstevel@tonic-gate /* at this point we are in a child: reset state */ 2511*7c478bd9Sstevel@tonic-gate sm_rpool_free(MainEnvelope.e_rpool); 2512*7c478bd9Sstevel@tonic-gate (void) newenvelope(&MainEnvelope, &MainEnvelope, 2513*7c478bd9Sstevel@tonic-gate sm_rpool_new_x(NULL)); 2514*7c478bd9Sstevel@tonic-gate } 2515*7c478bd9Sstevel@tonic-gate 2516*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 2517*7c478bd9Sstevel@tonic-gate { 2518*7c478bd9Sstevel@tonic-gate /* log connection information */ 2519*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo); 2520*7c478bd9Sstevel@tonic-gate } 2521*7c478bd9Sstevel@tonic-gate 2522*7c478bd9Sstevel@tonic-gate /* 2523*7c478bd9Sstevel@tonic-gate ** If running SMTP protocol, start collecting and executing 2524*7c478bd9Sstevel@tonic-gate ** commands. This will never return. 2525*7c478bd9Sstevel@tonic-gate */ 2526*7c478bd9Sstevel@tonic-gate 2527*7c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 2528*7c478bd9Sstevel@tonic-gate { 2529*7c478bd9Sstevel@tonic-gate char pbuf[20]; 2530*7c478bd9Sstevel@tonic-gate 2531*7c478bd9Sstevel@tonic-gate /* 2532*7c478bd9Sstevel@tonic-gate ** Save some macros for check_* rulesets. 2533*7c478bd9Sstevel@tonic-gate */ 2534*7c478bd9Sstevel@tonic-gate 2535*7c478bd9Sstevel@tonic-gate if (forged) 2536*7c478bd9Sstevel@tonic-gate { 2537*7c478bd9Sstevel@tonic-gate char ipbuf[103]; 2538*7c478bd9Sstevel@tonic-gate 2539*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 2540*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 2541*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 2542*7c478bd9Sstevel@tonic-gate macid("{client_name}"), ipbuf); 2543*7c478bd9Sstevel@tonic-gate } 2544*7c478bd9Sstevel@tonic-gate else 2545*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 2546*7c478bd9Sstevel@tonic-gate macid("{client_name}"), RealHostName); 2547*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 2548*7c478bd9Sstevel@tonic-gate macid("{client_ptr}"), RealHostName); 2549*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 2550*7c478bd9Sstevel@tonic-gate macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 2551*7c478bd9Sstevel@tonic-gate sm_getla(); 2552*7c478bd9Sstevel@tonic-gate 2553*7c478bd9Sstevel@tonic-gate switch (RealHostAddr.sa.sa_family) 2554*7c478bd9Sstevel@tonic-gate { 2555*7c478bd9Sstevel@tonic-gate #if NETINET 2556*7c478bd9Sstevel@tonic-gate case AF_INET: 2557*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 2558*7c478bd9Sstevel@tonic-gate RealHostAddr.sin.sin_port); 2559*7c478bd9Sstevel@tonic-gate break; 2560*7c478bd9Sstevel@tonic-gate #endif /* NETINET */ 2561*7c478bd9Sstevel@tonic-gate #if NETINET6 2562*7c478bd9Sstevel@tonic-gate case AF_INET6: 2563*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 2564*7c478bd9Sstevel@tonic-gate RealHostAddr.sin6.sin6_port); 2565*7c478bd9Sstevel@tonic-gate break; 2566*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 2567*7c478bd9Sstevel@tonic-gate default: 2568*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, "0"); 2569*7c478bd9Sstevel@tonic-gate break; 2570*7c478bd9Sstevel@tonic-gate } 2571*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 2572*7c478bd9Sstevel@tonic-gate macid("{client_port}"), pbuf); 2573*7c478bd9Sstevel@tonic-gate 2574*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON) 2575*7c478bd9Sstevel@tonic-gate { 2576*7c478bd9Sstevel@tonic-gate /* validate the connection */ 2577*7c478bd9Sstevel@tonic-gate HoldErrs = true; 2578*7c478bd9Sstevel@tonic-gate nullserver = validate_connection(&RealHostAddr, 2579*7c478bd9Sstevel@tonic-gate macvalue(macid("{client_name}"), 2580*7c478bd9Sstevel@tonic-gate &MainEnvelope), 2581*7c478bd9Sstevel@tonic-gate &MainEnvelope); 2582*7c478bd9Sstevel@tonic-gate HoldErrs = false; 2583*7c478bd9Sstevel@tonic-gate } 2584*7c478bd9Sstevel@tonic-gate else if (p_flags == NULL) 2585*7c478bd9Sstevel@tonic-gate { 2586*7c478bd9Sstevel@tonic-gate p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); 2587*7c478bd9Sstevel@tonic-gate clrbitmap(p_flags); 2588*7c478bd9Sstevel@tonic-gate } 2589*7c478bd9Sstevel@tonic-gate #if STARTTLS 2590*7c478bd9Sstevel@tonic-gate if (OpMode == MD_SMTP) 2591*7c478bd9Sstevel@tonic-gate (void) initsrvtls(tls_ok); 2592*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2593*7c478bd9Sstevel@tonic-gate 2594*7c478bd9Sstevel@tonic-gate /* turn off profiling */ 2595*7c478bd9Sstevel@tonic-gate SM_PROF(1); 2596*7c478bd9Sstevel@tonic-gate smtp(nullserver, *p_flags, &MainEnvelope); 2597*7c478bd9Sstevel@tonic-gate 2598*7c478bd9Sstevel@tonic-gate if (tTd(93, 100)) 2599*7c478bd9Sstevel@tonic-gate { 2600*7c478bd9Sstevel@tonic-gate /* turn off profiling */ 2601*7c478bd9Sstevel@tonic-gate SM_PROF(0); 2602*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON) 2603*7c478bd9Sstevel@tonic-gate goto nextreq; 2604*7c478bd9Sstevel@tonic-gate } 2605*7c478bd9Sstevel@tonic-gate } 2606*7c478bd9Sstevel@tonic-gate 2607*7c478bd9Sstevel@tonic-gate sm_rpool_free(MainEnvelope.e_rpool); 2608*7c478bd9Sstevel@tonic-gate clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 2609*7c478bd9Sstevel@tonic-gate if (OpMode == MD_VERIFY) 2610*7c478bd9Sstevel@tonic-gate { 2611*7c478bd9Sstevel@tonic-gate set_delivery_mode(SM_VERIFY, &MainEnvelope); 2612*7c478bd9Sstevel@tonic-gate PostMasterCopy = NULL; 2613*7c478bd9Sstevel@tonic-gate } 2614*7c478bd9Sstevel@tonic-gate else 2615*7c478bd9Sstevel@tonic-gate { 2616*7c478bd9Sstevel@tonic-gate /* interactive -- all errors are global */ 2617*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 2618*7c478bd9Sstevel@tonic-gate } 2619*7c478bd9Sstevel@tonic-gate 2620*7c478bd9Sstevel@tonic-gate /* 2621*7c478bd9Sstevel@tonic-gate ** Do basic system initialization and set the sender 2622*7c478bd9Sstevel@tonic-gate */ 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate initsys(&MainEnvelope); 2625*7c478bd9Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 2626*7c478bd9Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 2627*7c478bd9Sstevel@tonic-gate setsender(from, &MainEnvelope, NULL, '\0', false); 2628*7c478bd9Sstevel@tonic-gate if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 2629*7c478bd9Sstevel@tonic-gate (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 2630*7c478bd9Sstevel@tonic-gate strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 2631*7c478bd9Sstevel@tonic-gate { 2632*7c478bd9Sstevel@tonic-gate auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 2633*7c478bd9Sstevel@tonic-gate RealUserName, from, warn_f_flag); 2634*7c478bd9Sstevel@tonic-gate #if SASL 2635*7c478bd9Sstevel@tonic-gate auth = false; 2636*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2637*7c478bd9Sstevel@tonic-gate } 2638*7c478bd9Sstevel@tonic-gate if (auth) 2639*7c478bd9Sstevel@tonic-gate { 2640*7c478bd9Sstevel@tonic-gate char *fv; 2641*7c478bd9Sstevel@tonic-gate 2642*7c478bd9Sstevel@tonic-gate /* set the initial sender for AUTH= to $f@$j */ 2643*7c478bd9Sstevel@tonic-gate fv = macvalue('f', &MainEnvelope); 2644*7c478bd9Sstevel@tonic-gate if (fv == NULL || *fv == '\0') 2645*7c478bd9Sstevel@tonic-gate MainEnvelope.e_auth_param = NULL; 2646*7c478bd9Sstevel@tonic-gate else 2647*7c478bd9Sstevel@tonic-gate { 2648*7c478bd9Sstevel@tonic-gate if (strchr(fv, '@') == NULL) 2649*7c478bd9Sstevel@tonic-gate { 2650*7c478bd9Sstevel@tonic-gate i = strlen(fv) + strlen(macvalue('j', 2651*7c478bd9Sstevel@tonic-gate &MainEnvelope)) + 2; 2652*7c478bd9Sstevel@tonic-gate p = sm_malloc_x(i); 2653*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(p, i, 3, fv, "@", 2654*7c478bd9Sstevel@tonic-gate macvalue('j', 2655*7c478bd9Sstevel@tonic-gate &MainEnvelope)); 2656*7c478bd9Sstevel@tonic-gate } 2657*7c478bd9Sstevel@tonic-gate else 2658*7c478bd9Sstevel@tonic-gate p = sm_strdup_x(fv); 2659*7c478bd9Sstevel@tonic-gate MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 2660*7c478bd9Sstevel@tonic-gate xtextify(p, "=")); 2661*7c478bd9Sstevel@tonic-gate sm_free(p); /* XXX */ 2662*7c478bd9Sstevel@tonic-gate } 2663*7c478bd9Sstevel@tonic-gate } 2664*7c478bd9Sstevel@tonic-gate if (macvalue('s', &MainEnvelope) == NULL) 2665*7c478bd9Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 2666*7c478bd9Sstevel@tonic-gate 2667*7c478bd9Sstevel@tonic-gate av = argv + optind; 2668*7c478bd9Sstevel@tonic-gate if (*av == NULL && !GrabTo) 2669*7c478bd9Sstevel@tonic-gate { 2670*7c478bd9Sstevel@tonic-gate MainEnvelope.e_to = NULL; 2671*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS; 2672*7c478bd9Sstevel@tonic-gate HoldErrs = false; 2673*7c478bd9Sstevel@tonic-gate SuperSafe = SAFE_NO; 2674*7c478bd9Sstevel@tonic-gate usrerr("Recipient names must be specified"); 2675*7c478bd9Sstevel@tonic-gate 2676*7c478bd9Sstevel@tonic-gate /* collect body for UUCP return */ 2677*7c478bd9Sstevel@tonic-gate if (OpMode != MD_VERIFY) 2678*7c478bd9Sstevel@tonic-gate collect(InChannel, false, NULL, &MainEnvelope, true); 2679*7c478bd9Sstevel@tonic-gate finis(true, true, EX_USAGE); 2680*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2681*7c478bd9Sstevel@tonic-gate } 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate /* 2684*7c478bd9Sstevel@tonic-gate ** Scan argv and deliver the message to everyone. 2685*7c478bd9Sstevel@tonic-gate */ 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate save_val = LogUsrErrs; 2688*7c478bd9Sstevel@tonic-gate LogUsrErrs = true; 2689*7c478bd9Sstevel@tonic-gate sendtoargv(av, &MainEnvelope); 2690*7c478bd9Sstevel@tonic-gate LogUsrErrs = save_val; 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate /* if we have had errors sofar, arrange a meaningful exit stat */ 2693*7c478bd9Sstevel@tonic-gate if (Errors > 0 && ExitStat == EX_OK) 2694*7c478bd9Sstevel@tonic-gate ExitStat = EX_USAGE; 2695*7c478bd9Sstevel@tonic-gate 2696*7c478bd9Sstevel@tonic-gate #if _FFR_FIX_DASHT 2697*7c478bd9Sstevel@tonic-gate /* 2698*7c478bd9Sstevel@tonic-gate ** If using -t, force not sending to argv recipients, even 2699*7c478bd9Sstevel@tonic-gate ** if they are mentioned in the headers. 2700*7c478bd9Sstevel@tonic-gate */ 2701*7c478bd9Sstevel@tonic-gate 2702*7c478bd9Sstevel@tonic-gate if (GrabTo) 2703*7c478bd9Sstevel@tonic-gate { 2704*7c478bd9Sstevel@tonic-gate ADDRESS *q; 2705*7c478bd9Sstevel@tonic-gate 2706*7c478bd9Sstevel@tonic-gate for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 2707*7c478bd9Sstevel@tonic-gate q->q_state = QS_REMOVED; 2708*7c478bd9Sstevel@tonic-gate } 2709*7c478bd9Sstevel@tonic-gate #endif /* _FFR_FIX_DASHT */ 2710*7c478bd9Sstevel@tonic-gate 2711*7c478bd9Sstevel@tonic-gate /* 2712*7c478bd9Sstevel@tonic-gate ** Read the input mail. 2713*7c478bd9Sstevel@tonic-gate */ 2714*7c478bd9Sstevel@tonic-gate 2715*7c478bd9Sstevel@tonic-gate MainEnvelope.e_to = NULL; 2716*7c478bd9Sstevel@tonic-gate if (OpMode != MD_VERIFY || GrabTo) 2717*7c478bd9Sstevel@tonic-gate { 2718*7c478bd9Sstevel@tonic-gate int savederrors; 2719*7c478bd9Sstevel@tonic-gate unsigned long savedflags; 2720*7c478bd9Sstevel@tonic-gate 2721*7c478bd9Sstevel@tonic-gate /* 2722*7c478bd9Sstevel@tonic-gate ** workaround for compiler warning on Irix: 2723*7c478bd9Sstevel@tonic-gate ** do not initialize variable in the definition, but 2724*7c478bd9Sstevel@tonic-gate ** later on: 2725*7c478bd9Sstevel@tonic-gate ** warning(1548): transfer of control bypasses 2726*7c478bd9Sstevel@tonic-gate ** initialization of: 2727*7c478bd9Sstevel@tonic-gate ** variable "savederrors" (declared at line 2570) 2728*7c478bd9Sstevel@tonic-gate ** variable "savedflags" (declared at line 2571) 2729*7c478bd9Sstevel@tonic-gate ** goto giveup; 2730*7c478bd9Sstevel@tonic-gate */ 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate savederrors = Errors; 2733*7c478bd9Sstevel@tonic-gate savedflags = MainEnvelope.e_flags & EF_FATALERRS; 2734*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags |= EF_GLOBALERRS; 2735*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags &= ~EF_FATALERRS; 2736*7c478bd9Sstevel@tonic-gate Errors = 0; 2737*7c478bd9Sstevel@tonic-gate buffer_errors(); 2738*7c478bd9Sstevel@tonic-gate collect(InChannel, false, NULL, &MainEnvelope, true); 2739*7c478bd9Sstevel@tonic-gate 2740*7c478bd9Sstevel@tonic-gate /* header checks failed */ 2741*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2742*7c478bd9Sstevel@tonic-gate { 2743*7c478bd9Sstevel@tonic-gate giveup: 2744*7c478bd9Sstevel@tonic-gate if (!GrabTo) 2745*7c478bd9Sstevel@tonic-gate { 2746*7c478bd9Sstevel@tonic-gate /* Log who the mail would have gone to */ 2747*7c478bd9Sstevel@tonic-gate logundelrcpts(&MainEnvelope, 2748*7c478bd9Sstevel@tonic-gate MainEnvelope.e_message, 2749*7c478bd9Sstevel@tonic-gate 8, false); 2750*7c478bd9Sstevel@tonic-gate } 2751*7c478bd9Sstevel@tonic-gate flush_errors(true); 2752*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 2753*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2754*7c478bd9Sstevel@tonic-gate return -1; 2755*7c478bd9Sstevel@tonic-gate } 2756*7c478bd9Sstevel@tonic-gate 2757*7c478bd9Sstevel@tonic-gate /* bail out if message too large */ 2758*7c478bd9Sstevel@tonic-gate if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 2759*7c478bd9Sstevel@tonic-gate { 2760*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat != EX_OK ? ExitStat 2761*7c478bd9Sstevel@tonic-gate : EX_DATAERR); 2762*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2763*7c478bd9Sstevel@tonic-gate return -1; 2764*7c478bd9Sstevel@tonic-gate } 2765*7c478bd9Sstevel@tonic-gate 2766*7c478bd9Sstevel@tonic-gate /* set message size */ 2767*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%ld", 2768*7c478bd9Sstevel@tonic-gate MainEnvelope.e_msgsize); 2769*7c478bd9Sstevel@tonic-gate macdefine(&MainEnvelope.e_macro, A_TEMP, 2770*7c478bd9Sstevel@tonic-gate macid("{msg_size}"), buf); 2771*7c478bd9Sstevel@tonic-gate 2772*7c478bd9Sstevel@tonic-gate Errors = savederrors; 2773*7c478bd9Sstevel@tonic-gate MainEnvelope.e_flags |= savedflags; 2774*7c478bd9Sstevel@tonic-gate } 2775*7c478bd9Sstevel@tonic-gate errno = 0; 2776*7c478bd9Sstevel@tonic-gate 2777*7c478bd9Sstevel@tonic-gate if (tTd(1, 1)) 2778*7c478bd9Sstevel@tonic-gate sm_dprintf("From person = \"%s\"\n", 2779*7c478bd9Sstevel@tonic-gate MainEnvelope.e_from.q_paddr); 2780*7c478bd9Sstevel@tonic-gate 2781*7c478bd9Sstevel@tonic-gate /* Check if quarantining stats should be updated */ 2782*7c478bd9Sstevel@tonic-gate if (MainEnvelope.e_quarmsg != NULL) 2783*7c478bd9Sstevel@tonic-gate markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 2784*7c478bd9Sstevel@tonic-gate 2785*7c478bd9Sstevel@tonic-gate /* 2786*7c478bd9Sstevel@tonic-gate ** Actually send everything. 2787*7c478bd9Sstevel@tonic-gate ** If verifying, just ack. 2788*7c478bd9Sstevel@tonic-gate */ 2789*7c478bd9Sstevel@tonic-gate 2790*7c478bd9Sstevel@tonic-gate if (Errors == 0) 2791*7c478bd9Sstevel@tonic-gate { 2792*7c478bd9Sstevel@tonic-gate if (!split_by_recipient(&MainEnvelope) && 2793*7c478bd9Sstevel@tonic-gate bitset(EF_FATALERRS, MainEnvelope.e_flags)) 2794*7c478bd9Sstevel@tonic-gate goto giveup; 2795*7c478bd9Sstevel@tonic-gate } 2796*7c478bd9Sstevel@tonic-gate 2797*7c478bd9Sstevel@tonic-gate /* make sure we deliver at least the first envelope */ 2798*7c478bd9Sstevel@tonic-gate i = FastSplit > 0 ? 0 : -1; 2799*7c478bd9Sstevel@tonic-gate for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 2800*7c478bd9Sstevel@tonic-gate { 2801*7c478bd9Sstevel@tonic-gate ENVELOPE *next; 2802*7c478bd9Sstevel@tonic-gate 2803*7c478bd9Sstevel@tonic-gate e->e_from.q_state = QS_SENDER; 2804*7c478bd9Sstevel@tonic-gate if (tTd(1, 5)) 2805*7c478bd9Sstevel@tonic-gate { 2806*7c478bd9Sstevel@tonic-gate sm_dprintf("main[%d]: QS_SENDER ", i); 2807*7c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &e->e_from, false); 2808*7c478bd9Sstevel@tonic-gate } 2809*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 2810*7c478bd9Sstevel@tonic-gate sm_getla(); 2811*7c478bd9Sstevel@tonic-gate GrabTo = false; 2812*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 2813*7c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 2814*7c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 2815*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 2816*7c478bd9Sstevel@tonic-gate next = e->e_sibling; 2817*7c478bd9Sstevel@tonic-gate e->e_sibling = NULL; 2818*7c478bd9Sstevel@tonic-gate 2819*7c478bd9Sstevel@tonic-gate /* after FastSplit envelopes: queue up */ 2820*7c478bd9Sstevel@tonic-gate sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 2821*7c478bd9Sstevel@tonic-gate e->e_sibling = next; 2822*7c478bd9Sstevel@tonic-gate } 2823*7c478bd9Sstevel@tonic-gate 2824*7c478bd9Sstevel@tonic-gate /* 2825*7c478bd9Sstevel@tonic-gate ** All done. 2826*7c478bd9Sstevel@tonic-gate ** Don't send return error message if in VERIFY mode. 2827*7c478bd9Sstevel@tonic-gate */ 2828*7c478bd9Sstevel@tonic-gate 2829*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 2830*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2831*7c478bd9Sstevel@tonic-gate return ExitStat; 2832*7c478bd9Sstevel@tonic-gate } 2833*7c478bd9Sstevel@tonic-gate /* 2834*7c478bd9Sstevel@tonic-gate ** STOP_SENDMAIL -- Stop the running program 2835*7c478bd9Sstevel@tonic-gate ** 2836*7c478bd9Sstevel@tonic-gate ** Parameters: 2837*7c478bd9Sstevel@tonic-gate ** none. 2838*7c478bd9Sstevel@tonic-gate ** 2839*7c478bd9Sstevel@tonic-gate ** Returns: 2840*7c478bd9Sstevel@tonic-gate ** none. 2841*7c478bd9Sstevel@tonic-gate ** 2842*7c478bd9Sstevel@tonic-gate ** Side Effects: 2843*7c478bd9Sstevel@tonic-gate ** exits. 2844*7c478bd9Sstevel@tonic-gate */ 2845*7c478bd9Sstevel@tonic-gate 2846*7c478bd9Sstevel@tonic-gate void 2847*7c478bd9Sstevel@tonic-gate stop_sendmail() 2848*7c478bd9Sstevel@tonic-gate { 2849*7c478bd9Sstevel@tonic-gate /* reset uid for process accounting */ 2850*7c478bd9Sstevel@tonic-gate endpwent(); 2851*7c478bd9Sstevel@tonic-gate (void) setuid(RealUid); 2852*7c478bd9Sstevel@tonic-gate exit(EX_OK); 2853*7c478bd9Sstevel@tonic-gate } 2854*7c478bd9Sstevel@tonic-gate /* 2855*7c478bd9Sstevel@tonic-gate ** FINIS -- Clean up and exit. 2856*7c478bd9Sstevel@tonic-gate ** 2857*7c478bd9Sstevel@tonic-gate ** Parameters: 2858*7c478bd9Sstevel@tonic-gate ** drop -- whether or not to drop CurEnv envelope 2859*7c478bd9Sstevel@tonic-gate ** cleanup -- call exit() or _exit()? 2860*7c478bd9Sstevel@tonic-gate ** exitstat -- exit status to use for exit() call 2861*7c478bd9Sstevel@tonic-gate ** 2862*7c478bd9Sstevel@tonic-gate ** Returns: 2863*7c478bd9Sstevel@tonic-gate ** never 2864*7c478bd9Sstevel@tonic-gate ** 2865*7c478bd9Sstevel@tonic-gate ** Side Effects: 2866*7c478bd9Sstevel@tonic-gate ** exits sendmail 2867*7c478bd9Sstevel@tonic-gate */ 2868*7c478bd9Sstevel@tonic-gate 2869*7c478bd9Sstevel@tonic-gate void 2870*7c478bd9Sstevel@tonic-gate finis(drop, cleanup, exitstat) 2871*7c478bd9Sstevel@tonic-gate bool drop; 2872*7c478bd9Sstevel@tonic-gate bool cleanup; 2873*7c478bd9Sstevel@tonic-gate volatile int exitstat; 2874*7c478bd9Sstevel@tonic-gate { 2875*7c478bd9Sstevel@tonic-gate char pidpath[MAXPATHLEN]; 2876*7c478bd9Sstevel@tonic-gate 2877*7c478bd9Sstevel@tonic-gate /* Still want to process new timeouts added below */ 2878*7c478bd9Sstevel@tonic-gate sm_clear_events(); 2879*7c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM); 2880*7c478bd9Sstevel@tonic-gate 2881*7c478bd9Sstevel@tonic-gate if (tTd(2, 1)) 2882*7c478bd9Sstevel@tonic-gate { 2883*7c478bd9Sstevel@tonic-gate sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 2884*7c478bd9Sstevel@tonic-gate exitstat, 2885*7c478bd9Sstevel@tonic-gate CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 2886*7c478bd9Sstevel@tonic-gate printenvflags(CurEnv); 2887*7c478bd9Sstevel@tonic-gate } 2888*7c478bd9Sstevel@tonic-gate if (tTd(2, 9)) 2889*7c478bd9Sstevel@tonic-gate printopenfds(false); 2890*7c478bd9Sstevel@tonic-gate 2891*7c478bd9Sstevel@tonic-gate SM_TRY 2892*7c478bd9Sstevel@tonic-gate /* 2893*7c478bd9Sstevel@tonic-gate ** Clean up. This might raise E:mta.quickabort 2894*7c478bd9Sstevel@tonic-gate */ 2895*7c478bd9Sstevel@tonic-gate 2896*7c478bd9Sstevel@tonic-gate /* clean up temp files */ 2897*7c478bd9Sstevel@tonic-gate CurEnv->e_to = NULL; 2898*7c478bd9Sstevel@tonic-gate if (drop) 2899*7c478bd9Sstevel@tonic-gate { 2900*7c478bd9Sstevel@tonic-gate if (CurEnv->e_id != NULL) 2901*7c478bd9Sstevel@tonic-gate { 2902*7c478bd9Sstevel@tonic-gate dropenvelope(CurEnv, true, false); 2903*7c478bd9Sstevel@tonic-gate sm_rpool_free(CurEnv->e_rpool); 2904*7c478bd9Sstevel@tonic-gate CurEnv->e_rpool = NULL; 2905*7c478bd9Sstevel@tonic-gate } 2906*7c478bd9Sstevel@tonic-gate else 2907*7c478bd9Sstevel@tonic-gate poststats(StatFile); 2908*7c478bd9Sstevel@tonic-gate } 2909*7c478bd9Sstevel@tonic-gate 2910*7c478bd9Sstevel@tonic-gate /* flush any cached connections */ 2911*7c478bd9Sstevel@tonic-gate mci_flush(true, NULL); 2912*7c478bd9Sstevel@tonic-gate 2913*7c478bd9Sstevel@tonic-gate /* close maps belonging to this pid */ 2914*7c478bd9Sstevel@tonic-gate closemaps(false); 2915*7c478bd9Sstevel@tonic-gate 2916*7c478bd9Sstevel@tonic-gate #if USERDB 2917*7c478bd9Sstevel@tonic-gate /* close UserDatabase */ 2918*7c478bd9Sstevel@tonic-gate _udbx_close(); 2919*7c478bd9Sstevel@tonic-gate #endif /* USERDB */ 2920*7c478bd9Sstevel@tonic-gate 2921*7c478bd9Sstevel@tonic-gate #if SASL 2922*7c478bd9Sstevel@tonic-gate stop_sasl_client(); 2923*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2924*7c478bd9Sstevel@tonic-gate 2925*7c478bd9Sstevel@tonic-gate #if XLA 2926*7c478bd9Sstevel@tonic-gate /* clean up extended load average stuff */ 2927*7c478bd9Sstevel@tonic-gate xla_all_end(); 2928*7c478bd9Sstevel@tonic-gate #endif /* XLA */ 2929*7c478bd9Sstevel@tonic-gate 2930*7c478bd9Sstevel@tonic-gate SM_FINALLY 2931*7c478bd9Sstevel@tonic-gate /* 2932*7c478bd9Sstevel@tonic-gate ** And exit. 2933*7c478bd9Sstevel@tonic-gate */ 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate if (LogLevel > 78) 2936*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 2937*7c478bd9Sstevel@tonic-gate (int) CurrentPid); 2938*7c478bd9Sstevel@tonic-gate if (exitstat == EX_TEMPFAIL || 2939*7c478bd9Sstevel@tonic-gate CurEnv->e_errormode == EM_BERKNET) 2940*7c478bd9Sstevel@tonic-gate exitstat = EX_OK; 2941*7c478bd9Sstevel@tonic-gate 2942*7c478bd9Sstevel@tonic-gate /* XXX clean up queues and related data structures */ 2943*7c478bd9Sstevel@tonic-gate cleanup_queues(); 2944*7c478bd9Sstevel@tonic-gate #if SM_CONF_SHM 2945*7c478bd9Sstevel@tonic-gate cleanup_shm(DaemonPid == getpid()); 2946*7c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SHM */ 2947*7c478bd9Sstevel@tonic-gate 2948*7c478bd9Sstevel@tonic-gate /* close locked pid file */ 2949*7c478bd9Sstevel@tonic-gate close_sendmail_pid(); 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate if (DaemonPid == getpid() || PidFilePid == getpid()) 2952*7c478bd9Sstevel@tonic-gate { 2953*7c478bd9Sstevel@tonic-gate /* blow away the pid file */ 2954*7c478bd9Sstevel@tonic-gate expand(PidFile, pidpath, sizeof pidpath, CurEnv); 2955*7c478bd9Sstevel@tonic-gate (void) unlink(pidpath); 2956*7c478bd9Sstevel@tonic-gate } 2957*7c478bd9Sstevel@tonic-gate 2958*7c478bd9Sstevel@tonic-gate /* reset uid for process accounting */ 2959*7c478bd9Sstevel@tonic-gate endpwent(); 2960*7c478bd9Sstevel@tonic-gate sm_mbdb_terminate(); 2961*7c478bd9Sstevel@tonic-gate (void) setuid(RealUid); 2962*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 2963*7c478bd9Sstevel@tonic-gate /* dump the heap, if we are checking for memory leaks */ 2964*7c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmHeapCheck, 2)) 2965*7c478bd9Sstevel@tonic-gate sm_heap_report(smioout, 2966*7c478bd9Sstevel@tonic-gate sm_debug_level(&SmHeapCheck) - 1); 2967*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 2968*7c478bd9Sstevel@tonic-gate if (sm_debug_active(&SmXtrapReport, 1)) 2969*7c478bd9Sstevel@tonic-gate sm_dprintf("xtrap count = %d\n", SmXtrapCount); 2970*7c478bd9Sstevel@tonic-gate if (cleanup) 2971*7c478bd9Sstevel@tonic-gate exit(exitstat); 2972*7c478bd9Sstevel@tonic-gate else 2973*7c478bd9Sstevel@tonic-gate _exit(exitstat); 2974*7c478bd9Sstevel@tonic-gate SM_END_TRY 2975*7c478bd9Sstevel@tonic-gate } 2976*7c478bd9Sstevel@tonic-gate /* 2977*7c478bd9Sstevel@tonic-gate ** INTINDEBUG -- signal handler for SIGINT in -bt mode 2978*7c478bd9Sstevel@tonic-gate ** 2979*7c478bd9Sstevel@tonic-gate ** Parameters: 2980*7c478bd9Sstevel@tonic-gate ** sig -- incoming signal. 2981*7c478bd9Sstevel@tonic-gate ** 2982*7c478bd9Sstevel@tonic-gate ** Returns: 2983*7c478bd9Sstevel@tonic-gate ** none. 2984*7c478bd9Sstevel@tonic-gate ** 2985*7c478bd9Sstevel@tonic-gate ** Side Effects: 2986*7c478bd9Sstevel@tonic-gate ** longjmps back to test mode loop. 2987*7c478bd9Sstevel@tonic-gate ** 2988*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2989*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2990*7c478bd9Sstevel@tonic-gate ** DOING. 2991*7c478bd9Sstevel@tonic-gate */ 2992*7c478bd9Sstevel@tonic-gate 2993*7c478bd9Sstevel@tonic-gate /* Type of an exception generated on SIGINT during address test mode. */ 2994*7c478bd9Sstevel@tonic-gate static const SM_EXC_TYPE_T EtypeInterrupt = 2995*7c478bd9Sstevel@tonic-gate { 2996*7c478bd9Sstevel@tonic-gate SmExcTypeMagic, 2997*7c478bd9Sstevel@tonic-gate "S:mta.interrupt", 2998*7c478bd9Sstevel@tonic-gate "", 2999*7c478bd9Sstevel@tonic-gate sm_etype_printf, 3000*7c478bd9Sstevel@tonic-gate "interrupt", 3001*7c478bd9Sstevel@tonic-gate }; 3002*7c478bd9Sstevel@tonic-gate 3003*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3004*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 3005*7c478bd9Sstevel@tonic-gate intindebug(sig) 3006*7c478bd9Sstevel@tonic-gate int sig; 3007*7c478bd9Sstevel@tonic-gate { 3008*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3009*7c478bd9Sstevel@tonic-gate 3010*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, intindebug); 3011*7c478bd9Sstevel@tonic-gate errno = save_errno; 3012*7c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 3013*7c478bd9Sstevel@tonic-gate errno = save_errno; 3014*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeInterrupt); 3015*7c478bd9Sstevel@tonic-gate errno = save_errno; 3016*7c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 3017*7c478bd9Sstevel@tonic-gate } 3018*7c478bd9Sstevel@tonic-gate /* 3019*7c478bd9Sstevel@tonic-gate ** SIGTERM -- SIGTERM handler for the daemon 3020*7c478bd9Sstevel@tonic-gate ** 3021*7c478bd9Sstevel@tonic-gate ** Parameters: 3022*7c478bd9Sstevel@tonic-gate ** sig -- signal number. 3023*7c478bd9Sstevel@tonic-gate ** 3024*7c478bd9Sstevel@tonic-gate ** Returns: 3025*7c478bd9Sstevel@tonic-gate ** none. 3026*7c478bd9Sstevel@tonic-gate ** 3027*7c478bd9Sstevel@tonic-gate ** Side Effects: 3028*7c478bd9Sstevel@tonic-gate ** Sets ShutdownRequest which will hopefully trigger 3029*7c478bd9Sstevel@tonic-gate ** the daemon to exit. 3030*7c478bd9Sstevel@tonic-gate ** 3031*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3032*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3033*7c478bd9Sstevel@tonic-gate ** DOING. 3034*7c478bd9Sstevel@tonic-gate */ 3035*7c478bd9Sstevel@tonic-gate 3036*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3037*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 3038*7c478bd9Sstevel@tonic-gate sigterm(sig) 3039*7c478bd9Sstevel@tonic-gate int sig; 3040*7c478bd9Sstevel@tonic-gate { 3041*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3042*7c478bd9Sstevel@tonic-gate 3043*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigterm); 3044*7c478bd9Sstevel@tonic-gate ShutdownRequest = "signal"; 3045*7c478bd9Sstevel@tonic-gate errno = save_errno; 3046*7c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 3047*7c478bd9Sstevel@tonic-gate } 3048*7c478bd9Sstevel@tonic-gate /* 3049*7c478bd9Sstevel@tonic-gate ** SIGHUP -- handle a SIGHUP signal 3050*7c478bd9Sstevel@tonic-gate ** 3051*7c478bd9Sstevel@tonic-gate ** Parameters: 3052*7c478bd9Sstevel@tonic-gate ** sig -- incoming signal. 3053*7c478bd9Sstevel@tonic-gate ** 3054*7c478bd9Sstevel@tonic-gate ** Returns: 3055*7c478bd9Sstevel@tonic-gate ** none. 3056*7c478bd9Sstevel@tonic-gate ** 3057*7c478bd9Sstevel@tonic-gate ** Side Effects: 3058*7c478bd9Sstevel@tonic-gate ** Sets RestartRequest which should cause the daemon 3059*7c478bd9Sstevel@tonic-gate ** to restart. 3060*7c478bd9Sstevel@tonic-gate ** 3061*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3062*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3063*7c478bd9Sstevel@tonic-gate ** DOING. 3064*7c478bd9Sstevel@tonic-gate */ 3065*7c478bd9Sstevel@tonic-gate 3066*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3067*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 3068*7c478bd9Sstevel@tonic-gate sighup(sig) 3069*7c478bd9Sstevel@tonic-gate int sig; 3070*7c478bd9Sstevel@tonic-gate { 3071*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3072*7c478bd9Sstevel@tonic-gate 3073*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sighup); 3074*7c478bd9Sstevel@tonic-gate RestartRequest = "signal"; 3075*7c478bd9Sstevel@tonic-gate errno = save_errno; 3076*7c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 3077*7c478bd9Sstevel@tonic-gate } 3078*7c478bd9Sstevel@tonic-gate /* 3079*7c478bd9Sstevel@tonic-gate ** SIGPIPE -- signal handler for SIGPIPE 3080*7c478bd9Sstevel@tonic-gate ** 3081*7c478bd9Sstevel@tonic-gate ** Parameters: 3082*7c478bd9Sstevel@tonic-gate ** sig -- incoming signal. 3083*7c478bd9Sstevel@tonic-gate ** 3084*7c478bd9Sstevel@tonic-gate ** Returns: 3085*7c478bd9Sstevel@tonic-gate ** none. 3086*7c478bd9Sstevel@tonic-gate ** 3087*7c478bd9Sstevel@tonic-gate ** Side Effects: 3088*7c478bd9Sstevel@tonic-gate ** Sets StopRequest which should cause the mailq/hoststatus 3089*7c478bd9Sstevel@tonic-gate ** display to stop. 3090*7c478bd9Sstevel@tonic-gate ** 3091*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3092*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3093*7c478bd9Sstevel@tonic-gate ** DOING. 3094*7c478bd9Sstevel@tonic-gate */ 3095*7c478bd9Sstevel@tonic-gate 3096*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3097*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 3098*7c478bd9Sstevel@tonic-gate sigpipe(sig) 3099*7c478bd9Sstevel@tonic-gate int sig; 3100*7c478bd9Sstevel@tonic-gate { 3101*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3102*7c478bd9Sstevel@tonic-gate 3103*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigpipe); 3104*7c478bd9Sstevel@tonic-gate StopRequest = true; 3105*7c478bd9Sstevel@tonic-gate errno = save_errno; 3106*7c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 3107*7c478bd9Sstevel@tonic-gate } 3108*7c478bd9Sstevel@tonic-gate /* 3109*7c478bd9Sstevel@tonic-gate ** INTSIG -- clean up on interrupt 3110*7c478bd9Sstevel@tonic-gate ** 3111*7c478bd9Sstevel@tonic-gate ** This just arranges to exit. It pessimizes in that it 3112*7c478bd9Sstevel@tonic-gate ** may resend a message. 3113*7c478bd9Sstevel@tonic-gate ** 3114*7c478bd9Sstevel@tonic-gate ** Parameters: 3115*7c478bd9Sstevel@tonic-gate ** none. 3116*7c478bd9Sstevel@tonic-gate ** 3117*7c478bd9Sstevel@tonic-gate ** Returns: 3118*7c478bd9Sstevel@tonic-gate ** none. 3119*7c478bd9Sstevel@tonic-gate ** 3120*7c478bd9Sstevel@tonic-gate ** Side Effects: 3121*7c478bd9Sstevel@tonic-gate ** Unlocks the current job. 3122*7c478bd9Sstevel@tonic-gate ** 3123*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3124*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3125*7c478bd9Sstevel@tonic-gate ** DOING. 3126*7c478bd9Sstevel@tonic-gate ** 3127*7c478bd9Sstevel@tonic-gate ** XXX: More work is needed for this signal handler. 3128*7c478bd9Sstevel@tonic-gate */ 3129*7c478bd9Sstevel@tonic-gate 3130*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3131*7c478bd9Sstevel@tonic-gate SIGFUNC_DECL 3132*7c478bd9Sstevel@tonic-gate intsig(sig) 3133*7c478bd9Sstevel@tonic-gate int sig; 3134*7c478bd9Sstevel@tonic-gate { 3135*7c478bd9Sstevel@tonic-gate bool drop = false; 3136*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3137*7c478bd9Sstevel@tonic-gate 3138*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, intsig); 3139*7c478bd9Sstevel@tonic-gate errno = save_errno; 3140*7c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 3141*7c478bd9Sstevel@tonic-gate sm_allsignals(true); 3142*7c478bd9Sstevel@tonic-gate 3143*7c478bd9Sstevel@tonic-gate if (sig != 0 && LogLevel > 79) 3144*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 3145*7c478bd9Sstevel@tonic-gate FileName = NULL; 3146*7c478bd9Sstevel@tonic-gate 3147*7c478bd9Sstevel@tonic-gate /* Clean-up on aborted stdin message submission */ 3148*7c478bd9Sstevel@tonic-gate if (CurEnv->e_id != NULL && 3149*7c478bd9Sstevel@tonic-gate (OpMode == MD_SMTP || 3150*7c478bd9Sstevel@tonic-gate OpMode == MD_DELIVER || 3151*7c478bd9Sstevel@tonic-gate OpMode == MD_ARPAFTP)) 3152*7c478bd9Sstevel@tonic-gate { 3153*7c478bd9Sstevel@tonic-gate register ADDRESS *q; 3154*7c478bd9Sstevel@tonic-gate 3155*7c478bd9Sstevel@tonic-gate /* don't return an error indication */ 3156*7c478bd9Sstevel@tonic-gate CurEnv->e_to = NULL; 3157*7c478bd9Sstevel@tonic-gate CurEnv->e_flags &= ~EF_FATALERRS; 3158*7c478bd9Sstevel@tonic-gate CurEnv->e_flags |= EF_CLRQUEUE; 3159*7c478bd9Sstevel@tonic-gate 3160*7c478bd9Sstevel@tonic-gate /* 3161*7c478bd9Sstevel@tonic-gate ** Spin through the addresses and 3162*7c478bd9Sstevel@tonic-gate ** mark them dead to prevent bounces 3163*7c478bd9Sstevel@tonic-gate */ 3164*7c478bd9Sstevel@tonic-gate 3165*7c478bd9Sstevel@tonic-gate for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 3166*7c478bd9Sstevel@tonic-gate q->q_state = QS_DONTSEND; 3167*7c478bd9Sstevel@tonic-gate 3168*7c478bd9Sstevel@tonic-gate drop = true; 3169*7c478bd9Sstevel@tonic-gate } 3170*7c478bd9Sstevel@tonic-gate else if (OpMode != MD_TEST) 3171*7c478bd9Sstevel@tonic-gate { 3172*7c478bd9Sstevel@tonic-gate unlockqueue(CurEnv); 3173*7c478bd9Sstevel@tonic-gate } 3174*7c478bd9Sstevel@tonic-gate 3175*7c478bd9Sstevel@tonic-gate finis(drop, false, EX_OK); 3176*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3177*7c478bd9Sstevel@tonic-gate } 3178*7c478bd9Sstevel@tonic-gate /* 3179*7c478bd9Sstevel@tonic-gate ** DISCONNECT -- remove our connection with any foreground process 3180*7c478bd9Sstevel@tonic-gate ** 3181*7c478bd9Sstevel@tonic-gate ** Parameters: 3182*7c478bd9Sstevel@tonic-gate ** droplev -- how "deeply" we should drop the line. 3183*7c478bd9Sstevel@tonic-gate ** 0 -- ignore signals, mail back errors, make sure 3184*7c478bd9Sstevel@tonic-gate ** output goes to stdout. 3185*7c478bd9Sstevel@tonic-gate ** 1 -- also, make stdout go to /dev/null. 3186*7c478bd9Sstevel@tonic-gate ** 2 -- also, disconnect from controlling terminal 3187*7c478bd9Sstevel@tonic-gate ** (only for daemon mode). 3188*7c478bd9Sstevel@tonic-gate ** e -- the current envelope. 3189*7c478bd9Sstevel@tonic-gate ** 3190*7c478bd9Sstevel@tonic-gate ** Returns: 3191*7c478bd9Sstevel@tonic-gate ** none 3192*7c478bd9Sstevel@tonic-gate ** 3193*7c478bd9Sstevel@tonic-gate ** Side Effects: 3194*7c478bd9Sstevel@tonic-gate ** Trys to insure that we are immune to vagaries of 3195*7c478bd9Sstevel@tonic-gate ** the controlling tty. 3196*7c478bd9Sstevel@tonic-gate */ 3197*7c478bd9Sstevel@tonic-gate 3198*7c478bd9Sstevel@tonic-gate void 3199*7c478bd9Sstevel@tonic-gate disconnect(droplev, e) 3200*7c478bd9Sstevel@tonic-gate int droplev; 3201*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 3202*7c478bd9Sstevel@tonic-gate { 3203*7c478bd9Sstevel@tonic-gate int fd; 3204*7c478bd9Sstevel@tonic-gate 3205*7c478bd9Sstevel@tonic-gate if (tTd(52, 1)) 3206*7c478bd9Sstevel@tonic-gate sm_dprintf("disconnect: In %d Out %d, e=%p\n", 3207*7c478bd9Sstevel@tonic-gate sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 3208*7c478bd9Sstevel@tonic-gate sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e); 3209*7c478bd9Sstevel@tonic-gate if (tTd(52, 100)) 3210*7c478bd9Sstevel@tonic-gate { 3211*7c478bd9Sstevel@tonic-gate sm_dprintf("don't\n"); 3212*7c478bd9Sstevel@tonic-gate return; 3213*7c478bd9Sstevel@tonic-gate } 3214*7c478bd9Sstevel@tonic-gate if (LogLevel > 93) 3215*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, 3216*7c478bd9Sstevel@tonic-gate "disconnect level %d", 3217*7c478bd9Sstevel@tonic-gate droplev); 3218*7c478bd9Sstevel@tonic-gate 3219*7c478bd9Sstevel@tonic-gate /* be sure we don't get nasty signals */ 3220*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, SIG_IGN); 3221*7c478bd9Sstevel@tonic-gate (void) sm_signal(SIGQUIT, SIG_IGN); 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate /* we can't communicate with our caller, so.... */ 3224*7c478bd9Sstevel@tonic-gate HoldErrs = true; 3225*7c478bd9Sstevel@tonic-gate CurEnv->e_errormode = EM_MAIL; 3226*7c478bd9Sstevel@tonic-gate Verbose = 0; 3227*7c478bd9Sstevel@tonic-gate DisConnected = true; 3228*7c478bd9Sstevel@tonic-gate 3229*7c478bd9Sstevel@tonic-gate /* all input from /dev/null */ 3230*7c478bd9Sstevel@tonic-gate if (InChannel != smioin) 3231*7c478bd9Sstevel@tonic-gate { 3232*7c478bd9Sstevel@tonic-gate (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 3233*7c478bd9Sstevel@tonic-gate InChannel = smioin; 3234*7c478bd9Sstevel@tonic-gate } 3235*7c478bd9Sstevel@tonic-gate if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 3236*7c478bd9Sstevel@tonic-gate SM_IO_RDONLY, NULL, smioin) == NULL) 3237*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3238*7c478bd9Sstevel@tonic-gate "disconnect: sm_io_reopen(\"%s\") failed: %s", 3239*7c478bd9Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 3240*7c478bd9Sstevel@tonic-gate 3241*7c478bd9Sstevel@tonic-gate /* 3242*7c478bd9Sstevel@tonic-gate ** output to the transcript 3243*7c478bd9Sstevel@tonic-gate ** We also compare the fd numbers here since OutChannel 3244*7c478bd9Sstevel@tonic-gate ** might be a layer on top of smioout due to encryption 3245*7c478bd9Sstevel@tonic-gate ** (see sfsasl.c). 3246*7c478bd9Sstevel@tonic-gate */ 3247*7c478bd9Sstevel@tonic-gate 3248*7c478bd9Sstevel@tonic-gate if (OutChannel != smioout && 3249*7c478bd9Sstevel@tonic-gate sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 3250*7c478bd9Sstevel@tonic-gate sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 3251*7c478bd9Sstevel@tonic-gate { 3252*7c478bd9Sstevel@tonic-gate (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 3253*7c478bd9Sstevel@tonic-gate OutChannel = smioout; 3254*7c478bd9Sstevel@tonic-gate 3255*7c478bd9Sstevel@tonic-gate #if 0 3256*7c478bd9Sstevel@tonic-gate /* 3257*7c478bd9Sstevel@tonic-gate ** Has smioout been closed? Reopen it. 3258*7c478bd9Sstevel@tonic-gate ** This shouldn't happen anymore, the code is here 3259*7c478bd9Sstevel@tonic-gate ** just as a reminder. 3260*7c478bd9Sstevel@tonic-gate */ 3261*7c478bd9Sstevel@tonic-gate 3262*7c478bd9Sstevel@tonic-gate if (smioout->sm_magic == NULL && 3263*7c478bd9Sstevel@tonic-gate sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 3264*7c478bd9Sstevel@tonic-gate SM_IO_WRONLY, NULL, smioout) == NULL) 3265*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3266*7c478bd9Sstevel@tonic-gate "disconnect: sm_io_reopen(\"%s\") failed: %s", 3267*7c478bd9Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 3268*7c478bd9Sstevel@tonic-gate #endif /* 0 */ 3269*7c478bd9Sstevel@tonic-gate } 3270*7c478bd9Sstevel@tonic-gate if (droplev > 0) 3271*7c478bd9Sstevel@tonic-gate { 3272*7c478bd9Sstevel@tonic-gate fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 3273*7c478bd9Sstevel@tonic-gate if (fd == -1) 3274*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3275*7c478bd9Sstevel@tonic-gate "disconnect: open(\"%s\") failed: %s", 3276*7c478bd9Sstevel@tonic-gate SM_PATH_DEVNULL, sm_errstring(errno)); 3277*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 3278*7c478bd9Sstevel@tonic-gate (void) dup2(fd, STDOUT_FILENO); 3279*7c478bd9Sstevel@tonic-gate (void) dup2(fd, STDERR_FILENO); 3280*7c478bd9Sstevel@tonic-gate (void) close(fd); 3281*7c478bd9Sstevel@tonic-gate } 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate /* drop our controlling TTY completely if possible */ 3284*7c478bd9Sstevel@tonic-gate if (droplev > 1) 3285*7c478bd9Sstevel@tonic-gate { 3286*7c478bd9Sstevel@tonic-gate (void) setsid(); 3287*7c478bd9Sstevel@tonic-gate errno = 0; 3288*7c478bd9Sstevel@tonic-gate } 3289*7c478bd9Sstevel@tonic-gate 3290*7c478bd9Sstevel@tonic-gate #if XDEBUG 3291*7c478bd9Sstevel@tonic-gate checkfd012("disconnect"); 3292*7c478bd9Sstevel@tonic-gate #endif /* XDEBUG */ 3293*7c478bd9Sstevel@tonic-gate 3294*7c478bd9Sstevel@tonic-gate if (LogLevel > 71) 3295*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 3296*7c478bd9Sstevel@tonic-gate (int) CurrentPid); 3297*7c478bd9Sstevel@tonic-gate 3298*7c478bd9Sstevel@tonic-gate errno = 0; 3299*7c478bd9Sstevel@tonic-gate } 3300*7c478bd9Sstevel@tonic-gate 3301*7c478bd9Sstevel@tonic-gate static void 3302*7c478bd9Sstevel@tonic-gate obsolete(argv) 3303*7c478bd9Sstevel@tonic-gate char *argv[]; 3304*7c478bd9Sstevel@tonic-gate { 3305*7c478bd9Sstevel@tonic-gate register char *ap; 3306*7c478bd9Sstevel@tonic-gate register char *op; 3307*7c478bd9Sstevel@tonic-gate 3308*7c478bd9Sstevel@tonic-gate while ((ap = *++argv) != NULL) 3309*7c478bd9Sstevel@tonic-gate { 3310*7c478bd9Sstevel@tonic-gate /* Return if "--" or not an option of any form. */ 3311*7c478bd9Sstevel@tonic-gate if (ap[0] != '-' || ap[1] == '-') 3312*7c478bd9Sstevel@tonic-gate return; 3313*7c478bd9Sstevel@tonic-gate 3314*7c478bd9Sstevel@tonic-gate /* Don't allow users to use "-Q." or "-Q ." */ 3315*7c478bd9Sstevel@tonic-gate if ((ap[1] == 'Q' && ap[2] == '.') || 3316*7c478bd9Sstevel@tonic-gate (ap[1] == 'Q' && argv[1] != NULL && 3317*7c478bd9Sstevel@tonic-gate argv[1][0] == '.' && argv[1][1] == '\0')) 3318*7c478bd9Sstevel@tonic-gate { 3319*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3320*7c478bd9Sstevel@tonic-gate "Can not use -Q.\n"); 3321*7c478bd9Sstevel@tonic-gate exit(EX_USAGE); 3322*7c478bd9Sstevel@tonic-gate } 3323*7c478bd9Sstevel@tonic-gate 3324*7c478bd9Sstevel@tonic-gate /* skip over options that do have a value */ 3325*7c478bd9Sstevel@tonic-gate op = strchr(OPTIONS, ap[1]); 3326*7c478bd9Sstevel@tonic-gate if (op != NULL && *++op == ':' && ap[2] == '\0' && 3327*7c478bd9Sstevel@tonic-gate ap[1] != 'd' && 3328*7c478bd9Sstevel@tonic-gate #if defined(sony_news) 3329*7c478bd9Sstevel@tonic-gate ap[1] != 'E' && ap[1] != 'J' && 3330*7c478bd9Sstevel@tonic-gate #endif /* defined(sony_news) */ 3331*7c478bd9Sstevel@tonic-gate argv[1] != NULL && argv[1][0] != '-') 3332*7c478bd9Sstevel@tonic-gate { 3333*7c478bd9Sstevel@tonic-gate argv++; 3334*7c478bd9Sstevel@tonic-gate continue; 3335*7c478bd9Sstevel@tonic-gate } 3336*7c478bd9Sstevel@tonic-gate 3337*7c478bd9Sstevel@tonic-gate /* If -C doesn't have an argument, use sendmail.cf. */ 3338*7c478bd9Sstevel@tonic-gate #define __DEFPATH "sendmail.cf" 3339*7c478bd9Sstevel@tonic-gate if (ap[1] == 'C' && ap[2] == '\0') 3340*7c478bd9Sstevel@tonic-gate { 3341*7c478bd9Sstevel@tonic-gate *argv = xalloc(sizeof(__DEFPATH) + 2); 3342*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 3343*7c478bd9Sstevel@tonic-gate "-C", __DEFPATH); 3344*7c478bd9Sstevel@tonic-gate } 3345*7c478bd9Sstevel@tonic-gate 3346*7c478bd9Sstevel@tonic-gate /* If -q doesn't have an argument, run it once. */ 3347*7c478bd9Sstevel@tonic-gate if (ap[1] == 'q' && ap[2] == '\0') 3348*7c478bd9Sstevel@tonic-gate *argv = "-q0"; 3349*7c478bd9Sstevel@tonic-gate 3350*7c478bd9Sstevel@tonic-gate /* If -Q doesn't have an argument, disable quarantining */ 3351*7c478bd9Sstevel@tonic-gate if (ap[1] == 'Q' && ap[2] == '\0') 3352*7c478bd9Sstevel@tonic-gate *argv = "-Q."; 3353*7c478bd9Sstevel@tonic-gate 3354*7c478bd9Sstevel@tonic-gate /* if -d doesn't have an argument, use 0-99.1 */ 3355*7c478bd9Sstevel@tonic-gate if (ap[1] == 'd' && ap[2] == '\0') 3356*7c478bd9Sstevel@tonic-gate *argv = "-d0-99.1"; 3357*7c478bd9Sstevel@tonic-gate 3358*7c478bd9Sstevel@tonic-gate #if defined(sony_news) 3359*7c478bd9Sstevel@tonic-gate /* if -E doesn't have an argument, use -EC */ 3360*7c478bd9Sstevel@tonic-gate if (ap[1] == 'E' && ap[2] == '\0') 3361*7c478bd9Sstevel@tonic-gate *argv = "-EC"; 3362*7c478bd9Sstevel@tonic-gate 3363*7c478bd9Sstevel@tonic-gate /* if -J doesn't have an argument, use -JJ */ 3364*7c478bd9Sstevel@tonic-gate if (ap[1] == 'J' && ap[2] == '\0') 3365*7c478bd9Sstevel@tonic-gate *argv = "-JJ"; 3366*7c478bd9Sstevel@tonic-gate #endif /* defined(sony_news) */ 3367*7c478bd9Sstevel@tonic-gate } 3368*7c478bd9Sstevel@tonic-gate } 3369*7c478bd9Sstevel@tonic-gate /* 3370*7c478bd9Sstevel@tonic-gate ** AUTH_WARNING -- specify authorization warning 3371*7c478bd9Sstevel@tonic-gate ** 3372*7c478bd9Sstevel@tonic-gate ** Parameters: 3373*7c478bd9Sstevel@tonic-gate ** e -- the current envelope. 3374*7c478bd9Sstevel@tonic-gate ** msg -- the text of the message. 3375*7c478bd9Sstevel@tonic-gate ** args -- arguments to the message. 3376*7c478bd9Sstevel@tonic-gate ** 3377*7c478bd9Sstevel@tonic-gate ** Returns: 3378*7c478bd9Sstevel@tonic-gate ** none. 3379*7c478bd9Sstevel@tonic-gate */ 3380*7c478bd9Sstevel@tonic-gate 3381*7c478bd9Sstevel@tonic-gate void 3382*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 3383*7c478bd9Sstevel@tonic-gate auth_warning(register ENVELOPE *e, const char *msg, ...) 3384*7c478bd9Sstevel@tonic-gate #else /* __STDC__ */ 3385*7c478bd9Sstevel@tonic-gate auth_warning(e, msg, va_alist) 3386*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 3387*7c478bd9Sstevel@tonic-gate const char *msg; 3388*7c478bd9Sstevel@tonic-gate va_dcl 3389*7c478bd9Sstevel@tonic-gate #endif /* __STDC__ */ 3390*7c478bd9Sstevel@tonic-gate { 3391*7c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 3392*7c478bd9Sstevel@tonic-gate SM_VA_LOCAL_DECL 3393*7c478bd9Sstevel@tonic-gate 3394*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 3395*7c478bd9Sstevel@tonic-gate { 3396*7c478bd9Sstevel@tonic-gate register char *p; 3397*7c478bd9Sstevel@tonic-gate static char hostbuf[48]; 3398*7c478bd9Sstevel@tonic-gate 3399*7c478bd9Sstevel@tonic-gate if (hostbuf[0] == '\0') 3400*7c478bd9Sstevel@tonic-gate { 3401*7c478bd9Sstevel@tonic-gate struct hostent *hp; 3402*7c478bd9Sstevel@tonic-gate 3403*7c478bd9Sstevel@tonic-gate hp = myhostname(hostbuf, sizeof hostbuf); 3404*7c478bd9Sstevel@tonic-gate #if NETINET6 3405*7c478bd9Sstevel@tonic-gate if (hp != NULL) 3406*7c478bd9Sstevel@tonic-gate { 3407*7c478bd9Sstevel@tonic-gate freehostent(hp); 3408*7c478bd9Sstevel@tonic-gate hp = NULL; 3409*7c478bd9Sstevel@tonic-gate } 3410*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 3411*7c478bd9Sstevel@tonic-gate } 3412*7c478bd9Sstevel@tonic-gate 3413*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": "); 3414*7c478bd9Sstevel@tonic-gate p = &buf[strlen(buf)]; 3415*7c478bd9Sstevel@tonic-gate SM_VA_START(ap, msg); 3416*7c478bd9Sstevel@tonic-gate (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 3417*7c478bd9Sstevel@tonic-gate SM_VA_END(ap); 3418*7c478bd9Sstevel@tonic-gate addheader("X-Authentication-Warning", buf, 0, e); 3419*7c478bd9Sstevel@tonic-gate if (LogLevel > 3) 3420*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3421*7c478bd9Sstevel@tonic-gate "Authentication-Warning: %.400s", 3422*7c478bd9Sstevel@tonic-gate buf); 3423*7c478bd9Sstevel@tonic-gate } 3424*7c478bd9Sstevel@tonic-gate } 3425*7c478bd9Sstevel@tonic-gate /* 3426*7c478bd9Sstevel@tonic-gate ** GETEXTENV -- get from external environment 3427*7c478bd9Sstevel@tonic-gate ** 3428*7c478bd9Sstevel@tonic-gate ** Parameters: 3429*7c478bd9Sstevel@tonic-gate ** envar -- the name of the variable to retrieve 3430*7c478bd9Sstevel@tonic-gate ** 3431*7c478bd9Sstevel@tonic-gate ** Returns: 3432*7c478bd9Sstevel@tonic-gate ** The value, if any. 3433*7c478bd9Sstevel@tonic-gate */ 3434*7c478bd9Sstevel@tonic-gate 3435*7c478bd9Sstevel@tonic-gate static char * 3436*7c478bd9Sstevel@tonic-gate getextenv(envar) 3437*7c478bd9Sstevel@tonic-gate const char *envar; 3438*7c478bd9Sstevel@tonic-gate { 3439*7c478bd9Sstevel@tonic-gate char **envp; 3440*7c478bd9Sstevel@tonic-gate int l; 3441*7c478bd9Sstevel@tonic-gate 3442*7c478bd9Sstevel@tonic-gate l = strlen(envar); 3443*7c478bd9Sstevel@tonic-gate for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++) 3444*7c478bd9Sstevel@tonic-gate { 3445*7c478bd9Sstevel@tonic-gate if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 3446*7c478bd9Sstevel@tonic-gate return &(*envp)[l + 1]; 3447*7c478bd9Sstevel@tonic-gate } 3448*7c478bd9Sstevel@tonic-gate return NULL; 3449*7c478bd9Sstevel@tonic-gate } 3450*7c478bd9Sstevel@tonic-gate /* 3451*7c478bd9Sstevel@tonic-gate ** SETUSERENV -- set an environment in the propagated environment 3452*7c478bd9Sstevel@tonic-gate ** 3453*7c478bd9Sstevel@tonic-gate ** Parameters: 3454*7c478bd9Sstevel@tonic-gate ** envar -- the name of the environment variable. 3455*7c478bd9Sstevel@tonic-gate ** value -- the value to which it should be set. If 3456*7c478bd9Sstevel@tonic-gate ** null, this is extracted from the incoming 3457*7c478bd9Sstevel@tonic-gate ** environment. If that is not set, the call 3458*7c478bd9Sstevel@tonic-gate ** to setuserenv is ignored. 3459*7c478bd9Sstevel@tonic-gate ** 3460*7c478bd9Sstevel@tonic-gate ** Returns: 3461*7c478bd9Sstevel@tonic-gate ** none. 3462*7c478bd9Sstevel@tonic-gate */ 3463*7c478bd9Sstevel@tonic-gate 3464*7c478bd9Sstevel@tonic-gate void 3465*7c478bd9Sstevel@tonic-gate setuserenv(envar, value) 3466*7c478bd9Sstevel@tonic-gate const char *envar; 3467*7c478bd9Sstevel@tonic-gate const char *value; 3468*7c478bd9Sstevel@tonic-gate { 3469*7c478bd9Sstevel@tonic-gate int i, l; 3470*7c478bd9Sstevel@tonic-gate char **evp = UserEnviron; 3471*7c478bd9Sstevel@tonic-gate char *p; 3472*7c478bd9Sstevel@tonic-gate 3473*7c478bd9Sstevel@tonic-gate if (value == NULL) 3474*7c478bd9Sstevel@tonic-gate { 3475*7c478bd9Sstevel@tonic-gate value = getextenv(envar); 3476*7c478bd9Sstevel@tonic-gate if (value == NULL) 3477*7c478bd9Sstevel@tonic-gate return; 3478*7c478bd9Sstevel@tonic-gate } 3479*7c478bd9Sstevel@tonic-gate 3480*7c478bd9Sstevel@tonic-gate /* XXX enforce reasonable size? */ 3481*7c478bd9Sstevel@tonic-gate i = strlen(envar) + 1; 3482*7c478bd9Sstevel@tonic-gate l = strlen(value) + i + 1; 3483*7c478bd9Sstevel@tonic-gate p = (char *) xalloc(l); 3484*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(p, l, 3, envar, "=", value); 3485*7c478bd9Sstevel@tonic-gate 3486*7c478bd9Sstevel@tonic-gate while (*evp != NULL && strncmp(*evp, p, i) != 0) 3487*7c478bd9Sstevel@tonic-gate evp++; 3488*7c478bd9Sstevel@tonic-gate if (*evp != NULL) 3489*7c478bd9Sstevel@tonic-gate { 3490*7c478bd9Sstevel@tonic-gate *evp++ = p; 3491*7c478bd9Sstevel@tonic-gate } 3492*7c478bd9Sstevel@tonic-gate else if (evp < &UserEnviron[MAXUSERENVIRON]) 3493*7c478bd9Sstevel@tonic-gate { 3494*7c478bd9Sstevel@tonic-gate *evp++ = p; 3495*7c478bd9Sstevel@tonic-gate *evp = NULL; 3496*7c478bd9Sstevel@tonic-gate } 3497*7c478bd9Sstevel@tonic-gate 3498*7c478bd9Sstevel@tonic-gate /* make sure it is in our environment as well */ 3499*7c478bd9Sstevel@tonic-gate if (putenv(p) < 0) 3500*7c478bd9Sstevel@tonic-gate syserr("setuserenv: putenv(%s) failed", p); 3501*7c478bd9Sstevel@tonic-gate } 3502*7c478bd9Sstevel@tonic-gate /* 3503*7c478bd9Sstevel@tonic-gate ** DUMPSTATE -- dump state 3504*7c478bd9Sstevel@tonic-gate ** 3505*7c478bd9Sstevel@tonic-gate ** For debugging. 3506*7c478bd9Sstevel@tonic-gate */ 3507*7c478bd9Sstevel@tonic-gate 3508*7c478bd9Sstevel@tonic-gate void 3509*7c478bd9Sstevel@tonic-gate dumpstate(when) 3510*7c478bd9Sstevel@tonic-gate char *when; 3511*7c478bd9Sstevel@tonic-gate { 3512*7c478bd9Sstevel@tonic-gate register char *j = macvalue('j', CurEnv); 3513*7c478bd9Sstevel@tonic-gate int rs; 3514*7c478bd9Sstevel@tonic-gate extern int NextMacroId; 3515*7c478bd9Sstevel@tonic-gate 3516*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 3517*7c478bd9Sstevel@tonic-gate "--- dumping state on %s: $j = %s ---", 3518*7c478bd9Sstevel@tonic-gate when, 3519*7c478bd9Sstevel@tonic-gate j == NULL ? "<NULL>" : j); 3520*7c478bd9Sstevel@tonic-gate if (j != NULL) 3521*7c478bd9Sstevel@tonic-gate { 3522*7c478bd9Sstevel@tonic-gate if (!wordinclass(j, 'w')) 3523*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 3524*7c478bd9Sstevel@tonic-gate "*** $j not in $=w ***"); 3525*7c478bd9Sstevel@tonic-gate } 3526*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 3527*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 3528*7c478bd9Sstevel@tonic-gate NextMacroId, MAXMACROID); 3529*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 3530*7c478bd9Sstevel@tonic-gate printopenfds(true); 3531*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 3532*7c478bd9Sstevel@tonic-gate mci_dump_all(smioout, true); 3533*7c478bd9Sstevel@tonic-gate rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 3534*7c478bd9Sstevel@tonic-gate if (rs > 0) 3535*7c478bd9Sstevel@tonic-gate { 3536*7c478bd9Sstevel@tonic-gate int status; 3537*7c478bd9Sstevel@tonic-gate register char **pvp; 3538*7c478bd9Sstevel@tonic-gate char *pv[MAXATOM + 1]; 3539*7c478bd9Sstevel@tonic-gate 3540*7c478bd9Sstevel@tonic-gate pv[0] = NULL; 3541*7c478bd9Sstevel@tonic-gate status = REWRITE(pv, rs, CurEnv); 3542*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, 3543*7c478bd9Sstevel@tonic-gate "--- ruleset debug_dumpstate returns stat %d, pv: ---", 3544*7c478bd9Sstevel@tonic-gate status); 3545*7c478bd9Sstevel@tonic-gate for (pvp = pv; *pvp != NULL; pvp++) 3546*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 3547*7c478bd9Sstevel@tonic-gate } 3548*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 3549*7c478bd9Sstevel@tonic-gate } 3550*7c478bd9Sstevel@tonic-gate 3551*7c478bd9Sstevel@tonic-gate #ifdef SIGUSR1 3552*7c478bd9Sstevel@tonic-gate /* 3553*7c478bd9Sstevel@tonic-gate ** SIGUSR1 -- Signal a request to dump state. 3554*7c478bd9Sstevel@tonic-gate ** 3555*7c478bd9Sstevel@tonic-gate ** Parameters: 3556*7c478bd9Sstevel@tonic-gate ** sig -- calling signal. 3557*7c478bd9Sstevel@tonic-gate ** 3558*7c478bd9Sstevel@tonic-gate ** Returns: 3559*7c478bd9Sstevel@tonic-gate ** none. 3560*7c478bd9Sstevel@tonic-gate ** 3561*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3562*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3563*7c478bd9Sstevel@tonic-gate ** DOING. 3564*7c478bd9Sstevel@tonic-gate ** 3565*7c478bd9Sstevel@tonic-gate ** XXX: More work is needed for this signal handler. 3566*7c478bd9Sstevel@tonic-gate */ 3567*7c478bd9Sstevel@tonic-gate 3568*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3569*7c478bd9Sstevel@tonic-gate static SIGFUNC_DECL 3570*7c478bd9Sstevel@tonic-gate sigusr1(sig) 3571*7c478bd9Sstevel@tonic-gate int sig; 3572*7c478bd9Sstevel@tonic-gate { 3573*7c478bd9Sstevel@tonic-gate int save_errno = errno; 3574*7c478bd9Sstevel@tonic-gate # if SM_HEAP_CHECK 3575*7c478bd9Sstevel@tonic-gate extern void dumpstab __P((void)); 3576*7c478bd9Sstevel@tonic-gate # endif /* SM_HEAP_CHECK */ 3577*7c478bd9Sstevel@tonic-gate 3578*7c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sigusr1); 3579*7c478bd9Sstevel@tonic-gate errno = save_errno; 3580*7c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig); 3581*7c478bd9Sstevel@tonic-gate dumpstate("user signal"); 3582*7c478bd9Sstevel@tonic-gate # if SM_HEAP_CHECK 3583*7c478bd9Sstevel@tonic-gate dumpstab(); 3584*7c478bd9Sstevel@tonic-gate # endif /* SM_HEAP_CHECK */ 3585*7c478bd9Sstevel@tonic-gate errno = save_errno; 3586*7c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN; 3587*7c478bd9Sstevel@tonic-gate } 3588*7c478bd9Sstevel@tonic-gate #endif /* SIGUSR1 */ 3589*7c478bd9Sstevel@tonic-gate 3590*7c478bd9Sstevel@tonic-gate /* 3591*7c478bd9Sstevel@tonic-gate ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 3592*7c478bd9Sstevel@tonic-gate ** 3593*7c478bd9Sstevel@tonic-gate ** Parameters: 3594*7c478bd9Sstevel@tonic-gate ** to_real_uid -- if set, drop to the real uid instead 3595*7c478bd9Sstevel@tonic-gate ** of the RunAsUser. 3596*7c478bd9Sstevel@tonic-gate ** 3597*7c478bd9Sstevel@tonic-gate ** Returns: 3598*7c478bd9Sstevel@tonic-gate ** EX_OSERR if the setuid failed. 3599*7c478bd9Sstevel@tonic-gate ** EX_OK otherwise. 3600*7c478bd9Sstevel@tonic-gate */ 3601*7c478bd9Sstevel@tonic-gate 3602*7c478bd9Sstevel@tonic-gate int 3603*7c478bd9Sstevel@tonic-gate drop_privileges(to_real_uid) 3604*7c478bd9Sstevel@tonic-gate bool to_real_uid; 3605*7c478bd9Sstevel@tonic-gate { 3606*7c478bd9Sstevel@tonic-gate int rval = EX_OK; 3607*7c478bd9Sstevel@tonic-gate GIDSET_T emptygidset[1]; 3608*7c478bd9Sstevel@tonic-gate 3609*7c478bd9Sstevel@tonic-gate if (tTd(47, 1)) 3610*7c478bd9Sstevel@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", 3611*7c478bd9Sstevel@tonic-gate (int) to_real_uid, 3612*7c478bd9Sstevel@tonic-gate (int) RealUid, (int) RealGid, 3613*7c478bd9Sstevel@tonic-gate (int) getuid(), (int) getgid(), 3614*7c478bd9Sstevel@tonic-gate (int) geteuid(), (int) getegid(), 3615*7c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 3616*7c478bd9Sstevel@tonic-gate 3617*7c478bd9Sstevel@tonic-gate if (to_real_uid) 3618*7c478bd9Sstevel@tonic-gate { 3619*7c478bd9Sstevel@tonic-gate RunAsUserName = RealUserName; 3620*7c478bd9Sstevel@tonic-gate RunAsUid = RealUid; 3621*7c478bd9Sstevel@tonic-gate RunAsGid = RealGid; 3622*7c478bd9Sstevel@tonic-gate EffGid = RunAsGid; 3623*7c478bd9Sstevel@tonic-gate } 3624*7c478bd9Sstevel@tonic-gate 3625*7c478bd9Sstevel@tonic-gate /* make sure no one can grab open descriptors for secret files */ 3626*7c478bd9Sstevel@tonic-gate endpwent(); 3627*7c478bd9Sstevel@tonic-gate sm_mbdb_terminate(); 3628*7c478bd9Sstevel@tonic-gate 3629*7c478bd9Sstevel@tonic-gate /* reset group permissions; these can be set later */ 3630*7c478bd9Sstevel@tonic-gate emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 3631*7c478bd9Sstevel@tonic-gate 3632*7c478bd9Sstevel@tonic-gate /* 3633*7c478bd9Sstevel@tonic-gate ** Notice: on some OS (Linux...) the setgroups() call causes 3634*7c478bd9Sstevel@tonic-gate ** a logfile entry if sendmail is not run by root. 3635*7c478bd9Sstevel@tonic-gate ** However, it is unclear (no POSIX standard) whether 3636*7c478bd9Sstevel@tonic-gate ** setgroups() can only succeed if executed by root. 3637*7c478bd9Sstevel@tonic-gate ** So for now we keep it as it is; if you want to change it, use 3638*7c478bd9Sstevel@tonic-gate ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 3639*7c478bd9Sstevel@tonic-gate */ 3640*7c478bd9Sstevel@tonic-gate 3641*7c478bd9Sstevel@tonic-gate if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 3642*7c478bd9Sstevel@tonic-gate { 3643*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setgroups(1, %d) failed", 3644*7c478bd9Sstevel@tonic-gate (int) emptygidset[0]); 3645*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3646*7c478bd9Sstevel@tonic-gate } 3647*7c478bd9Sstevel@tonic-gate 3648*7c478bd9Sstevel@tonic-gate /* reset primary group id */ 3649*7c478bd9Sstevel@tonic-gate if (to_real_uid) 3650*7c478bd9Sstevel@tonic-gate { 3651*7c478bd9Sstevel@tonic-gate /* 3652*7c478bd9Sstevel@tonic-gate ** Drop gid to real gid. 3653*7c478bd9Sstevel@tonic-gate ** On some OS we must reset the effective[/real[/saved]] gid, 3654*7c478bd9Sstevel@tonic-gate ** and then use setgid() to finally drop all group privileges. 3655*7c478bd9Sstevel@tonic-gate ** Later on we check whether we can get back the 3656*7c478bd9Sstevel@tonic-gate ** effective gid. 3657*7c478bd9Sstevel@tonic-gate */ 3658*7c478bd9Sstevel@tonic-gate 3659*7c478bd9Sstevel@tonic-gate #if HASSETEGID 3660*7c478bd9Sstevel@tonic-gate if (setegid(RunAsGid) < 0) 3661*7c478bd9Sstevel@tonic-gate { 3662*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setegid(%d) failed", 3663*7c478bd9Sstevel@tonic-gate (int) RunAsGid); 3664*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3665*7c478bd9Sstevel@tonic-gate } 3666*7c478bd9Sstevel@tonic-gate #else /* HASSETEGID */ 3667*7c478bd9Sstevel@tonic-gate # if HASSETREGID 3668*7c478bd9Sstevel@tonic-gate if (setregid(RunAsGid, RunAsGid) < 0) 3669*7c478bd9Sstevel@tonic-gate { 3670*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setregid(%d, %d) failed", 3671*7c478bd9Sstevel@tonic-gate (int) RunAsGid, (int) RunAsGid); 3672*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3673*7c478bd9Sstevel@tonic-gate } 3674*7c478bd9Sstevel@tonic-gate # else /* HASSETREGID */ 3675*7c478bd9Sstevel@tonic-gate # if HASSETRESGID 3676*7c478bd9Sstevel@tonic-gate if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 3677*7c478bd9Sstevel@tonic-gate { 3678*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setresgid(%d, %d, %d) failed", 3679*7c478bd9Sstevel@tonic-gate (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 3680*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3681*7c478bd9Sstevel@tonic-gate } 3682*7c478bd9Sstevel@tonic-gate # endif /* HASSETRESGID */ 3683*7c478bd9Sstevel@tonic-gate # endif /* HASSETREGID */ 3684*7c478bd9Sstevel@tonic-gate #endif /* HASSETEGID */ 3685*7c478bd9Sstevel@tonic-gate } 3686*7c478bd9Sstevel@tonic-gate if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 3687*7c478bd9Sstevel@tonic-gate { 3688*7c478bd9Sstevel@tonic-gate if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 3689*7c478bd9Sstevel@tonic-gate { 3690*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setgid(%d) failed", 3691*7c478bd9Sstevel@tonic-gate (int) RunAsGid); 3692*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3693*7c478bd9Sstevel@tonic-gate } 3694*7c478bd9Sstevel@tonic-gate errno = 0; 3695*7c478bd9Sstevel@tonic-gate if (rval == EX_OK && getegid() != RunAsGid) 3696*7c478bd9Sstevel@tonic-gate { 3697*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", 3698*7c478bd9Sstevel@tonic-gate (int) getegid(), (int) RunAsGid); 3699*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3700*7c478bd9Sstevel@tonic-gate } 3701*7c478bd9Sstevel@tonic-gate } 3702*7c478bd9Sstevel@tonic-gate 3703*7c478bd9Sstevel@tonic-gate /* fiddle with uid */ 3704*7c478bd9Sstevel@tonic-gate if (to_real_uid || RunAsUid != 0) 3705*7c478bd9Sstevel@tonic-gate { 3706*7c478bd9Sstevel@tonic-gate uid_t euid; 3707*7c478bd9Sstevel@tonic-gate 3708*7c478bd9Sstevel@tonic-gate /* 3709*7c478bd9Sstevel@tonic-gate ** Try to setuid(RunAsUid). 3710*7c478bd9Sstevel@tonic-gate ** euid must be RunAsUid, 3711*7c478bd9Sstevel@tonic-gate ** ruid must be RunAsUid unless (e|r)uid wasn't 0 3712*7c478bd9Sstevel@tonic-gate ** and we didn't have to drop privileges to the real uid. 3713*7c478bd9Sstevel@tonic-gate */ 3714*7c478bd9Sstevel@tonic-gate 3715*7c478bd9Sstevel@tonic-gate if (setuid(RunAsUid) < 0 || 3716*7c478bd9Sstevel@tonic-gate geteuid() != RunAsUid || 3717*7c478bd9Sstevel@tonic-gate (getuid() != RunAsUid && 3718*7c478bd9Sstevel@tonic-gate (to_real_uid || geteuid() == 0 || getuid() == 0))) 3719*7c478bd9Sstevel@tonic-gate { 3720*7c478bd9Sstevel@tonic-gate #if HASSETREUID 3721*7c478bd9Sstevel@tonic-gate /* 3722*7c478bd9Sstevel@tonic-gate ** if ruid != RunAsUid, euid == RunAsUid, then 3723*7c478bd9Sstevel@tonic-gate ** try resetting just the real uid, then using 3724*7c478bd9Sstevel@tonic-gate ** setuid() to drop the saved-uid as well. 3725*7c478bd9Sstevel@tonic-gate */ 3726*7c478bd9Sstevel@tonic-gate 3727*7c478bd9Sstevel@tonic-gate if (geteuid() == RunAsUid) 3728*7c478bd9Sstevel@tonic-gate { 3729*7c478bd9Sstevel@tonic-gate if (setreuid(RunAsUid, -1) < 0) 3730*7c478bd9Sstevel@tonic-gate { 3731*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setreuid(%d, -1) failed", 3732*7c478bd9Sstevel@tonic-gate (int) RunAsUid); 3733*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3734*7c478bd9Sstevel@tonic-gate } 3735*7c478bd9Sstevel@tonic-gate if (setuid(RunAsUid) < 0) 3736*7c478bd9Sstevel@tonic-gate { 3737*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: second setuid(%d) attempt failed", 3738*7c478bd9Sstevel@tonic-gate (int) RunAsUid); 3739*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3740*7c478bd9Sstevel@tonic-gate } 3741*7c478bd9Sstevel@tonic-gate } 3742*7c478bd9Sstevel@tonic-gate else 3743*7c478bd9Sstevel@tonic-gate #endif /* HASSETREUID */ 3744*7c478bd9Sstevel@tonic-gate { 3745*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setuid(%d) failed", 3746*7c478bd9Sstevel@tonic-gate (int) RunAsUid); 3747*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3748*7c478bd9Sstevel@tonic-gate } 3749*7c478bd9Sstevel@tonic-gate } 3750*7c478bd9Sstevel@tonic-gate euid = geteuid(); 3751*7c478bd9Sstevel@tonic-gate if (RunAsUid != 0 && setuid(0) == 0) 3752*7c478bd9Sstevel@tonic-gate { 3753*7c478bd9Sstevel@tonic-gate /* 3754*7c478bd9Sstevel@tonic-gate ** Believe it or not, the Linux capability model 3755*7c478bd9Sstevel@tonic-gate ** allows a non-root process to override setuid() 3756*7c478bd9Sstevel@tonic-gate ** on a process running as root and prevent that 3757*7c478bd9Sstevel@tonic-gate ** process from dropping privileges. 3758*7c478bd9Sstevel@tonic-gate */ 3759*7c478bd9Sstevel@tonic-gate 3760*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 3761*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3762*7c478bd9Sstevel@tonic-gate } 3763*7c478bd9Sstevel@tonic-gate else if (RunAsUid != euid && setuid(euid) == 0) 3764*7c478bd9Sstevel@tonic-gate { 3765*7c478bd9Sstevel@tonic-gate /* 3766*7c478bd9Sstevel@tonic-gate ** Some operating systems will keep the saved-uid 3767*7c478bd9Sstevel@tonic-gate ** if a non-root effective-uid calls setuid(real-uid) 3768*7c478bd9Sstevel@tonic-gate ** making it possible to set it back again later. 3769*7c478bd9Sstevel@tonic-gate */ 3770*7c478bd9Sstevel@tonic-gate 3771*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 3772*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3773*7c478bd9Sstevel@tonic-gate } 3774*7c478bd9Sstevel@tonic-gate } 3775*7c478bd9Sstevel@tonic-gate 3776*7c478bd9Sstevel@tonic-gate if ((to_real_uid || RunAsGid != 0) && 3777*7c478bd9Sstevel@tonic-gate rval == EX_OK && RunAsGid != EffGid && 3778*7c478bd9Sstevel@tonic-gate getuid() != 0 && geteuid() != 0) 3779*7c478bd9Sstevel@tonic-gate { 3780*7c478bd9Sstevel@tonic-gate errno = 0; 3781*7c478bd9Sstevel@tonic-gate if (setgid(EffGid) == 0) 3782*7c478bd9Sstevel@tonic-gate { 3783*7c478bd9Sstevel@tonic-gate syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 3784*7c478bd9Sstevel@tonic-gate (int) EffGid); 3785*7c478bd9Sstevel@tonic-gate rval = EX_OSERR; 3786*7c478bd9Sstevel@tonic-gate } 3787*7c478bd9Sstevel@tonic-gate } 3788*7c478bd9Sstevel@tonic-gate 3789*7c478bd9Sstevel@tonic-gate if (tTd(47, 5)) 3790*7c478bd9Sstevel@tonic-gate { 3791*7c478bd9Sstevel@tonic-gate sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 3792*7c478bd9Sstevel@tonic-gate (int) geteuid(), (int) getuid(), 3793*7c478bd9Sstevel@tonic-gate (int) getegid(), (int) getgid()); 3794*7c478bd9Sstevel@tonic-gate sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 3795*7c478bd9Sstevel@tonic-gate (int) RunAsUid, (int) RunAsGid); 3796*7c478bd9Sstevel@tonic-gate if (tTd(47, 10)) 3797*7c478bd9Sstevel@tonic-gate sm_dprintf("drop_privileges: rval = %d\n", rval); 3798*7c478bd9Sstevel@tonic-gate } 3799*7c478bd9Sstevel@tonic-gate return rval; 3800*7c478bd9Sstevel@tonic-gate } 3801*7c478bd9Sstevel@tonic-gate /* 3802*7c478bd9Sstevel@tonic-gate ** FILL_FD -- make sure a file descriptor has been properly allocated 3803*7c478bd9Sstevel@tonic-gate ** 3804*7c478bd9Sstevel@tonic-gate ** Used to make sure that stdin/out/err are allocated on startup 3805*7c478bd9Sstevel@tonic-gate ** 3806*7c478bd9Sstevel@tonic-gate ** Parameters: 3807*7c478bd9Sstevel@tonic-gate ** fd -- the file descriptor to be filled. 3808*7c478bd9Sstevel@tonic-gate ** where -- a string used for logging. If NULL, this is 3809*7c478bd9Sstevel@tonic-gate ** being called on startup, and logging should 3810*7c478bd9Sstevel@tonic-gate ** not be done. 3811*7c478bd9Sstevel@tonic-gate ** 3812*7c478bd9Sstevel@tonic-gate ** Returns: 3813*7c478bd9Sstevel@tonic-gate ** none 3814*7c478bd9Sstevel@tonic-gate ** 3815*7c478bd9Sstevel@tonic-gate ** Side Effects: 3816*7c478bd9Sstevel@tonic-gate ** possibly changes MissingFds 3817*7c478bd9Sstevel@tonic-gate */ 3818*7c478bd9Sstevel@tonic-gate 3819*7c478bd9Sstevel@tonic-gate void 3820*7c478bd9Sstevel@tonic-gate fill_fd(fd, where) 3821*7c478bd9Sstevel@tonic-gate int fd; 3822*7c478bd9Sstevel@tonic-gate char *where; 3823*7c478bd9Sstevel@tonic-gate { 3824*7c478bd9Sstevel@tonic-gate int i; 3825*7c478bd9Sstevel@tonic-gate struct stat stbuf; 3826*7c478bd9Sstevel@tonic-gate 3827*7c478bd9Sstevel@tonic-gate if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 3828*7c478bd9Sstevel@tonic-gate return; 3829*7c478bd9Sstevel@tonic-gate 3830*7c478bd9Sstevel@tonic-gate if (where != NULL) 3831*7c478bd9Sstevel@tonic-gate syserr("fill_fd: %s: fd %d not open", where, fd); 3832*7c478bd9Sstevel@tonic-gate else 3833*7c478bd9Sstevel@tonic-gate MissingFds |= 1 << fd; 3834*7c478bd9Sstevel@tonic-gate i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 3835*7c478bd9Sstevel@tonic-gate if (i < 0) 3836*7c478bd9Sstevel@tonic-gate { 3837*7c478bd9Sstevel@tonic-gate syserr("!fill_fd: %s: cannot open %s", 3838*7c478bd9Sstevel@tonic-gate where == NULL ? "startup" : where, SM_PATH_DEVNULL); 3839*7c478bd9Sstevel@tonic-gate } 3840*7c478bd9Sstevel@tonic-gate if (fd != i) 3841*7c478bd9Sstevel@tonic-gate { 3842*7c478bd9Sstevel@tonic-gate (void) dup2(i, fd); 3843*7c478bd9Sstevel@tonic-gate (void) close(i); 3844*7c478bd9Sstevel@tonic-gate } 3845*7c478bd9Sstevel@tonic-gate } 3846*7c478bd9Sstevel@tonic-gate /* 3847*7c478bd9Sstevel@tonic-gate ** SM_PRINTOPTIONS -- print options 3848*7c478bd9Sstevel@tonic-gate ** 3849*7c478bd9Sstevel@tonic-gate ** Parameters: 3850*7c478bd9Sstevel@tonic-gate ** options -- array of options. 3851*7c478bd9Sstevel@tonic-gate ** 3852*7c478bd9Sstevel@tonic-gate ** Returns: 3853*7c478bd9Sstevel@tonic-gate ** none. 3854*7c478bd9Sstevel@tonic-gate */ 3855*7c478bd9Sstevel@tonic-gate 3856*7c478bd9Sstevel@tonic-gate static void 3857*7c478bd9Sstevel@tonic-gate sm_printoptions(options) 3858*7c478bd9Sstevel@tonic-gate char **options; 3859*7c478bd9Sstevel@tonic-gate { 3860*7c478bd9Sstevel@tonic-gate int ll; 3861*7c478bd9Sstevel@tonic-gate char **av; 3862*7c478bd9Sstevel@tonic-gate 3863*7c478bd9Sstevel@tonic-gate av = options; 3864*7c478bd9Sstevel@tonic-gate ll = 7; 3865*7c478bd9Sstevel@tonic-gate while (*av != NULL) 3866*7c478bd9Sstevel@tonic-gate { 3867*7c478bd9Sstevel@tonic-gate if (ll + strlen(*av) > 63) 3868*7c478bd9Sstevel@tonic-gate { 3869*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 3870*7c478bd9Sstevel@tonic-gate ll = 0; 3871*7c478bd9Sstevel@tonic-gate } 3872*7c478bd9Sstevel@tonic-gate if (ll == 0) 3873*7c478bd9Sstevel@tonic-gate sm_dprintf("\t\t"); 3874*7c478bd9Sstevel@tonic-gate else 3875*7c478bd9Sstevel@tonic-gate sm_dprintf(" "); 3876*7c478bd9Sstevel@tonic-gate sm_dprintf("%s", *av); 3877*7c478bd9Sstevel@tonic-gate ll += strlen(*av++) + 1; 3878*7c478bd9Sstevel@tonic-gate } 3879*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 3880*7c478bd9Sstevel@tonic-gate } 3881*7c478bd9Sstevel@tonic-gate /* 3882*7c478bd9Sstevel@tonic-gate ** TESTMODELINE -- process a test mode input line 3883*7c478bd9Sstevel@tonic-gate ** 3884*7c478bd9Sstevel@tonic-gate ** Parameters: 3885*7c478bd9Sstevel@tonic-gate ** line -- the input line. 3886*7c478bd9Sstevel@tonic-gate ** e -- the current environment. 3887*7c478bd9Sstevel@tonic-gate ** Syntax: 3888*7c478bd9Sstevel@tonic-gate ** # a comment 3889*7c478bd9Sstevel@tonic-gate ** .X process X as a configuration line 3890*7c478bd9Sstevel@tonic-gate ** =X dump a configuration item (such as mailers) 3891*7c478bd9Sstevel@tonic-gate ** $X dump a macro or class 3892*7c478bd9Sstevel@tonic-gate ** /X try an activity 3893*7c478bd9Sstevel@tonic-gate ** X normal process through rule set X 3894*7c478bd9Sstevel@tonic-gate */ 3895*7c478bd9Sstevel@tonic-gate 3896*7c478bd9Sstevel@tonic-gate static void 3897*7c478bd9Sstevel@tonic-gate testmodeline(line, e) 3898*7c478bd9Sstevel@tonic-gate char *line; 3899*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3900*7c478bd9Sstevel@tonic-gate { 3901*7c478bd9Sstevel@tonic-gate register char *p; 3902*7c478bd9Sstevel@tonic-gate char *q; 3903*7c478bd9Sstevel@tonic-gate auto char *delimptr; 3904*7c478bd9Sstevel@tonic-gate int mid; 3905*7c478bd9Sstevel@tonic-gate int i, rs; 3906*7c478bd9Sstevel@tonic-gate STAB *map; 3907*7c478bd9Sstevel@tonic-gate char **s; 3908*7c478bd9Sstevel@tonic-gate struct rewrite *rw; 3909*7c478bd9Sstevel@tonic-gate ADDRESS a; 3910*7c478bd9Sstevel@tonic-gate static int tryflags = RF_COPYNONE; 3911*7c478bd9Sstevel@tonic-gate char exbuf[MAXLINE]; 3912*7c478bd9Sstevel@tonic-gate extern unsigned char TokTypeNoC[]; 3913*7c478bd9Sstevel@tonic-gate 3914*7c478bd9Sstevel@tonic-gate /* skip leading spaces */ 3915*7c478bd9Sstevel@tonic-gate while (*line == ' ') 3916*7c478bd9Sstevel@tonic-gate line++; 3917*7c478bd9Sstevel@tonic-gate 3918*7c478bd9Sstevel@tonic-gate switch (line[0]) 3919*7c478bd9Sstevel@tonic-gate { 3920*7c478bd9Sstevel@tonic-gate case '#': 3921*7c478bd9Sstevel@tonic-gate case '\0': 3922*7c478bd9Sstevel@tonic-gate return; 3923*7c478bd9Sstevel@tonic-gate 3924*7c478bd9Sstevel@tonic-gate case '?': 3925*7c478bd9Sstevel@tonic-gate help("-bt", e); 3926*7c478bd9Sstevel@tonic-gate return; 3927*7c478bd9Sstevel@tonic-gate 3928*7c478bd9Sstevel@tonic-gate case '.': /* config-style settings */ 3929*7c478bd9Sstevel@tonic-gate switch (line[1]) 3930*7c478bd9Sstevel@tonic-gate { 3931*7c478bd9Sstevel@tonic-gate case 'D': 3932*7c478bd9Sstevel@tonic-gate mid = macid_parse(&line[2], &delimptr); 3933*7c478bd9Sstevel@tonic-gate if (mid == 0) 3934*7c478bd9Sstevel@tonic-gate return; 3935*7c478bd9Sstevel@tonic-gate translate_dollars(delimptr); 3936*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, mid, delimptr); 3937*7c478bd9Sstevel@tonic-gate break; 3938*7c478bd9Sstevel@tonic-gate 3939*7c478bd9Sstevel@tonic-gate case 'C': 3940*7c478bd9Sstevel@tonic-gate if (line[2] == '\0') /* not to call syserr() */ 3941*7c478bd9Sstevel@tonic-gate return; 3942*7c478bd9Sstevel@tonic-gate 3943*7c478bd9Sstevel@tonic-gate mid = macid_parse(&line[2], &delimptr); 3944*7c478bd9Sstevel@tonic-gate if (mid == 0) 3945*7c478bd9Sstevel@tonic-gate return; 3946*7c478bd9Sstevel@tonic-gate translate_dollars(delimptr); 3947*7c478bd9Sstevel@tonic-gate expand(delimptr, exbuf, sizeof exbuf, e); 3948*7c478bd9Sstevel@tonic-gate p = exbuf; 3949*7c478bd9Sstevel@tonic-gate while (*p != '\0') 3950*7c478bd9Sstevel@tonic-gate { 3951*7c478bd9Sstevel@tonic-gate register char *wd; 3952*7c478bd9Sstevel@tonic-gate char delim; 3953*7c478bd9Sstevel@tonic-gate 3954*7c478bd9Sstevel@tonic-gate while (*p != '\0' && isascii(*p) && isspace(*p)) 3955*7c478bd9Sstevel@tonic-gate p++; 3956*7c478bd9Sstevel@tonic-gate wd = p; 3957*7c478bd9Sstevel@tonic-gate while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3958*7c478bd9Sstevel@tonic-gate p++; 3959*7c478bd9Sstevel@tonic-gate delim = *p; 3960*7c478bd9Sstevel@tonic-gate *p = '\0'; 3961*7c478bd9Sstevel@tonic-gate if (wd[0] != '\0') 3962*7c478bd9Sstevel@tonic-gate setclass(mid, wd); 3963*7c478bd9Sstevel@tonic-gate *p = delim; 3964*7c478bd9Sstevel@tonic-gate } 3965*7c478bd9Sstevel@tonic-gate break; 3966*7c478bd9Sstevel@tonic-gate 3967*7c478bd9Sstevel@tonic-gate case '\0': 3968*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3969*7c478bd9Sstevel@tonic-gate "Usage: .[DC]macro value(s)\n"); 3970*7c478bd9Sstevel@tonic-gate break; 3971*7c478bd9Sstevel@tonic-gate 3972*7c478bd9Sstevel@tonic-gate default: 3973*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3974*7c478bd9Sstevel@tonic-gate "Unknown \".\" command %s\n", line); 3975*7c478bd9Sstevel@tonic-gate break; 3976*7c478bd9Sstevel@tonic-gate } 3977*7c478bd9Sstevel@tonic-gate return; 3978*7c478bd9Sstevel@tonic-gate 3979*7c478bd9Sstevel@tonic-gate case '=': /* config-style settings */ 3980*7c478bd9Sstevel@tonic-gate switch (line[1]) 3981*7c478bd9Sstevel@tonic-gate { 3982*7c478bd9Sstevel@tonic-gate case 'S': /* dump rule set */ 3983*7c478bd9Sstevel@tonic-gate rs = strtorwset(&line[2], NULL, ST_FIND); 3984*7c478bd9Sstevel@tonic-gate if (rs < 0) 3985*7c478bd9Sstevel@tonic-gate { 3986*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3987*7c478bd9Sstevel@tonic-gate "Undefined ruleset %s\n", &line[2]); 3988*7c478bd9Sstevel@tonic-gate return; 3989*7c478bd9Sstevel@tonic-gate } 3990*7c478bd9Sstevel@tonic-gate rw = RewriteRules[rs]; 3991*7c478bd9Sstevel@tonic-gate if (rw == NULL) 3992*7c478bd9Sstevel@tonic-gate return; 3993*7c478bd9Sstevel@tonic-gate do 3994*7c478bd9Sstevel@tonic-gate { 3995*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 3996*7c478bd9Sstevel@tonic-gate 'R'); 3997*7c478bd9Sstevel@tonic-gate s = rw->r_lhs; 3998*7c478bd9Sstevel@tonic-gate while (*s != NULL) 3999*7c478bd9Sstevel@tonic-gate { 4000*7c478bd9Sstevel@tonic-gate xputs(smioout, *s++); 4001*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, 4002*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, ' '); 4003*7c478bd9Sstevel@tonic-gate } 4004*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4005*7c478bd9Sstevel@tonic-gate '\t'); 4006*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4007*7c478bd9Sstevel@tonic-gate '\t'); 4008*7c478bd9Sstevel@tonic-gate s = rw->r_rhs; 4009*7c478bd9Sstevel@tonic-gate while (*s != NULL) 4010*7c478bd9Sstevel@tonic-gate { 4011*7c478bd9Sstevel@tonic-gate xputs(smioout, *s++); 4012*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, 4013*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, ' '); 4014*7c478bd9Sstevel@tonic-gate } 4015*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4016*7c478bd9Sstevel@tonic-gate '\n'); 4017*7c478bd9Sstevel@tonic-gate } while ((rw = rw->r_next) != NULL); 4018*7c478bd9Sstevel@tonic-gate break; 4019*7c478bd9Sstevel@tonic-gate 4020*7c478bd9Sstevel@tonic-gate case 'M': 4021*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXMAILERS; i++) 4022*7c478bd9Sstevel@tonic-gate { 4023*7c478bd9Sstevel@tonic-gate if (Mailer[i] != NULL) 4024*7c478bd9Sstevel@tonic-gate printmailer(smioout, Mailer[i]); 4025*7c478bd9Sstevel@tonic-gate } 4026*7c478bd9Sstevel@tonic-gate break; 4027*7c478bd9Sstevel@tonic-gate 4028*7c478bd9Sstevel@tonic-gate case '\0': 4029*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4030*7c478bd9Sstevel@tonic-gate "Usage: =Sruleset or =M\n"); 4031*7c478bd9Sstevel@tonic-gate break; 4032*7c478bd9Sstevel@tonic-gate 4033*7c478bd9Sstevel@tonic-gate default: 4034*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4035*7c478bd9Sstevel@tonic-gate "Unknown \"=\" command %s\n", line); 4036*7c478bd9Sstevel@tonic-gate break; 4037*7c478bd9Sstevel@tonic-gate } 4038*7c478bd9Sstevel@tonic-gate return; 4039*7c478bd9Sstevel@tonic-gate 4040*7c478bd9Sstevel@tonic-gate case '-': /* set command-line-like opts */ 4041*7c478bd9Sstevel@tonic-gate switch (line[1]) 4042*7c478bd9Sstevel@tonic-gate { 4043*7c478bd9Sstevel@tonic-gate case 'd': 4044*7c478bd9Sstevel@tonic-gate tTflag(&line[2]); 4045*7c478bd9Sstevel@tonic-gate break; 4046*7c478bd9Sstevel@tonic-gate 4047*7c478bd9Sstevel@tonic-gate case '\0': 4048*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4049*7c478bd9Sstevel@tonic-gate "Usage: -d{debug arguments}\n"); 4050*7c478bd9Sstevel@tonic-gate break; 4051*7c478bd9Sstevel@tonic-gate 4052*7c478bd9Sstevel@tonic-gate default: 4053*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4054*7c478bd9Sstevel@tonic-gate "Unknown \"-\" command %s\n", line); 4055*7c478bd9Sstevel@tonic-gate break; 4056*7c478bd9Sstevel@tonic-gate } 4057*7c478bd9Sstevel@tonic-gate return; 4058*7c478bd9Sstevel@tonic-gate 4059*7c478bd9Sstevel@tonic-gate case '$': 4060*7c478bd9Sstevel@tonic-gate if (line[1] == '=') 4061*7c478bd9Sstevel@tonic-gate { 4062*7c478bd9Sstevel@tonic-gate mid = macid(&line[2]); 4063*7c478bd9Sstevel@tonic-gate if (mid != 0) 4064*7c478bd9Sstevel@tonic-gate stabapply(dump_class, mid); 4065*7c478bd9Sstevel@tonic-gate return; 4066*7c478bd9Sstevel@tonic-gate } 4067*7c478bd9Sstevel@tonic-gate mid = macid(&line[1]); 4068*7c478bd9Sstevel@tonic-gate if (mid == 0) 4069*7c478bd9Sstevel@tonic-gate return; 4070*7c478bd9Sstevel@tonic-gate p = macvalue(mid, e); 4071*7c478bd9Sstevel@tonic-gate if (p == NULL) 4072*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4073*7c478bd9Sstevel@tonic-gate "Undefined\n"); 4074*7c478bd9Sstevel@tonic-gate else 4075*7c478bd9Sstevel@tonic-gate { 4076*7c478bd9Sstevel@tonic-gate xputs(smioout, p); 4077*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4078*7c478bd9Sstevel@tonic-gate "\n"); 4079*7c478bd9Sstevel@tonic-gate } 4080*7c478bd9Sstevel@tonic-gate return; 4081*7c478bd9Sstevel@tonic-gate 4082*7c478bd9Sstevel@tonic-gate case '/': /* miscellaneous commands */ 4083*7c478bd9Sstevel@tonic-gate p = &line[strlen(line)]; 4084*7c478bd9Sstevel@tonic-gate while (--p >= line && isascii(*p) && isspace(*p)) 4085*7c478bd9Sstevel@tonic-gate *p = '\0'; 4086*7c478bd9Sstevel@tonic-gate p = strpbrk(line, " \t"); 4087*7c478bd9Sstevel@tonic-gate if (p != NULL) 4088*7c478bd9Sstevel@tonic-gate { 4089*7c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 4090*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 4091*7c478bd9Sstevel@tonic-gate } 4092*7c478bd9Sstevel@tonic-gate else 4093*7c478bd9Sstevel@tonic-gate p = ""; 4094*7c478bd9Sstevel@tonic-gate if (line[1] == '\0') 4095*7c478bd9Sstevel@tonic-gate { 4096*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4097*7c478bd9Sstevel@tonic-gate "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 4098*7c478bd9Sstevel@tonic-gate return; 4099*7c478bd9Sstevel@tonic-gate } 4100*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(&line[1], "quit") == 0) 4101*7c478bd9Sstevel@tonic-gate { 4102*7c478bd9Sstevel@tonic-gate CurEnv->e_id = NULL; 4103*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 4104*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4105*7c478bd9Sstevel@tonic-gate } 4106*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(&line[1], "mx") == 0) 4107*7c478bd9Sstevel@tonic-gate { 4108*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 4109*7c478bd9Sstevel@tonic-gate /* look up MX records */ 4110*7c478bd9Sstevel@tonic-gate int nmx; 4111*7c478bd9Sstevel@tonic-gate auto int rcode; 4112*7c478bd9Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 4113*7c478bd9Sstevel@tonic-gate 4114*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4115*7c478bd9Sstevel@tonic-gate { 4116*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4117*7c478bd9Sstevel@tonic-gate "Usage: /mx address\n"); 4118*7c478bd9Sstevel@tonic-gate return; 4119*7c478bd9Sstevel@tonic-gate } 4120*7c478bd9Sstevel@tonic-gate nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true, 4121*7c478bd9Sstevel@tonic-gate NULL); 4122*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4123*7c478bd9Sstevel@tonic-gate "getmxrr(%s) returns %d value(s):\n", 4124*7c478bd9Sstevel@tonic-gate p, nmx); 4125*7c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 4126*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4127*7c478bd9Sstevel@tonic-gate "\t%s\n", mxhosts[i]); 4128*7c478bd9Sstevel@tonic-gate #else /* NAMED_BIND */ 4129*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4130*7c478bd9Sstevel@tonic-gate "No MX code compiled in\n"); 4131*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 4132*7c478bd9Sstevel@tonic-gate } 4133*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "canon") == 0) 4134*7c478bd9Sstevel@tonic-gate { 4135*7c478bd9Sstevel@tonic-gate char host[MAXHOSTNAMELEN]; 4136*7c478bd9Sstevel@tonic-gate 4137*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4138*7c478bd9Sstevel@tonic-gate { 4139*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4140*7c478bd9Sstevel@tonic-gate "Usage: /canon address\n"); 4141*7c478bd9Sstevel@tonic-gate return; 4142*7c478bd9Sstevel@tonic-gate } 4143*7c478bd9Sstevel@tonic-gate else if (sm_strlcpy(host, p, sizeof host) >= sizeof host) 4144*7c478bd9Sstevel@tonic-gate { 4145*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4146*7c478bd9Sstevel@tonic-gate "Name too long\n"); 4147*7c478bd9Sstevel@tonic-gate return; 4148*7c478bd9Sstevel@tonic-gate } 4149*7c478bd9Sstevel@tonic-gate (void) getcanonname(host, sizeof host, !HasWildcardMX, 4150*7c478bd9Sstevel@tonic-gate NULL); 4151*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4152*7c478bd9Sstevel@tonic-gate "getcanonname(%s) returns %s\n", 4153*7c478bd9Sstevel@tonic-gate p, host); 4154*7c478bd9Sstevel@tonic-gate } 4155*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "map") == 0) 4156*7c478bd9Sstevel@tonic-gate { 4157*7c478bd9Sstevel@tonic-gate auto int rcode = EX_OK; 4158*7c478bd9Sstevel@tonic-gate char *av[2]; 4159*7c478bd9Sstevel@tonic-gate 4160*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4161*7c478bd9Sstevel@tonic-gate { 4162*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4163*7c478bd9Sstevel@tonic-gate "Usage: /map mapname key\n"); 4164*7c478bd9Sstevel@tonic-gate return; 4165*7c478bd9Sstevel@tonic-gate } 4166*7c478bd9Sstevel@tonic-gate for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 4167*7c478bd9Sstevel@tonic-gate continue; 4168*7c478bd9Sstevel@tonic-gate if (*q == '\0') 4169*7c478bd9Sstevel@tonic-gate { 4170*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4171*7c478bd9Sstevel@tonic-gate "No key specified\n"); 4172*7c478bd9Sstevel@tonic-gate return; 4173*7c478bd9Sstevel@tonic-gate } 4174*7c478bd9Sstevel@tonic-gate *q++ = '\0'; 4175*7c478bd9Sstevel@tonic-gate map = stab(p, ST_MAP, ST_FIND); 4176*7c478bd9Sstevel@tonic-gate if (map == NULL) 4177*7c478bd9Sstevel@tonic-gate { 4178*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4179*7c478bd9Sstevel@tonic-gate "Map named \"%s\" not found\n", p); 4180*7c478bd9Sstevel@tonic-gate return; 4181*7c478bd9Sstevel@tonic-gate } 4182*7c478bd9Sstevel@tonic-gate if (!bitset(MF_OPEN, map->s_map.map_mflags) && 4183*7c478bd9Sstevel@tonic-gate !openmap(&(map->s_map))) 4184*7c478bd9Sstevel@tonic-gate { 4185*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4186*7c478bd9Sstevel@tonic-gate "Map named \"%s\" not open\n", p); 4187*7c478bd9Sstevel@tonic-gate return; 4188*7c478bd9Sstevel@tonic-gate } 4189*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4190*7c478bd9Sstevel@tonic-gate "map_lookup: %s (%s) ", p, q); 4191*7c478bd9Sstevel@tonic-gate av[0] = q; 4192*7c478bd9Sstevel@tonic-gate av[1] = NULL; 4193*7c478bd9Sstevel@tonic-gate p = (*map->s_map.map_class->map_lookup) 4194*7c478bd9Sstevel@tonic-gate (&map->s_map, q, av, &rcode); 4195*7c478bd9Sstevel@tonic-gate if (p == NULL) 4196*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4197*7c478bd9Sstevel@tonic-gate "no match (%d)\n", 4198*7c478bd9Sstevel@tonic-gate rcode); 4199*7c478bd9Sstevel@tonic-gate else 4200*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4201*7c478bd9Sstevel@tonic-gate "returns %s (%d)\n", p, 4202*7c478bd9Sstevel@tonic-gate rcode); 4203*7c478bd9Sstevel@tonic-gate } 4204*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "try") == 0) 4205*7c478bd9Sstevel@tonic-gate { 4206*7c478bd9Sstevel@tonic-gate MAILER *m; 4207*7c478bd9Sstevel@tonic-gate STAB *st; 4208*7c478bd9Sstevel@tonic-gate auto int rcode = EX_OK; 4209*7c478bd9Sstevel@tonic-gate 4210*7c478bd9Sstevel@tonic-gate q = strpbrk(p, " \t"); 4211*7c478bd9Sstevel@tonic-gate if (q != NULL) 4212*7c478bd9Sstevel@tonic-gate { 4213*7c478bd9Sstevel@tonic-gate while (isascii(*q) && isspace(*q)) 4214*7c478bd9Sstevel@tonic-gate *q++ = '\0'; 4215*7c478bd9Sstevel@tonic-gate } 4216*7c478bd9Sstevel@tonic-gate if (q == NULL || *q == '\0') 4217*7c478bd9Sstevel@tonic-gate { 4218*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4219*7c478bd9Sstevel@tonic-gate "Usage: /try mailer address\n"); 4220*7c478bd9Sstevel@tonic-gate return; 4221*7c478bd9Sstevel@tonic-gate } 4222*7c478bd9Sstevel@tonic-gate st = stab(p, ST_MAILER, ST_FIND); 4223*7c478bd9Sstevel@tonic-gate if (st == NULL) 4224*7c478bd9Sstevel@tonic-gate { 4225*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4226*7c478bd9Sstevel@tonic-gate "Unknown mailer %s\n", p); 4227*7c478bd9Sstevel@tonic-gate return; 4228*7c478bd9Sstevel@tonic-gate } 4229*7c478bd9Sstevel@tonic-gate m = st->s_mailer; 4230*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4231*7c478bd9Sstevel@tonic-gate "Trying %s %s address %s for mailer %s\n", 4232*7c478bd9Sstevel@tonic-gate bitset(RF_HEADERADDR, tryflags) ? "header" 4233*7c478bd9Sstevel@tonic-gate : "envelope", 4234*7c478bd9Sstevel@tonic-gate bitset(RF_SENDERADDR, tryflags) ? "sender" 4235*7c478bd9Sstevel@tonic-gate : "recipient", q, p); 4236*7c478bd9Sstevel@tonic-gate p = remotename(q, m, tryflags, &rcode, CurEnv); 4237*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4238*7c478bd9Sstevel@tonic-gate "Rcode = %d, addr = %s\n", 4239*7c478bd9Sstevel@tonic-gate rcode, p == NULL ? "<NULL>" : p); 4240*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 4241*7c478bd9Sstevel@tonic-gate } 4242*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "tryflags") == 0) 4243*7c478bd9Sstevel@tonic-gate { 4244*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4245*7c478bd9Sstevel@tonic-gate { 4246*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4247*7c478bd9Sstevel@tonic-gate "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 4248*7c478bd9Sstevel@tonic-gate return; 4249*7c478bd9Sstevel@tonic-gate } 4250*7c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 4251*7c478bd9Sstevel@tonic-gate { 4252*7c478bd9Sstevel@tonic-gate switch (*p) 4253*7c478bd9Sstevel@tonic-gate { 4254*7c478bd9Sstevel@tonic-gate case 'H': 4255*7c478bd9Sstevel@tonic-gate case 'h': 4256*7c478bd9Sstevel@tonic-gate tryflags |= RF_HEADERADDR; 4257*7c478bd9Sstevel@tonic-gate break; 4258*7c478bd9Sstevel@tonic-gate 4259*7c478bd9Sstevel@tonic-gate case 'E': 4260*7c478bd9Sstevel@tonic-gate case 'e': 4261*7c478bd9Sstevel@tonic-gate tryflags &= ~RF_HEADERADDR; 4262*7c478bd9Sstevel@tonic-gate break; 4263*7c478bd9Sstevel@tonic-gate 4264*7c478bd9Sstevel@tonic-gate case 'S': 4265*7c478bd9Sstevel@tonic-gate case 's': 4266*7c478bd9Sstevel@tonic-gate tryflags |= RF_SENDERADDR; 4267*7c478bd9Sstevel@tonic-gate break; 4268*7c478bd9Sstevel@tonic-gate 4269*7c478bd9Sstevel@tonic-gate case 'R': 4270*7c478bd9Sstevel@tonic-gate case 'r': 4271*7c478bd9Sstevel@tonic-gate tryflags &= ~RF_SENDERADDR; 4272*7c478bd9Sstevel@tonic-gate break; 4273*7c478bd9Sstevel@tonic-gate } 4274*7c478bd9Sstevel@tonic-gate } 4275*7c478bd9Sstevel@tonic-gate exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 4276*7c478bd9Sstevel@tonic-gate exbuf[1] = ' '; 4277*7c478bd9Sstevel@tonic-gate exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 4278*7c478bd9Sstevel@tonic-gate exbuf[3] = '\0'; 4279*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 4280*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), exbuf); 4281*7c478bd9Sstevel@tonic-gate } 4282*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(&line[1], "parse") == 0) 4283*7c478bd9Sstevel@tonic-gate { 4284*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4285*7c478bd9Sstevel@tonic-gate { 4286*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4287*7c478bd9Sstevel@tonic-gate "Usage: /parse address\n"); 4288*7c478bd9Sstevel@tonic-gate return; 4289*7c478bd9Sstevel@tonic-gate } 4290*7c478bd9Sstevel@tonic-gate q = crackaddr(p, e); 4291*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4292*7c478bd9Sstevel@tonic-gate "Cracked address = "); 4293*7c478bd9Sstevel@tonic-gate xputs(smioout, q); 4294*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4295*7c478bd9Sstevel@tonic-gate "\nParsing %s %s address\n", 4296*7c478bd9Sstevel@tonic-gate bitset(RF_HEADERADDR, tryflags) ? 4297*7c478bd9Sstevel@tonic-gate "header" : "envelope", 4298*7c478bd9Sstevel@tonic-gate bitset(RF_SENDERADDR, tryflags) ? 4299*7c478bd9Sstevel@tonic-gate "sender" : "recipient"); 4300*7c478bd9Sstevel@tonic-gate if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 4301*7c478bd9Sstevel@tonic-gate == NULL) 4302*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4303*7c478bd9Sstevel@tonic-gate "Cannot parse\n"); 4304*7c478bd9Sstevel@tonic-gate else if (a.q_host != NULL && a.q_host[0] != '\0') 4305*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4306*7c478bd9Sstevel@tonic-gate "mailer %s, host %s, user %s\n", 4307*7c478bd9Sstevel@tonic-gate a.q_mailer->m_name, 4308*7c478bd9Sstevel@tonic-gate a.q_host, 4309*7c478bd9Sstevel@tonic-gate a.q_user); 4310*7c478bd9Sstevel@tonic-gate else 4311*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4312*7c478bd9Sstevel@tonic-gate "mailer %s, user %s\n", 4313*7c478bd9Sstevel@tonic-gate a.q_mailer->m_name, 4314*7c478bd9Sstevel@tonic-gate a.q_user); 4315*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 4316*7c478bd9Sstevel@tonic-gate } 4317*7c478bd9Sstevel@tonic-gate else 4318*7c478bd9Sstevel@tonic-gate { 4319*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4320*7c478bd9Sstevel@tonic-gate "Unknown \"/\" command %s\n", 4321*7c478bd9Sstevel@tonic-gate line); 4322*7c478bd9Sstevel@tonic-gate } 4323*7c478bd9Sstevel@tonic-gate return; 4324*7c478bd9Sstevel@tonic-gate } 4325*7c478bd9Sstevel@tonic-gate 4326*7c478bd9Sstevel@tonic-gate for (p = line; isascii(*p) && isspace(*p); p++) 4327*7c478bd9Sstevel@tonic-gate continue; 4328*7c478bd9Sstevel@tonic-gate q = p; 4329*7c478bd9Sstevel@tonic-gate while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4330*7c478bd9Sstevel@tonic-gate p++; 4331*7c478bd9Sstevel@tonic-gate if (*p == '\0') 4332*7c478bd9Sstevel@tonic-gate { 4333*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4334*7c478bd9Sstevel@tonic-gate "No address!\n"); 4335*7c478bd9Sstevel@tonic-gate return; 4336*7c478bd9Sstevel@tonic-gate } 4337*7c478bd9Sstevel@tonic-gate *p = '\0'; 4338*7c478bd9Sstevel@tonic-gate if (invalidaddr(p + 1, NULL, true)) 4339*7c478bd9Sstevel@tonic-gate return; 4340*7c478bd9Sstevel@tonic-gate do 4341*7c478bd9Sstevel@tonic-gate { 4342*7c478bd9Sstevel@tonic-gate register char **pvp; 4343*7c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 4344*7c478bd9Sstevel@tonic-gate 4345*7c478bd9Sstevel@tonic-gate pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, &delimptr, 4346*7c478bd9Sstevel@tonic-gate ConfigLevel >= 9 ? TokTypeNoC : NULL, false); 4347*7c478bd9Sstevel@tonic-gate if (pvp == NULL) 4348*7c478bd9Sstevel@tonic-gate continue; 4349*7c478bd9Sstevel@tonic-gate p = q; 4350*7c478bd9Sstevel@tonic-gate while (*p != '\0') 4351*7c478bd9Sstevel@tonic-gate { 4352*7c478bd9Sstevel@tonic-gate int status; 4353*7c478bd9Sstevel@tonic-gate 4354*7c478bd9Sstevel@tonic-gate rs = strtorwset(p, NULL, ST_FIND); 4355*7c478bd9Sstevel@tonic-gate if (rs < 0) 4356*7c478bd9Sstevel@tonic-gate { 4357*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4358*7c478bd9Sstevel@tonic-gate "Undefined ruleset %s\n", 4359*7c478bd9Sstevel@tonic-gate p); 4360*7c478bd9Sstevel@tonic-gate break; 4361*7c478bd9Sstevel@tonic-gate } 4362*7c478bd9Sstevel@tonic-gate status = REWRITE(pvp, rs, e); 4363*7c478bd9Sstevel@tonic-gate if (status != EX_OK) 4364*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4365*7c478bd9Sstevel@tonic-gate "== Ruleset %s (%d) status %d\n", 4366*7c478bd9Sstevel@tonic-gate p, rs, status); 4367*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p++ != ',') 4368*7c478bd9Sstevel@tonic-gate continue; 4369*7c478bd9Sstevel@tonic-gate } 4370*7c478bd9Sstevel@tonic-gate } while (*(p = delimptr) != '\0'); 4371*7c478bd9Sstevel@tonic-gate } 4372*7c478bd9Sstevel@tonic-gate 4373*7c478bd9Sstevel@tonic-gate static void 4374*7c478bd9Sstevel@tonic-gate dump_class(s, id) 4375*7c478bd9Sstevel@tonic-gate register STAB *s; 4376*7c478bd9Sstevel@tonic-gate int id; 4377*7c478bd9Sstevel@tonic-gate { 4378*7c478bd9Sstevel@tonic-gate if (s->s_symtype != ST_CLASS) 4379*7c478bd9Sstevel@tonic-gate return; 4380*7c478bd9Sstevel@tonic-gate if (bitnset(bitidx(id), s->s_class)) 4381*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4382*7c478bd9Sstevel@tonic-gate "%s\n", s->s_name); 4383*7c478bd9Sstevel@tonic-gate } 4384*7c478bd9Sstevel@tonic-gate 4385*7c478bd9Sstevel@tonic-gate /* 4386*7c478bd9Sstevel@tonic-gate ** An exception type used to create QuickAbort exceptions. 4387*7c478bd9Sstevel@tonic-gate ** This is my first cut at converting QuickAbort from longjmp to exceptions. 4388*7c478bd9Sstevel@tonic-gate ** These exceptions have a single integer argument, which is the argument 4389*7c478bd9Sstevel@tonic-gate ** to longjmp in the original code (either 1 or 2). I don't know the 4390*7c478bd9Sstevel@tonic-gate ** significance of 1 vs 2: the calls to setjmp don't care. 4391*7c478bd9Sstevel@tonic-gate */ 4392*7c478bd9Sstevel@tonic-gate 4393*7c478bd9Sstevel@tonic-gate const SM_EXC_TYPE_T EtypeQuickAbort = 4394*7c478bd9Sstevel@tonic-gate { 4395*7c478bd9Sstevel@tonic-gate SmExcTypeMagic, 4396*7c478bd9Sstevel@tonic-gate "E:mta.quickabort", 4397*7c478bd9Sstevel@tonic-gate "i", 4398*7c478bd9Sstevel@tonic-gate sm_etype_printf, 4399*7c478bd9Sstevel@tonic-gate "quick abort %0", 4400*7c478bd9Sstevel@tonic-gate }; 4401