aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-05-07 01:42:03 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-05-07 01:42:03 +0300
commit9f8f65324491b4186f4fd3c2580a8e0b14a248d9 (patch)
tree4b89cee9f26b33494ed917bab471ae233956bc93
parent2ed8f73ceee292855a07483d758d1f7181867ec9 (diff)
downloadmailfromd-9f8f65324491b4186f4fd3c2580a8e0b14a248d9.tar.gz
mailfromd-9f8f65324491b4186f4fd3c2580a8e0b14a248d9.tar.bz2
Implement Milter protocol version 6.
* gacopyz/Makefile.am (trans.h): Pass -vheader_file argument to the trans.awk script. * gacopyz/dummy.c (smfilter): Update initialization. * gacopyz/gacopyz.c (trans_fixup): New function. (convert_sfsistat): Handle new codes. (make_optneg_buf): New function. (send_reply): Handle SMFIP_NR_* flags. Update SMFIC_OPTNEG case. (shan_optneg): Implement milter 1.0 (proto 6) (gacopyz_context_loop): Call trans_fixup. (ok_to_send): Use the negotiated aflags. (gacopyz_addrcpt_par, gacopyz_chgfrom) (gacopyz_setsymlist): New functions. * gacopyz/gacopyz.h (GACOPYZ_VERSION_MAJOR): Raise to 2. (SMFI_VERSION): Set to 0x01000000 (SMFI_PROT_VERSION, SMFI_PROT_VERSION_MIN): New defines. (SMFIR_ADDRCPT_PAR, SMFIR_CHGFROM): New defines. (SMFIP_NR_HDR, SMFIP_SKIP, SMFIP_RCPT_REJ): New defines. (SMFIP_NR_CONN, SMFIP_NR_HELO, SMFIP_NR_MAIL) (SMFIP_NR_RCPT, SMFIP_NR_DATA, SMFIP_NR_UNKN) (SMFIP_NR_EOH, SMFIP_NR_BODY, SMFIP_HDR_LEADSPC) (SMFI_DEFAULT_PROT, SMFIF_CHGFROM) (SMFIF_ADDRCPT_PAR): New defines. (SMFIS_NOREPLY, SMFIS_SKIP, SMFIS_ALL_OPTS): New constants. (enum macro_index): New data type, from gacopyz_priv.h (SMFIM_CONNECT, SMFIM_HELO, SMFIM_ENVFROM) (SMFIM_ENVRCPT, SMFIM_DATA, SMFIM_EOM) (SMFIM_EOH): New defines. (struct gacopyz_milter_descr): New member: xxfi_negotiate (smfi_addrcpt_par, smfi_chgfrom, smfi_setsymlist) (gacopyz_addrcpt_par, gacopyz_setsymlist) (gacopyz_chgfrom): New protos. * gacopyz/gacopyz_priv.h (struct macro_assoc): Rename flags to pflags. New members: aflags, version, mta_pflags, req_macros. * gacopyz/server.c (struct gacopyz_srv): Remove flags. (struct gacopyz_srv.version, acts, proto): Change type. (gacopyz_srv_create): Change defaults. (gacopyz_srv_negotiate): Rewrite. * gacopyz/smfi.c (smfi_addrcpt_par, smfi_chgfrom) (smfi_setsymlist): New functions. * gacopyz/trans.awk (END): Print the state_nr_mask array. * mfd/bi_db.m4: Add missing includes. * mfd/engine.c: Implement mlfi_negotiate. * mfd/gram.y (register_macro): Arrange stored macros by gacopyz macro index. All uses updated. (get_stage_macro_string): New function. * mfd/mailfromd.h (get_stage_macro_string): New proto. (check_tbf_rate): Add proto.
-rw-r--r--gacopyz/Makefile.am5
-rw-r--r--gacopyz/dummy.c2
-rw-r--r--gacopyz/gacopyz.c397
-rw-r--r--gacopyz/gacopyz.h103
-rw-r--r--gacopyz/gacopyz_priv.h21
-rw-r--r--gacopyz/server.c58
-rw-r--r--gacopyz/smfi.c23
-rw-r--r--gacopyz/trans.awk11
-rw-r--r--mfd/bi_db.m41
-rw-r--r--mfd/engine.c29
-rw-r--r--mfd/gram.y113
-rw-r--r--mfd/mailfromd.h6
-rw-r--r--mfd/tbf_rate.c3
13 files changed, 601 insertions, 171 deletions
diff --git a/gacopyz/Makefile.am b/gacopyz/Makefile.am
index 4dbef83a..7d8c012b 100644
--- a/gacopyz/Makefile.am
+++ b/gacopyz/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of mailfrom filter.
-# Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff
+# Copyright (C) 2006, 2007, 2008, 2009 Sergey Poznyakoff
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@ EXTRA_DIST=trans.tab trans.awk
BUILT_SOURCES=trans.h
INCLUDES=-I$(top_srcdir)/gnu -I../gnu
-trans.h: ${top_srcdir}/gacopyz/trans.tab ${top_srcdir}/gacopyz/trans.awk
+trans.h: ${top_srcdir}/gacopyz/trans.tab ${top_srcdir}/gacopyz/trans.awk ${top_srcdir}/gacopyz/gacopyz.h
$(AWK) -f ${top_srcdir}/gacopyz/trans.awk \
+ -vheader_file=${top_srcdir}/gacopyz/gacopyz.h\
${top_srcdir}/gacopyz/trans.tab > trans.h
diff --git a/gacopyz/dummy.c b/gacopyz/dummy.c
index 01c8eef5..be577300 100644
--- a/gacopyz/dummy.c
+++ b/gacopyz/dummy.c
@@ -68,6 +68,8 @@ struct smfiDesc smfilter =
NULL, /* connection cleanup */
NULL, /* unknown command handler */
NULL, /* data handler */
+ NULL, /* negotiate */
+
NULL, /* child start */
NULL, /* child finish */
NULL /* idle callback */
diff --git a/gacopyz/gacopyz.c b/gacopyz/gacopyz.c
index 02c833e9..f29681be 100644
--- a/gacopyz/gacopyz.c
+++ b/gacopyz/gacopyz.c
@@ -1,5 +1,5 @@
/* This file is part of gacopyz.
- Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff
+ Copyright (C) 2006, 2007, 2008, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -526,6 +526,21 @@ trans_ok(enum state from, enum state to)
}
}
+/* Fix up the transition table */
+static void
+trans_fixup(SMFICTX *ctx)
+{
+ transtab[st_conn][st_skip] = !!(ctx->pflags & SMFIP_NOCONNECT);
+ transtab[st_helo][st_skip] = !!(ctx->pflags & SMFIP_NOHELO);
+ transtab[st_mail][st_skip] = !!(ctx->pflags & SMFIP_NOMAIL);
+ transtab[st_rcpt][st_skip] = !!(ctx->pflags & SMFIP_NORCPT);
+ transtab[st_hdrs][st_skip] = !!(ctx->pflags & SMFIP_NOHDRS);
+ transtab[st_eohs][st_skip] = !!(ctx->pflags & SMFIP_NOEOH);
+ transtab[st_body][st_skip] = !!(ctx->pflags & SMFIP_NOBODY);
+ transtab[st_data][st_skip] = !!(ctx->pflags & SMFIP_NODATA);
+ transtab[st_unkn][st_skip] = !!(ctx->pflags & SMFIP_NOUNKNOWN);
+}
+
static int
ctx_read(SMFICTX *ctx, char *buf, size_t size)
{
@@ -713,6 +728,84 @@ get_command(SMFICTX *ctx, unsigned char *cmd, size_t *pcount,
return MI_SUCCESS;
}
+#define _GACOPYZ_R_NOREPLY 0
+
+static unsigned char
+convert_sfsistat(sfsistat stat)
+{
+ switch (stat) {
+ case SMFIS_CONTINUE:
+ return SMFIR_CONTINUE;
+ case SMFIS_REJECT:
+ return SMFIR_REJECT;
+ case SMFIS_DISCARD:
+ return SMFIR_DISCARD;
+ case SMFIS_ACCEPT:
+ return SMFIR_ACCEPT;
+ case SMFIS_TEMPFAIL:
+ return SMFIR_TEMPFAIL;
+ case SMFIS_NOREPLY:
+ return _GACOPYZ_R_NOREPLY;
+ case SMFIS_SKIP:
+ return SMFIR_SKIP;
+ default:
+ break;
+ }
+ return SMFIR_TEMPFAIL; /* Just in case */
+}
+
+#define OPTLEN 3*sizeof(gacopyz_uint32_t)
+
+static int
+make_optneg_buf(SMFICTX *ctx, gacopyz_uint32_t *vbuf,
+ size_t *psize, char **pbuf)
+{
+ char *buf;
+ size_t bufsize = 0;
+ int i;
+
+ for (i = 0; i < maci_max; i++) {
+ if (ctx->req_macros[i])
+ bufsize += strlen(ctx->req_macros[i]) + 1 +
+ sizeof(gacopyz_uint32_t);
+ }
+
+ if (bufsize == 0)
+ buf = (char*) vbuf;
+ else {
+ bufsize += OPTLEN;
+ buf = malloc(bufsize);
+ if (!buf)
+ return MI_FAILURE;
+ vbuf = (gacopyz_uint32_t*)buf;
+ }
+ vbuf[0] = htonl(ctx->version);
+ vbuf[1] = htonl(ctx->aflags);
+ vbuf[2] = htonl(ctx->pflags);
+
+ if (bufsize) {
+ /*char *endp = buf + bufsize;*/
+ *psize = bufsize;
+ *pbuf = buf;
+
+ buf += OPTLEN;
+ for (i = 0; i < maci_max; i++) {
+ if (ctx->req_macros[i]) {
+ gacopyz_uint32_t v;
+ size_t len;
+
+ v = htonl(i);
+ memcpy(buf, &v, sizeof(v));
+ buf += sizeof(v);
+ len = strlen(ctx->req_macros[i]) + 1;
+ memcpy(buf, ctx->req_macros[i], len);
+ buf += len;
+ }
+ }
+ }
+ return MI_SUCCESS;
+}
+
static int
send_reply(SMFICTX *ctx, unsigned char cmd)
{
@@ -720,8 +813,29 @@ send_reply(SMFICTX *ctx, unsigned char cmd)
union header header;
char *buf = NULL;
size_t bufsize = 0;
+ char *alloc_mem = NULL;
+ gacopyz_uint32_t v[3];
+ unsigned long nrmask = state_nr_mask[ctx->state];
+
+ if (nrmask && (ctx->pflags & nrmask) && cmd != _GACOPYZ_R_NOREPLY) {
+ if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_WARN))
+ gacopyz_log(SMI_LOG_WARN,
+ _("%s: milter claimed not to reply in state %d, but it did"),
+ ctx->desc->xxfi_name,
+ ctx->state);
+ cmd = _GACOPYZ_R_NOREPLY;
+ }
switch (cmd) {
+ case _GACOPYZ_R_NOREPLY:
+ if (nrmask && (ctx->pflags & nrmask)) {
+ if (ctx->mta_pflags & nrmask)
+ return 0;
+ else
+ cmd = SMFIR_CONTINUE;
+ }
+ break;
+
case SMFIR_CONTINUE:
break;
@@ -748,15 +862,14 @@ send_reply(SMFICTX *ctx, unsigned char cmd)
break;
case SMFIC_OPTNEG:
- {
- gacopyz_uint32_t v[3];
- v[0] = htonl(ctx->desc->xxfi_version);
- v[1] = htonl(ctx->desc->xxfi_flags);
- v[2] = htonl(ctx->flags);
buf = (char*) v;
bufsize = sizeof v;
+ if (make_optneg_buf(ctx, v, &bufsize, &alloc_mem)
+ != MI_SUCCESS)
+ return MI_FAILURE;
+ if (alloc_mem)
+ buf = alloc_mem;
break;
- }
default: /* Ignore */
break;
@@ -767,10 +880,12 @@ send_reply(SMFICTX *ctx, unsigned char cmd)
header.hdr.size = htonl(bufsize + 1);
header.hdr.cmd = cmd;
rc = ctx_write(ctx, header.buf, sizeof header.buf);
- if (rc != MI_SUCCESS)
- return rc;
- if (bufsize)
- rc = ctx_write(ctx, buf, bufsize);
+ if (rc == MI_SUCCESS) {
+ if (bufsize)
+ rc = ctx_write(ctx, buf, bufsize);
+ }
+ if (alloc_mem)
+ free(alloc_mem);
return rc;
}
@@ -836,24 +951,6 @@ struct state_disp {
int macro_ind;
};
-static unsigned char
-convert_sfsistat(sfsistat stat)
-{
- switch (stat) {
- case SMFIS_CONTINUE:
- return SMFIR_CONTINUE;
- case SMFIS_REJECT:
- return SMFIR_REJECT;
- case SMFIS_DISCARD:
- return SMFIR_DISCARD;
- case SMFIS_ACCEPT:
- return SMFIR_ACCEPT;
- case SMFIS_TEMPFAIL:
- return SMFIR_TEMPFAIL;
- }
- return SMFIR_TEMPFAIL; /* Just in case */
-}
-
static state_ret_type
shan_abort(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
@@ -924,10 +1021,10 @@ static state_ret_type
shan_body(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (ctx->desc->xxfi_body) {
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_body(ctx,
- arg->string.ptr,
- arg->string.len));
+ arg->string.ptr,
+ arg->string.len));
} else
*cmd = SMFIR_CONTINUE;
return sret_reply;
@@ -999,11 +1096,11 @@ shan_connect(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
}
}
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_connect(ctx,
arg->strings[0],
family != SMFIA_UNKNOWN ?
- &sockaddr : NULL));
+ &sockaddr : NULL));
return sret_reply;
}
@@ -1011,14 +1108,14 @@ static state_ret_type
shan_endm(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (arg->string.len && ctx->desc->xxfi_body) {
- sfsistat r = ctx->desc->xxfi_body(ctx,
+ sfsistat r = ctx->desc->xxfi_body(ctx,
arg->string.ptr,
arg->string.len);
if (r != SMFIS_CONTINUE
- && send_reply(ctx, convert_sfsistat(r) != MI_SUCCESS))
+ && send_reply(ctx, convert_sfsistat(r)) != MI_SUCCESS)
return sret_abort;
}
- if (ctx->desc->xxfi_eom)
+ if (ctx->desc->xxfi_eom)
*cmd = convert_sfsistat(ctx->desc->xxfi_eom(ctx));
else
*cmd = SMFIR_CONTINUE;
@@ -1029,7 +1126,7 @@ static state_ret_type
shan_helo(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (ctx->desc->xxfi_helo)
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_helo(ctx, arg->string.ptr));
else
*cmd = SMFIR_CONTINUE;
@@ -1039,8 +1136,8 @@ shan_helo(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
static state_ret_type
shan_header(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
- if (ctx->desc->xxfi_header)
- *cmd = convert_sfsistat(
+ if (ctx->desc->xxfi_header)
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_header(ctx,
arg->strings[0],
arg->strings[1]));
@@ -1053,54 +1150,143 @@ static state_ret_type
shan_mail(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (ctx->desc->xxfi_envfrom) {
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_envfrom(ctx, arg->argv.v));
} else
*cmd = SMFIR_CONTINUE;
return sret_reply;
}
+#define ALL_NR_FLAGS \
+ (SMFIP_NR_CONN|\
+ SMFIP_NR_HELO|\
+ SMFIP_NR_MAIL|\
+ SMFIP_NR_RCPT|\
+ SMFIP_NR_DATA|\
+ SMFIP_NR_UNKN|\
+ SMFIP_NR_HDR|\
+ SMFIP_NR_EOH|\
+ SMFIP_NR_BODY)
+
+
static state_ret_type
shan_optneg(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
gacopyz_uint32_t val;
-
- if (arg->ints[0] < ctx->desc->xxfi_version) {
+ unsigned long mta_aflags, mta_pflags;
+
+ val = arg->ints[0];
+ if (val < SMFI_PROT_VERSION_MIN) {
if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_ERR))
gacopyz_log(SMI_LOG_ERR,
- _("%s: shan_optneg: version mismatch; "
- "MTA: %ld < milter: %d"),
- ctx->desc->xxfi_name,
- arg->ints[0],
- ctx->desc->xxfi_version);
+ _("protocol version too old: %lu"),
+ val);
return sret_abort;
}
-
+ if (val > SMFI_PROT_VERSION)
+ val = SMFI_PROT_VERSION;
+ ctx->version = val;
+
val = arg->ints[1];
if (!val)
val = SMFI_V1_ACTS;
- if ((val & ctx->desc->xxfi_flags) != ctx->desc->xxfi_flags) {
- if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_ERR))
- gacopyz_log(SMI_LOG_ERR,
- _("%s: shan_optneg: flags %#x do not match "
- "actions requirements %#x"),
- ctx->desc->xxfi_name, val,
- ctx->desc->xxfi_flags);
- return sret_abort;
- }
+ mta_aflags = val;
val = arg->ints[2];
if (!val)
val = SMFI_V1_PROT;
- if ((val & ctx->flags) != ctx->flags) {
+ ctx->mta_pflags = mta_pflags = val;
+
+ ctx->aflags = ctx->desc->xxfi_flags;
+ if (ctx->version > SMFI_PROT_VERSION_MIN
+ && ctx->desc->xxfi_negotiate) {
+ int res;
+ unsigned long m_aflags = mta_aflags, m_pflags = ctx->pflags;
+ unsigned long m_f2 = 0, m_f3 = 0; /* reserved */
+
+ if (mta_pflags & SMFIP_SKIP)
+ m_pflags |= SMFIP_SKIP;
+ res = ctx->desc->xxfi_negotiate(ctx,
+ mta_aflags,
+ mta_pflags|ALL_NR_FLAGS,
+ 0, 0,
+ &m_aflags, &m_pflags,
+ &m_f2, &m_f3);
+ switch (res) {
+ case SMFIS_ALL_OPTS:
+ ctx->aflags = mta_aflags;
+ /* ctx->pflags not changed */
+ if (mta_pflags & SMFIP_SKIP)
+ ctx->pflags |= SMFIP_SKIP;
+ break;
+
+ case SMFIS_CONTINUE:
+ ctx->aflags = m_aflags;
+ ctx->pflags = m_pflags;
+ break;
+
+ default:
+ if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_ERR))
+ gacopyz_log(SMI_LOG_ERR,
+ _("xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)"),
+ res, mta_pflags, mta_aflags);
+ return sret_abort;
+ }
+
+ if ((mta_pflags & ctx->pflags) != ctx->pflags) {
+ unsigned i;
+
+ for (i = 0; i < 32; i++) {
+ unsigned long bit = 1 << i;
+ if ((mta_pflags & bit) != bit
+ && (bit & ALL_NR_FLAGS) == bit)
+ ctx->pflags &= ~bit;
+ }
+ }
+ }
+
+ if ((mta_aflags & ctx->aflags) != ctx->aflags) {
if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_ERR))
gacopyz_log(SMI_LOG_ERR,
- _("%s: shan_optneg: flags %#x do not match "
- "protocol requirement %#x"),
- ctx->desc->xxfi_name, val,
- ctx->flags);
+ _("%s: shan_optneg: NTA flags %#lx do not match "
+ "actions requirements %#lx"),
+ ctx->desc->xxfi_name,
+ mta_aflags,
+ ctx->aflags);
+ return sret_abort;
+ }
+
+ if ((mta_pflags & ctx->pflags) != ctx->pflags) {
+ /* Disable protocol steps not supported by older MTAs */
+ if ((ctx->pflags & SMFIP_NODATA)
+ && !(mta_pflags & SMFIP_NODATA))
+ ctx->pflags &= ~SMFIP_NODATA;
+
+ if ((ctx->pflags & SMFIP_NOUNKNOWN)
+ && !(mta_pflags & SMFIP_NOUNKNOWN))
+ ctx->pflags &= ~SMFIP_NOUNKNOWN;
+ }
+
+ if ((mta_pflags & ctx->pflags) != ctx->pflags) {
+ if (GACOPYZ_CTX_LOG_MATCH(ctx, SMI_LOG_ERR))
+ gacopyz_log(SMI_LOG_ERR,
+ _("%s: shan_optneg: MTA flags %#lx do not match "
+ "protocol requirements %#lx"),
+ ctx->desc->xxfi_name,
+ mta_pflags,
+ ctx->pflags);
return sret_abort;
}
+
+ if (GACOPYZ_DESC_LOG_MATCH(ctx->desc, SMI_LOG_DEBUG))
+ gacopyz_log(SMI_LOG_DEBUG,
+ "version=%#lx, mta_aflags=%#lx, mta_pflags=%#lx"
+ " aflags=%#lx, pflags=%#lx",
+ ctx->version,
+ mta_aflags, mta_pflags,
+ ctx->aflags, ctx->pflags);
+ trans_fixup(ctx);
+
*cmd = SMFIC_OPTNEG;
return sret_reply;
}
@@ -1108,7 +1294,7 @@ shan_optneg(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
static state_ret_type
shan_eoh(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
- if (ctx->desc->xxfi_eoh)
+ if (ctx->desc->xxfi_eoh)
*cmd = convert_sfsistat(ctx->desc->xxfi_eoh(ctx));
else
*cmd = SMFIR_CONTINUE;
@@ -1124,7 +1310,7 @@ shan_quit(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
static state_ret_type
shan_data(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
- if (ctx->desc->xxfi_data)
+ if (ctx->desc->xxfi_data)
*cmd = convert_sfsistat(ctx->desc->xxfi_data(ctx));
else
*cmd = SMFIR_CONTINUE;
@@ -1135,7 +1321,7 @@ static state_ret_type
shan_rcpt(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (ctx->desc->xxfi_envrcpt) {
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_envrcpt(ctx, arg->argv.v));
} else
*cmd = SMFIR_CONTINUE;
@@ -1146,7 +1332,7 @@ static state_ret_type
shan_unkn(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
if (ctx->desc->xxfi_unknown) {
- *cmd = convert_sfsistat(
+ *cmd = convert_sfsistat(
ctx->desc->xxfi_unknown(ctx, arg->string.ptr));
} else
*cmd = SMFIR_CONTINUE;
@@ -1322,29 +1508,26 @@ gacopyz_context_loop(int fd, struct smfiDesc *desc)
ctx.desc = desc;
ctx.sd = fd;
if (!desc->xxfi_connect)
- ctx.flags |= SMFIP_NOCONNECT;
+ ctx.pflags |= SMFIP_NOCONNECT;
if (!desc->xxfi_helo)
- ctx.flags |= SMFIP_NOHELO;
+ ctx.pflags |= SMFIP_NOHELO;
if (!desc->xxfi_envfrom)
- ctx.flags |= SMFIP_NOMAIL;
+ ctx.pflags |= SMFIP_NOMAIL;
if (!desc->xxfi_envrcpt)
- ctx.flags |= SMFIP_NORCPT;
+ ctx.pflags |= SMFIP_NORCPT;
if (!desc->xxfi_header)
- ctx.flags |= SMFIP_NOHDRS;
+ ctx.pflags |= SMFIP_NOHDRS;
if (!desc->xxfi_eoh)
- ctx.flags |= SMFIP_NOEOH;
+ ctx.pflags |= SMFIP_NOEOH;
if (!desc->xxfi_body)
- ctx.flags |= SMFIP_NOBODY;
-
- /* Fix up the transition table */
- transtab[st_conn][st_skip] = !!(ctx.flags & SMFIP_NOCONNECT);
- transtab[st_helo][st_skip] = !!(ctx.flags & SMFIP_NOHELO);
- transtab[st_mail][st_skip] = !!(ctx.flags & SMFIP_NOMAIL);
- transtab[st_rcpt][st_skip] = !!(ctx.flags & SMFIP_NORCPT);
- transtab[st_hdrs][st_skip] = !!(ctx.flags & SMFIP_NOHDRS);
- transtab[st_eohs][st_skip] = !!(ctx.flags & SMFIP_NOEOH);
- transtab[st_body][st_skip] = !!(ctx.flags & SMFIP_NOBODY);
-
+ ctx.pflags |= SMFIP_NOBODY;
+ if (!desc->xxfi_data)
+ ctx.pflags |= SMFIP_NODATA;
+ if (!desc->xxfi_unknown)
+ ctx.pflags |= SMFIP_NOUNKNOWN;
+
+ trans_fixup(&ctx);
+
if (GACOPYZ_DESC_LOG_MATCH(desc, SMI_LOG_DEBUG))
gacopyz_log(SMI_LOG_DEBUG, _("Begin context loop"));
@@ -1421,11 +1604,11 @@ gacopyz_context_loop(int fd, struct smfiDesc *desc)
clear_macros(&ctx, sd->macro_ind + 1);
ret = sd->fn(&ctx, &arg, &cmd);
arg_free(&arg, sd->arg_type);
-
+
switch (ret) {
case sret_noreply:
break;
-
+
case sret_reply:
rc = send_reply(&ctx, cmd);
break;
@@ -1733,12 +1916,15 @@ gacopyz_rcpt_command(SMFICTX *ctx, unsigned char cmd, const char *rcpt)
return rc;
}
+#define gacopyz_arg2_command(ctx, cmd, arg0, arg1) \
+ gacopyz_header_command0(ctx, cmd, -1, arg0, arg1)
+
static int
ok_to_send(SMFICTX *ctx, int cmd)
{
if (!ctx)
return 0;
- if (cmd && !(ctx->desc->xxfi_flags & cmd))
+ if (cmd && !(ctx->aflags & cmd))
return 0;
return ctx->state == st_endm;
}
@@ -1838,3 +2024,40 @@ gacopyz_quarantine(SMFICTX *ctx, const char *reason)
return MI_FAILURE;
return gacopyz_rcpt_command(ctx, SMFIR_QUARANTINE, reason);
}
+
+int
+gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args)
+{
+ if (!rcpt || !*rcpt)
+ return MI_FAILURE;
+ if (!ok_to_send(ctx, SMFIF_ADDRCPT_PAR))
+ return MI_FAILURE;
+ return gacopyz_arg2_command(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
+}
+
+int
+gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args)
+{
+ if (!from || !*from)
+ return MI_FAILURE;
+ if (!ok_to_send(ctx, SMFIF_CHGFROM))
+ return MI_FAILURE;
+ return gacopyz_arg2_command(ctx, SMFIR_CHGFROM, from, args);
+}
+
+int
+gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros)
+{
+ if (ind < 0 || ind >= maci_max)
+ return MI_FAILURE;
+ if (ctx->req_macros[ind])
+ free(ctx->req_macros[ind]);
+ if (macros == NULL)
+ ctx->req_macros[ind] = NULL;
+ else {
+ ctx->req_macros[ind] = strdup(macros);
+ if (!ctx->req_macros[ind])
+ return MI_FAILURE;
+ }
+ return MI_SUCCESS;
+}
diff --git a/gacopyz/gacopyz.h b/gacopyz/gacopyz.h
index 706a9c87..f0b5bff2 100644
--- a/gacopyz/gacopyz.h
+++ b/gacopyz/gacopyz.h
@@ -1,5 +1,5 @@
/* This file is part of gacopyz.
- Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff
+ Copyright (C) 2006, 2007, 2008, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,11 +42,17 @@
extern "C" {
#endif
-#define GACOPYZ_VERSION_MAJOR 1
+#define GACOPYZ_VERSION_MAJOR 2
#define GACOPYZ_VERSION_MINOR 0
/* Implementation version number */
-#define SMFI_VERSION 2
+#define SMFI_VERSION 0x01000000
+
+/* Milter protocol version */
+#define SMFI_PROT_VERSION 6
+
+/* Minimal supported protocol version */
+#define SMFI_PROT_VERSION_MIN 2
/* commands: don't use anything smaller than ' ' */
#define SMFIC_ABORT 'A' /* Abort */
@@ -67,20 +73,26 @@ extern "C" {
/* actions (replies) */
#define SMFIR_ADDRCPT '+' /* add recipient */
#define SMFIR_DELRCPT '-' /* remove recipient */
+#define SMFIR_ADDRCPT_PAR '2' /* add recipient */
+#define SMFIR_SHUTDOWN '4' /* 421: shutdown (internal to MTA) */
#define SMFIR_ACCEPT 'a' /* accept */
#define SMFIR_REPLBODY 'b' /* replace body (chunk) */
#define SMFIR_CONTINUE 'c' /* continue */
#define SMFIR_DISCARD 'd' /* discard */
+#define SMFIR_CHGFROM 'e' /* change envelope sender (from) */
#define SMFIR_CONN_FAIL 'f' /* cause a connection failure */
+#define SMFIR_ADDHEADER 'h' /* add header */
+#define SMFIR_INSHEADER 'i' /* insert header */
+#if 0
+#define SMFIR_SETSYMLIST 'l' /* set list of macros (unused) */
+#endif
#define SMFIR_CHGHEADER 'm' /* change header */
#define SMFIR_PROGRESS 'p' /* progress */
+#define SMFIR_QUARANTINE 'q' /* quarantine */
#define SMFIR_REJECT 'r' /* reject */
+#define SMFIR_SKIP 's' /* skip */
#define SMFIR_TEMPFAIL 't' /* tempfail */
-#define SMFIR_SHUTDOWN '4' /* 421: shutdown (internal to MTA) */
-#define SMFIR_ADDHEADER 'h' /* add header */
-#define SMFIR_INSHEADER 'i' /* insert header */
#define SMFIR_REPLYCODE 'y' /* reply code etc */
-#define SMFIR_QUARANTINE 'q' /* quarantine */
/* What the MTA can send/filter wants in protocol */
#define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */
@@ -90,17 +102,33 @@ extern "C" {
#define SMFIP_NOBODY 0x00000010L /* MTA should not send body */
#define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */
#define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */
-#define SMFIP_NOHREPL 0x00000080L /* No reply for headers */
+#define SMFIP_NR_HDR 0x00000080L /* No reply for headers */
+#define SMFIP_NOHREPL SMFIP_NR_HDR /* No reply for headers */
#define SMFIP_NOUNKNOWN 0x00000100L /* MTA should not send unknown
- command */
+ commands */
#define SMFIP_NODATA 0x00000200L /* MTA should not send DATA */
-
+#define SMFIP_SKIP 0x00000400L /* MTA understands SMFIS_SKIP */
+#define SMFIP_RCPT_REJ 0x00000800L /* MTA should also send rejected
+ RCPTs */
+#define SMFIP_NR_CONN 0x00001000L /* No reply for connect */
+#define SMFIP_NR_HELO 0x00002000L /* No reply for HELO */
+#define SMFIP_NR_MAIL 0x00004000L /* No reply for MAIL */
+#define SMFIP_NR_RCPT 0x00008000L /* No reply for RCPT */
+#define SMFIP_NR_DATA 0x00010000L /* No reply for DATA */
+#define SMFIP_NR_UNKN 0x00020000L /* No reply for UNKN */
+#define SMFIP_NR_EOH 0x00040000L /* No reply for eoh */
+#define SMFIP_NR_BODY 0x00080000L /* No reply for body chunk */
+#define SMFIP_HDR_LEADSPC 0x00100000L /* header value leading space */
+
/* The protocol of V1 filter */
#define SMFI_V1_PROT (SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NOMAIL|\
SMFIP_NORCPT|SMFIP_NOBODY|SMFIP_NOHDRS)
/* The protocol of V2 filter */
#define SMFI_V2_PROT (SMFI_V1_PROT|SMFIP_NOEOH)
+/* All defined prot bits */
+#define SMFI_DEFAULT_PROT 0x001FFFFFL
+
/* Flags, defining milter capabilities */
#define SMFIF_NONE 0x00000000L /* no flags */
#define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */
@@ -110,12 +138,14 @@ extern "C" {
#define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */
#define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */
#define SMFIF_QUARANTINE 0x00000020L /* filter may quarantine envelope */
-
+#define SMFIF_CHGFROM 0x00000040L /* filter may change envelope "from" */
+#define SMFIF_ADDRCPT_PAR 0x00000080L /* add recipients incl. args */
+
#define SMFI_V1_ACTS (SMFIF_ADDHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT)
#define SMFI_V2_ACTS (SMFI_V1_ACTS|SMFIF_CHGHDRS|SMFIF_QUARANTINE)
-
-#define SMFI_DEFAULT_ACTS SMFI_V2_ACTS
-#define SMFI_DEFAULT_PROT SMFI_V2_PROT
+#define SMFI_V6_ACTS (SMFI_V2_ACTS|SMFIF_CHGFROM|SMFIF_ADDRCPT_PAR)
+
+#define SMFI_DEFAULT_ACTS SMFI_V6_ACTS
/* Log levels */
#define SMI_LOG_PROTO 0
@@ -157,15 +187,39 @@ typedef enum {
SMFIS_REJECT,
SMFIS_DISCARD,
SMFIS_ACCEPT,
- SMFIS_TEMPFAIL
+ SMFIS_TEMPFAIL,
+ SMFIS_NOREPLY = 7,
+ SMFIS_SKIP = 8,
+ SMFIS_ALL_OPTS = 10
} sfsistat;
-
+
typedef union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_un sunix;
} milter_sockaddr_t;
+enum macro_index {
+ maci_conn,
+ maci_helo,
+ maci_mail,
+ maci_rcpt,
+ maci_data,
+ maci_eom,
+ maci_eoh,
+
+ maci_max,
+ maci_none = maci_max
+};
+
+#define SMFIM_CONNECT maci_conn
+#define SMFIM_HELO maci_helo
+#define SMFIM_ENVFROM maci_mail
+#define SMFIM_ENVRCPT maci_rcpt
+#define SMFIM_DATA maci_data
+#define SMFIM_EOM maci_eom
+#define SMFIM_EOH maci_eoh
+
#define _SOCK_ADDR milter_sockaddr_t
#define smfiDesc gacopyz_milter_descr
@@ -201,7 +255,13 @@ struct gacopyz_milter_descr
sfsistat (*xxfi_unknown) (SMFICTX *, char *);
/* SMTP DATA command (SMFI_VERSION > 3) */
sfsistat (*xxfi_data) (SMFICTX *);
-
+ /* Milter negotiation (SMFI_VERSION > 3) */
+ sfsistat (*xxfi_negotiate) (SMFICTX *,
+ unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+
/* Extensions: */
int (*xxfi_start) (); /* Child start callback */
@@ -234,10 +294,13 @@ int smfi_delrcpt (SMFICTX *, char *);
int smfi_progress (SMFICTX *);
int smfi_replacebody (SMFICTX *, unsigned char *, int);
int smfi_quarantine (SMFICTX *ctx, char *reason);
+int smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args);
+int smfi_chgfrom(SMFICTX *ctx, char *from, char *args);
#define smfi_setpriv gacopyz_setpriv
#define smfi_getpriv gacopyz_getpriv
size_t smfi_setmaxdatasize (size_t);
-
+int smfi_setsymlist(SMFICTX *ctx, int stage, char *macros);
+
/* Replies: */
extern int smfi_setreply (SMFICTX *, char *, char *, char *);
int smfi_setmlreply (SMFICTX *, const char *, const char *, ...);
@@ -302,7 +365,11 @@ int gacopyz_replace_body(SMFICTX *ctx, const unsigned char *bodyp,
size_t bodylen);
int gacopyz_progress(SMFICTX *ctx);
int gacopyz_quarantine(SMFICTX *ctx, const char *reason);
+int gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args);
+int gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args);
+int gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros);
+
int gacopyz_setpriv (SMFICTX *ctx, void *data);
void *gacopyz_getpriv (SMFICTX *ctx);
diff --git a/gacopyz/gacopyz_priv.h b/gacopyz/gacopyz_priv.h
index 3f29546a..76be1611 100644
--- a/gacopyz/gacopyz_priv.h
+++ b/gacopyz/gacopyz_priv.h
@@ -1,5 +1,5 @@
/* This file is part of gacopyz.
- Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff
+ Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,19 +20,6 @@
#include <gacopyz.h>
-enum macro_index {
- maci_conn,
- maci_helo,
- maci_mail,
- maci_rcpt,
- maci_data,
- maci_eom,
- maci_eoh,
-
- maci_max,
- maci_none = maci_max
-};
-
typedef struct macro_assoc {
char **argv;
char *buffer;
@@ -42,9 +29,13 @@ struct smfi_str {
struct smfiDesc *desc; /* parent description */
int sd; /* socket descriptor */
int state; /* state; FIXME: should be enum state */
- unsigned long flags; /* protocol flags */
+ unsigned long version; /* negotiated protocol version */
+ unsigned long pflags; /* protocol flags */
+ unsigned long mta_pflags; /* pflags supported by MTA */
+ unsigned long aflags; /* milter action flags (from xxfi_flags) */
int nmacros; /* Number of entries in macros */
macro_assoc_t macros[maci_max]; /* Macro tables */
+ char *req_macros[maci_max]; /* Required macros */
char *reply; /* reply code */
void *privdata; /* private data */
};
diff --git a/gacopyz/server.c b/gacopyz/server.c
index fb0c52f3..a61836e8 100644
--- a/gacopyz/server.c
+++ b/gacopyz/server.c
@@ -38,17 +38,18 @@ struct gacopyz_srv {
char *portspec; /* Port spec */
struct gacopyz_iod iod;
enum gacopyz_srv_state state;
- unsigned long flags;
+
gacopyz_macro_def_t def;
size_t ndefs;
size_t maxdefs;
gacopyz_uint32_t source_addr;
int onerror;
void (*memerror) (gacopyz_srv_t, const char *, unsigned int);
- int version;
- int acts;
- int proto;
+ unsigned long version;
+ unsigned long acts;
+ unsigned long proto;
+
int (*cb_reply) (gacopyz_srv_t srv, int cmd, int rcmd, void *data);
void *cb_data;
@@ -305,8 +306,8 @@ gacopyz_srv_create(gacopyz_srv_t *p, const char *name,
srv->source_addr = INADDR_ANY;
srv->onerror = SMFIR_TEMPFAIL;
srv->version = SMFI_VERSION;
- srv->proto = SMFI_V2_PROT;
- srv->acts = SMFI_V2_ACTS;
+ srv->proto = SMFI_DEFAULT_PROT;
+ srv->acts = SMFI_DEFAULT_ACTS;
srv->memerror = default_memerror;
*p = srv;
return MI_SUCCESS;
@@ -865,6 +866,7 @@ gacopyz_srv_negotiate(gacopyz_srv_t srv)
gacopyz_uint32_t ibuf[3];
size_t size;
unsigned char cmd;</