1N/A * Copyright (c) 1998-2006, 2008, 2009, 2011 Sendmail, Inc. and its suppliers. 1N/A * All rights reserved. 1N/A * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 1N/A * Copyright (c) 1988, 1993 1N/A * The Regents of the University of California. All rights reserved. 1N/A * By using this file, you agree to the terms and conditions set 1N/A * forth in the LICENSE file which can be found at the top level of 1N/A * the sendmail distribution. 1N/A * Copyright 1996-2006 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A"@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\ 1N/A@(#) All rights reserved.\n\ 1N/A@(#) Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 1N/A@(#) Copyright (c) 1988, 1993\n\ 1N/A@(#) The Regents of the University of California. All rights reserved.\n\ 1N/A@(#) Copyright 1996-2006 Sun Microsystems, Inc. All rights reserved.\n\ 1N/A@(#) Use is subject to license terms.\n";
1N/A#
endif /* NETINET || NETINET6 */ 1N/A/* for getcfname() */ 1N/A "@(#)$Debug: no_persistent_restart - don't restart, log only $");
1N/A** SENDMAIL -- Post mail to a set of destinations. 1N/A** This is the basic mail router. All user mail programs should 1N/A** call this routine to actually deliver mail. Sendmail in 1N/A** turn calls a bunch of mail servers that do the real work of 1N/A** delivering the mail. 1N/A** See the associated documentation for details. 1N/A** Britton-Lee, Inc., purveyors of fine 1N/A** database computers (11/81 - 10/88). 1N/A** International Computer Science Institute 1N/A** InReference, Inc. (8/95 - 1/97). 1N/A** Sendmail, Inc. (1/98 - present). 1N/A** The support of my employers is gratefully acknowledged. 1N/A** Few of them (Britton-Lee in particular) have had 1N/A** anything to gain from my involvement in this project. 1N/A** Gregory Neil Shapiro, 1N/A** Worcester Polytechnic Institute (until 3/98). 1N/A** Sendmail, Inc. (3/98 - present). 1N/A** Sendmail, Inc. (12/98 - present). 1N/Astatic int MissingFds = 0;
/* bit map of fds missing on startup */ 1N/A#
endif /* NGROUPS_MAX */ 1N/A#
define PIDLEN 6 /* pid length for computing SyslogPrefixLen */ 1N/A#
define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */ 1N/A#
endif /* ! SL_FUDGE */ 1N/A#
define SLDLL 8 /* est. length of default syslog label */ 1N/A/* Some options are dangerous to allow users to use in non-submit mode */ 1N/A "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
1N/A "WARNING: Ignoring submission mode -%c option with -q\n", \
1N/A bool auth =
true;
/* whether to set e_auth_param */ 1N/A#
endif /* STARTTLS */ 1N/A#
endif /* USE_ENVIRON */ 1N/A /* turn off profiling */ 1N/A /* install default exception handler */ 1N/A /* set the default in/out channel so errors reported to screen */ 1N/A ** Check to see if we reentered. 1N/A ** This would normally happen if e_putheader or e_putbody 1N/A ** were NULL when invoked. 1N/A /* avoid null pointer dereferences */ 1N/A /* Check if sendmail is running with extra privs */ 1N/A /* get whatever .cf file is right for the opmode */ 1N/A /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 1N/A ** Be sure we have enough file descriptors. 1N/A ** But also be sure that 0, 1, & 2 are open. 1N/A /* reset errno and fill_errno; the latter is used way down below */ 1N/A#
endif /* ! SM_LOG_STR */ 1N/A#
else /* LOG_MAIL */ 1N/A#
endif /* LOG_MAIL */ 1N/A ** Seed the random number generator. 1N/A ** Used for queue file names, picking a queue directory, and 1N/A ** MX randomization. 1N/A /* do machine-dependent initializations */ 1N/A /* reset status from syserr() calls for missing file descriptors */ 1N/A#
endif /* NETINET6 */ 1N/A#
endif /* _FFR_LOCAL_DAEMON */ 1N/A /* save initial group set for future checks */ 1N/A#
endif /* NGROUPS_MAX */ 1N/A /* drop group id privileges (RunAsUser not yet set) */ 1N/A /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 1N/A /* arrange to dump state on user-1 signal */ 1N/A /* ignore user-1 signal */ 1N/A /* initialize for setproctitle */ 1N/A /* Handle any non-getoptable constructions. */ 1N/A ** Do a quick prescan of the argument list. 1N/A /* find initial opMode */ 1N/A#
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" 1N/A#
endif /* defined(__osf__) || defined(_AIX3) */ 1N/A#
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:" 1N/A#
endif /* defined(sony_news) */ 1N/A#
define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:" 1N/A#
endif /* ! OPTIONS */ 1N/A /* Set to 0 to allow -b; need to check optarg before using it! */ 1N/A case 'b':
/* operations mode */ 1N/A#
endif /* _FFR_CHECKCONFIG */ 1N/A#
endif /* _FFR_LOCAL_DAEMON */ 1N/A "Frozen configurations unsupported\n");
1N/A "Invalid operation mode %c\n",
1N/A case 'G':
/* relay (gateway) submission */ 1N/A "option requires an argument -- '%c'",
1N/A /* just check if it is there */ 1N/A /* Don't leak queue information via debug flags */ 1N/A "WARNING: Can not use -d with -q. Disabling debugging.\n");
1N/A /* Sanitize the string */ 1N/A#
else /* LOG_MAIL */ 1N/A#
endif /* LOG_MAIL */ 1N/A /* set up the blank envelope */ 1N/A ** Set default values for variables. 1N/A ** These cannot be in initialized data space. 1N/A ** if running non-set-user-ID binary as non-root, pretend 1N/A ** we are the RunAsUid 1N/A /* save command line arguments */ 1N/A#
endif /* _PATH_UNIX */ 1N/A /* clear sendmail's environment */ 1N/A ** restore any original TZ setting until TimeZoneSpec has been 1N/A ** determined - or early log messages may get bogus time stamps 1N/A /* XXX check for reasonable length? */ 1N/A /* XXX check return code? */ 1N/A /* prime the child environment */ 1N/A ** Initialize name server if it is going to be used. 1N/A#
endif /* RES_NOALIASES */ 1N/A#
endif /* NAMED_BIND */ 1N/A /* initialize some macros, etc. */ 1N/A#
endif /* NETINET6 */ 1N/A#
endif /* NETINET */ 1N/A#
endif /* NETINET */ 1N/A#
endif /* NETINET6 */ 1N/A#
endif /* NETINET || NETINET6 */ 1N/A#
endif /* NETINET6 */ 1N/A /* current load average */ 1N/A case 'b':
/* operations mode */ 1N/A case 'B':
/* body type */ 1N/A case 'C':
/* select configuration file (already done) */ 1N/A case 'd':
/* debugging */ 1N/A case 'f':
/* from address */ 1N/A case 'r':
/* obsolete -f flag */ 1N/A case 'F':
/* set full name */ 1N/A case 'G':
/* relay (gateway) submission */ 1N/A case 'h':
/* hop count */ 1N/A case 'L':
/* program label */ 1N/A case 'n':
/* don't alias */ 1N/A case 'N':
/* delivery status notifications */ 1N/A case 'o':
/* set option */ 1N/A case 'O':
/* set option (long form) */ 1N/A case 'p':
/* set protocol */ 1N/A case 'Q':
/* change quarantining on queued items */ 1N/A case 'q':
/* run queue files at intervals */ 1N/A /* don't override -bd, -bD or -bp */ 1N/A /* negate meaning of pattern match */ 1N/A case 'G':
/* Limit by queue group name */ 1N/A case 'I':
/* Limit by ID */ 1N/A case 'R':
/* Limit by recipient */ 1N/A case 'S':
/* Limit by sender */ 1N/A case 'f':
/* foreground queue run */ 1N/A case 'Q':
/* Limit by quarantine message */ 1N/A case 'L':
/* act on lost items */ 1N/A case 'p':
/* Persistent queue */ 1N/A /* check for bad conversion */ 1N/A case 'R':
/* DSN RET: what to return */ 1N/A case 't':
/* read recipients from message */ 1N/A case 'V':
/* DSN ENVID: set "original" envelope id */ 1N/A case 'X':
/* traffic log file */ 1N/A /* compatibility flags */ 1N/A case 'c':
/* connect to non-local mailers */ 1N/A case 'i':
/* don't let dot stop me */ 1N/A case 'm':
/* send to me too */ 1N/A case 'T':
/* set timeout interval */ 1N/A case 'v':
/* give blow-by-blow description */ 1N/A case 'e':
/* error message disposition */ 1N/A case 'M':
/* define macro */ 1N/A case 's':
/* save From lines in headers */ 1N/A case 'I':
/* initialize alias DBM file */ 1N/A case 'x':
/* random flag that OSF/1 & AIX mailx passes */ 1N/A#
endif /* defined(__osf__) || defined(_AIX3) */ 1N/A case 'J':
/* ignore flags for Japanese code conversion 1N/A implemented on Sony NEWS */ 1N/A#
endif /* defined(sony_news) */ 1N/A /* if we've had errors so far, exit now */ 1N/A /* If set daemon_flags on command line, don't reset it */ 1N/A /* If set daemon_flags on command line, don't reset it */ 1N/A ** Do basic initialization. 1N/A ** Read system control file. 1N/A ** Extract special fields for local use. 1N/A#
endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 1N/A /* now we can complain about missing fds */ 1N/A /* Notice: fill_errno is from high above: fill_fd() */ 1N/A "File descriptors missing on startup: %s; %s",
1N/A /* Remove the ability for a normal user to send signals */ 1N/A ** Since we can differentiate between uid and euid, 1N/A ** make the uid a different user so the real user 1N/A ** can't send signals. However, it doesn't need to be 1N/A ** root (euid has root). 1N/A#
else /* HASSETREUID */ 1N/A ** Have to change both effective and real so need to 1N/A ** change them both to effective to keep privs. 1N/A#
endif /* HASSETREUID */ 1N/A#
endif /* NAMED_BIND */ 1N/A "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n");
1N/A usrerr(
"Mail submission program cannot be used as daemon");
1N/A /* set up the basic signal handlers */ 1N/A /* Enforce use of local time (null string overrides this) */ 1N/A /* initialize mailbox database */ 1N/A usrerr(
"Can't initialize mailbox database \"%s\": %s",
1N/A /* avoid denial-of-service attacks */ 1N/A /* can't be done after readcf if RunAs* is used */ 1N/A usrerr(
"Mail submission program must have RunAsUser set to non root user");
1N/A#
endif /* NAMED_BIND */ 1N/A ** Find our real host name for future logging. 1N/A /* suppress error printing if errors mailed back or whatever */ 1N/A /* set up the $=m class now, after .cf has a chance to redefine $m */ 1N/A /* probe interfaces and locate any additional names */ 1N/A /* Now we know which .cf file we use */ 1N/A sm_dprintf(
"\n============ SYSTEM IDENTITY (after readcf) ============");
1N/A sm_dprintf(
"\n========================================================\n\n");
1N/A ** Do more command line checking -- these are things that 1N/A ** have to modify the results of reading the config file. 1N/A /* process authorization warnings from command line */ 1N/A /* check body type for legality */ 1N/A /* tweak default DSN notifications */ 1N/A /* check for sane configuration level */ 1N/A syserr(
"Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1N/A /* need MCI cache to have persistence */ 1N/A "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1N/A /* need HostStatusDir in order to have SingleThreadDelivery */ 1N/A "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1N/A "cannot get memory statistics, settings ignored, error=%d" 1N/A#
endif /* _FFR_MEMSTAT */ 1N/A /* check for permissions */ 1N/A /* Normal users can do a single queue run */ 1N/A /* but not persistent queue runners */ 1N/A "user %d attempted to %s",
1N/A usrerr(
"Permission denied (real uid not trusted)");
1N/A ** If -bv and RestrictExpand, 1N/A ** drop privs to prevent normal 1N/A ** users from reading private 1N/A sm_dprintf(
"Drop privs for user %d attempt to expand (RestrictExpand)\n",
1N/A /* Fake address safety */ 1N/A sm_dprintf(
"Failed to drop privs for user %d attempt to expand, exiting\n",
1N/A /* Nothing special to check */ 1N/A "user %d attempted to rebuild the alias map",
1N/A usrerr(
"Permission denied (real uid not trusted)");
1N/A usrerr(
"User %d cannot rebuild aliases in mail submission program",
1N/A ** If -v and RestrictExpand, reset 1N/A ** Verbose to prevent normal users 1N/A ** from seeing the expansion of 1N/A /* don't have persistent host status in test mode */ 1N/A /* arrange to exit cleanly on hangup signal */ 1N/A "Notice: -bv may give misleading output for non-privileged user\n");
1N/A /* remove things that don't make sense in daemon mode */ 1N/A /* arrange to restart on hangup signal */ 1N/A "daemon invoked without full pathname; kill -1 won't work");
1N/A /* arrange to exit cleanly on hangup signal */ 1N/A /* special considerations for FullName */ 1N/A /* full names can't have newlines */ 1N/A /* check for characters that may have to be quoted */ 1N/A ** Quote a full name with special characters 1N/A ** as a comment so crackaddr() doesn't destroy 1N/A ** the name portion of the address. 1N/A /* do heuristic mode adjustment */ 1N/A /* turn off noconnect option */ 1N/A /* turn on interactive delivery */ 1N/A /* check for vendor mismatch */ 1N/A message(
"Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1N/A#
endif /* VENDOR_CODE */ 1N/A /* check for out of date configuration level */ 1N/A message(
"Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1N/A /* set options that were previous macros */ 1N/A /* our name for SMTP codes */ 1N/A /* make certain that this name is part of the $=w class */ 1N/A /* fill in the structure of the *default* queue */ 1N/A /* the indices of built-in mailers */ 1N/A /* heuristic tweaking of local mailer for back compat */ 1N/A /* MIME Content-Types that cannot be transfer encoded */ 1N/A /* MIME Content-Transfer-Encodings that can be encoded */ 1N/A /* MIME Content-Types that should be treated as binary */ 1N/A#
endif /* USE_B_CLASS */ 1N/A /* MIME headers which have fields to check for overflow */ 1N/A /* MIME headers to check for length overflow */ 1N/A /* MIME headers to check for overflow and rebalance */ 1N/A /* Macros to save in the queue file -- don't remove any */ 1N/A /* operate in queue directory */ 1N/A syserr(
"QueueDirectory (Q) option must be set");
1N/A /* check host status directory for validity */ 1N/A /* cannot use this value */ 1N/A "Warning: Cannot use HostStatusDirectory = %s: %s\n",
1N/A /* check to see if we own the queue directory */ 1N/A /* nope, really a botch */ 1N/A usrerr(
"You do not have permission to process the queue");
1N/A /* sanity checks on milter filters */ 1N/A /* Convert queuegroup string to qgrp number */ 1N/A /* if checking config or have had errors so far, exit now */ 1N/A /* sendmail specific SASL initialization */ 1N/A ** Do operation-mode-dependent initialization. 1N/A /* print the queue */ 1N/A /* Selecting a particular queue group to run */ 1N/A /* print number of entries in queue */ 1N/A /* only handle quarantining here */ 1N/A /* initialize maps */ 1N/A /* reset DSN parameters */ 1N/A /* don't open maps for daemon -- done below in child */ 1N/A /* print configuration table (or at least part of it) */ 1N/A ** Switch to the main envelope. 1N/A ** If test mode, read addresses from stdin and process. 1N/A "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1N/A "Enter <ruleset> <address>\n");
1N/A ** 8.10 just prints \n on interrupt. 1N/A ** I'm printing the exception here in case 1N/A ** sendmail is extended to raise additional 1N/A ** exceptions in this context. 1N/A /* check whether STARTTLS is turned off for the client */ 1N/A /* check whether STARTTLS is turned off */ 1N/A else /* other modes don't need STARTTLS */ 1N/A /* basic TLS initialization */ 1N/A /* disable TLS for client */ 1N/A#
endif /* STARTTLS */ 1N/A ** If collecting stuff from the queue, go start doing that. 1N/A /* init TLS for client, ignore result for now */ 1N/A#
endif /* STARTTLS */ 1N/A ** The parent process of the caller of runqueue() needs 1N/A ** to stay around for a possible SIGTERM. The SIGTERM will 1N/A ** tell this process that all of the queue runners children 1N/A ** need to be sent SIGTERM as well. At the same time, we 1N/A ** want to return control to the command line. So we do an 1N/A ** If the fork() failed we should still try to do 1N/A ** the queue run. If it succeeded then the child 1N/A ** is going to start the run and wait for all 1N/A ** of the children to finish. 1N/A /* Reset global flags */ 1N/A /* disconnect from terminal */ 1N/A ** To run a specific queue group mark it to 1N/A ** be run, select the work group it's in and 1N/A ** increment the work counter. 1N/A /* set the title to make it easier to find */ 1N/A ** Oops... something got messed 1N/A ** up really bad. Waiting for 1N/A ** non-existent children 1N/A ** shouldn't happen. Let's get 1N/A /* something is really really wrong */ 1N/A "queue control process: lost all children: wait returned ECHILD");
1N/A /* Only drop when a child gives status */ 1N/A /* check whether AUTH is turned off for the server */ 1N/A /* clean up background delivery children */ 1N/A ** If a daemon, wait for a request. 1N/A ** getrequests will always return in a child. 1N/A ** If we should also be processing the queue, start 1N/A ** doing it in background. 1N/A ** We check for any errors that might have happened 1N/A /* avoid cleanup in finis(), DaemonPid will be set below */ 1N/A /* put us in background */ 1N/A ** Initialize exception stack and default exception 1N/A ** handler for child process. 1N/A /* Reset global flags */ 1N/A /* disconnect from our controlling tty */ 1N/A ?
"+persistent-queueing@" 1N/A /* save daemon type in a macro for possible PidFile use */ 1N/A /* save queue interval in a macro for possible PidFile use */ 1N/A /* workaround: can't seem to release the signal in the parent */ 1N/A ** To run a specific queue group mark it to 1N/A ** be run, select the work group it's in and 1N/A ** increment the work counter. 1N/A#
endif /* _FFR_RUNPQG */ 1N/A ** If queuepersistent but not in daemon mode then 1N/A ** we're going to do the queue runner monitoring here. 1N/A ** If in daemon mode then the monitoring will happen 1N/A ** Write the pid to file 1N/A ** XXX Overwrites sendmail.pid 1N/A /* set the title to make it easier to find */ 1N/A ** Waiting for non-existent 1N/A ** children shouldn't happen. 1N/A ** Let's get out of here if 1N/A /* something is really really wrong */ 1N/A "persistent queue runner control process: lost all children: wait returned ECHILD");
1N/A /* Probe only on a child status */ 1N/A "persistent queue runner=%d core dumped, signal=%d",
1N/A /* don't restart this */ 1N/A "persistent queue runner=%d died, pid=%ld, signal=%d",
1N/A ** When debugging active, don't 1N/A ** restart the persistent queues. 1N/A ** But do log this as info. 1N/A "persistent queue runner=%d, exited",
1N/A ** Write the pid to file 1N/A ** XXX Overwrites sendmail.pid 1N/A /* set the title to make it easier to find */ 1N/A /* init TLS for server, ignore result for now */ 1N/A#
endif /* STARTTLS */ 1N/A /* drop privileges */ 1N/A ** Get authentication data 1N/A ** Set _ macro in BlankEnvelope before calling newenvelope(). 1N/A /* at this point we are in a child: reset state */ 1N/A /* log connection information */ 1N/A ** If running SMTP protocol, start collecting and executing 1N/A ** commands. This will never return. 1N/A ** Save some macros for check_* rulesets. 1N/A#
endif /* NETINET6 */ 1N/A /* validate the connection */ 1N/A#
endif /* STARTTLS */ 1N/A /* turn off profiling */ 1N/A /* turn off profiling */ 1N/A /* interactive -- all errors are global */ 1N/A ** Do basic system initialization and set the sender 1N/A /* set the initial sender for AUTH= to $f@$j */ 1N/A /* collect body for UUCP return */ 1N/A ** Scan argv and deliver the message to everyone. 1N/A /* if we have had errors sofar, arrange a meaningful exit stat */ 1N/A ** If using -t, force not sending to argv recipients, even 1N/A ** if they are mentioned in the headers. 1N/A#
endif /* _FFR_FIX_DASHT */ 1N/A ** Read the input mail. 1N/A ** workaround for compiler warning on Irix: 1N/A ** do not initialize variable in the definition, but 1N/A ** warning(1548): transfer of control bypasses 1N/A ** initialization of: 1N/A ** variable "savederrors" (declared at line 2570) 1N/A ** variable "savedflags" (declared at line 2571) 1N/A /* header checks failed */ 1N/A /* Log who the mail would have gone to */ 1N/A /* bail out if message too large */ 1N/A /* set message size */ 1N/A /* Check if quarantining stats should be updated */ 1N/A ** Actually send everything. 1N/A ** If verifying, just ack. 1N/A /* make sure we deliver at least the first envelope */ 1N/A#
endif /* NAMED_BIND */ 1N/A /* after FastSplit envelopes: queue up */ 1N/A ** Don't send return error message if in VERIFY mode. 1N/A** STOP_SENDMAIL -- Stop the running program 1N/A /* reset uid for process accounting */ 1N/A** FINIS -- Clean up and exit. 1N/A** drop -- whether or not to drop CurEnv envelope 1N/A** cleanup -- call exit() or _exit()? 1N/A** exitstat -- exit status to use for exit() call 1N/A /* Still want to process new timeouts added below */ 1N/A ** Clean up. This might raise E:mta.quickabort 1N/A /* clean up temp files */ 1N/A /* these may have pointed to the rpool */ 1N/A /* flush any cached connections */ 1N/A /* close maps belonging to this pid */ 1N/A /* close UserDatabase */ 1N/A /* clean up extended load average stuff */ 1N/A /* XXX clean up queues and related data structures */ 1N/A#
endif /* SM_CONF_SHM */ 1N/A /* close locked pid file */ 1N/A /* blow away the pid file */ 1N/A /* reset uid for process accounting */ 1N/A#
endif /* _FFR_MEMSTAT */ 1N/A /* dump the heap, if we are checking for memory leaks */ 1N/A#
endif /* SM_HEAP_CHECK */ 1N/A** INTINDEBUG -- signal handler for SIGINT in -bt mode 1N/A** sig -- incoming signal. 1N/A** longjmps back to test mode loop. 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A/* Type of an exception generated on SIGINT during address test mode. */ 1N/A** SIGTERM -- SIGTERM handler for the daemon 1N/A** sig -- signal number. 1N/A** Sets ShutdownRequest which will hopefully trigger 1N/A** the daemon to exit. 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A** SIGHUP -- handle a SIGHUP signal 1N/A** sig -- incoming signal. 1N/A** Sets RestartRequest which should cause the daemon 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A** SIGPIPE -- signal handler for SIGPIPE 1N/A** sig -- incoming signal. 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A** INTSIG -- clean up on interrupt 1N/A** This just arranges to exit. It pessimizes in that it 1N/A** may resend a message. 1N/A** sig -- incoming signal. 1N/A** Unlocks the current job. 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A /* Clean-up on aborted stdin message submission */ 1N/A** DISCONNECT -- remove our connection with any foreground process 1N/A** droplev -- how "deeply" we should drop the line. 1N/A** 0 -- ignore signals, mail back errors, make sure 1N/A** output goes to stdout. 1N/A** 2 -- also, disconnect from controlling terminal 1N/A** (only for daemon mode). 1N/A** e -- the current envelope. 1N/A** Trys to insure that we are immune to vagaries of 1N/A** the controlling tty. 1N/A "disconnect level %d",
1N/A /* be sure we don't get nasty signals */ 1N/A /* we can't communicate with our caller, so.... */ 1N/A "disconnect: sm_io_reopen(\"%s\") failed: %s",
1N/A ** output to the transcript 1N/A ** We also compare the fd numbers here since OutChannel 1N/A ** might be a layer on top of smioout due to encryption 1N/A ** Has smioout been closed? Reopen it. 1N/A ** This shouldn't happen anymore, the code is here 1N/A ** just as a reminder. 1N/A "disconnect: sm_io_reopen(\"%s\") failed: %s",
1N/A "disconnect: open(\"%s\") failed: %s",
1N/A /* drop our controlling TTY completely if possible */ 1N/A /* Return if "--" or not an option of any form. */ 1N/A /* Don't allow users to use "-Q." or "-Q ." */ 1N/A if ((
ap[
1] ==
'Q' &&
ap[
2] ==
'.') ||
1N/A "Can not use -Q.\n");
1N/A /* skip over options that do have a value */ 1N/A#
endif /* defined(sony_news) */ 1N/A /* If -q doesn't have an argument, run it once. */ 1N/A /* If -Q doesn't have an argument, disable quarantining */ 1N/A /* if -d doesn't have an argument, use 0-99.1 */ 1N/A /* if -E doesn't have an argument, use -EC */ 1N/A /* if -J doesn't have an argument, use -JJ */ 1N/A#
endif /* defined(sony_news) */ 1N/A** AUTH_WARNING -- specify authorization warning 1N/A** e -- the current envelope. 1N/A** msg -- the text of the message. 1N/A** args -- arguments to the message. 1N/A#
endif /* __STDC__ */ 1N/A#
endif /* NETINET6 */ 1N/A "Authentication-Warning: %.400s",
1N/A** GETEXTENV -- get from external environment 1N/A** envar -- the name of the variable to retrieve 1N/A** The value, if any. 1N/A** SM_SETUSERENV -- set an environment variable in the propagated environment 1N/A** envar -- the name of the environment variable. 1N/A** value -- the value to which it should be set. If 1N/A** null, this is extracted from the incoming 1N/A** environment. If that is not set, the call 1N/A** to sm_setuserenv is ignored. 1N/A /* XXX enforce reasonable size? */ 1N/A /* make sure it is in our environment as well */ 1N/A syserr(
"sm_setuserenv: putenv(%s) failed", p);
1N/A** DUMPSTATE -- dump state 1N/A "--- dumping state on %s: $j = %s ---",
1N/A "*** $j not in $=w ***");
1N/A "--- ruleset debug_dumpstate returns stat %d, pv: ---",
1N/A** SIGUSR1 -- Signal a request to dump state. 1N/A** sig -- calling signal. 1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1N/A** XXX: More work is needed for this signal handler. 1N/A#
endif /* SM_HEAP_CHECK */ 1N/A** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 1N/A** to_real_uid -- if set, drop to the real uid instead 1N/A** EX_OSERR if the setuid failed. 1N/A 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",
1N/A /* make sure no one can grab open descriptors for secret files */ 1N/A /* reset group permissions; these can be set later */ 1N/A ** Notice: on some OS (Linux...) the setgroups() call causes 1N/A ** a logfile entry if sendmail is not run by root. 1N/A ** However, it is unclear (no POSIX standard) whether 1N/A ** setgroups() can only succeed if executed by root. 1N/A ** So for now we keep it as it is; if you want to change it, use 1N/A ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 1N/A syserr(
"drop_privileges: setgroups(1, %d) failed",
1N/A /* reset primary group id */ 1N/A ** Drop gid to real gid. 1N/A ** On some OS we must reset the effective[/real[/saved]] gid, 1N/A ** and then use setgid() to finally drop all group privileges. 1N/A ** Later on we check whether we can get back the 1N/A syserr(
"drop_privileges: setegid(%d) failed",
1N/A#
else /* HASSETEGID */ 1N/A syserr(
"drop_privileges: setregid(%d, %d) failed",
1N/A#
else /* HASSETREGID */ 1N/A syserr(
"drop_privileges: setresgid(%d, %d, %d) failed",
1N/A#
endif /* HASSETRESGID */ 1N/A#
endif /* HASSETREGID */ 1N/A#
endif /* HASSETEGID */ 1N/A syserr(
"drop_privileges: Unable to set effective gid=%d to RunAsGid=%d",
1N/A /* fiddle with uid */ 1N/A ** Try to setuid(RunAsUid). 1N/A ** euid must be RunAsUid, 1N/A ** ruid must be RunAsUid unless (e|r)uid wasn't 0 1N/A ** and we didn't have to drop privileges to the real uid. 1N/A ** if ruid != RunAsUid, euid == RunAsUid, then 1N/A ** try resetting just the real uid, then using 1N/A ** setuid() to drop the saved-uid as well. 1N/A syserr(
"drop_privileges: setreuid(%d, -1) failed",
1N/A syserr(
"drop_privileges: second setuid(%d) attempt failed",
1N/A#
endif /* HASSETREUID */ 1N/A ** Believe it or not, the Linux capability model 1N/A ** allows a non-root process to override setuid() 1N/A ** on a process running as root and prevent that 1N/A ** process from dropping privileges. 1N/A syserr(
"drop_privileges: setuid(0) succeeded (when it should not)");
1N/A ** Some operating systems will keep the saved-uid 1N/A ** if a non-root effective-uid calls setuid(real-uid) 1N/A ** making it possible to set it back again later. 1N/A syserr(
"drop_privileges: Unable to drop non-root set-user-ID privileges");
1N/A syserr(
"drop_privileges: setgid(%d) succeeded (when it should not)",
1N/A** FILL_FD -- make sure a file descriptor has been properly allocated 1N/A** fd -- the file descriptor to be filled. 1N/A** where -- a string used for logging. If NULL, this is 1N/A** being called on startup, and logging should 1N/A** possibly changes MissingFds 1N/A** SM_PRINTOPTIONS -- print options 1N/A** options -- array of options. 1N/A** TO8BIT -- convert \octal sequences in a test mode input line 1N/A** str -- the input line. 1N/A** replaces \0octal in str with octal value. 1N/A while ((c = (*
str++ & 0
377)) !=
'\0')
1N/A** TESTMODELINE -- process a test mode input line 1N/A** line -- the input line. 1N/A** e -- the current environment. 1N/A** .X process X as a configuration line 1N/A** =X dump a configuration item (such as mailers) 1N/A** $X dump a macro or class 1N/A** /X try an activity 1N/A** X normal process through rule set X 1N/A /* skip leading spaces */ 1N/A case '.':
/* config-style settings */ 1N/A if (
line[
2] ==
'\0')
/* not to call syserr() */ 1N/A "Usage: .[DC]macro value(s)\n");
1N/A "Unknown \".\" command %s\n",
line);
1N/A case '=':
/* config-style settings */ 1N/A case 'S':
/* dump rule set */ 1N/A "Undefined ruleset %s\n", &
line[
2]);
1N/A "Usage: =Sruleset or =M\n");
1N/A "Unknown \"=\" command %s\n",
line);
1N/A case '-':
/* set command-line-like opts */ 1N/A "Usage: -d{debug arguments}\n");
1N/A "Unknown \"-\" command %s\n",
line);
1N/A case '/':
/* miscellaneous commands */ 1N/A "Usage: /[canon|map|mx|parse|try|tryflags]\n");
1N/A /* look up MX records */ 1N/A "Usage: /mx address\n");
1N/A "getmxrr(%s) returns %d value(s):\n",
1N/A#
else /* NAMED_BIND */ 1N/A "No MX code compiled in\n");
1N/A#
endif /* NAMED_BIND */ 1N/A "Usage: /canon address\n");
1N/A "getcanonname(%s) returns %s\n",
1N/A "Usage: /map mapname key\n");
1N/A "No key specified\n");
1N/A "Map named \"%s\" not found\n", p);
1N/A "Map named \"%s\" not open\n", p);
1N/A "map_lookup: %s (%s) ", p, q);
1N/A "returns %s (%d)\n", p,
1N/A "Usage: /try mailer address\n");
1N/A "Unknown mailer %s\n", p);
1N/A "Trying %s %s address %s for mailer %s\n",
1N/A :
"recipient", q, p);
1N/A "Rcode = %d, addr = %s\n",
1N/A "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
1N/A for (; *p !=
'\0'; p++)
1N/A "Usage: /parse address\n");
1N/A "Cracked address = ");
1N/A "\nParsing %s %s address\n",
1N/A "header" :
"envelope",
1N/A "sender" :
"recipient");
1N/A "mailer %s, host %s, user %s\n",
1N/A "mailer %s, user %s\n",
1N/A "Unknown \"/\" command %s\n",
1N/A "Undefined ruleset %s\n",
1N/A "== Ruleset %s (%d) status %d\n",
1N/A while (*p !=
'\0' && *p++ !=
',')
1N/A** An exception type used to create QuickAbort exceptions. 1N/A** This is my first cut at converting QuickAbort from longjmp to exceptions. 1N/A** These exceptions have a single integer argument, which is the argument 1N/A** to longjmp in the original code (either 1 or 2). I don't know the 1N/A** significance of 1 vs 2: the calls to setjmp don't care.