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