📄 milter.c
字号:
h->h_value == NULL ? "<NULL>" : h->h_value,
val);
}
}
if (h->h_value != NULL)
{
e->e_msgsize -= strlen(h->h_value);
free(h->h_value);
}
if (*val == '\0')
{
/* Remove "Field: " from message size */
e->e_msgsize -= strlen(h->h_field) + 2;
h->h_value = NULL;
}
else
{
h->h_value = newstr(val);
e->e_msgsize += strlen(h->h_value);
}
}
/*
** MILTER_ADDRCPT -- Add the supplied recipient to the message
**
** Parameters:
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
**
** Returns:
** none
*/
static void
milter_addrcpt(response, rlen, e)
char *response;
ssize_t rlen;
ENVELOPE *e;
{
if (tTd(64, 10))
dprintf("milter_addrcpt: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
dprintf("NULL response\n");
return;
}
if (*response == '\0' ||
strlen(response) + 1 != (size_t) rlen)
{
if (tTd(64, 10))
dprintf("didn't follow protocol (total len %d != rlen %d)\n",
strlen(response), rlen -1);
return;
}
if (tTd(64, 10))
dprintf("%s\n", response);
(void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
return;
}
/*
** MILTER_DELRCPT -- Delete the supplied recipient from the message
**
** Parameters:
** response -- encoded form of recipient address.
** rlen -- length of response.
** e -- current envelope.
**
** Returns:
** none
*/
static void
milter_delrcpt(response, rlen, e)
char *response;
ssize_t rlen;
ENVELOPE *e;
{
if (tTd(64, 10))
dprintf("milter_delrcpt: ");
/* sanity checks */
if (response == NULL)
{
if (tTd(64, 10))
dprintf("NULL response\n");
return;
}
if (*response == '\0' ||
strlen(response) + 1 != (size_t) rlen)
{
if (tTd(64, 10))
dprintf("didn't follow protocol (total len)\n");
return;
}
if (tTd(64, 10))
dprintf("%s\n", response);
(void) removefromlist(response, &e->e_sendqueue, e);
return;
}
/*
** MILTER_REPLBODY -- Replace the current df file with new body
**
** Parameters:
** response -- encoded form of new body.
** rlen -- length of response.
** newfilter -- if first time called by a new filter
** e -- current envelope.
**
** Returns:
** 0 upon success, -1 upon failure
*/
static int
milter_replbody(response, rlen, newfilter, e)
char *response;
ssize_t rlen;
bool newfilter;
ENVELOPE *e;
{
static char prevchar;
int i;
if (tTd(64, 10))
dprintf("milter_replbody\n");
/* If a new filter, reset previous character and truncate df */
if (newfilter)
{
off_t prevsize = 0;
char dfname[MAXPATHLEN];
(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
/* Reset prevchar */
prevchar = '\0';
/* Get the current df information */
if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
{
int afd;
struct stat st;
afd = fileno(e->e_dfp);
if (afd > 0 && fstat(afd, &st) == 0)
prevsize = st.st_size;
}
/* truncate current df file */
if (bftruncate(e->e_dfp) < 0)
{
MILTER_DF_ERROR("milter_reopen_df: bftruncate %s: %s");
return -1;
}
else
{
if (prevsize > e->e_msgsize)
e->e_msgsize = 0;
else
e->e_msgsize -= prevsize;
}
}
if (response == NULL)
{
/* Flush the buffered '\r' */
if (prevchar == '\r')
{
(void) putc(prevchar, e->e_dfp);
e->e_msgsize++;
}
return 0;
}
for (i = 0; i < rlen; i++)
{
/* Buffered char from last chunk */
if (i == 0 && prevchar == '\r')
{
/* Not CRLF, output prevchar */
if (response[i] != '\n')
{
(void) putc(prevchar, e->e_dfp);
e->e_msgsize++;
}
prevchar = '\0';
}
/* Turn CRLF into LF */
if (response[i] == '\r')
{
/* check if at end of chunk */
if (i + 1 < rlen)
{
/* If LF, strip CR */
if (response[i + 1] == '\n')
i++;
}
else
{
/* check next chunk */
prevchar = '\r';
continue;
}
}
(void) putc(response[i], e->e_dfp);
e->e_msgsize++;
}
return 0;
}
/*
** MTA callouts
*/
/*
** MILTER_INIT -- open and negotiate with all of the filters
**
** Parameters:
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** none
*/
/* ARGSUSED */
void
milter_init(e, state)
ENVELOPE *e;
char *state;
{
int i;
if (tTd(64, 10))
dprintf("milter_init\n");
*state = SMFIR_CONTINUE;
for (i = 0; InputFilters[i] != NULL; i++)
{
struct milter *m = InputFilters[i];
m->mf_sock = milter_open(m, FALSE, e);
if (m->mf_state == SMFS_ERROR)
{
MILTER_CHECK_ERROR(continue);
break;
}
if (m->mf_sock < 0 ||
milter_negotiate(m, e) < 0 ||
m->mf_state == SMFS_ERROR)
{
if (tTd(64, 5))
dprintf("milter_init(%s): failed to %s\n",
m->mf_name,
m->mf_sock < 0 ? "open" : "negotiate");
/* if negotation failure, close socket */
if (m->mf_sock >= 0)
{
(void) close(m->mf_sock);
m->mf_sock = -1;
}
milter_error(m);
if (m->mf_state == SMFS_ERROR)
{
MILTER_CHECK_ERROR(continue);
break;
}
}
}
/*
** If something temp/perm failed with one of the filters,
** we won't be using any of them, so clear any existing
** connections.
*/
if (*state != SMFIR_CONTINUE)
milter_quit(e);
}
/*
** MILTER_CONNECT -- send connection info to milter filters
**
** Parameters:
** hostname -- hostname of remote machine.
** addr -- address of remote machine.
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** response string (may be NULL)
*/
char *
milter_connect(hostname, addr, e, state)
char *hostname;
SOCKADDR addr;
ENVELOPE *e;
char *state;
{
char family;
u_short port;
char *buf, *bp;
char *response;
char *sockinfo = NULL;
ssize_t s;
# if NETINET6
char buf6[INET6_ADDRSTRLEN];
# endif /* NETINET6 */
if (tTd(64, 10))
dprintf("milter_connect(%s)\n", hostname);
/* gather data */
switch (addr.sa.sa_family)
{
# if NETUNIX
case AF_UNIX:
family = SMFIA_UNIX;
port = htons(0);
sockinfo = addr.sunix.sun_path;
break;
# endif /* NETUNIX */
# if NETINET
case AF_INET:
family = SMFIA_INET;
port = htons(addr.sin.sin_port);
sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
break;
# endif /* NETINET */
# if NETINET6
case AF_INET6:
family = SMFIA_INET6;
port = htons(addr.sin6.sin6_port);
sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
sizeof buf6);
if (sockinfo == NULL)
sockinfo = "";
break;
# endif /* NETINET6 */
default:
family = SMFIA_UNKNOWN;
break;
}
s = strlen(hostname) + 1 + sizeof(family);
if (family != SMFIA_UNKNOWN)
s += sizeof(port) + strlen(sockinfo) + 1;
buf = (char *)xalloc(s);
bp = buf;
/* put together data */
(void) memcpy(bp, hostname, strlen(hostname));
bp += strlen(hostname);
*bp++ = '\0';
(void) memcpy(bp, &family, sizeof family);
bp += sizeof family;
if (family != SMFIA_UNKNOWN)
{
(void) memcpy(bp, &port, sizeof port);
bp += sizeof port;
/* include trailing '\0' */
(void) memcpy(bp, sockinfo, strlen(sockinfo) + 1);
}
response = milter_command(SMFIC_CONNECT, buf, s,
MilterConnectMacros, e, state);
free(buf);
/*
** If this message connection is done for,
** close the filters.
*/
if (*state != SMFIR_CONTINUE)
milter_quit(e);
else
milter_per_connection_check(e);
/*
** SMFIR_REPLYCODE can't work with connect due to
** the requirements of SMTP. Therefore, ignore the
** reply code text but keep the state it would reflect.
*/
if (*state == SMFIR_REPLYCODE)
{
if (response != NULL &&
*response == '4')
*state = SMFIR_TEMPFAIL;
else
*state = SMFIR_REJECT;
if (response != NULL)
{
free(response);
response = NULL;
}
}
return response;
}
/*
** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
**
** Parameters:
** helo -- argument to SMTP HELO/EHLO command.
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** response string (may be NULL)
*/
char *
milter_helo(helo, e, state)
char *helo;
ENVELOPE *e;
char *state;
{
char *response;
if (tTd(64, 10))
dprintf("milter_helo(%s)\n", helo);
response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1,
MilterHeloMacros, e, state);
milter_per_connection_check(e);
return response;
}
/*
** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
**
** Parameters:
** args -- SMTP MAIL command args (args[0] == sender).
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** response string (may be NULL)
*/
char *
milter_envfrom(args, e, state)
char **args;
ENVELOPE *e;
char *state;
{
int i;
char *buf, *bp;
char *response;
ssize_t s;
if (tTd(64, 10))
{
dprintf("milter_envfrom:");
for (i = 0; args[i] != NULL; i++)
dprintf(" %s", args[i]);
dprintf("\n");
}
/* sanity check */
if (args[0] == NULL)
{
*state = SMFIR_REJECT;
return NULL;
}
/* new message, so ... */
for (i = 0; InputFilters[i] != NULL; i++)
{
struct milter *m = InputFilters[i];
switch (m->mf_state)
{
case SMFS_INMSG:
/* abort in message filters */
milter_abort_filter(m, e);
/* FALLTHROUGH */
case SMFS_DONE:
/* reset done filters */
m->mf_state = SMFS_OPEN;
break;
}
}
/* put together data */
s = 0;
for (i = 0; args[i] != NULL; i++)
s += strlen(args[i]) + 1;
buf = (char *)xalloc(s);
bp = buf;
for (i = 0; args[i] != NULL; i++)
{
(void) strlcpy(bp, args[i], s - (bp - buf));
bp += strlen(bp) + 1;
}
/* send it over */
response = milter_command(SMFIC_MAIL, buf, s,
MilterEnvFromMacros, e, state);
free(buf);
/*
** If filter rejects/discards a per message command,
** abort the other filters since we are done with the
** current message.
*/
MILTER_CHECK_DONE_MSG();
return response;
}
/*
** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
**
** Parameters:
** args -- SMTP MAIL command args (args[0] == recipient).
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** response string (may be NULL)
*/
char *
milter_envrcpt(args, e, state)
char **args;
ENVELOPE *e;
char *state;
{
int i;
char *buf, *bp;
char *response;
ssize_t s;
if (tTd(64, 10))
{
dprintf("milter_envrcpt:");
for (i = 0; args[i] != NULL; i++)
dprintf(" %s", args[i]);
dprintf("\n");
}
/* sanity check */
if (args[0] == NULL)
{
*state = SMFIR_REJECT;
return NULL;
}
/* put together data */
s = 0;
for (i = 0; args[i] != NULL; i++)
s += strlen(args[i]) + 1;
buf = (char *)xalloc(s);
bp = buf;
for (i = 0; args[i] != NULL; i++)
{
(void) strlcpy(bp, args[i], s - (bp - buf));
bp += strlen(bp) + 1;
}
/* send it over */
response = milter_command(SMFIC_RCPT, buf, s,
MilterEnvRcptMacros, e, state);
free(buf);
return response;
}
/*
** MILTER_DATA -- send message headers/body and gather final message results
**
** Parameters:
** e -- current envelope.
** state -- return state from response.
**
** Returns:
** response string (may be NULL)
**
** Side effects:
** - Uses e->e_dfp for access to the body
** - Can call the various milter action routines to
** modify the envelope or message.
*/
# define MILTER_CHECK_RESULTS() \
if (*state == SMFIR_ACCEPT || \
m->mf_state == SMFS_DONE || \
m->mf_state == SMFS_ERROR) \
{ \
if (m->mf_state != SMFS_ERROR) \
m->mf_state = SMFS_DONE; \
continue; /
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -