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

📄 milter.c

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

static char *
milter_command(command, data, sz, macros, e, state)
	char command;
	void *data;
	ssize_t sz;
	char **macros;
	ENVELOPE *e;
	char *state;
{
	int i;
	char *response = NULL;

	if (tTd(64, 10))
		dprintf("milter_command: cmd %c len %ld\n",
			(char) command, (long) sz);

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

		/* sanity check */
		if (m->mf_sock < 0 ||
		    (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
			continue;

		/* send macros (regardless of whether we send command) */
		if (macros != NULL && macros[0] != NULL)
		{
			milter_send_macros(m, macros, command, e);
			if (m->mf_state == SMFS_ERROR)
			{
				MILTER_CHECK_ERROR(continue);
				break;
			}
		}

		response = milter_send_command(m, command, data, sz, e, state);
		if (*state != SMFIR_CONTINUE)
			break;
	}
	return response;
}
/*
**  MILTER_NEGOTIATE -- get version and flags from filter
**
**	Parameters:
**		m -- milter filter structure.
**		e -- current envelope.
**
**	Returns:
**		0 on success, -1 otherwise
*/

static int
milter_negotiate(m, e)
	struct milter *m;
	ENVELOPE *e;
{
	char rcmd;
	mi_int32 fvers;
	mi_int32 fflags;
	mi_int32 pflags;
	char *response;
	ssize_t rlen;
	char data[MILTER_OPTLEN];

	/* sanity check */
	if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
	{
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): impossible state",
				  m->mf_name);
		milter_error(m);
		return -1;
	}

	fvers = htonl(SMFI_VERSION);
	fflags = htonl(SMFI_CURR_ACTS);
	pflags = htonl(SMFI_CURR_PROT);
	(void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES);
	(void) memcpy(data + MILTER_LEN_BYTES,
		      (char *) &fflags, MILTER_LEN_BYTES);
	(void) memcpy(data + (MILTER_LEN_BYTES * 2),
		      (char *) &pflags, MILTER_LEN_BYTES);
	(void) milter_write(m, SMFIC_OPTNEG, data, sizeof data,
			    m->mf_timeout[SMFTO_WRITE], e);

	if (m->mf_state == SMFS_ERROR)
		return -1;

	response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e);
	if (m->mf_state == SMFS_ERROR)
		return -1;

	if (rcmd != SMFIC_OPTNEG)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): returned %c instead of %c\n",
				m->mf_name, rcmd, SMFIC_OPTNEG);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): returned %c instead of %c",
				  m->mf_name, rcmd, SMFIC_OPTNEG);
		if (response != NULL)
			free(response);
		milter_error(m);
		return -1;
	}

	/* Make sure we have enough bytes for the version */
	if (response == NULL || rlen < MILTER_LEN_BYTES)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): did not return valid info\n",
				m->mf_name);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): did not return valid info",
				  m->mf_name);
		if (response != NULL)
			free(response);
		milter_error(m);
		return -1;
	}

	/* extract information */
	(void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES);

	/* Now make sure we have enough for the feature bitmap */
	if (rlen != MILTER_OPTLEN)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): did not return enough info\n",
				m->mf_name);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): did not return enough info",
				  m->mf_name);
		if (response != NULL)
			free(response);
		milter_error(m);
		return -1;
	}

	(void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES,
		      MILTER_LEN_BYTES);
	(void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
		      MILTER_LEN_BYTES);
	free(response);
	response = NULL;

	m->mf_fvers = ntohl(fvers);
	m->mf_fflags = ntohl(fflags);
	m->mf_pflags = ntohl(pflags);

	/* check for version compatibility */
	if (m->mf_fvers == 1 ||
	    m->mf_fvers > SMFI_VERSION)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): version %lu != MTA milter version %d\n",
				m->mf_name, m->mf_fvers, SMFI_VERSION);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): version %ld != MTA milter version %d",
				  m->mf_name, m->mf_fvers, SMFI_VERSION);
		milter_error(m);
		return -1;
	}

	/* check for filter feature mismatch */
	if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
				m->mf_name, m->mf_fflags,
				(u_long) SMFI_CURR_ACTS);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): filter abilities 0x%lx != MTA milter abilities 0x%lx\n",
				  m->mf_name, m->mf_fflags,
				  (u_long) SMFI_CURR_ACTS);
		milter_error(m);
		return -1;
	}

	/* check for protocol feature mismatch */
	if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags)
	{
		if (tTd(64, 5))
			dprintf("milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
				m->mf_name, m->mf_pflags,
				(u_long) SMFI_CURR_PROT);
		if (LogLevel > 0)
			sm_syslog(LOG_ERR, e->e_id,
				  "milter_negotiate(%s): protocol abilities 0x%lx != MTA milter abilities 0x%lx\n",
				  m->mf_name, m->mf_pflags,
				  (u_long) SMFI_CURR_PROT);
		milter_error(m);
		return -1;
	}

	if (tTd(64, 5))
		dprintf("milter_negotiate(%s): version %lu, fflags 0x%lx, pflags 0x%lx\n",
			m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
	return 0;
}
/*
**  MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
**
**	Reduce code duplication by putting these checks in one place
**
**	Parameters:
**		e -- current envelope.
**
**	Returns:
**		none
*/

static void
milter_per_connection_check(e)
	ENVELOPE *e;
{
	int i;

	/* see if we are done with any of the filters */
	for (i = 0; InputFilters[i] != NULL; i++)
	{
		struct milter *m = InputFilters[i];

		if (m->mf_state == SMFS_DONE)
			milter_quit_filter(m, e);
	}
}
/*
**  MILTER_ERROR -- Put a milter filter into error state
**
**	Parameters:
**		m -- the broken filter.
**
**	Returns:
**		none
*/

static void
milter_error(m)
	struct milter *m;
{
	/*
	**  We could send a quit here but
	**  we may have gotten here due to
	**  an I/O error so we don't want
	**  to try to make things worse.
	*/

	if (m->mf_sock >= 0)
	{
		(void) close(m->mf_sock);
		m->mf_sock = -1;
	}
	m->mf_state = SMFS_ERROR;
}
/*
**  MILTER_HEADERS -- send headers to a single milter filter
**
**	Parameters:
**		m -- current filter.
**		e -- current envelope.
**		state -- return state from response.
**
**	Returns:
**		response string (may be NULL)
*/

static char *
milter_headers(m, e, state)
	struct milter *m;
	ENVELOPE *e;
	char *state;
{
	char *response = NULL;
	HDR *h;

	for (h = e->e_header; h != NULL; h = h->h_link)
	{
		char *buf;
		ssize_t s;

		/* don't send over deleted headers */
		if (h->h_value == NULL)
		{
			/* strip H_USER so not counted in milter_chgheader() */
			h->h_flags &= ~H_USER;
			continue;
		}

		/* skip auto-generated */
		if (!bitset(H_USER, h->h_flags))
			continue;

		if (tTd(64, 10))
			dprintf("milter_headers: %s: %s\n",
				h->h_field, h->h_value);

		s = strlen(h->h_field) + 1 +
			strlen(h->h_value) + 1;
		buf = (char *) xalloc(s);
		snprintf(buf, s, "%s%c%s", h->h_field, '\0', h->h_value);

		/* send it over */
		response = milter_send_command(m, SMFIC_HEADER, buf,
					       s, e, state);
		free(buf);
		if (m->mf_state == SMFS_ERROR ||
		    m->mf_state == SMFS_DONE ||
		    *state != SMFIR_CONTINUE)
			break;
	}
	return response;
}
/*
**  MILTER_BODY -- send the body to a filter
**
**	Parameters:
**		m -- current filter.
**		e -- current envelope.
**		state -- return state from response.
**
**	Returns:
**		response string (may be NULL)
*/

static char *
milter_body(m, e, state)
	struct milter *m;
	ENVELOPE *e;
	char *state;
{
	char bufchar = '\0';
	char prevchar = '\0';
	int c;
	char *response = NULL;
	char *bp;
	char buf[MILTER_CHUNK_SIZE];

	if (tTd(64, 10))
		dprintf("milter_body\n");

	if (bfrewind(e->e_dfp) < 0)
	{
		ExitStat = EX_IOERR;
		*state = SMFIR_TEMPFAIL;
		syserr("milter_body: %s/df%s: rewind error",
		       qid_printqueue(e->e_queuedir), e->e_id);
		return NULL;
	}

	bp = buf;
	while ((c = getc(e->e_dfp)) != EOF)
	{
		/*  Change LF to CRLF */
		if (c == '\n')
		{
			/* Not a CRLF already? */
			if (prevchar != '\r')
			{
				/* Room for CR now? */
				if (bp + 2 > &buf[sizeof buf])
				{
					/* No room, buffer LF */
					bufchar = c;

					/* and send CR now */
					c = '\r';
				}
				else
				{
					/* Room to do it now */
					*bp++ = '\r';
					prevchar = '\r';
				}
			}
		}
		*bp++ = (char) c;
		prevchar = c;
		if (bp >= &buf[sizeof buf])
		{
			/* send chunk */
			response = milter_send_command(m, SMFIC_BODY, buf,
						       bp - buf, e, state);
			bp = buf;
			if (bufchar != '\0')
			{
				*bp++ = bufchar;
				bufchar = '\0';
				prevchar = bufchar;
			}
		}
		if (m->mf_state == SMFS_ERROR ||
		    m->mf_state == SMFS_DONE ||
		    *state != SMFIR_CONTINUE)
			break;
	}

	/* check for read errors */
	if (ferror(e->e_dfp))
	{
		ExitStat = EX_IOERR;
		if (*state == SMFIR_CONTINUE ||
		    *state == SMFIR_ACCEPT)
		{
			*state = SMFIR_TEMPFAIL;
			if (response != NULL)
			{
				free(response);
				response = NULL;
			}
		}
		syserr("milter_body: %s/df%s: read error",
		       qid_printqueue(e->e_queuedir), e->e_id);
		return response;
	}

	/* send last body chunk */
	if (bp > buf &&
	    m->mf_state != SMFS_ERROR &&
	    m->mf_state != SMFS_DONE &&
	    *state == SMFIR_CONTINUE)
	{
		/* send chunk */
		response = milter_send_command(m, SMFIC_BODY, buf, bp - buf,
					       e, state);
		bp = buf;
	}
	return response;
}

/*
**  Actions
*/

/*
**  MILTER_ADDHEADER -- Add the supplied header to the message
**
**	Parameters:
**		response -- encoded form of header/value.
**		rlen -- length of response.
**		e -- current envelope.
**
**	Returns:
**		none
*/

static void
milter_addheader(response, rlen, e)
	char *response;
	ssize_t rlen;
	ENVELOPE *e;
{
	char *val;

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

	/* sanity checks */
	if (response == NULL)
	{
		if (tTd(64, 10))
			dprintf("NULL response\n");
		return;
	}

	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
	{
		if (tTd(64, 10))
			dprintf("didn't follow protocol (total len)\n");
		return;
	}

	/* Find separating NUL */
	val = response + strlen(response) + 1;

	/* another sanity check */
	if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
	{
		if (tTd(64, 10))
			dprintf("didn't follow protocol (part len)\n");
		return;
	}

	if (*response == '\0')
	{
		if (tTd(64, 10))
			dprintf("empty field name\n");
		return;
	}

	/* add to e_msgsize */
	e->e_msgsize += strlen(response) + 2 + strlen(val);

	if (tTd(64, 10))
		dprintf("Add %s: %s\n", response, val);

	addheader(newstr(response), val, H_USER, &e->e_header);
}
/*
**  MILTER_CHANGEHEADER -- Change the supplied header in the message
**
**	Parameters:
**		response -- encoded form of header/index/value.
**		rlen -- length of response.
**		e -- current envelope.
**
**	Returns:
**		none
*/

static void
milter_changeheader(response, rlen, e)
	char *response;
	ssize_t rlen;
	ENVELOPE *e;
{
	mi_int32 i, index;
	char *field, *val;
	HDR *h;

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

	/* sanity checks */
	if (response == NULL)
	{
		if (tTd(64, 10))
			dprintf("NULL response\n");
		return;
	}

	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
	{
		if (tTd(64, 10))
			dprintf("didn't follow protocol (total len)\n");
		return;
	}

	/* Find separating NUL */
	(void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
	index = ntohl(i);
	field = response + MILTER_LEN_BYTES;
	val = field + strlen(field) + 1;

	/* another sanity check */
	if (MILTER_LEN_BYTES + strlen(field) + 1 +
	    strlen(val) + 1 != (size_t) rlen)
	{
		if (tTd(64, 10))
			dprintf("didn't follow protocol (part len)\n");
		return;
	}

	if (*field == '\0')
	{
		if (tTd(64, 10))
			dprintf("empty field name\n");
		return;
	}

	for (h = e->e_header; h != NULL; h = h->h_link)
	{
		if (bitset(H_USER, h->h_flags) &&
		    strcasecmp(h->h_field, field) == 0 &&
		    --index <= 0)
			break;
	}

	if (h == NULL)
	{
		if (*val == '\0')
		{
			if (tTd(64, 10))
				dprintf("Delete (noop) %s:\n", field);
		}
		else
		{
			/* treat modify value with no existing header as add */
			if (tTd(64, 10))
				dprintf("Add %s: %s\n",	field, val);

			addheader(newstr(field), val, H_USER, &e->e_header);
		}
		return;
	}

	if (tTd(64, 10))
	{
		if (*val == '\0')
		{
			dprintf("Delete %s: %s\n", field,
				h->h_value == NULL ? "<NULL>" : h->h_value);
		}
		else
		{
			dprintf("Change %s: from %s to %s\n",
				field,

⌨️ 快捷键说明

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