📄 main.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\
Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
static char id[] = "@(#)$Id: main.c,v 8.485.4.27 2000/09/26 01:30:38 gshapiro Exp $";
#endif /* ! lint */
#define _DEFINE
#include <sendmail.h>
#if NETINET || NETINET6
# include <arpa/inet.h>
#endif /* NETINET || NETINET6 */
static void dump_class __P((STAB *, int));
static void obsolete __P((char **));
static void testmodeline __P((char *, ENVELOPE *));
/*
** SENDMAIL -- Post mail to a set of destinations.
**
** This is the basic mail router. All user mail programs should
** call this routine to actually deliver mail. Sendmail in
** turn calls a bunch of mail servers that do the real work of
** delivering the mail.
**
** Sendmail is driven by settings read in from /etc/mail/sendmail.cf
** (read by readcf.c).
**
** Usage:
** /usr/lib/sendmail [flags] addr ...
**
** See the associated documentation for details.
**
** Author:
** Eric Allman, UCB/INGRES (until 10/81).
** Britton-Lee, Inc., purveyors of fine
** database computers (11/81 - 10/88).
** International Computer Science Institute
** (11/88 - 9/89).
** UCB/Mammoth Project (10/89 - 7/95).
** InReference, Inc. (8/95 - 1/97).
** Sendmail, Inc. (1/98 - present).
** The support of the my employers is gratefully acknowledged.
** Few of them (Britton-Lee in particular) have had
** anything to gain from my involvement in this project.
*/
int NextMailer; /* "free" index into Mailer struct */
char *FullName; /* sender's full name */
ENVELOPE BlankEnvelope; /* a "blank" envelope */
static ENVELOPE MainEnvelope; /* the envelope around the basic letter */
ADDRESS NullAddress = /* a null address */
{ "", "", NULL, "" };
char *CommandLineArgs; /* command line args for pid file */
bool Warn_Q_option = FALSE; /* warn about Q option use */
char **SaveArgv; /* argument vector for re-execing */
static int MissingFds = 0; /* bit map of fds missing on startup */
#ifdef NGROUPS_MAX
GIDSET_T InitialGidSet[NGROUPS_MAX];
#endif /* NGROUPS_MAX */
#if DAEMON && !SMTP
ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR
#endif /* DAEMON && !SMTP */
#if SMTP && !QUEUE
ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR
#endif /* SMTP && !QUEUE */
#define MAXCONFIGLEVEL 9 /* highest config version level known */
#if SASL
static sasl_callback_t srvcallbacks[] =
{
{ SASL_CB_VERIFYFILE, &safesaslfile, NULL },
{ SASL_CB_PROXY_POLICY, &proxy_policy, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
#endif /* SASL */
int SubmitMode;
int
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
register char *p;
char **av;
extern char Version[];
char *ep, *from;
STAB *st;
register int i;
int j;
int dp;
bool safecf = TRUE;
BITMAP256 *p_flags = NULL; /* daemon flags */
bool warn_C_flag = FALSE;
bool auth = TRUE; /* whether to set e_auth_param */
char warn_f_flag = '\0';
bool run_in_foreground = FALSE; /* -bD mode */
static bool reenter = FALSE;
struct passwd *pw;
struct hostent *hp;
char *nullserver = NULL;
char *authinfo = NULL;
char *sysloglabel = NULL; /* label for syslog */
bool forged;
struct stat traf_st; /* for TrafficLog FIFO check */
char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
static char rnamebuf[MAXNAME]; /* holds RealUserName */
char *emptyenviron[1];
# if STARTTLS
bool tls_ok;
# endif /* STARTTLS */
QUEUE_CHAR *new;
extern int DtableSize;
extern int optind;
extern int opterr;
extern char *optarg;
extern char **environ;
/*
** Check to see if we reentered.
** This would normally happen if e_putheader or e_putbody
** were NULL when invoked.
*/
if (reenter)
{
syserr("main: reentered!");
abort();
}
reenter = TRUE;
/* avoid null pointer dereferences */
TermEscape.te_rv_on = TermEscape.te_rv_off = "";
/* do machine-dependent initializations */
init_md(argc, argv);
/* in 4.4BSD, the table can be huge; impose a reasonable limit */
DtableSize = getdtsize();
if (DtableSize > 256)
DtableSize = 256;
/*
** Be sure we have enough file descriptors.
** But also be sure that 0, 1, & 2 are open.
*/
fill_fd(STDIN_FILENO, NULL);
fill_fd(STDOUT_FILENO, NULL);
fill_fd(STDERR_FILENO, NULL);
i = DtableSize;
while (--i > 0)
{
if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
(void) close(i);
}
errno = 0;
#if LOG
# ifdef LOG_MAIL
openlog("sendmail", LOG_PID, LOG_MAIL);
# else /* LOG_MAIL */
openlog("sendmail", LOG_PID);
# endif /* LOG_MAIL */
#endif /* LOG */
if (MissingFds != 0)
{
char mbuf[MAXLINE];
mbuf[0] = '\0';
if (bitset(1 << STDIN_FILENO, MissingFds))
(void) strlcat(mbuf, ", stdin", sizeof mbuf);
if (bitset(1 << STDOUT_FILENO, MissingFds))
(void) strlcat(mbuf, ", stdout", sizeof mbuf);
if (bitset(1 << STDERR_FILENO, MissingFds))
(void) strlcat(mbuf, ", stderr", sizeof mbuf);
syserr("File descriptors missing on startup: %s", &mbuf[2]);
}
/* reset status from syserr() calls for missing file descriptors */
Errors = 0;
ExitStat = EX_OK;
SubmitMode = SUBMIT_UNKNOWN;
#if XDEBUG
checkfd012("after openlog");
#endif /* XDEBUG */
/*
** Seed the random number generator.
** Used for queue file names, picking a queue directory, and
** MX randomization.
*/
seed_random();
tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
#ifdef NGROUPS_MAX
/* save initial group set for future checks */
i = getgroups(NGROUPS_MAX, InitialGidSet);
if (i == 0)
InitialGidSet[0] = (GID_T) -1;
while (i < NGROUPS_MAX)
InitialGidSet[i++] = InitialGidSet[0];
#endif /* NGROUPS_MAX */
/* drop group id privileges (RunAsUser not yet set) */
dp = drop_privileges(FALSE);
setstat(dp);
# ifdef SIGUSR1
/* arrange to dump state on user-1 signal */
(void) setsignal(SIGUSR1, sigusr1);
# endif /* SIGUSR1 */
/* initialize for setproctitle */
initsetproctitle(argc, argv, envp);
/* Handle any non-getoptable constructions. */
obsolete(argv);
/*
** Do a quick prescan of the argument list.
*/
#if defined(__osf__) || defined(_AIX3)
# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x"
#endif /* defined(__osf__) || defined(_AIX3) */
#if defined(sony_news)
# define OPTIONS "B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
#endif /* defined(sony_news) */
#ifndef OPTIONS
# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
#endif /* ! OPTIONS */
opterr = 0;
while ((j = getopt(argc, argv, OPTIONS)) != -1)
{
switch (j)
{
case 'd':
/* hack attack -- see if should use ANSI mode */
if (strcmp(optarg, "ANSI") == 0)
{
TermEscape.te_rv_on = "\033[7m";
TermEscape.te_rv_off = "\033[0m";
break;
}
tTflag(optarg);
setbuf(stdout, (char *) NULL);
break;
case 'G': /* relay (gateway) submission */
SubmitMode |= SUBMIT_MTA;
break;
case 'L':
j = min(strlen(optarg), 24) + 1;
sysloglabel = xalloc(j);
(void) strlcpy(sysloglabel, optarg, j);
break;
case 'U': /* initial (user) submission */
SubmitMode |= SUBMIT_MSA;
break;
}
}
opterr = 1;
if (sysloglabel != NULL)
{
#if LOG
closelog();
# ifdef LOG_MAIL
openlog(sysloglabel, LOG_PID, LOG_MAIL);
# else /* LOG_MAIL */
openlog(sysloglabel, LOG_PID);
# endif /* LOG_MAIL */
#endif /* LOG */
}
/* set up the blank envelope */
BlankEnvelope.e_puthdr = putheader;
BlankEnvelope.e_putbody = putbody;
BlankEnvelope.e_xfp = NULL;
STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
CurEnv = &BlankEnvelope;
STRUCTCOPY(NullAddress, MainEnvelope.e_from);
/*
** Set default values for variables.
** These cannot be in initialized data space.
*/
setdefaults(&BlankEnvelope);
RealUid = getuid();
RealGid = getgid();
pw = sm_getpwuid(RealUid);
if (pw != NULL)
(void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
else
(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
(int) RealUid);
RealUserName = rnamebuf;
if (tTd(0, 101))
{
dprintf("Version %s\n", Version);
finis(FALSE, EX_OK);
}
/*
** if running non-setuid binary as non-root, pretend
** we are the RunAsUid
*/
if (RealUid != 0 && geteuid() == RealUid)
{
if (tTd(47, 1))
dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n",
(int)RealUid);
RunAsUid = RealUid;
}
else if (geteuid() != 0)
RunAsUid = geteuid();
if (RealUid != 0 && getegid() == RealGid)
RunAsGid = RealGid;
if (tTd(47, 5))
{
dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
(int)geteuid(), (int)getuid(),
(int)getegid(), (int)getgid());
dprintf("main: RunAsUser = %d:%d\n",
(int)RunAsUid, (int)RunAsGid);
}
/* save command line arguments */
j = 0;
for (av = argv; *av != NULL; )
j += strlen(*av++) + 1;
SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
CommandLineArgs = xalloc(j);
p = CommandLineArgs;
for (av = argv, i = 0; *av != NULL; )
{
int h;
SaveArgv[i++] = newstr(*av);
if (av != argv)
*p++ = ' ';
(void) strlcpy(p, *av++, j);
h = strlen(p);
p += h;
j -= h + 1;
}
SaveArgv[i] = NULL;
if (tTd(0, 1))
{
int ll;
extern char *CompileOptions[];
dprintf("Version %s\n Compiled with:", Version);
av = CompileOptions;
ll = 7;
while (*av != NULL)
{
if (ll + strlen(*av) > 63)
{
dprintf("\n");
ll = 0;
}
if (ll == 0)
dprintf("\t\t");
else
dprintf(" ");
dprintf("%s", *av);
ll += strlen(*av++) + 1;
}
dprintf("\n");
}
if (tTd(0, 10))
{
int ll;
extern char *OsCompileOptions[];
dprintf(" OS Defines:");
av = OsCompileOptions;
ll = 7;
while (*av != NULL)
{
if (ll + strlen(*av) > 63)
{
dprintf("\n");
ll = 0;
}
if (ll == 0)
dprintf("\t\t");
else
dprintf(" ");
dprintf("%s", *av);
ll += strlen(*av++) + 1;
}
dprintf("\n");
#ifdef _PATH_UNIX
dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
#endif /* _PATH_UNIX */
dprintf(" Def Conf file:\t%s\n", getcfname());
dprintf(" Def Pid file:\t%s\n", PidFile);
}
InChannel = stdin;
OutChannel = stdout;
/* clear sendmail's environment */
ExternalEnviron = environ;
emptyenviron[0] = NULL;
environ = emptyenviron;
/*
** restore any original TZ setting until TimeZoneSpec has been
** determined - or early log messages may get bogus time stamps
*/
if ((p = getextenv("TZ")) != NULL)
{
char *tz;
int tzlen;
tzlen = strlen(p) + 4;
tz = xalloc(tzlen);
(void) snprintf(tz, tzlen, "TZ=%s", p);
(void) putenv(tz);
}
/* prime the child environment */
setuserenv("AGENT", "sendmail");
if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
(void) setsignal(SIGINT, intsig);
(void) setsignal(SIGTERM, intsig);
(void) setsignal(SIGPIPE, SIG_IGN);
OldUmask = umask(022);
OpMode = MD_DELIVER;
FullName = getextenv("NAME");
/*
** Initialize name server if it is going to be used.
*/
#if NAMED_BIND
if (!bitset(RES_INIT, _res.options))
(void) res_init();
/*
** hack to avoid crashes when debugging for the resolver is
** turned on and sfio is used
*/
if (tTd(8, 8))
# if !SFIO || SFIO_STDIO_COMPAT
_res.options |= RES_DEBUG;
# else /* !SFIO || SFIO_STDIO_COMPAT */
dprintf("RES_DEBUG not available due to SFIO\n");
# endif /* !SFIO || SFIO_STDIO_COMPAT */
else
_res.options &= ~RES_DEBUG;
# ifdef RES_NOALIASES
_res.options |= RES_NOALIASES;
# endif /* RES_NOALIASES */
TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
#endif /* NAMED_BIND */
errno = 0;
from = NULL;
/* initialize some macros, etc. */
initmacros(CurEnv);
init_vendor_macros(CurEnv);
/* version */
define('v', Version, CurEnv);
/* hostname */
hp = myhostname(jbuf, sizeof jbuf);
if (jbuf[0] != '\0')
{
struct utsname utsname;
if (tTd(0, 4))
dprintf("canonical name: %s\n", jbuf);
define('w', newstr(jbuf), CurEnv); /* must be new string */
define('j', newstr(jbuf), CurEnv);
setclass('w', jbuf);
p = strchr(jbuf, '.');
if (p != NULL)
{
if (p[1] != '\0')
{
define('m', newstr(&p[1]), CurEnv);
}
while (p != NULL && strchr(&p[1], '.') != NULL)
{
*p = '\0';
if (tTd(0, 4))
dprintf("\ta.k.a.: %s\n", jbuf);
setclass('w', jbuf);
*p++ = '.';
p = strchr(p, '.');
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -