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

📄 srvrsmtp.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				     macvalue(macid("{verify}", NULL), e),
				     "STARTTLS", e, TRUE, TRUE, 6) != EX_OK ||
			    Errors > 0)
			{
				extern char MsgBuf[];

				if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf))
					nullserver = newstr(MsgBuf);
				else
					nullserver = "503 5.7.0 Authentication required.";
			}
			QuickAbort = saveQuickAbort;
			SuprErrs = saveSuprErrs;

			tls_ok = FALSE;	/* don't offer STARTTLS again */
			gothello = FALSE;	/* discard info */
			n_helo = 0;
			OneXact = TRUE;	/* only one xaction this run */
#  if SASL
			if (sasl_ok)
			{
				char *s;

				if ((s = macvalue(macid("{cipher_bits}", NULL), e)) != NULL &&
				    (ext_ssf.ssf = atoi(s)) > 0)
				{
#  if _FFR_EXT_MECH
					ext_ssf.auth_id = macvalue(macid("{cert_subject}",
									 NULL),
								   e);
#  endif /* _FFR_EXT_MECH */
					sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
							       &ext_ssf) == SASL_OK;
					if (mechlist != NULL)
						free(mechlist);
					mechlist = NULL;
					if (sasl_ok)
					{
						n_mechs = saslmechs(conn,
								    &mechlist);
						sasl_ok = n_mechs > 0;
					}
				}
			}
#  endif /* SASL */

			/* switch to secure connection */
#if SFIO
			r = sfdctls(InChannel, OutChannel, srv_ssl);
#else /* SFIO */
# if _FFR_TLS_TOREK
			r = sfdctls(&InChannel, &OutChannel, srv_ssl);
# endif /* _FFR_TLS_TOREK */
#endif /* SFIO */
			if (r == 0)
				tls_active = TRUE;
			else
			{
				/*
				**  XXX this is an internal error
				**  how to deal with it?
				**  we can't generate an error message
				**  since the other side switched to an
				**  encrypted layer, but we could not...
				**  just "hang up"?
				*/
				nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer";
				syserr("TLS: can't switch to encrypted layer");
			}
			break;
# endif /* STARTTLS */

		  case CMDHELO:		/* hello -- introduce yourself */
		  case CMDEHLO:		/* extended hello */
			if (c->cmd_code == CMDEHLO)
			{
				protocol = "ESMTP";
				SmtpPhase = "server EHLO";
			}
			else
			{
				protocol = "SMTP";
				SmtpPhase = "server HELO";
			}

			/* avoid denial-of-service */
			(void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, TRUE,
					       "HELO/EHLO", e);

			/* check for duplicate HELO/EHLO per RFC 1651 4.2 */
			if (gothello)
			{
				usrerr("503 %s Duplicate HELO/EHLO",
					MyHostName);
				break;
			}

			/* check for valid domain name (re 1123 5.2.5) */
			if (*p == '\0' && !AllowBogusHELO)
			{
				usrerr("501 %s requires domain address",
					cmdbuf);
				break;
			}

			/* check for long domain name (hides Received: info) */
			if (strlen(p) > MAXNAME)
			{
				usrerr("501 Invalid domain name");
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, CurEnv->e_id,
						  "invalid domain name (too long) from %.100s",
						  CurSmtpClient);
				break;
			}

			for (q = p; *q != '\0'; q++)
			{
				if (!isascii(*q))
					break;
				if (isalnum(*q))
					continue;
				if (isspace(*q))
				{
					*q = '\0';
					break;
				}
				if (strchr("[].-_#", *q) == NULL)
					break;
			}

			if (*q == '\0')
			{
				q = "pleased to meet you";
				sendinghost = newstr(p);
			}
			else if (!AllowBogusHELO)
			{
				usrerr("501 Invalid domain name");
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, CurEnv->e_id,
						  "invalid domain name (%.100s) from %.100s",
						  p, CurSmtpClient);
				break;
			}
			else
			{
				q = "accepting invalid domain name";
			}

			gothello = TRUE;

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

				response = milter_helo(p, e, &state);
				switch (state)
				{
				  case SMFIR_REPLYCODE:
					nullserver = response;
					milterize = FALSE;
					break;

				  case SMFIR_REJECT:
					nullserver = "Command rejected";
					milterize = FALSE;
					break;

				  case SMFIR_TEMPFAIL:
					tempfail = TRUE;
					milterize = FALSE;
					break;
				}
			}
# endif /* _FFR_MILTER */

			/* print HELO response message */
			if (c->cmd_code != CMDEHLO)
			{
				message("250 %s Hello %s, %s",
					MyHostName, CurSmtpClient, q);
				break;
			}

			message("250-%s Hello %s, %s",
				MyHostName, CurSmtpClient, q);

			/* offer ENHSC even for nullserver */
			if (nullserver != NULL)
			{
				message("250 ENHANCEDSTATUSCODES");
				break;
			}

			/*
			**  print EHLO features list
			**
			**  Note: If you change this list,
			**        remember to update 'helpfile'
			*/


			message("250-ENHANCEDSTATUSCODES");
			if (!bitset(PRIV_NOEXPN, PrivacyFlags))
			{
				message("250-EXPN");
				if (!bitset(PRIV_NOVERB, PrivacyFlags))
					message("250-VERB");
			}
# if MIME8TO7
			message("250-8BITMIME");
# endif /* MIME8TO7 */
			if (MaxMessageSize > 0)
				message("250-SIZE %ld", MaxMessageSize);
			else
				message("250-SIZE");
# if DSN
			if (SendMIMEErrors &&
			    !bitset(PRIV_NORECEIPTS, PrivacyFlags))
				message("250-DSN");
# endif /* DSN */
			message("250-ONEX");
			if (!bitset(PRIV_NOETRN, PrivacyFlags) &&
			    !bitnset(D_NOETRN, d_flags))
				message("250-ETRN");
			message("250-XUSR");

# if SASL
			if (sasl_ok && mechlist != NULL && *mechlist != '\0')
				message("250-AUTH %s", mechlist);
# endif /* SASL */
# if STARTTLS
			if (tls_ok && usetls)
				message("250-STARTTLS");
# endif /* STARTTLS */
			message("250 HELP");
			break;

		  case CMDMAIL:		/* mail -- designate sender */
			SmtpPhase = "server MAIL";

			/* check for validity of this command */
			if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
			{
				usrerr("503 5.0.0 Polite people say HELO first");
				break;
			}
			if (gotmail)
			{
				usrerr("503 5.5.0 Sender already specified");
				break;
			}
			if (InChild)
			{
				errno = 0;
				syserr("503 5.5.0 Nested MAIL command: MAIL %s", p);
				finis(TRUE, ExitStat);
			}
# if SASL
			if (bitnset(D_AUTHREQ, d_flags) &&
			    authenticating != SASL_IS_AUTH)
			{
				usrerr("530 5.7.0 Authentication required");
				break;
			}
# endif /* SASL */

			p = skipword(p, "from");
			if (p == NULL)
				break;
			if (tempfail)
			{
				if (LogLevel > 9)
					sm_syslog(LOG_INFO, e->e_id,
						  "SMTP MAIL command (%.100s) from %.100s tempfailed (due to previous checks)",
						  p, CurSmtpClient);
				usrerr("451 4.7.1 Please try again later");
				break;
			}

			/* make sure we know who the sending host is */
			if (sendinghost == NULL)
				sendinghost = peerhostname;


			/* fork a subprocess to process this command */
			ric = runinchild("SMTP-MAIL", e);

			/* Catch a problem and stop processing */
			if (ric == RIC_TEMPFAIL && nullserver == NULL)
				nullserver = "452 4.3.0 Internal software error";
			if (ric != RIC_INCHILD)
				break;

			if (Errors > 0)
				goto undo_subproc_no_pm;
			if (!gothello)
			{
				auth_warning(e,
					"%s didn't use HELO protocol",
					CurSmtpClient);
			}
# ifdef PICKY_HELO_CHECK
			if (strcasecmp(sendinghost, peerhostname) != 0 &&
			    (strcasecmp(peerhostname, "localhost") != 0 ||
			     strcasecmp(sendinghost, MyHostName) != 0))
			{
				auth_warning(e, "Host %s claimed to be %s",
					CurSmtpClient, sendinghost);
			}
# endif /* PICKY_HELO_CHECK */

			if (protocol == NULL)
				protocol = "SMTP";
			define('r', protocol, e);
			define('s', sendinghost, e);

			if (Errors > 0)
				goto undo_subproc_no_pm;
			nrcpts = 0;
			define(macid("{ntries}", NULL), "0", e);
			e->e_flags |= EF_CLRQUEUE;
			sm_setproctitle(TRUE, e, "%s %s: %.80s",
					qid_printname(e),
					CurSmtpClient, inp);

			/* child -- go do the processing */
			if (setjmp(TopFrame) > 0)
			{
				/* this failed -- undo work */
 undo_subproc_no_pm:
				e->e_flags &= ~EF_PM_NOTIFY;
 undo_subproc:
				if (InChild)
				{
					QuickAbort = FALSE;
					SuprErrs = TRUE;
					e->e_flags &= ~EF_FATALERRS;

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

					finis(TRUE, ExitStat);
				}
				break;
			}
			QuickAbort = TRUE;

			/* must parse sender first */
			delimptr = NULL;
			setsender(p, e, &delimptr, ' ', FALSE);
			if (delimptr != NULL && *delimptr != '\0')
				*delimptr++ = '\0';
			if (Errors > 0)
				goto undo_subproc_no_pm;

			/* Successfully set e_from, allow logging */
			e->e_flags |= EF_LOGSENDER;

			/* put resulting triple from parseaddr() into macros */
			if (e->e_from.q_mailer != NULL)
				 define(macid("{mail_mailer}", NULL),
					e->e_from.q_mailer->m_name, e);
			else
				 define(macid("{mail_mailer}", NULL),
					NULL, e);
			if (e->e_from.q_host != NULL)
				define(macid("{mail_host}", NULL),
				       e->e_from.q_host, e);
			else
				define(macid("{mail_host}", NULL),
				       "localhost", e);
			if (e->e_from.q_user != NULL)
				define(macid("{mail_addr}", NULL),
				       e->e_from.q_user, e);
			else
				define(macid("{mail_addr}", NULL),
				       NULL, e);
			if (Errors > 0)
			  goto undo_subproc_no_pm;

			/* check for possible spoofing */
			if (RealUid != 0 && OpMode == MD_SMTP &&
			    !wordinclass(RealUserName, 't') &&
			    (!bitnset(M_LOCALMAILER,
				      e->e_from.q_mailer->m_flags) ||
			     strcmp(e->e_from.q_user, RealUserName) != 0))
			{
				auth_warning(e, "%s owned process doing -bs",
					RealUserName);
			}

			/* now parse ESMTP arguments */
			e->e_msgsize = 0;
			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("MAIL: got arg %s=\"%s\"\n", kp,
						vp == NULL ? "<null>" : vp);

				mail_esmtp_args(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)
					goto undo_subproc_no_pm;
			}
			args[argno] = NULL;
			if (Errors > 0)
				goto undo_subproc_no_pm;

			/* do config file checking of the sender */
			if (rscheck("check_mail", addr,
				    NULL, e, TRUE, TRUE, 4) != EX_OK ||
			    Errors > 0)
				goto undo_subproc_no_pm;

			if (MaxMessageSize > 0 &&
			   (e->e_msgsize > MaxMessageSize || e->e_msgsize < 0))
			{
				usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)",
					MaxMessageSize);
				goto undo_subproc_no_pm;
			}

			if (!enoughdiskspace(e->e_msgsize, TRUE))
			{
				usrerr("452 4.4.5 Insufficient disk space; try again later");
				goto undo_subproc_no_pm;
			}
			if (Errors > 0)
				goto undo_subproc_no_pm;

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

				response = milter_envfrom(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 */
			if (Errors > 0)
				goto undo_subproc_no_pm;

			message("250 2.1.0 Sender ok");
			gotmail = TRUE;
			break;

		  case CMDRCPT:		/* rcpt -- designate recipient */
			if (!gotmail)
			{
				usrerr("503 5.0.0 Need MAIL before RCPT");
				break;
			}
			SmtpPhase = "server RCPT";
			if (setjmp(TopFrame) > 0)
			{
				e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
				break;
			}
			QuickAbort = TRUE;
			LogUsrErrs = TRUE;

			/* limit flooding of our machine */
			if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg)
			{
				usrerr("452 4.5.3 Too many recipients");
				break;
			}

			if (e->e_sendmode != SM_DELIVER)

⌨️ 快捷键说明

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