⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:

		/* 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 + -