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

📄 srvrsmtp.c

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

			/* crude way to avoid denial-of-service attacks */
			(void) checksmtpattack(&n_etrn, MAXETRNCOMMANDS, TRUE,
					     "ETRN", e);

			/* do config file checking of the parameter */
			if (rscheck("check_etrn", p, NULL, e, TRUE, FALSE, 4)
			    != EX_OK || Errors > 0)
				break;

			if (LogLevel > 5)
				sm_syslog(LOG_INFO, e->e_id,
					  "%.100s: ETRN %s",
					  CurSmtpClient,
					  shortenstring(p, MAXSHORTSTR));

			id = p;
			if (*id == '@')
				id++;
			else
				*--id = '@';

			if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
			{
				syserr("500 5.5.0 ETRN out of memory");
				break;
			}
			new->queue_match = id;
			new->queue_next = NULL;
			QueueLimitRecipient = new;
			ok = runqueue(TRUE, FALSE);
			free(QueueLimitRecipient);
			QueueLimitRecipient = NULL;
			if (ok && Errors == 0)
				message("250 2.0.0 Queuing for node %s started", p);
			break;

		  case CMDHELP:		/* help -- give user info */
			help(p, e);
			break;

		  case CMDNOOP:		/* noop -- do nothing */
			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
					       "NOOP", e);
			message("250 2.0.0 OK");
			break;

		  case CMDQUIT:		/* quit -- leave mail */
			message("221 2.0.0 %s closing connection", MyHostName);

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

# if STARTTLS
			/* shutdown TLS connection */
			if (tls_active)
			{
				(void) endtls(srv_ssl, "server");
				tls_active = FALSE;
			}
# endif /* STARTTLS */
# if SASL
			if (authenticating == SASL_IS_AUTH)
			{
				sasl_dispose(&conn);
				authenticating = SASL_NOT_AUTH;
			}
# endif /* SASL */

doquit:
			/* avoid future 050 messages */
			disconnect(1, e);

# if _FFR_MILTER
			/* close out milter filters */
			milter_quit(e);
# endif /* _FFR_MILTER */

			if (InChild)
				ExitStat = EX_QUIT;

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

			if (lognullconnection && LogLevel > 5)
			{
				char *d;

				d = macvalue(macid("{daemon_name}", NULL), e);
				if (d == NULL)
					d = "stdin";
				sm_syslog(LOG_INFO, NULL,
					 "%.100s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s",
					  CurSmtpClient, d);
			}
			finis(TRUE, ExitStat);
			/* NOTREACHED */

		  case CMDVERB:		/* set verbose mode */
			if (bitset(PRIV_NOEXPN, PrivacyFlags) ||
			    bitset(PRIV_NOVERB, PrivacyFlags))
			{
				/* this would give out the same info */
				message("502 5.7.0 Verbose unavailable");
				break;
			}
			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
					       "VERB", e);
			Verbose = 1;
			set_delivery_mode(SM_DELIVER, e);
			message("250 2.0.0 Verbose mode");
			break;

		  case CMDONEX:		/* doing one transaction only */
			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
					       "ONEX", e);
			OneXact = TRUE;
			message("250 2.0.0 Only one transaction");
			break;

		  case CMDXUSR:		/* initial (user) submission */
			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, TRUE,
					       "XUSR", e);
			define(macid("{daemon_flags}", NULL), "c u", CurEnv);
			message("250 2.0.0 Initial submission");
			break;

# if SMTPDEBUG
		  case CMDDBGQSHOW:	/* show queues */
			printf("Send Queue=");
			printaddr(e->e_sendqueue, TRUE);
			break;

		  case CMDDBGDEBUG:	/* set debug mode */
			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
			tTflag(p);
			message("200 2.0.0 Debug set");
			break;

# else /* SMTPDEBUG */
		  case CMDDBGQSHOW:	/* show queues */
		  case CMDDBGDEBUG:	/* set debug mode */
# endif /* SMTPDEBUG */
		  case CMDLOGBOGUS:	/* bogus command */
			if (LogLevel > 0)
				sm_syslog(LOG_CRIT, e->e_id,
					  "\"%s\" command from %.100s (%.100s)",
					  c->cmd_name, CurSmtpClient,
					  anynet_ntoa(&RealHostAddr));
			/* FALLTHROUGH */

		  case CMDERROR:	/* unknown command */
			if (++badcommands > MAXBADCOMMANDS)
			{
				message("421 4.7.0 %s Too many bad commands; closing connection",
					MyHostName);

				/* arrange to ignore any current send list */
				e->e_sendqueue = NULL;
				goto doquit;
			}

			usrerr("500 5.5.1 Command unrecognized: \"%s\"",
			       shortenstring(inp, MAXSHORTSTR));
			break;

		  case CMDUNIMPL:
			usrerr("502 5.5.1 Command not implemented: \"%s\"",
			       shortenstring(inp, MAXSHORTSTR));
			break;

		  default:
			errno = 0;
			syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code);
			break;
		}
# if SASL
		}
# endif /* SASL */
	}

}
/*
**  CHECKSMTPATTACK -- check for denial-of-service attack by repetition
**
**	Parameters:
**		pcounter -- pointer to a counter for this command.
**		maxcount -- maximum value for this counter before we
**			slow down.
**		waitnow -- sleep now (in this routine)?
**		cname -- command name for logging.
**		e -- the current envelope.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Slows down if we seem to be under attack.
*/

static time_t
checksmtpattack(pcounter, maxcount, waitnow, cname, e)
	volatile int *pcounter;
	int maxcount;
	bool waitnow;
	char *cname;
	ENVELOPE *e;
{
	if (++(*pcounter) >= maxcount)
	{
		time_t s;

		if (*pcounter == maxcount && LogLevel > 5)
		{
			sm_syslog(LOG_INFO, e->e_id,
				  "%.100s: %.40s attack?",
				  CurSmtpClient, cname);
		}
		s = 1 << (*pcounter - maxcount);
		if (s >= MAXTIMEOUT)
			s = MAXTIMEOUT;
		/* sleep at least 1 second before returning */
		(void) sleep(*pcounter / maxcount);
		s -= *pcounter / maxcount;
		if (waitnow)
		{
			(void) sleep(s);
			return(0);
		}
		return(s);
	}
	return((time_t) 0);
}
/*
**  SKIPWORD -- skip a fixed word.
**
**	Parameters:
**		p -- place to start looking.
**		w -- word to skip.
**
**	Returns:
**		p following w.
**		NULL on error.
**
**	Side Effects:
**		clobbers the p data area.
*/

static char *
skipword(p, w)
	register char *volatile p;
	char *w;
{
	register char *q;
	char *firstp = p;

	/* find beginning of word */
	while (isascii(*p) && isspace(*p))
		p++;
	q = p;

	/* find end of word */
	while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
		p++;
	while (isascii(*p) && isspace(*p))
		*p++ = '\0';
	if (*p != ':')
	{
	  syntax:
		usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"",
			shortenstring(firstp, MAXSHORTSTR));
		return NULL;
	}
	*p++ = '\0';
	while (isascii(*p) && isspace(*p))
		p++;

	if (*p == '\0')
		goto syntax;

	/* see if the input word matches desired word */
	if (strcasecmp(q, w))
		goto syntax;

	return p;
}
/*
**  MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
**
**	Parameters:
**		kp -- the parameter key.
**		vp -- the value of that parameter.
**		e -- the envelope.
**
**	Returns:
**		none.
*/

static void
mail_esmtp_args(kp, vp, e)
	char *kp;
	char *vp;
	ENVELOPE *e;
{
	if (strcasecmp(kp, "size") == 0)
	{
		if (vp == NULL)
		{
			usrerr("501 5.5.2 SIZE requires a value");
			/* NOTREACHED */
		}
		define(macid("{msg_size}", NULL), newstr(vp), e);
  		e->e_msgsize = strtol(vp, (char **) NULL, 10);
		if (e->e_msgsize == LONG_MAX && errno == ERANGE)
		{
			usrerr("552 5.2.3 Message size exceeds maximum value");
			/* NOTREACHED */
		}
	}
	else if (strcasecmp(kp, "body") == 0)
	{
		if (vp == NULL)
		{
			usrerr("501 5.5.2 BODY requires a value");
			/* NOTREACHED */
		}
		else if (strcasecmp(vp, "8bitmime") == 0)
		{
			SevenBitInput = FALSE;
		}
		else if (strcasecmp(vp, "7bit") == 0)
		{
			SevenBitInput = TRUE;
		}
		else
		{
			usrerr("501 5.5.4 Unknown BODY type %s",
				vp);
			/* NOTREACHED */
		}
		e->e_bodytype = newstr(vp);
	}
	else if (strcasecmp(kp, "envid") == 0)
	{
		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
		{
			usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN");
			/* NOTREACHED */
		}
		if (vp == NULL)
		{
			usrerr("501 5.5.2 ENVID requires a value");
			/* NOTREACHED */
		}
		if (!xtextok(vp))
		{
			usrerr("501 5.5.4 Syntax error in ENVID parameter value");
			/* NOTREACHED */
		}
		if (e->e_envid != NULL)
		{
			usrerr("501 5.5.0 Duplicate ENVID parameter");
			/* NOTREACHED */
		}
		e->e_envid = newstr(vp);
		define(macid("{dsn_envid}", NULL), newstr(vp), e);
	}
	else if (strcasecmp(kp, "ret") == 0)
	{
		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
		{
			usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN");
			/* NOTREACHED */
		}
		if (vp == NULL)
		{
			usrerr("501 5.5.2 RET requires a value");
			/* NOTREACHED */
		}
		if (bitset(EF_RET_PARAM, e->e_flags))
		{
			usrerr("501 5.5.0 Duplicate RET parameter");
			/* NOTREACHED */
		}
		e->e_flags |= EF_RET_PARAM;
		if (strcasecmp(vp, "hdrs") == 0)
			e->e_flags |= EF_NO_BODY_RETN;
		else if (strcasecmp(vp, "full") != 0)
		{
			usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp);
			/* NOTREACHED */
		}
		define(macid("{dsn_ret}", NULL), newstr(vp), e);
	}
# if SASL
	else if (strcasecmp(kp, "auth") == 0)
	{
		int len;
		char *q;
		char *auth_param;	/* the value of the AUTH=x */
		bool saveQuickAbort = QuickAbort;
		bool saveSuprErrs = SuprErrs;
		char pbuf[256];

		if (vp == NULL)
		{
			usrerr("501 5.5.2 AUTH= requires a value");
			/* NOTREACHED */
		}
		if (e->e_auth_param != NULL)
		{
			usrerr("501 5.5.0 Duplicate AUTH parameter");
			/* NOTREACHED */
		}
		if ((q = strchr(vp, ' ')) != NULL)
			len = q - vp + 1;
		else
			len = strlen(vp) + 1;
		auth_param = xalloc(len);
		(void) strlcpy(auth_param, vp, len);
		if (!xtextok(auth_param))
		{
			usrerr("501 5.5.4 Syntax error in AUTH parameter value");
			/* just a warning? */
			/* NOTREACHED */
		}

		/* XXX this might be cut off */
		snprintf(pbuf, sizeof pbuf, "%s", xuntextify(auth_param));
		/* xalloc() the buffer instead? */

		/* XXX define this always or only if trusted? */
		define(macid("{auth_author}", NULL), newstr(pbuf), e);

		/*
		**  call Strust_auth to find out whether
		**  auth_param is acceptable (trusted)
		**  we shouldn't trust it if not authenticated
		**  (required by RFC, leave it to ruleset?)
		*/

		SuprErrs = TRUE;
		QuickAbort = FALSE;
		if (strcmp(auth_param, "<>") != 0 &&
		     (rscheck("trust_auth", pbuf, NULL, e, TRUE, FALSE, 10)
		      != EX_OK || Errors > 0))
		{
			if (tTd(95, 8))
			{
				q = e->e_auth_param;
				dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n",
					pbuf, (q == NULL) ? "" : q);
			}
			/* not trusted */
			e->e_auth_param = newstr("<>");
		}
		else
		{
			if (tTd(95, 8))
				dprintf("auth=\"%.100s\" trusted\n", pbuf);
			e->e_auth_param = newstr(auth_param);
		}
		free(auth_param);
		/* reset values */
		Errors = 0;
		QuickAbort = saveQuickAbort;
		SuprErrs = saveSuprErrs;
	}
# endif /* SASL */
	else
	{
		usrerr("555 5.5.4 %s parameter unrecognized", kp);
		/* NOTREACHED */
	}
}
/*
**  RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
**
**	Parameters:
**		a -- the address corresponding to the To: parameter.
**		kp -- the parameter key.
**		vp -- the value of that parameter.
**		e -- the envelope.
**
**	Returns:
**		none.
*/

static void
rcpt_esmtp_args(a, kp, vp, e)
	ADDRESS *a;
	char *kp;
	char *vp;
	ENVELOPE *e;
{
	if (strcasecmp(kp, "notify") == 0)
	{
		char *p;

		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
		{
			usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN");
			/* NOTREACHED */
		}
		if (vp == NULL)
		{
			usrerr("501 5.5.2 NOTIFY requires a value");
			/* NOTREACHED */
		}
		a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
		a->q_flags |= QHASNOTIFY;
		define(macid("{dsn_notify}", NULL), newstr(vp), e);

		if (strcasecmp(vp, "never") == 0)
			return;
		for (p = vp; p != NULL; vp = p)
		{
			p = strchr(p, ',');
			if (p != NULL)
				*p++ = '\0';
			if (strcasecmp(vp, "success") == 0)
				a->q_flags |= QPINGONSUCCESS;
			else if (strcasecmp(vp, "failure") == 0)
				a->q_flags |= QPINGONFAILURE;
			else if (strcasecmp(vp, "delay") == 0)
				a->q_flags |= QPINGONDELAY;
			else
			{
				usrerr("501 5.5.4 Bad argument \"%s\"  to NOTIFY",
					vp);
				/* N

⌨️ 快捷键说明

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