📄 main.c
字号:
/* save daemon type in a macro for possible PidFile use */
define(macid("{daemon_info}", NULL),
newstr(dtype + 1), &BlankEnvelope);
/* save queue interval in a macro for possible PidFile use */
define(macid("{queue_interval}", NULL),
newstr(pintvl(QueueIntvl, TRUE)), CurEnv);
#if QUEUE
if (QueueIntvl != 0)
{
(void) runqueue(TRUE, FALSE);
if (OpMode != MD_DAEMON)
{
/* write the pid to file */
log_sendmail_pid(CurEnv);
for (;;)
{
(void) pause();
if (DoQueueRun)
(void) runqueue(TRUE, FALSE);
}
}
}
#endif /* QUEUE */
dropenvelope(CurEnv, TRUE);
#if DAEMON
# if STARTTLS
/* init TLS for server, ignore result for now */
(void) initsrvtls();
# endif /* STARTTLS */
p_flags = getrequests(CurEnv);
/* drop privileges */
(void) drop_privileges(FALSE);
/* at this point we are in a child: reset state */
(void) newenvelope(CurEnv, CurEnv);
/*
** Get authentication data
*/
authinfo = getauthinfo(fileno(InChannel), &forged);
define('_', authinfo, &BlankEnvelope);
#endif /* DAEMON */
}
if (LogLevel > 9)
{
/* log connection information */
sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo);
}
#if SMTP
/*
** If running SMTP protocol, start collecting and executing
** commands. This will never return.
*/
if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
{
char pbuf[20];
/*
** Save some macros for check_* rulesets.
*/
if (forged)
{
char ipbuf[103];
(void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
anynet_ntoa(&RealHostAddr));
define(macid("{client_name}", NULL),
newstr(ipbuf), &BlankEnvelope);
define(macid("{client_resolve}", NULL),
"FORGED", &BlankEnvelope);
}
else
define(macid("{client_name}", NULL), RealHostName,
&BlankEnvelope);
define(macid("{client_addr}", NULL),
newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
(void)sm_getla(&BlankEnvelope);
switch(RealHostAddr.sa.sa_family)
{
# if NETINET
case AF_INET:
(void) snprintf(pbuf, sizeof pbuf, "%d",
RealHostAddr.sin.sin_port);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
(void) snprintf(pbuf, sizeof pbuf, "%d",
RealHostAddr.sin6.sin6_port);
break;
# endif /* NETINET6 */
default:
(void) snprintf(pbuf, sizeof pbuf, "0");
break;
}
define(macid("{client_port}", NULL),
newstr(pbuf), &BlankEnvelope);
#if SASL
/* give a syserr or just disable AUTH ? */
if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
syserr("!sasl_server_init failed! [%s]",
sasl_errstring(i, NULL, NULL));
#endif /* SASL */
if (OpMode == MD_DAEMON)
{
/* validate the connection */
HoldErrs = TRUE;
nullserver = validate_connection(&RealHostAddr,
RealHostName, CurEnv);
HoldErrs = FALSE;
}
else if (p_flags == NULL)
{
p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
clrbitmap(p_flags);
}
# if STARTTLS
if (OpMode == MD_SMTP)
(void) initsrvtls();
# endif /* STARTTLS */
smtp(nullserver, *p_flags, CurEnv);
}
#endif /* SMTP */
clearenvelope(CurEnv, FALSE);
if (OpMode == MD_VERIFY)
{
set_delivery_mode(SM_VERIFY, CurEnv);
PostMasterCopy = NULL;
}
else
{
/* interactive -- all errors are global */
CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
}
/*
** Do basic system initialization and set the sender
*/
initsys(CurEnv);
define(macid("{ntries}", NULL), "0", CurEnv);
setsender(from, CurEnv, NULL, '\0', FALSE);
if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
(!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) ||
strcmp(CurEnv->e_from.q_user, RealUserName) != 0))
{
auth_warning(CurEnv, "%s set sender to %s using -%c",
RealUserName, from, warn_f_flag);
#if SASL
auth = FALSE;
#endif /* SASL */
}
if (auth)
{
char *fv;
/* set the initial sender for AUTH= to $f@$j */
fv = macvalue('f', CurEnv);
if (fv == NULL || *fv == '\0')
CurEnv->e_auth_param = NULL;
else
{
if (strchr(fv, '@') == NULL)
{
i = strlen(fv) + strlen(macvalue('j', CurEnv))
+ 2;
p = xalloc(i);
(void) snprintf(p, i, "%s@%s", fv,
macvalue('j', CurEnv));
}
else
p = newstr(fv);
CurEnv->e_auth_param = newstr(xtextify(p, NULL));
}
}
if (macvalue('s', CurEnv) == NULL)
define('s', RealHostName, CurEnv);
if (*av == NULL && !GrabTo)
{
CurEnv->e_to = NULL;
CurEnv->e_flags |= EF_GLOBALERRS;
HoldErrs = FALSE;
usrerr("Recipient names must be specified");
/* collect body for UUCP return */
if (OpMode != MD_VERIFY)
collect(InChannel, FALSE, NULL, CurEnv);
finis(TRUE, EX_USAGE);
}
/*
** Scan argv and deliver the message to everyone.
*/
sendtoargv(av, CurEnv);
/* if we have had errors sofar, arrange a meaningful exit stat */
if (Errors > 0 && ExitStat == EX_OK)
ExitStat = EX_USAGE;
#if _FFR_FIX_DASHT
/*
** If using -t, force not sending to argv recipients, even
** if they are mentioned in the headers.
*/
if (GrabTo)
{
ADDRESS *q;
for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
q->q_state = QS_REMOVED;
}
#endif /* _FFR_FIX_DASHT */
/*
** Read the input mail.
*/
CurEnv->e_to = NULL;
if (OpMode != MD_VERIFY || GrabTo)
{
int savederrors = Errors;
long savedflags = CurEnv->e_flags & EF_FATALERRS;
CurEnv->e_flags |= EF_GLOBALERRS;
CurEnv->e_flags &= ~EF_FATALERRS;
Errors = 0;
buffer_errors();
collect(InChannel, FALSE, NULL, CurEnv);
/* header checks failed */
if (Errors > 0)
{
/* Log who the mail would have gone to */
if (LogLevel > 8 && CurEnv->e_message != NULL &&
!GrabTo)
{
ADDRESS *a;
for (a = CurEnv->e_sendqueue;
a != NULL;
a = a->q_next)
{
if (!QS_IS_UNDELIVERED(a->q_state))
continue;
CurEnv->e_to = a->q_paddr;
logdelivery(NULL, NULL, NULL,
CurEnv->e_message,
NULL, (time_t) 0, CurEnv);
}
CurEnv->e_to = NULL;
}
flush_errors(TRUE);
finis(TRUE, ExitStat);
/* NOTREACHED */
return -1;
}
/* bail out if message too large */
if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
{
finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR);
/* NOTREACHED */
return -1;
}
Errors = savederrors;
CurEnv->e_flags |= savedflags;
}
errno = 0;
if (tTd(1, 1))
dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
/*
** Actually send everything.
** If verifying, just ack.
*/
CurEnv->e_from.q_state = QS_SENDER;
if (tTd(1, 5))
{
dprintf("main: QS_SENDER ");
printaddr(&CurEnv->e_from, FALSE);
}
CurEnv->e_to = NULL;
CurrentLA = sm_getla(CurEnv);
GrabTo = FALSE;
#if NAMED_BIND
_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
#endif /* NAMED_BIND */
sendall(CurEnv, SM_DEFAULT);
/*
** All done.
** Don't send return error message if in VERIFY mode.
*/
finis(TRUE, ExitStat);
/* NOTREACHED */
return ExitStat;
}
/* ARGSUSED */
SIGFUNC_DECL
quiesce(sig)
int sig;
{
clear_events();
finis(FALSE, EX_OK);
}
/* ARGSUSED */
SIGFUNC_DECL
intindebug(sig)
int sig;
{
longjmp(TopFrame, 1);
return SIGFUNC_RETURN;
}
/*
** FINIS -- Clean up and exit.
**
** Parameters:
** drop -- whether or not to drop CurEnv envelope
** exitstat -- exit status to use for exit() call
**
** Returns:
** never
**
** Side Effects:
** exits sendmail
*/
void
finis(drop, exitstat)
bool drop;
volatile int exitstat;
{
if (tTd(2, 1))
{
dprintf("\n====finis: stat %d e_id=%s e_flags=",
exitstat,
CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
printenvflags(CurEnv);
}
if (tTd(2, 9))
printopenfds(FALSE);
/* if we fail in finis(), just exit */
if (setjmp(TopFrame) != 0)
{
/* failed -- just give it up */
goto forceexit;
}
/* clean up temp files */
CurEnv->e_to = NULL;
if (drop)
{
if (CurEnv->e_id != NULL)
dropenvelope(CurEnv, TRUE);
else
poststats(StatFile);
}
/* flush any cached connections */
mci_flush(TRUE, NULL);
/* close maps belonging to this pid */
closemaps();
#if USERDB
/* close UserDatabase */
_udbx_close();
#endif /* USERDB */
#ifdef XLA
/* clean up extended load average stuff */
xla_all_end();
#endif /* XLA */
/* and exit */
forceexit:
if (LogLevel > 78)
sm_syslog(LOG_DEBUG, CurEnv->e_id,
"finis, pid=%d",
getpid());
if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
exitstat = EX_OK;
sync_queue_time();
/* reset uid for process accounting */
endpwent();
(void) setuid(RealUid);
exit(exitstat);
}
/*
** INTSIG -- clean up on interrupt
**
** This just arranges to exit. It pessimizes in that it
** may resend a message.
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** Unlocks the current job.
*/
/* ARGSUSED */
SIGFUNC_DECL
intsig(sig)
int sig;
{
bool drop = FALSE;
clear_events();
if (sig != 0 && LogLevel > 79)
sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
FileName = NULL;
closecontrolsocket(TRUE);
#ifdef XLA
xla_all_end();
#endif /* XLA */
/* Clean-up on aborted stdin message submission */
if (CurEnv->e_id != NULL &&
(OpMode == MD_SMTP ||
OpMode == MD_DELIVER ||
OpMode == MD_ARPAFTP))
{
register ADDRESS *q;
/* don't return an error indication */
CurEnv->e_to = NULL;
CurEnv->e_flags &= ~EF_FATALERRS;
CurEnv->e_flags |= EF_CLRQUEUE;
/*
** Spin through the addresses and
** mark them dead to prevent bounces
*/
for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
q->q_state = QS_DONTSEND;
/* and don't try to deliver the partial message either */
if (InChild)
ExitStat = EX_QUIT;
drop = TRUE;
}
else
unlockqueue(CurEnv);
finis(drop, EX_OK);
}
/*
** INITMACROS -- initialize the macro system
**
** This just involves defining some macros that are actually
** used internally as metasymbols to be themselves.
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** initializes several macros to be themselves.
*/
struct metamac MetaMacros[] =
{
/* LHS pattern matching characters */
{ '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
{ '=', MATCHCLASS }, { '~', MATCHNCLASS },
/* these are RHS metasymbols */
{ '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
{ '>', CALLSUBR },
/* the conditional operations */
{ '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
/* the hostname lookup characters */
{ '[', HOSTBEGIN }, { ']', HOSTEND },
{ '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
/* miscellaneous control characters */
{ '&', MACRODEXPAND },
{ '\0' }
};
#define MACBINDING(name, mid) \
stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
MacroName[mid] = name;
void
initmacros(e)
register ENVELOPE *e;
{
register struct metamac *m;
register int c;
char buf[5];
extern char *MacroName[256];
for (m = MetaMacros; m->metaname != '\0'; m++)
{
buf[0] = m->metaval;
buf[1] = '\0';
define(m->metaname, newstr(buf), e);
}
buf[0] = MATCHREPL;
buf[2] = '\0';
for (c = '0'; c <= '9'; c++)
{
buf[1] = c;
define(c, newstr(buf), e);
}
/* set defaults for some macros sendmail will use later */
define('n', "MAILER-DAEMON", e);
/* set up external names for some internal macros */
MACBINDING("opMode", MID_OPMODE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -