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

📄 srvrsmtp.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				e->e_flags |= EF_VRFYONLY;

# if _FFR_MILTER
			/*
			**  If the filter will be deleting recipients,
			**  don't expand them at RCPT time (in the call
			**  to recipient()).  If they are expanded, it
			**  is impossible for removefromlist() to figure
			**  out the expanded members of the original
			**  recipient and mark them as QS_DONTSEND.
			*/

			if (milter_can_delrcpts())
				e->e_flags |= EF_VRFYONLY;
# endif /* _FFR_MILTER */

			p = skipword(p, "to");
			if (p == NULL)
				break;
# if _FFR_ADDR_TYPE
			define(macid("{addr_type}", NULL), "e r", e);
# endif /* _FFR_ADDR_TYPE */
			a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
#if _FFR_ADDR_TYPE
			define(macid("{addr_type}", NULL), NULL, e);
#endif /* _FFR_ADDR_TYPE */
			if (Errors > 0)
				break;
			if (a == NULL)
			{
				usrerr("501 5.0.0 Missing recipient");
				break;
			}

			if (delimptr != NULL && *delimptr != '\0')
				*delimptr++ = '\0';

			/* put resulting triple from parseaddr() into macros */
			if (a->q_mailer != NULL)
				define(macid("{rcpt_mailer}", NULL),
				       a->q_mailer->m_name, e);
			else
				define(macid("{rcpt_mailer}", NULL),
				       NULL, e);
			if (a->q_host != NULL)
				define(macid("{rcpt_host}", NULL),
				       a->q_host, e);
			else
				define(macid("{rcpt_host}", NULL),
				       "localhost", e);
			if (a->q_user != NULL)
				define(macid("{rcpt_addr}", NULL),
				       a->q_user, e);
			else
				define(macid("{rcpt_addr}", NULL),
				       NULL, e);
			if (Errors > 0)
				break;

			/* now parse ESMTP arguments */
			addr = p;
			argno = 0;
			args[argno++] = p;
			p = delimptr;
			while (p != NULL && *p != '\0')
			{
				char *kp;
				char *vp = NULL;
				char *equal = NULL;

				/* locate the beginning of the keyword */
				while (isascii(*p) && isspace(*p))
					p++;
				if (*p == '\0')
					break;
				kp = p;

				/* skip to the value portion */
				while ((isascii(*p) && isalnum(*p)) || *p == '-')
					p++;
				if (*p == '=')
				{
					equal = p;
					*p++ = '\0';
					vp = p;

					/* skip to the end of the value */
					while (*p != '\0' && *p != ' ' &&
					       !(isascii(*p) && iscntrl(*p)) &&
					       *p != '=')
						p++;
				}

				if (*p != '\0')
					*p++ = '\0';

				if (tTd(19, 1))
					dprintf("RCPT: got arg %s=\"%s\"\n", kp,
						vp == NULL ? "<null>" : vp);

				rcpt_esmtp_args(a, kp, vp, e);
				if (equal != NULL)
					*equal = '=';
				args[argno++] = kp;
				if (argno >= MAXSMTPARGS - 1)
					usrerr("501 5.5.4 Too many parameters");
				if (Errors > 0)
					break;
			}
			args[argno] = NULL;
			if (Errors > 0)
				break;

			/* do config file checking of the recipient */
			if (rscheck("check_rcpt", addr,
				    NULL, e, TRUE, TRUE, 4) != EX_OK ||
			    Errors > 0)
				break;

# if _FFR_MILTER
			if (milterize && !bitset(EF_DISCARD, e->e_flags))
			{
				char state;
				char *response;

				response = milter_envrcpt(args, e, &state);
				switch (state)
				{
				  case SMFIR_REPLYCODE:
					usrerr(response);
					break;

				  case SMFIR_REJECT:
					usrerr("550 5.7.1 Command rejected");
					break;

				  case SMFIR_DISCARD:
					e->e_flags |= EF_DISCARD;
					break;

				  case SMFIR_TEMPFAIL:
					usrerr("451 4.7.1 Please try again later");
					break;
				}
				if (response != NULL)
					free(response);
			}
# endif /* _FFR_MILTER */

			define(macid("{rcpt_mailer}", NULL), NULL, e);
			define(macid("{rcpt_relay}", NULL), NULL, e);
			define(macid("{rcpt_addr}", NULL), NULL, e);
			define(macid("{dsn_notify}", NULL), NULL, e);
			if (Errors > 0)
				break;

			/* save in recipient list after ESMTP mods */
			a = recipient(a, &e->e_sendqueue, 0, e);
			if (Errors > 0)
				break;

			/* no errors during parsing, but might be a duplicate */
			e->e_to = a->q_paddr;
			if (!QS_IS_BADADDR(a->q_state))
			{
				if (e->e_queuedir == NOQDIR)
					initsys(e);
				message("250 2.1.5 Recipient ok%s",
					QS_IS_QUEUEUP(a->q_state) ?
						" (will queue)" : "");
				nrcpts++;
			}
			else
			{
				/* punt -- should keep message in ADDRESS.... */
				usrerr("550 5.1.1 Addressee unknown");
			}
			break;

		  case CMDDATA:		/* data -- text of mail */
			SmtpPhase = "server DATA";
			if (!gotmail)
			{
				usrerr("503 5.0.0 Need MAIL command");
				break;
			}
			else if (nrcpts <= 0)
			{
				usrerr("503 5.0.0 Need RCPT (recipient)");
				break;
			}

			/* put back discard bit */
			if (discard)
				e->e_flags |= EF_DISCARD;

			/* check to see if we need to re-expand aliases */
			/* also reset QS_BADADDR on already-diagnosted addrs */
			doublequeue = FALSE;
			for (a = e->e_sendqueue; a != NULL; a = a->q_next)
			{
				if (QS_IS_VERIFIED(a->q_state) &&
				    !bitset(EF_DISCARD, e->e_flags))
				{
					/* need to re-expand aliases */
					doublequeue = TRUE;
				}
				if (QS_IS_BADADDR(a->q_state))
				{
					/* make this "go away" */
					a->q_state = QS_DONTSEND;
				}
			}

			/* collect the text of the message */
			SmtpPhase = "collect";
			buffer_errors();
			collect(InChannel, TRUE, NULL, e);

# if _FFR_MILTER
			if (milterize &&
			    Errors <= 0 &&
			    !bitset(EF_DISCARD, e->e_flags))
			{
				char state;
				char *response;

				response = milter_data(e, &state);
				switch (state)
				{
				  case SMFIR_REPLYCODE:
					usrerr(response);
					break;

				  case SMFIR_REJECT:
					usrerr("554 5.7.1 Command rejected");
					break;

				  case SMFIR_DISCARD:
					e->e_flags |= EF_DISCARD;
					break;

				  case SMFIR_TEMPFAIL:
					usrerr("451 4.7.1 Please try again later");
					break;
				}
				if (response != NULL)
					free(response);
			}

			/* abort message filters that didn't get the body */
			if (milterize)
				milter_abort(e);
# endif /* _FFR_MILTER */

			/* redefine message size */
			if ((q = macvalue(macid("{msg_size}", NULL), e))
			    != NULL)
				free(q);
			snprintf(inp, sizeof inp, "%ld", e->e_msgsize);
			define(macid("{msg_size}", NULL), newstr(inp), e);
			if (Errors > 0)
			{
				/* Log who the mail would have gone to */
				if (LogLevel > 8 &&
				    e->e_message != NULL)
				{
					for (a = e->e_sendqueue;
					     a != NULL;
					     a = a->q_next)
					{
						if (!QS_IS_UNDELIVERED(a->q_state))
							continue;

						e->e_to = a->q_paddr;
						logdelivery(NULL, NULL,
							    a->q_status,
							    e->e_message,
							    NULL,
							    (time_t) 0, e);
					}
					e->e_to = NULL;
				}
				flush_errors(TRUE);
				buffer_errors();
				goto abortmessage;
			}

			/* make sure we actually do delivery */
			e->e_flags &= ~EF_CLRQUEUE;

			/* from now on, we have to operate silently */
			buffer_errors();
			e->e_errormode = EM_MAIL;

			/*
			**  Arrange to send to everyone.
			**	If sending to multiple people, mail back
			**		errors rather than reporting directly.
			**	In any case, don't mail back errors for
			**		anything that has happened up to
			**		now (the other end will do this).
			**	Truncate our transcript -- the mail has gotten
			**		to us successfully, and if we have
			**		to mail this back, it will be easier
			**		on the reader.
			**	Then send to everyone.
			**	Finally give a reply code.  If an error has
			**		already been given, don't mail a
			**		message back.
			**	We goose error returns by clearing error bit.
			*/

			SmtpPhase = "delivery";
			(void) bftruncate(e->e_xfp);
			id = e->e_id;

			/*
			**  If a header/body check (header checks or milter)
			**  set EF_DISCARD, don't queueup the message --
			**  that would lose the EF_DISCARD bit and deliver
			**  the message.
			*/

			if (bitset(EF_DISCARD, e->e_flags))
				doublequeue = FALSE;

			if (doublequeue)
			{
				/* make sure it is in the queue */
				queueup(e, FALSE);
			}
			else
			{
				/* send to all recipients */
# if NAMED_BIND
				_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
				_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
# endif /* NAMED_BIND */
				sendall(e, SM_DEFAULT);
			}
			e->e_to = NULL;

			/* issue success message */
			message("250 2.0.0 %s Message accepted for delivery", id);

			/* if we just queued, poke it */
			if (doublequeue &&
			    e->e_sendmode != SM_QUEUE &&
			    e->e_sendmode != SM_DEFER)
			{
				CurrentLA = sm_getla(e);

				if (!shouldqueue(e->e_msgpriority, e->e_ctime))
				{
					/* close all the queue files */
					closexscript(e);
					if (e->e_dfp != NULL)
						(void) bfclose(e->e_dfp);
					e->e_dfp = NULL;
					unlockqueue(e);

					(void) dowork(e->e_queuedir, id,
						      TRUE, TRUE, e);
				}
			}

  abortmessage:
			if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
				logsender(e, NULL);
			e->e_flags &= ~EF_LOGSENDER;

			/* if in a child, pop back to our parent */
			if (InChild)
				finis(TRUE, ExitStat);

			/* clean up a bit */
			gotmail = FALSE;
			dropenvelope(e, TRUE);
			CurEnv = e = newenvelope(e, CurEnv);
			e->e_flags = BlankEnvelope.e_flags;
			break;

		  case CMDRSET:		/* rset -- reset state */
# if _FFR_MILTER
			/* abort milter filters */
			milter_abort(e);
# endif /* _FFR_MILTER */

			if (tTd(94, 100))
				message("451 4.0.0 Test failure");
			else
				message("250 2.0.0 Reset state");

			/* arrange to ignore any current send list */
			e->e_sendqueue = NULL;
			e->e_flags |= EF_CLRQUEUE;

			if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
				logsender(e, NULL);
			e->e_flags &= ~EF_LOGSENDER;

			if (InChild)
				finis(TRUE, ExitStat);

			/* clean up a bit */
			gotmail = FALSE;
			SuprErrs = TRUE;
			dropenvelope(e, TRUE);
			CurEnv = e = newenvelope(e, CurEnv);
			break;

		  case CMDVRFY:		/* vrfy -- verify address */
		  case CMDEXPN:		/* expn -- expand address */
			if (tempfail)
			{
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, e->e_id,
						  "SMTP %s command (%.100s) from %.100s tempfailed (due to previous checks)",
						  c->cmd_code == CMDVRFY ? "VRFY" : "EXPN",
						  p, CurSmtpClient);
				usrerr("550 5.7.1 Please try again later");
				break;
			}
			wt = checksmtpattack(&nverifies, MAXVRFYCOMMANDS, FALSE,
				c->cmd_code == CMDVRFY ? "VRFY" : "EXPN", e);
			previous = curtime();
			vrfy = c->cmd_code == CMDVRFY;
			if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
						PrivacyFlags))
			{
				if (vrfy)
					message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
				else
					message("502 5.7.0 Sorry, we do not allow this operation");
				if (LogLevel > 5)
					sm_syslog(LOG_INFO, e->e_id,
						  "%.100s: %s [rejected]",
						  CurSmtpClient,
						  shortenstring(inp, MAXSHORTSTR));
				break;
			}
			else if (!gothello &&
				 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
						PrivacyFlags))
			{
				usrerr("503 5.0.0 I demand that you introduce yourself first");
				break;
			}
			if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
				break;
			if (Errors > 0)
				goto undo_subproc;
			if (LogLevel > 5)
				sm_syslog(LOG_INFO, e->e_id,
					  "%.100s: %s",
					  CurSmtpClient,
					  shortenstring(inp, MAXSHORTSTR));
			if (setjmp(TopFrame) > 0)
				goto undo_subproc;
			QuickAbort = TRUE;
			vrfyqueue = NULL;
			if (vrfy)
				e->e_flags |= EF_VRFYONLY;
			while (*p != '\0' && isascii(*p) && isspace(*p))
				p++;
			if (*p == '\0')
			{
				usrerr("501 5.5.2 Argument required");
			}
			else
			{
				/* do config file checking of the address */
				if (rscheck(vrfy ? "check_vrfy" : "check_expn",
					    p, NULL, e, TRUE, FALSE, 4)
				    != EX_OK || Errors > 0)
					goto undo_subproc;
				(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
			}
			if (wt > 0)
				(void) sleep(wt - (curtime() - previous));
			if (Errors > 0)
				goto undo_subproc;
			if (vrfyqueue == NULL)
			{
				usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN");
			}
			while (vrfyqueue != NULL)
			{
				if (!QS_IS_UNDELIVERED(vrfyqueue->q_state))
				{
					vrfyqueue = vrfyqueue->q_next;
					continue;
				}

				/* see if there is more in the vrfy list */
				a = vrfyqueue;
				while ((a = a->q_next) != NULL &&
				       (!QS_IS_UNDELIVERED(a->q_state)))
					continue;
				printvrfyaddr(vrfyqueue, a == NULL, vrfy);
				vrfyqueue = a;
			}
			if (InChild)
				finis(TRUE, ExitStat);
			break;

		  case CMDETRN:		/* etrn -- force queue flush */
			if (bitset(PRIV_NOETRN, PrivacyFlags) ||
			    bitnset(D_NOETRN, d_flags))
			{
				/* different message for MSA ? */
				message("502 5.7.0 Sorry, we do not allow this operation");
				if (LogLevel > 5)
					sm_syslog(LOG_INFO, e->e_id,
						  "%.100s: %s [rejected]",
						  CurSmtpClient,
						  shortenstring(inp, MAXSHORTSTR));
				break;
			}
			if (tempfail)
			{
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, e->e_id,
						  "SMTP ETRN command (%.100s) from %.100s tempfailed (due to previous checks)",
						  p, CurSmtpClient);
				usrerr("451 4.7.1 Please try again later");
				break;
			}

			if (strlen(p) <= 0)
			{
				usrerr("500 5.5.2 Parameter required");
				break;

⌨️ 快捷键说明

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