📄 main.c
字号:
usrerr("Illegal body type %s", CurEnv->e_bodytype);
CurEnv->e_bodytype = NULL;
}
/* tweak default DSN notifications */
if (DefaultNotify == 0)
DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
/* be sure we don't pick up bogus HOSTALIASES environment variable */
if (OpMode == MD_QUEUERUN && RealUid != 0)
(void) unsetenv("HOSTALIASES");
/* check for sane configuration level */
if (ConfigLevel > MAXCONFIGLEVEL)
{
syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
ConfigLevel, Version, MAXCONFIGLEVEL);
}
/* need MCI cache to have persistence */
if (HostStatDir != NULL && MaxMciCache == 0)
{
HostStatDir = NULL;
printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
}
/* need HostStatusDir in order to have SingleThreadDelivery */
if (SingleThreadDelivery && HostStatDir == NULL)
{
SingleThreadDelivery = FALSE;
printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
}
/* check for permissions */
if ((OpMode == MD_DAEMON ||
OpMode == MD_FGDAEMON ||
OpMode == MD_PURGESTAT) &&
RealUid != 0 &&
RealUid != TrustedUid)
{
if (LogLevel > 1)
sm_syslog(LOG_ALERT, NOQID,
"user %d attempted to %s",
RealUid,
OpMode != MD_PURGESTAT ? "run daemon"
: "purge host status");
usrerr("Permission denied");
finis(FALSE, EX_USAGE);
}
if (OpMode == MD_INITALIAS &&
RealUid != 0 &&
RealUid != TrustedUid &&
!wordinclass(RealUserName, 't'))
{
if (LogLevel > 1)
sm_syslog(LOG_ALERT, NOQID,
"user %d attempted to rebuild the alias map",
RealUid);
usrerr("Permission denied");
finis(FALSE, EX_USAGE);
}
if (MeToo)
BlankEnvelope.e_flags |= EF_METOO;
switch (OpMode)
{
case MD_TEST:
/* don't have persistent host status in test mode */
HostStatDir = NULL;
if (Verbose == 0)
Verbose = 2;
CurEnv->e_errormode = EM_PRINT;
HoldErrs = FALSE;
break;
case MD_VERIFY:
CurEnv->e_errormode = EM_PRINT;
HoldErrs = FALSE;
/* arrange to exit cleanly on hangup signal */
if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
(void) setsignal(SIGHUP, intsig);
break;
case MD_FGDAEMON:
run_in_foreground = TRUE;
OpMode = MD_DAEMON;
/* FALLTHROUGH */
case MD_DAEMON:
vendor_daemon_setup(CurEnv);
/* remove things that don't make sense in daemon mode */
FullName = NULL;
GrabTo = FALSE;
/* arrange to restart on hangup signal */
if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
sm_syslog(LOG_WARNING, NOQID,
"daemon invoked without full pathname; kill -1 won't work");
(void) setsignal(SIGHUP, sighup);
/* workaround: can't seem to release the signal in the parent */
(void) releasesignal(SIGHUP);
break;
case MD_INITALIAS:
Verbose = 2;
CurEnv->e_errormode = EM_PRINT;
HoldErrs = FALSE;
/* FALLTHROUGH */
default:
/* arrange to exit cleanly on hangup signal */
if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
(void) setsignal(SIGHUP, intsig);
break;
}
/* special considerations for FullName */
if (FullName != NULL)
{
char *full = NULL;
/* full names can't have newlines */
if (strchr(FullName, '\n') != NULL)
{
FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
}
/* check for characters that may have to be quoted */
if (!rfc822_string(FullName))
{
/*
** Quote a full name with special characters
** as a comment so crackaddr() doesn't destroy
** the name portion of the address.
*/
FullName = addquotes(FullName);
if (full != NULL)
free(full);
}
}
/* do heuristic mode adjustment */
if (Verbose)
{
/* turn off noconnect option */
setoption('c', "F", TRUE, FALSE, CurEnv);
/* turn on interactive delivery */
setoption('d', "", TRUE, FALSE, CurEnv);
}
#ifdef VENDOR_CODE
/* check for vendor mismatch */
if (VendorCode != VENDOR_CODE)
{
message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
getvendor(VENDOR_CODE), getvendor(VendorCode));
}
#endif /* VENDOR_CODE */
/* check for out of date configuration level */
if (ConfigLevel < MAXCONFIGLEVEL)
{
message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
Version, MAXCONFIGLEVEL, ConfigLevel);
}
if (ConfigLevel < 3)
UseErrorsTo = TRUE;
/* set options that were previous macros */
if (SmtpGreeting == NULL)
{
if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
SmtpGreeting = newstr(p);
else
SmtpGreeting = "\201j Sendmail \201v ready at \201b";
}
if (UnixFromLine == NULL)
{
if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
UnixFromLine = newstr(p);
else
UnixFromLine = "From \201g \201d";
}
SmtpError[0] = '\0';
/* our name for SMTP codes */
expand("\201j", jbuf, sizeof jbuf, CurEnv);
MyHostName = jbuf;
if (strchr(jbuf, '.') == NULL)
message("WARNING: local host name (%s) is not qualified; fix $j in config file",
jbuf);
/* make certain that this name is part of the $=w class */
setclass('w', MyHostName);
/* the indices of built-in mailers */
st = stab("local", ST_MAILER, ST_FIND);
if (st != NULL)
LocalMailer = st->s_mailer;
else if (OpMode != MD_TEST || !warn_C_flag)
syserr("No local mailer defined");
st = stab("prog", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No prog mailer defined");
else
{
ProgMailer = st->s_mailer;
clrbitn(M_MUSER, ProgMailer->m_flags);
}
st = stab("*file*", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No *file* mailer defined");
else
{
FileMailer = st->s_mailer;
clrbitn(M_MUSER, FileMailer->m_flags);
}
st = stab("*include*", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No *include* mailer defined");
else
InclMailer = st->s_mailer;
if (ConfigLevel < 6)
{
/* heuristic tweaking of local mailer for back compat */
if (LocalMailer != NULL)
{
setbitn(M_ALIASABLE, LocalMailer->m_flags);
setbitn(M_HASPWENT, LocalMailer->m_flags);
setbitn(M_TRYRULESET5, LocalMailer->m_flags);
setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
setbitn(M_CHECKPROG, LocalMailer->m_flags);
setbitn(M_CHECKFILE, LocalMailer->m_flags);
setbitn(M_CHECKUDB, LocalMailer->m_flags);
}
if (ProgMailer != NULL)
setbitn(M_RUNASRCPT, ProgMailer->m_flags);
if (FileMailer != NULL)
setbitn(M_RUNASRCPT, FileMailer->m_flags);
}
if (ConfigLevel < 7)
{
if (LocalMailer != NULL)
setbitn(M_VRFY250, LocalMailer->m_flags);
if (ProgMailer != NULL)
setbitn(M_VRFY250, ProgMailer->m_flags);
if (FileMailer != NULL)
setbitn(M_VRFY250, FileMailer->m_flags);
}
/* MIME Content-Types that cannot be transfer encoded */
setclass('n', "multipart/signed");
/* MIME message/xxx subtypes that can be treated as messages */
setclass('s', "rfc822");
/* MIME Content-Transfer-Encodings that can be encoded */
setclass('e', "7bit");
setclass('e', "8bit");
setclass('e', "binary");
#ifdef USE_B_CLASS
/* MIME Content-Types that should be treated as binary */
setclass('b', "image");
setclass('b', "audio");
setclass('b', "video");
setclass('b', "application/octet-stream");
#endif /* USE_B_CLASS */
/* MIME headers which have fields to check for overflow */
setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
/* MIME headers to check for length overflow */
setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
/* MIME headers to check for overflow and rebalance */
setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
/* Macros to save in the qf file -- don't remove any */
setclass(macid("{persistentMacros}", NULL), "r");
setclass(macid("{persistentMacros}", NULL), "s");
setclass(macid("{persistentMacros}", NULL), "_");
setclass(macid("{persistentMacros}", NULL), "{if_addr}");
setclass(macid("{persistentMacros}", NULL), "{daemon_flags}");
setclass(macid("{persistentMacros}", NULL), "{client_flags}");
/* operate in queue directory */
if (QueueDir == NULL)
{
if (OpMode != MD_TEST)
{
syserr("QueueDirectory (Q) option must be set");
ExitStat = EX_CONFIG;
}
}
else
{
/*
** If multiple queues wildcarded, use one for
** the daemon's home. Note that this preconditions
** a wildcarded QueueDir to a real pathname.
*/
if (OpMode != MD_TEST)
multiqueue_cache();
}
/* check host status directory for validity */
if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
{
/* cannot use this value */
if (tTd(0, 2))
dprintf("Cannot use HostStatusDirectory = %s: %s\n",
HostStatDir, errstring(errno));
HostStatDir = NULL;
}
#if QUEUE
if (OpMode == MD_QUEUERUN && RealUid != 0 &&
bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
{
struct stat stbuf;
/* check to see if we own the queue directory */
if (stat(".", &stbuf) < 0)
syserr("main: cannot stat %s", QueueDir);
if (stbuf.st_uid != RealUid)
{
/* nope, really a botch */
usrerr("You do not have permission to process the queue");
finis(FALSE, EX_NOPERM);
}
}
#endif /* QUEUE */
#if _FFR_MILTER
/* sanity checks on milter filters */
if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
milter_parse_list(InputFilterList, InputFilters, MAXFILTERS);
#endif /* _FFR_MILTER */
/* if we've had errors so far, exit now */
if (ExitStat != EX_OK && OpMode != MD_TEST)
finis(FALSE, ExitStat);
#if XDEBUG
checkfd012("before main() initmaps");
#endif /* XDEBUG */
/*
** Do operation-mode-dependent initialization.
*/
switch (OpMode)
{
case MD_PRINT:
/* print the queue */
#if QUEUE
dropenvelope(CurEnv, TRUE);
(void) setsignal(SIGPIPE, quiesce);
printqueue();
finis(FALSE, EX_OK);
#else /* QUEUE */
usrerr("No queue to print");
finis(FALSE, EX_UNAVAILABLE);
#endif /* QUEUE */
break;
case MD_HOSTSTAT:
(void) setsignal(SIGPIPE, quiesce);
(void) mci_traverse_persistent(mci_print_persistent, NULL);
finis(FALSE, EX_OK);
break;
case MD_PURGESTAT:
(void) mci_traverse_persistent(mci_purge_persistent, NULL);
finis(FALSE, EX_OK);
break;
case MD_INITALIAS:
/* initialize maps */
initmaps();
finis(FALSE, ExitStat);
break;
case MD_SMTP:
case MD_DAEMON:
/* reset DSN parameters */
DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
define(macid("{dsn_notify}", NULL), NULL, CurEnv);
CurEnv->e_envid = NULL;
define(macid("{dsn_envid}", NULL), NULL, CurEnv);
CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
define(macid("{dsn_ret}", NULL), NULL, CurEnv);
/* don't open maps for daemon -- done below in child */
break;
}
if (tTd(0, 15))
{
/* print configuration table (or at least part of it) */
if (tTd(0, 90))
printrules();
for (i = 0; i < MAXMAILERS; i++)
{
if (Mailer[i] != NULL)
printmailer(Mailer[i]);
}
}
/*
** Switch to the main envelope.
*/
CurEnv = newenvelope(&MainEnvelope, CurEnv);
MainEnvelope.e_flags = BlankEnvelope.e_flags;
/*
** If test mode, read addresses from stdin and process.
*/
if (OpMode == MD_TEST)
{
char buf[MAXLINE];
if (isatty(fileno(stdin)))
Verbose = 2;
if (Verbose)
{
printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
printf("Enter <ruleset> <address>\n");
}
if (setjmp(TopFrame) > 0)
printf("\n");
(void) setsignal(SIGINT, intindebug);
for (;;)
{
if (Verbose == 2)
printf("> ");
(void) fflush(stdout);
if (fgets(buf, sizeof buf, stdin) == NULL)
testmodeline("/quit", CurEnv);
p = strchr(buf, '\n');
if (p != NULL)
*p = '\0';
if (Verbose < 2)
printf("> %s\n", buf);
testmodeline(buf, CurEnv);
}
}
#if SMTP
# if STARTTLS
/*
** basic TLS initialization
** ignore result for now
*/
SSL_library_init();
SSL_load_error_strings();
# if 0
/* this is currently a macro for SSL_library_init */
SSLeay_add_ssl_algorithms();
# endif /* 0 */
/* initialize PRNG */
tls_ok = tls_rand_init(RandFile, 7);
# endif /* STARTTLS */
#endif /* SMTP */
#if QUEUE
/*
** If collecting stuff from the queue, go start doing that.
*/
if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
{
# if SMTP
# if STARTTLS
if (tls_ok
)
{
/* init TLS for client, ignore result for now */
(void) initclttls();
}
# endif /* STARTTLS */
# endif /* SMTP */
(void) runqueue(FALSE, Verbose);
finis(TRUE, ExitStat);
}
#endif /* QUEUE */
/*
** If a daemon, wait for a request.
** getrequests will always return in a child.
** If we should also be processing the queue, start
** doing it in background.
** We check for any errors that might have happened
** during startup.
*/
if (OpMode == MD_DAEMON || QueueIntvl != 0)
{
char dtype[200];
if (!run_in_foreground && !tTd(99, 100))
{
/* put us in background */
i = fork();
if (i < 0)
syserr("daemon: cannot fork");
if (i != 0)
finis(FALSE, EX_OK);
/* disconnect from our controlling tty */
disconnect(2, CurEnv);
}
dtype[0] = '\0';
if (OpMode == MD_DAEMON)
(void) strlcat(dtype, "+SMTP", sizeof dtype);
if (QueueIntvl != 0)
{
(void) strlcat(dtype, "+queueing@", sizeof dtype);
(void) strlcat(dtype, pintvl(QueueIntvl, TRUE),
sizeof dtype);
}
if (tTd(0, 1))
(void) strlcat(dtype, "+debugging", sizeof dtype);
sm_syslog(LOG_INFO, NOQID,
"starting daemon (%s): %s", Version, dtype + 1);
#ifdef XLA
xla_create_file();
#endif /* XLA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -