📄 milter.c
字号:
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 + -