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

📄 milter.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		  case 'S':
			m->mf_timeout[SMFTO_WRITE] = convtime(p, 's');
			if (tTd(64, 5))
				printf("X%s: %c=%ld\n",
				       m->mf_name, fcode,
				       (u_long) m->mf_timeout[SMFTO_WRITE]);
			break;

		  case 'R':
			m->mf_timeout[SMFTO_READ] = convtime(p, 's');
			if (tTd(64, 5))
				printf("X%s: %c=%ld\n",
				       m->mf_name, fcode,
				       (u_long) m->mf_timeout[SMFTO_READ]);
			break;

		  case 'E':
			m->mf_timeout[SMFTO_EOM] = convtime(p, 's');
			if (tTd(64, 5))
				printf("X%s: %c=%ld\n",
				       m->mf_name, fcode,
				       (u_long) m->mf_timeout[SMFTO_EOM]);
			break;

		  default:
			if (tTd(64, 5))
				printf("X%s: %c unknown\n",
				       m->mf_name, fcode);
			syserr("X%s: unknown filter timeout %c",
			       m->mf_name, fcode);
			break;
		}
		p = delimptr;
	}
}
/*
**  MILTER_SET_OPTION -- set an individual milter option
**
**	Parameters:
**		name -- the name of the option.
**		val -- the value of the option.
**		sticky -- if set, don't let other setoptions override
**			this value.
**
**	Returns:
**		none.
*/

/* set if Milter sub-option is stuck */
static BITMAP256	StickyMilterOpt;

static struct milteropt
{
	char	*mo_name;	/* long name of milter option */
	u_char	mo_code;	/* code for option */
} MilterOptTab[] =
{
# define MO_MACROS_CONNECT		0x01
	{ "macros.connect",		MO_MACROS_CONNECT		},
# define MO_MACROS_HELO			0x02
	{ "macros.helo",		MO_MACROS_HELO			},
# define MO_MACROS_ENVFROM		0x03
	{ "macros.envfrom",		MO_MACROS_ENVFROM		},
# define MO_MACROS_ENVRCPT		0x04
	{ "macros.envrcpt",		MO_MACROS_ENVRCPT		},
	{ NULL,				0				},
};

void
milter_set_option(name, val, sticky)
	char *name;
	char *val;
	bool sticky;
{
	int nummac = 0;
	register struct milteropt *mo;
	char *p;
	char **macros = NULL;

	if (tTd(37, 2) || tTd(64, 5))
		dprintf("milter_set_option(%s = %s)", name, val);

	for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
	{
		if (strcasecmp(mo->mo_name, name) == 0)
			break;
	}

	if (mo->mo_name == NULL)
		syserr("milter_set_option: invalid Milter option %s", name);

	/*
	**  See if this option is preset for us.
	*/

	if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
	{
		if (tTd(37, 2) || tTd(64,5))
			dprintf(" (ignored)\n");
		return;
	}

	if (tTd(37, 2) || tTd(64,5))
		dprintf("\n");

	switch (mo->mo_code)
	{
	  case MO_MACROS_CONNECT:
		if (macros == NULL)
			macros = MilterConnectMacros;
		/* FALLTHROUGH */

	  case MO_MACROS_HELO:
		if (macros == NULL)
			macros = MilterHeloMacros;
		/* FALLTHROUGH */

	  case MO_MACROS_ENVFROM:
		if (macros == NULL)
			macros = MilterEnvFromMacros;
		/* FALLTHROUGH */

	  case MO_MACROS_ENVRCPT:
		if (macros == NULL)
			macros = MilterEnvRcptMacros;

		p = newstr(val);
		while (*p != '\0')
		{
			char *macro;

			/* Skip leading commas, spaces */
			while (*p != '\0' &&
			       (*p == ',' || (isascii(*p) && isspace(*p))))
				p++;

			if (*p == '\0')
				break;

			/* Find end of macro */
			macro = p;
			while (*p != '\0' && *p != ',' &&
			       isascii(*p) && !isspace(*p))
				p++;
			if (*p != '\0')
				*p++ = '\0';

			if (nummac >= MAXFILTERMACROS)
			{
				syserr("milter_set_option: too many macros in Milter.%s (max %d)",
				       name, MAXFILTERMACROS);
				macros[nummac] = NULL;
				break;
			}
			macros[nummac++] = macro;
		}
		macros[nummac] = NULL;
		break;

	  default:
		syserr("milter_set_option: invalid Milter option %s", name);
		break;
	}

	if (sticky)
		setbitn(mo->mo_code, StickyMilterOpt);
}
/*
**  MILTER_REOPEN_DF -- open & truncate the df file (for replbody)
**
**	Parameters:
**		e -- current envelope.
**
**	Returns:
**		0 if succesful, -1 otherwise
*/

static int
milter_reopen_df(e)
	ENVELOPE *e;
{
	char dfname[MAXPATHLEN];

	(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);

	/*
	**  In SuperSafe mode, e->e_dfp is a read-only FP so
	**  close and reopen writable (later close and reopen
	**  read only again).
	**
	**  In !SuperSafe mode, e->e_dfp still points at the
	**  buffered file I/O descriptor, still open for writing
	**  so there isn't as much work to do, just truncate it
	**  and go.
	*/

	if (SuperSafe)
	{
		/* close read-only df */
		if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
		{
			(void) fclose(e->e_dfp);
			e->e_flags &= ~EF_HAS_DF;
		}

		/* open writable */
		if ((e->e_dfp = fopen(dfname, "w+")) == NULL)
		{
			MILTER_DF_ERROR("milter_reopen_df: fopen %s: %s");
			return -1;
		}
	}
	else if (e->e_dfp == NULL)
	{
		/* shouldn't happen */
		errno = ENOENT;
		MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)");
		return -1;
	}
	return 0;
}
/*
**  MILTER_RESET_DF -- re-open read-only the df file (for replbody)
**
**	Parameters:
**		e -- current envelope.
**
**	Returns:
**		0 if succesful, -1 otherwise
*/

static int
milter_reset_df(e)
	ENVELOPE *e;
{
	int afd;
	char dfname[MAXPATHLEN];

	(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);

	if (fflush(e->e_dfp) != 0 || ferror(e->e_dfp))
	{
		MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
		return -1;
	}
	else if (!SuperSafe)
	{
		/* skip next few clauses */
		/* EMPTY */
	}
	else if ((afd = fileno(e->e_dfp)) >= 0 && fsync(afd) < 0)
	{
		MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
		return -1;
	}
	else if (fclose(e->e_dfp) < 0)
	{
		MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
		return -1;
	}
	else if ((e->e_dfp = fopen(dfname, "r")) == NULL)
	{
		MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
		return -1;
	}
	else
		e->e_flags |= EF_HAS_DF;
	return 0;
}
/*
**  MILTER_CAN_DELRCPTS -- can any milter filters delete recipients?
**
**	Parameters:
**		none
**
**	Returns:
**		TRUE if any filter deletes recipients, FALSE otherwise
*/

bool
milter_can_delrcpts()
{
	bool can = FALSE;
	int i;

	if (tTd(64, 10))
		dprintf("milter_can_delrcpts:");

	for (i = 0; InputFilters[i] != NULL; i++)
	{
		struct milter *m = InputFilters[i];

		if (bitset(SMFIF_DELRCPT, m->mf_fflags))
		{
			can = TRUE;
			break;
		}
	}
	if (tTd(64, 10))
		dprintf("%s\n", can ? "TRUE" : "FALSE");

	return can;
}
/*
**  MILTER_QUIT_FILTER -- close down a single filter
**
**	Parameters:
**		m -- milter structure of filter to close down.
**		e -- current envelope.
**
**	Returns:
**		none
*/

static void
milter_quit_filter(m, e)
	struct milter *m;
	ENVELOPE *e;
{
	if (tTd(64, 10))
		dprintf("milter_quit_filter(%s)\n", m->mf_name);

	/* Never replace error state */
	if (m->mf_state == SMFS_ERROR)
		return;

	if (m->mf_sock < 0 ||
	    m->mf_state == SMFS_CLOSED ||
	    m->mf_state == SMFS_READY)
	{
		m->mf_sock = -1;
		m->mf_state = SMFS_CLOSED;
		return;
	}

	(void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0,
			    m->mf_timeout[SMFTO_WRITE], e);
	(void) close(m->mf_sock);
	m->mf_sock = -1;
	if (m->mf_state != SMFS_ERROR)
		m->mf_state = SMFS_CLOSED;
}
/*
**  MILTER_ABORT_FILTER -- tell filter to abort current message
**
**	Parameters:
**		m -- milter structure of filter to abort.
**		e -- current envelope.
**
**	Returns:
**		none
*/

static void
milter_abort_filter(m, e)
	struct milter *m;
	ENVELOPE *e;
{
	if (tTd(64, 10))
		dprintf("milter_abort_filter(%s)\n", m->mf_name);

	if (m->mf_sock < 0 ||
	    m->mf_state != SMFS_INMSG)
		return;

	(void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0,
			    m->mf_timeout[SMFTO_WRITE], e);
	if (m->mf_state != SMFS_ERROR)
		m->mf_state = SMFS_DONE;
}
/*
**  MILTER_SEND_MACROS -- provide macros to the filters
**
**	Parameters:
**		m -- milter to send macros to.
**		macros -- macros to send for filter smfi_getsymval().
**		cmd -- which command the macros are associated with.
**		e -- current envelope (for macro access).
**
**	Returns:
**		none
*/

static void
milter_send_macros(m, macros, cmd, e)
	struct milter *m;
	char **macros;
	char cmd;
	ENVELOPE *e;
{
	int i;
	int mid;
	char *v;
	char *buf, *bp;
	ssize_t s;

	/* sanity check */
	if (macros == NULL || macros[0] == NULL)
		return;

	/* put together data */
	s = 1;			/* for the command character */
	for (i = 0; macros[i] != NULL; i++)
	{
		mid = macid(macros[i], NULL);
		if (mid == '\0')
			continue;
		v = macvalue(mid, e);
		if (v == NULL)
			continue;
		s += strlen(macros[i]) + 1 + strlen(v) + 1;
	}

	buf = (char *)xalloc(s);
	bp = buf;
	*bp++ = cmd;
	for (i = 0; macros[i] != NULL; i++)
	{
		mid = macid(macros[i], NULL);
		if (mid == '\0')
			continue;
		v = macvalue(mid, e);
		if (v == NULL)
			continue;

		if (tTd(64, 10))
			dprintf("milter_send_macros(%s, %c): %s=%s\n",
				m->mf_name, cmd, macros[i], v);

		(void) strlcpy(bp, macros[i], s - (bp - buf));
		bp += strlen(bp) + 1;
		(void) strlcpy(bp, v, s - (bp - buf));
		bp += strlen(bp) + 1;
	}
	(void) milter_write(m, SMFIC_MACRO, buf, s,
			    m->mf_timeout[SMFTO_WRITE], e);
	free(buf);
}

/*
**  MILTER_SEND_COMMAND -- send a command and return the response for a filter
**
**	Parameters:
**		m -- current milter filter
**		command -- command to send.
**		data -- optional command data.
**		sz -- length of buf.
**		e -- current envelope (for e->e_id).
**		state -- return state word.
**
**	Returns:
**		response string (may be NULL)
*/

static char *
milter_send_command(m, command, data, sz, e, state)
	struct milter *m;
	char command;
	void *data;
	ssize_t sz;
	ENVELOPE *e;
	char *state;
{
	char rcmd;
	ssize_t rlen;
	u_long skipflag;
	char *defresponse;
	char *response;

	if (tTd(64, 10))
		dprintf("milter_send_command(%s): cmd %c len %ld\n",
			m->mf_name, (char) command, (long) sz);

	/* find skip flag and default failure */
	switch (command)
	{
	  case SMFIC_CONNECT:
		skipflag = SMFIP_NOCONNECT;
		defresponse = "554 Command rejected";
		break;

	  case SMFIC_HELO:
		skipflag = SMFIP_NOHELO;
		defresponse = "550 Command rejected";
		break;

	  case SMFIC_MAIL:
		skipflag = SMFIP_NOMAIL;
		defresponse = "550 5.7.1 Command rejected";
		break;

	  case SMFIC_RCPT:
		skipflag = SMFIP_NORCPT;
		defresponse = "550 5.7.1 Command rejected";
		break;

	  case SMFIC_HEADER:
		skipflag = SMFIP_NOHDRS;
		defresponse = "550 5.7.1 Command rejected";
		break;

	  case SMFIC_BODY:
		skipflag = SMFIP_NOBODY;
		defresponse = "554 5.7.1 Command rejected";
		break;

	  case SMFIC_EOH:
		skipflag = SMFIP_NOEOH;
		defresponse = "550 5.7.1 Command rejected";
		break;

	  case SMFIC_BODYEOB:
	  case SMFIC_OPTNEG:
	  case SMFIC_MACRO:
	  case SMFIC_ABORT:
	  case SMFIC_QUIT:
		/* NOTE: not handled by milter_send_command() */
		/* FALLTHROUGH */

	  default:
		skipflag = 0;
		defresponse = "550 5.7.1 Command rejected";
		break;
	}

	/* check if filter wants this command */
	if (skipflag != 0 &&
	    bitset(skipflag, m->mf_pflags))
		return NULL;


	(void) milter_write(m, command, data, sz,
			    m->mf_timeout[SMFTO_WRITE], e);
	if (m->mf_state == SMFS_ERROR)
	{
		MILTER_CHECK_ERROR(/* EMPTY */;);
		return NULL;
	}

	response = milter_read(m, &rcmd, &rlen,
			       m->mf_timeout[SMFTO_READ], e);
	if (m->mf_state == SMFS_ERROR)
	{
		MILTER_CHECK_ERROR(/* EMPTY */;);
		return NULL;
	}

	if (tTd(64, 10))
		dprintf("milter_send_command(%s): returned %c\n",
			m->mf_name, (char) rcmd);

	switch (rcmd)
	{
	  case SMFIR_REPLYCODE:
		MILTER_CHECK_REPLYCODE(defresponse);
		/* FALLTHROUGH */

	  case SMFIR_REJECT:
	  case SMFIR_DISCARD:
	  case SMFIR_TEMPFAIL:
		*state = rcmd;
		break;

	  case SMFIR_ACCEPT:
		/* this filter is done with message/connection */
		m->mf_state = SMFS_DONE;
		break;

	  case SMFIR_CONTINUE:
		/* if MAIL command is ok, filter is in message state */
		if (command == SMFIC_MAIL)
			m->mf_state = SMFS_INMSG;
		break;

	  default:
		/* Invalid response to command */
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_send_command(%s): returned bogus response %c",
				  m->mf_name, rcmd);
		milter_error(m);
		break;
	}

	if (*state != SMFIR_REPLYCODE &&
	    response != NULL)
	{
		free(response);
		response = NULL;
	}
	return response;
}

/*
**  MILTER_COMMAND -- send a command and return the response for each filter
**
**	Parameters:
**		command -- command to send.
**		data -- optional command data.
**		sz -- length of buf.
**		macros -- macros to send for filter smfi_getsymval().
**		e -- current envelope (for macro access).
**		state -- return state word.
**
**	Returns:
**		response string (may be NULL)
*/

⌨️ 快捷键说明

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