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

📄 usersmtp.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		}
#  endif /* SFIO */
		return EX_TEMPFAIL;
	}

	*mechused = mechusing;

	/* send the info across the wire */
	if (outlen > 0)
	{
		saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL);
		if (saslresult != SASL_OK) /* internal error */
		{
			if (LogLevel > 8)
				sm_syslog(LOG_ERR, e->e_id,
					"encode64 for AUTH failed");
			return EX_TEMPFAIL;
		}
		smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
	}
	else
	{
		smtpmessage("AUTH %s", m, mci, mechusing);
	}

	/* get the reply */
	smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL);
	/* which timeout? XXX */

	for (;;)
	{
		/* check return code from server */
		if (smtpresult == 235)
		{
			define(macid("{auth_type}", NULL),
			       newstr(mechusing), e);
#  if !SFIO
			if (LogLevel > 9)
				sm_syslog(LOG_INFO, NOQID,
					  "SASL: outgoing connection to %.64s: mech=%.16s",
					  mci->mci_host, mechusing);
#  endif /* !SFIO */
			return EX_OK;
		}
		if (smtpresult == -1)
			return EX_IOERR;
		if (smtpresult != 334)
			return EX_TEMPFAIL;

		saslresult = sasl_client_step(mci->mci_conn,
					      mci->mci_sasl_string,
					      mci->mci_sasl_string_len,
					      &client_interact,
					      &out, &outlen);

		if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
		{
			if (tTd(95, 5))
				dprintf("AUTH FAIL: %s (%d)\n",
					sasl_errstring(saslresult, NULL, NULL),
					saslresult);

			/* fail deliberately, see RFC 2254 4. */
			smtpmessage("*", m, mci);

			/*
			**  but we should only fail for this authentication
			**  mechanism; how to do that?
			*/

			smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
					   getsasldata, NULL);
			return EX_TEMPFAIL;
		}

		if (outlen > 0)
		{
			saslresult = sasl_encode64(out, outlen, in64,
						   MAXOUTLEN, NULL);
			if (saslresult != SASL_OK)
			{
				/* give an error reply to the other side! */
				smtpmessage("*", m, mci);
				return EX_TEMPFAIL;
			}
		}
		else
			in64[0] = '\0';
		smtpmessage(in64, m, mci);
		smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
				   getsasldata, NULL);
		/* which timeout? XXX */
	}
	/* NOTREACHED */
}

/*
**  SMTPAUTH -- try to AUTHenticate
**
**	This will try mechanisms in the order the sasl library decided until:
**	- there are no more mechanisms
**	- a mechanism succeeds
**	- the sasl library fails initializing
**
**	Parameters:
**		m -- the mailer.
**		mci -- the mailer connection info.
**		e -- the envelope.
**
**	Returns:
**		EX_OK/EX_TEMPFAIL
*/

int
smtpauth(m, mci, e)
	MAILER *m;
	MCI *mci;
	ENVELOPE *e;
{
	int result;
	char *mechused;
	char *h;
	static char *defrealm = NULL;
	static char *mechs = NULL;

	mci->mci_sasl_auth = FALSE;
	if (defrealm == NULL)
	{
		h = readauth(SASL_DEFREALM, SASLInfo, TRUE);
		if (h != NULL && *h != '\0')
			defrealm = newstr(h);
	}
	if (defrealm == NULL || *defrealm == '\0')
		defrealm = newstr(macvalue('j', CurEnv));
	callbacks[CB_GETREALM_IDX].context = defrealm;

# if _FFR_DEFAUTHINFO_MECHS
	if (mechs == NULL)
	{
		h = readauth(SASL_MECH, SASLInfo, TRUE);
		if (h != NULL && *h != '\0')
			mechs = newstr(h);
	}
# endif /* _FFR_DEFAUTHINFO_MECHS */
	if (mechs == NULL || *mechs == '\0')
		mechs = AuthMechanisms;
	mci->mci_saslcap = intersect(mechs, mci->mci_saslcap);

	/* initialize sasl client library */
	result = sasl_client_init(callbacks);
	if (result != SASL_OK)
		return EX_TEMPFAIL;
	do
	{
		result = attemptauth(m, mci, e, &mechused);
		if (result == EX_OK)
			mci->mci_sasl_auth = TRUE;
		else if (result == EX_TEMPFAIL)
		{
			mci->mci_saslcap = removemech(mechused,
						      mci->mci_saslcap);
			if (mci->mci_saslcap == NULL ||
			    *(mci->mci_saslcap) == '\0')
				return EX_TEMPFAIL;
		}
		else	/* all others for now */
			return EX_TEMPFAIL;
	} while (result != EX_OK);
	return result;
}
# endif /* SASL */

/*
**  SMTPMAILFROM -- send MAIL command
**
**	Parameters:
**		m -- the mailer.
**		mci -- the mailer connection structure.
**		e -- the envelope (including the sender to specify).
*/

int
smtpmailfrom(m, mci, e)
	MAILER *m;
	MCI *mci;
	ENVELOPE *e;
{
	int r;
	char *bufp;
	char *bodytype;
	char buf[MAXNAME + 1];
	char optbuf[MAXLINE];
	char *enhsc;

	if (tTd(18, 2))
		dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
	enhsc = NULL;

	/* set up appropriate options to include */
	if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
	{
		snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
		bufp = &optbuf[strlen(optbuf)];
	}
	else
	{
		optbuf[0] = '\0';
		bufp = optbuf;
	}

	bodytype = e->e_bodytype;
	if (bitset(MCIF_8BITMIME, mci->mci_flags))
	{
		if (bodytype == NULL &&
		    bitset(MM_MIME8BIT, MimeMode) &&
		    bitset(EF_HAS8BIT, e->e_flags) &&
		    !bitset(EF_DONT_MIME, e->e_flags) &&
		    !bitnset(M_8BITS, m->m_flags))
			bodytype = "8BITMIME";
		if (bodytype != NULL &&
		    SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
		{
			snprintf(bufp, SPACELEFT(optbuf, bufp),
				 " BODY=%s", bodytype);
			bufp += strlen(bufp);
		}
	}
	else if (bitnset(M_8BITS, m->m_flags) ||
		 !bitset(EF_HAS8BIT, e->e_flags) ||
		 bitset(MCIF_8BITOK, mci->mci_flags))
	{
		/* EMPTY */
		/* just pass it through */
	}
# if MIME8TO7
	else if (bitset(MM_CVTMIME, MimeMode) &&
		 !bitset(EF_DONT_MIME, e->e_flags) &&
		 (!bitset(MM_PASS8BIT, MimeMode) ||
		  bitset(EF_IS_MIME, e->e_flags)))
	{
		/* must convert from 8bit MIME format to 7bit encoded */
		mci->mci_flags |= MCIF_CVT8TO7;
	}
# endif /* MIME8TO7 */
	else if (!bitset(MM_PASS8BIT, MimeMode))
	{
		/* cannot just send a 8-bit version */
		extern char MsgBuf[];

		usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
		mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
		return EX_DATAERR;
	}

	if (bitset(MCIF_DSN, mci->mci_flags))
	{
		if (e->e_envid != NULL &&
		    SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
		{
			snprintf(bufp, SPACELEFT(optbuf, bufp),
				 " ENVID=%s", e->e_envid);
			bufp += strlen(bufp);
		}

		/* RET= parameter */
		if (bitset(EF_RET_PARAM, e->e_flags) &&
		    SPACELEFT(optbuf, bufp) > 9)
		{
			snprintf(bufp, SPACELEFT(optbuf, bufp),
				 " RET=%s",
				 bitset(EF_NO_BODY_RETN, e->e_flags) ?
					"HDRS" : "FULL");
			bufp += strlen(bufp);
		}
	}

	if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
	    SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
# if SASL
	     && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
# endif /* SASL */
	    )
	{
		snprintf(bufp, SPACELEFT(optbuf, bufp),
			 " AUTH=%s", e->e_auth_param);
		bufp += strlen(bufp);
	}

	/*
	**  Send the MAIL command.
	**	Designates the sender.
	*/

	mci->mci_state = MCIS_ACTIVE;

	if (bitset(EF_RESPONSE, e->e_flags) &&
	    !bitnset(M_NO_NULL_FROM, m->m_flags))
		buf[0] = '\0';
	else
		expand("\201g", buf, sizeof buf, e);
	if (buf[0] == '<')
	{
		/* strip off <angle brackets> (put back on below) */
		bufp = &buf[strlen(buf) - 1];
		if (*bufp == '>')
			*bufp = '\0';
		bufp = &buf[1];
	}
	else
		bufp = buf;
	if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
	    !bitnset(M_FROMPATH, m->m_flags))
	{
		smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
	}
	else
	{
		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
			*bufp == '@' ? ',' : ':', bufp, optbuf);
	}
	SmtpPhase = mci->mci_phase = "client MAIL";
	sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
			CurHostName, mci->mci_phase);
	r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc);
	if (r < 0)
	{
		/* communications failure */
		mci->mci_errno = errno;
		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}
	else if (r == 421)
	{
		/* service shutting down */
		mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
			    SmtpReplyBuffer);
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}
	else if (REPLYTYPE(r) == 4)
	{
		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
			    SmtpReplyBuffer);
		return EX_TEMPFAIL;
	}
	else if (REPLYTYPE(r) == 2)
	{
		return EX_OK;
	}
	else if (r == 501)
	{
		/* syntax error in arguments */
		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
			    SmtpReplyBuffer);
		return EX_DATAERR;
	}
	else if (r == 553)
	{
		/* mailbox name not allowed */
		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
			    SmtpReplyBuffer);
		return EX_DATAERR;
	}
	else if (r == 552)
	{
		/* exceeded storage allocation */
		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
			    SmtpReplyBuffer);
		if (bitset(MCIF_SIZE, mci->mci_flags))
			e->e_flags |= EF_NO_BODY_RETN;
		return EX_UNAVAILABLE;
	}
	else if (REPLYTYPE(r) == 5)
	{
		/* unknown error */
		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
			    SmtpReplyBuffer);
		return EX_UNAVAILABLE;
	}

	if (LogLevel > 1)
	{
		sm_syslog(LOG_CRIT, e->e_id,
			  "%.100s: SMTP MAIL protocol error: %s",
			  CurHostName,
			  shortenstring(SmtpReplyBuffer, 403));
	}

	/* protocol error -- close up */
	mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
		    SmtpReplyBuffer);
	smtpquit(m, mci, e);
	return EX_PROTOCOL;
}
/*
**  SMTPRCPT -- designate recipient.
**
**	Parameters:
**		to -- address of recipient.
**		m -- the mailer we are sending to.
**		mci -- the connection info for this transaction.
**		e -- the envelope for this transaction.
**
**	Returns:
**		exit status corresponding to recipient status.
**
**	Side Effects:
**		Sends the mail via SMTP.
*/

int
smtprcpt(to, m, mci, e)
	ADDRESS *to;
	register MAILER *m;
	MCI *mci;
	ENVELOPE *e;
{
	register int r;
	char *bufp;
	char optbuf[MAXLINE];
	char *enhsc;

	enhsc = NULL;
	optbuf[0] = '\0';
	bufp = optbuf;

	/*
	**  warning: in the following it is assumed that the free space
	**  in bufp is sizeof optbuf
	*/
	if (bitset(MCIF_DSN, mci->mci_flags))
	{
		/* NOTIFY= parameter */
		if (bitset(QHASNOTIFY, to->q_flags) &&
		    bitset(QPRIMARY, to->q_flags) &&
		    !bitnset(M_LOCALMAILER, m->m_flags))
		{
			bool firstone = TRUE;

			(void) strlcat(bufp, " NOTIFY=", sizeof optbuf);
			if (bitset(QPINGONSUCCESS, to->q_flags))
			{
				(void) strlcat(bufp, "SUCCESS", sizeof optbuf);
				firstone = FALSE;
			}
			if (bitset(QPINGONFAILURE, to->q_flags))
			{
				if (!firstone)
					(void) strlcat(bufp, ",",
						       sizeof optbuf);
				(void) strlcat(bufp, "FAILURE", sizeof optbuf);
				firstone = FALSE;
			}
			if (bitset(QPINGONDELAY, to->q_flags))
			{
				if (!firstone)
					(void) strlcat(bufp, ",",
						       sizeof optbuf);
				(void) strlcat(bufp, "DELAY", sizeof optbuf);
				firstone = FALSE;
			}
			if (firstone)
				(void) strlcat(bufp, "NEVER", sizeof optbuf);
			bufp += strlen(bufp);
		}

		/* ORCPT= parameter */
		if (to->q_orcpt != NULL &&
		    SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
		{
			snprintf(bufp, SPACELEFT(optbuf, bufp),
				 " ORCPT=%s", to->q_orcpt);
			bufp += strlen(bufp);
		}
	}

	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);

	SmtpPhase = mci->mci_phase = "client RCPT";
	sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
			CurHostName, mci->mci_phase);
	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc);
	to->q_rstatus = newstr(SmtpReplyBuffer);
	to->q_status = ENHSCN(enhsc, smtptodsn(r));
	if (!bitnset(M_LMTP, m->m_flags))
		to->q_statmta = mci->mci_host;
	if (r < 0 || REPLYTYPE(r) == 4)
		return EX_TEMPFAIL;
	else if (REPLYTYPE(r) == 2)
		return EX_OK;
	else if (r == 550)
	{
		to->q_status = ENHSCN(enhsc, "5.1.1");
		return EX_NOUSER;
	}
	else if (r == 551)
	{
		to->q_status = ENHSCN(enhsc, "5.1.6");
		return EX_NOUSER;
	}
	else if (r == 553)
	{
		to->q_status = ENHSCN(enhsc, "5.1.3");
		return EX_NOUSER;
	}
	else if (REPLYTYPE(r) == 5)
	{
		return EX_UNAVAILABLE;
	}

	if (LogLevel > 1)
	{
		sm_syslog(LOG_CRIT, e->e_id,
			  "%.100s: SMTP RCPT protocol error: %s",
			  CurHostName,
			  shortenstring(SmtpReplyBuffer, 403));
	}

	mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
		    SmtpReplyBuffer);
	return EX_PROTOCOL;
}
/*
**  SMTPDATA -- send the data and clean up the transaction.
**
**	Parameters:
**		m -- mailer being sent to.
**		mci -- the mailer connection information.
**		e -- the envelope for this message.
**
**	Returns:
**		exit status corresponding to DATA command.
**
**	Side Effects:
**		none.
*/

static jmp_buf	CtxDataTimeout;

int
smtpdata(m, mci, e)
	MAILER *m;
	register MCI *mci;
	register ENVELOPE *e;
{
	register int r;
	register EVENT *ev;
	int rstat;
	int xstat;
	time_t timeout;
	char *enhsc;

	enhsc = NULL;
	/*
	**  Send the data.
	**	First send the command and check that it is ok.
	**	Then send the data.
	**	Follow it up with a dot to terminate.
	**	Finally get the results of the transaction.
	*/

	/* send the command and check ok to proceed */
	smtpmessage("DATA", m, mci);
	SmtpPhase = mci->mci_phase = "client DATA 354";
	sm_setproctitle(TRUE, e, "%s %s: %s",
			qid_printname(e), CurHostName, mci->mci_phase);
	r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc);
	if (r < 0 || REPLYTYPE(r) == 4)
	{
		smtpquit(m, mci, e);
		return EX_TEMPFAIL;
	}
	else if (REPLYTYPE(r) == 5)
	{
		smtprset(m, mci, e);
		return EX_UNAVAILABLE;
	}
	else if (REPLYTYPE(r) != 3)
	{
		if (LogLevel > 1)
		{
			sm_syslog(LOG_CRIT, e->e_id,
				  "%.100s: SMTP DATA-1 protocol error: %s",
				  CurHostName,
				  shortenstring(SmtpReplyBuffer, 403));
		}
		smtprset(m, mci, e);
		mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
			    SmtpReplyBuffer);
		return EX_PROTOCOL;
	}

	/*
	**  Set timeout around data writes.  Make it at least large
	**  enough for DNS timeouts on all recipients plus some fudge
	**  factor.  The main thing is that it should not be infinite.
	*/

	if (setjmp(CtxDataTimeout) != 0)
	{
		mci->mci_errno = errno;
		mci->mci_state = MCIS_ERROR;
		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);

		/*

⌨️ 快捷键说明

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