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

📄 deliver.c

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

			/* run disconnected from terminal */
			(void) setsid();

			/* try to execute the mailer */
			(void) execve(m->m_mailer, (ARGV_T) pv,
				      (ARGV_T) UserEnviron);
			save_errno = errno;
			syserr("Cannot exec %s", m->m_mailer);
			if (bitnset(M_LOCALMAILER, m->m_flags) ||
			    transienterror(save_errno))
				_exit(EX_OSERR);
			_exit(EX_UNAVAILABLE);
		}

		/*
		**  Set up return value.
		*/

		if (mci == NULL)
		{
			mci = (MCI *) xalloc(sizeof *mci);
			memset((char *) mci, '\0', sizeof *mci);
		}
		mci->mci_mailer = m;
		if (clever)
		{
			mci->mci_state = MCIS_OPENING;
			mci_cache(mci);
		}
		else
		{
			mci->mci_state = MCIS_OPEN;
		}
		mci->mci_pid = pid;
		(void) close(mpvect[0]);
		mci->mci_out = fdopen(mpvect[1], "w");
		if (mci->mci_out == NULL)
		{
			syserr("deliver: cannot create mailer output channel, fd=%d",
				mpvect[1]);
			(void) close(mpvect[1]);
			(void) close(rpvect[0]);
			(void) close(rpvect[1]);
			rcode = EX_OSERR;
			goto give_up;
		}

		(void) close(rpvect[1]);
		mci->mci_in = fdopen(rpvect[0], "r");
		if (mci->mci_in == NULL)
		{
			syserr("deliver: cannot create mailer input channel, fd=%d",
			       mpvect[1]);
			(void) close(rpvect[0]);
			(void) fclose(mci->mci_out);
			mci->mci_out = NULL;
			rcode = EX_OSERR;
			goto give_up;
		}

		/* Don't cache non-clever connections */
		if (!clever)
			mci->mci_flags |= MCIF_TEMP;
	}

	/*
	**  If we are in SMTP opening state, send initial protocol.
	*/

	if (bitnset(M_7BITS, m->m_flags) &&
	    (!clever || mci->mci_state == MCIS_OPENING))
		mci->mci_flags |= MCIF_7BIT;
#if SMTP
	if (clever && mci->mci_state != MCIS_CLOSED)
	{
		static u_short again;
# if SASL && SFIO
#  define DONE_TLS_B	0x01
#  define DONE_TLS	bitset(DONE_TLS_B, again)
# endif /* SASL && SFIO */
# if STARTTLS
#  define DONE_STARTTLS_B	0x02
#  define DONE_STARTTLS	bitset(DONE_STARTTLS_B, again)
# endif /* STARTTLS */
# define ONLY_HELO_B	0x04
# define ONLY_HELO	bitset(ONLY_HELO_B, again)
# define SET_HELO	again |= ONLY_HELO_B
# define CLR_HELO	again &= ~ONLY_HELO_B

		again = 0;
# if STARTTLS || (SASL && SFIO)
reconnect:	/* after switching to an authenticated connection */
# endif /* STARTTLS || (SASL && SFIO) */

# if SASL
		mci->mci_saslcap = NULL;
# endif /* SASL */
		smtpinit(m, mci, e, ONLY_HELO);
		CLR_HELO;

# if STARTTLS
		/* first TLS then AUTH to provide a security layer */
		if (mci->mci_state != MCIS_CLOSED && !DONE_STARTTLS)
		{
			int olderrors;
			bool hasdot;
			bool usetls;
			bool saveQuickAbort = QuickAbort;
			bool saveSuprErrs = SuprErrs;
#  if _FFR_TLS_CLT1
			char *p;
#  endif /* _FFR_TLS_CLT1 */
			extern SOCKADDR CurHostAddr;

			rcode = EX_OK;
			usetls = bitset(MCIF_TLS, mci->mci_flags);
#  if _FFR_TLS_CLT1
			if (usetls &&
			    (p = macvalue(macid("{client_flags}", NULL), e))
			    != NULL)
			{
				for (; *p != '\0'; p++)
				{
					/* look for just this one flag */
					if (*p == D_CLTNOTLS)
					{
						usetls = FALSE;
						break;
					}
				}
			}
#  endif /* _FFR_TLS_CLT1 */

			hasdot = CurHostName[strlen(CurHostName) - 1] == '.';
			if (hasdot)
				CurHostName[strlen(CurHostName) - 1] = '\0';
			define(macid("{server_name}", NULL),
			       newstr(CurHostName), e);
			if (CurHostAddr.sa.sa_family != 0)
				define(macid("{server_addr}", NULL),
				       newstr(anynet_ntoa(&CurHostAddr)), e);
			else
				define(macid("{server_addr}", NULL), NULL, e);
#  if _FFR_TLS_O_T
			if (usetls)
			{
				olderrors = Errors;
				QuickAbort = FALSE;
				SuprErrs = TRUE;
				if (rscheck("try_tls", CurHostName, NULL,
					    e, TRUE, FALSE, 8) != EX_OK
				    || Errors > olderrors)
					usetls = FALSE;
				SuprErrs = saveSuprErrs;
				QuickAbort = saveQuickAbort;
			}
#  endif /* _FFR_TLS_O_T */

			/* undo change of CurHostName */
			if (hasdot)
				CurHostName[strlen(CurHostName)] = '.';
			if (usetls)
			{
				if ((rcode = starttls(m, mci, e)) == EX_OK)
				{
					/* start again without STARTTLS */
					again |= DONE_STARTTLS_B;
					mci->mci_flags |= MCIF_TLSACT;
				}
				else
				{
					char *s;

					/*
					**  TLS negotation failed, what to do?
					**  fall back to unencrypted connection
					**  or abort? How to decide?
					**  set a macro and call a ruleset.
					*/
					mci->mci_flags &= ~MCIF_TLS;
					switch (rcode)
					{
					  case EX_TEMPFAIL:
						s = "TEMP";
						break;
					  case EX_USAGE:
						s = "USAGE";
						break;
					  case EX_PROTOCOL:
						s = "PROTOCOL";
						break;
					  case EX_SOFTWARE:
						s = "SOFTWARE";
						break;

					  /* everything else is a failure */
					  default:
						s = "FAILURE";
						rcode = EX_TEMPFAIL;
					}
					define(macid("{verify}", NULL),
					       newstr(s), e);
				}
			}
			else
				define(macid("{verify}", NULL), "NONE", e);
			olderrors = Errors;
			QuickAbort = FALSE;
			SuprErrs = TRUE;

			/*
			**  rcode == EX_SOFTWARE is special:
			**  the TLS negotation failed
			**  we have to drop the connection no matter what
			**  However, we call tls_server to give it the chance
			**  to log the problem and return an appropriate
			**  error code.
			*/
			if (rscheck("tls_server",
				     macvalue(macid("{verify}", NULL), e),
				     NULL, e, TRUE, TRUE, 6) != EX_OK ||
			    Errors > olderrors ||
			    rcode == EX_SOFTWARE)
			{
				char enhsc[ENHSCLEN];
				extern char MsgBuf[];

				if (ISSMTPCODE(MsgBuf) &&
				    extenhsc(MsgBuf + 4, ' ', enhsc) > 0)
				{
					p = newstr(MsgBuf);
				}
				else
				{
					p = "403 4.7.0 server not authenticated.";
					(void) strlcpy(enhsc, "4.7.0",
						       sizeof enhsc);
				}
				SuprErrs = saveSuprErrs;
				QuickAbort = saveQuickAbort;

				if (rcode == EX_SOFTWARE)
				{
					/* drop the connection */
					mci->mci_state = MCIS_QUITING;
					if (mci->mci_in != NULL)
					{
						(void) fclose(mci->mci_in);
						mci->mci_in = NULL;
					}
					mci->mci_flags &= ~MCIF_TLSACT;
					(void) endmailer(mci, e, pv);
				}
				else
				{
					/* abort transfer */
					smtpquit(m, mci, e);
				}

				/* temp or permanent failure? */
				rcode = (*p == '4') ? EX_TEMPFAIL
						    : EX_UNAVAILABLE;
				mci_setstat(mci, rcode, newstr(enhsc), p);

				/*
				**  hack to get the error message into
				**  the envelope (done in giveresponse())
				*/
				(void) strlcpy(SmtpError, p, sizeof SmtpError);
			}
			QuickAbort = saveQuickAbort;
			SuprErrs = saveSuprErrs;
			if (DONE_STARTTLS && mci->mci_state != MCIS_CLOSED)
			{
				SET_HELO;
				mci->mci_flags &= ~MCIF_EXTENS;
				goto reconnect;
			}
		}
# endif /* STARTTLS */
# if SASL
		/* if other server supports authentication let's authenticate */
		if (mci->mci_state != MCIS_CLOSED &&
		    mci->mci_saslcap != NULL &&
#  if SFIO
		    !DONE_TLS &&
#  endif /* SFIO */
		    SASLInfo != NULL)
		{
			/*
			**  should we require some minimum authentication?
			**  XXX ignore result?
			*/
			if (smtpauth(m, mci, e) == EX_OK)
			{
#  if SFIO
				int result;
				sasl_ssf_t *ssf;

				/* get security strength (features) */
				result = sasl_getprop(mci->mci_conn, SASL_SSF,
						      (void **) &ssf);
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, NOQID,
						  "SASL: outgoing connection to %.64s: mech=%.16s, bits=%d",
						  mci->mci_host,
						  macvalue(macid("{auth_type}",
								 NULL), e),
						  *ssf);
				/*
				**  only switch to encrypted connection
				**  if a security layer has been negotiated
				*/
				if (result == SASL_OK && *ssf > 0)
				{
					/*
					**  convert sfio stuff to use SASL
					**  check return values
					**  if the call fails,
					**  fall back to unencrypted version
					**  unless some cf option requires
					**  encryption then the connection must
					**  be aborted
					*/
					if (sfdcsasl(mci->mci_in, mci->mci_out,
						     mci->mci_conn) == 0)
					{
						again |= DONE_TLS_B;
						SET_HELO;
						mci->mci_flags &= ~MCIF_EXTENS;
						mci->mci_flags |= MCIF_AUTHACT;
						goto reconnect;
					}
					syserr("SASL TLS switch failed in client");
				}
				/* else? XXX */
#  endif /* SFIO */
				mci->mci_flags |= MCIF_AUTHACT;

			}
		}
# endif /* SASL */
	}

#endif /* SMTP */

do_transfer:
	/* clear out per-message flags from connection structure */
	mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);

	if (bitset(EF_HAS8BIT, e->e_flags) &&
	    !bitset(EF_DONT_MIME, e->e_flags) &&
	    bitnset(M_7BITS, m->m_flags))
		mci->mci_flags |= MCIF_CVT8TO7;

#if MIME7TO8
	if (bitnset(M_MAKE8BIT, m->m_flags) &&
	    !bitset(MCIF_7BIT, mci->mci_flags) &&
	    (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
	     (strcasecmp(p, "quoted-printable") == 0 ||
	      strcasecmp(p, "base64") == 0) &&
	    (p = hvalue("Content-Type", e->e_header)) != NULL)
	{
		/* may want to convert 7 -> 8 */
		/* XXX should really parse it here -- and use a class XXX */
		if (strncasecmp(p, "text/plain", 10) == 0 &&
		    (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
			mci->mci_flags |= MCIF_CVT7TO8;
	}
#endif /* MIME7TO8 */

	if (tTd(11, 1))
	{
		dprintf("openmailer: ");
		mci_dump(mci, FALSE);
	}

	if (mci->mci_state != MCIS_OPEN)
	{
		/* couldn't open the mailer */
		rcode = mci->mci_exitstat;
		errno = mci->mci_errno;
#if NAMED_BIND
		h_errno = mci->mci_herrno;
#endif /* NAMED_BIND */
		if (rcode == EX_OK)
		{
			/* shouldn't happen */
			syserr("554 5.3.5 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
				(u_long) mci, rcode, errno, mci->mci_state,
				firstsig);
			mci_dump_all(TRUE);
			rcode = EX_SOFTWARE;
		}
#if DAEMON
		else if (nummxhosts > hostnum)
		{
			/* try next MX site */
			goto tryhost;
		}
#endif /* DAEMON */
	}
	else if (!clever)
	{
		/*
		**  Format and send message.
		*/

		putfromline(mci, e);
		(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
		(*e->e_putbody)(mci, e, NULL);

		/* get the exit status */
		rcode = endmailer(mci, e, pv);
	}
	else
#if SMTP
	{
		/*
		**  Send the MAIL FROM: protocol
		*/

		rcode = smtpmailfrom(m, mci, e);
		if (rcode == EX_OK)
		{
			register char *t = tobuf;
			register int i;

			/* send the recipient list */
			tobuf[0] = '\0';

			for (to = tochain; to != NULL; to = to->q_tchain)
			{
				e->e_to = to->q_paddr;
#if !_FFR_DYNAMIC_TOBUF
				if (strlen(to->q_paddr) +
				    (t - tobuf) + 2 > sizeof tobuf)
				{
					/* not enough room */
					continue;
				}
#endif /* !_FFR_DYNAMIC_TOBUF */

# if STARTTLS
#  if _FFR_TLS_RCPT
				i = rscheck("tls_rcpt", to->q_user, NULL, e,
					    TRUE, TRUE, 4);
				if (i != EX_OK)
				{
					markfailure(e, to, mci, i, FALSE);
					giveresponse(i, to->q_status,  m,
						     mci, ctladdr, xstart, e);
					continue;
				}
#  endif /* _FFR_TLS_RCPT */
# endif /* STARTTLS */

				if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
				{
					markfailure(e, to, mci, i, FALSE);
					giveresponse(i, to->q_status,  m,
						     mci, ctladdr, xstart, e);
				}
				else
				{
					*t++ = ',';
					for (p = to->q_paddr; *p; *t++ = *p++)
						continue;
					*t = '\0';
				}
			}

			/* now send the data */
			if (tobuf[0] == '\0')
			{
				rcode = EX_OK;
				e->e_to = NULL;
				if (bitset(MCIF_CACHED, mci->mci_flags))
					smtprset(m, mci, e);
			}
			else
			{
				e->e_to = tobuf + 1;
				rcode = smtpdata(m, mci, e);
			}
		}
# if DAEMON
		if (rcode == EX_TEMPFAIL && nummxhosts > hostnum)
		{
			/* try next MX site */
			goto tryhost;
		}
# endif /* DAEMON */
	}
#else /* SMTP */
	{
		syserr("554 5.3.5 deliver: need SMTP compiled to use clever mailer");
		rcode = EX_CONFIG;
		goto give_up;
	}
#endif /* SMTP */
#if NAMED_BIND
	if (ConfigLevel < 2)
		_res.options |= RES_DEFNAMES | RES_DNSRCH;	/* XXX */
#endif /* NAMED_BIND */

	if (tTd(62, 1))
		checkfds("after delivery");

	/*
	**  Do final status disposal.
	**	We check for something in tobuf for the SMTP case.
	**	If we got a temporary failure, arrange to queue the
	**		addressees.
	*/

  give_up:
#if SMTP
	if (bitnset(M_LMTP, m->m_flags))
	{
		lmtp_rcode = rcode;
		tobuf[0] = '\0';
		anyok = FALSE;
	}
	else
#endif /* SMTP */
		anyok = rcode == EX_OK;

	for (to = tochain; to != NULL; to = to->q_tchain)
	{
		/* see if address already marked */
		if (!QS_IS_OK(to->q_state))
			continue;

#if SMTP
		/* if running LMTP, get the status fo

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -