-TMILTER
-TMILTER8
-TMILTERS
+-TMILTER_MACROS
-TMILTER_MSG_CONTEXT
-TMIME_ENCODING
-TMIME_INFO
Further polishing of the Milter code and logging. File:
milter/milter8.c.
+
+20071123
+
+ Further polishing of the Milter code. With SETSYMLIST, each
+ Milter can update its own macros instead of clobbering
+ the global copy is shared with other Milters. Also an
+ opportunity to clean up some ad-hoc code for sending macro
+ lists from smtp(8) to cleanup(8). Files: milter/milter.c,
+ milter/milter8.c, milter/milter_macros.c.
/* specified attribute scan routine. dsb_scan() is meant
/* to be passed as a call-back to attr_scan(), thusly:
/*
-/* ... ATTR_SCAN_FUNC, dsb_scan, (void *) &dsbuf, ...
+/* ... ATTR_TYPE_FUNC, dsb_scan, (void *) &dsbuf, ...
/* DIAGNOSTICS
/* Fatal: out of memory.
/* LICENSE
/* the specified attribute print routine. dsn_print() is meant
/* to be passed as a call-back to attr_print(), thusly:
/*
-/* ... ATTR_PRINT_FUNC, dsn_print, (void *) dsn, ...
+/* ... ATTR_TYPE_FUNC, dsn_print, (void *) dsn, ...
/* DIAGNOSTICS
/* Fatal: out of memory.
/* LICENSE
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20071222"
+#define MAIL_RELEASE_DATE "20071223"
#define MAIL_VERSION_NUMBER "2.5"
#ifdef SNAPSHOT
/* msg_stats_print() is meant to be passed as a call-back to
/* attr_print(), thusly:
/*
-/* ... ATTR_PRINT_FUNC, msg_stats_print, (void *) stats, ...
+/* ... ATTR_TYPE_FUNC, msg_stats_print, (void *) stats, ...
/* DIAGNOSTICS
/* Fatal: out of memory.
/* LICENSE
/* using the specified attribute scan routine. rcpb_scan()
/* is meant to be passed as a call-back to attr_scan(), thusly:
/*
-/* ... ATTR_SCAN_FUNC, rcpb_scan, (void *) rcpt_buf, ...
+/* ... ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, ...
/*
/* rcpb_create(), rcpb_reset() and rcpb_free() create, wipe
/* and destroy recipient buffer instances.
/* routine. rcpt_print() is meant to be passed as a call-back
/* to attr_print(), thusly:
/*
-/* ... ATTR_PRINT_FUNC, rcpt_print, (void *) recipient, ...
+/* ... ATTR_TYPE_FUNC, rcpt_print, (void *) recipient, ...
/* DIAGNOSTICS
/* Fatal: out of memory.
/* LICENSE
SHELL = /bin/sh
-SRCS = milter.c milter8.c
-OBJS = milter.o milter8.o
+SRCS = milter.c milter8.c milter_macros.c
+OBJS = milter.o milter8.o milter_macros.o
HDRS = milter.h
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
milter8.o: ../../include/vstring.h
milter8.o: milter.h
milter8.o: milter8.c
+milter_macros.o: ../../include/argv.h
+milter_macros.o: ../../include/attr.h
+milter_macros.o: ../../include/iostuff.h
+milter_macros.o: ../../include/mail_proto.h
+milter_macros.o: ../../include/mymalloc.h
+milter_macros.o: ../../include/sys_defs.h
+milter_macros.o: ../../include/vbuf.h
+milter_macros.o: ../../include/vstream.h
+milter_macros.o: ../../include/vstring.h
+milter_macros.o: milter.h
+milter_macros.o: milter_macros.c
test-milter.o: test-milter.c
{
const char *resp;
MILTER *m;
- ARGV *macros;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
+
+#define MILTER_MACRO_EVAL(global_macros, m, milters, member) \
+ ((m->macros && m->macros->member[0]) ? \
+ milter_macro_lookup(milters, m->macros->member) : \
+ global_macros ? global_macros : \
+ (global_macros = \
+ milter_macro_lookup(milters, milters->macros->member)))
if (msg_verbose)
msg_info("report connect to all milters");
- macros = milter_macro_lookup(milters, milters->conn_macros);
- for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
+ for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, conn_macros);
resp = m->conn_event(m, client_name, client_addr, client_port,
- addr_family, macros);
- argv_free(macros);
+ addr_family, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
+ }
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
{
const char *resp;
MILTER *m;
- ARGV *macros;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
if (msg_verbose)
msg_info("report helo to all milters");
- macros = milters->helo_macros == 0 ? 0 :
- milter_macro_lookup(milters, milters->helo_macros);
- for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
- resp = m->helo_event(m, helo_name, esmtp_flag, macros);
- if (macros)
- argv_free(macros);
+ for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, helo_macros);
+ resp = m->helo_event(m, helo_name, esmtp_flag, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
+ }
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
{
const char *resp;
MILTER *m;
- ARGV *macros;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
if (msg_verbose)
msg_info("report sender to all milters");
- macros = milters->mail_macros == 0 ? 0 :
- milter_macro_lookup(milters, milters->mail_macros);
- for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
- resp = m->mail_event(m, argv, macros);
- if (macros)
- argv_free(macros);
+ for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, mail_macros);
+ resp = m->mail_event(m, argv, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
+ }
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
{
const char *resp;
MILTER *m;
- ARGV *macros;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
if (msg_verbose)
msg_info("report recipient to all milters");
- macros = milters->rcpt_macros == 0 ? 0 :
- milter_macro_lookup(milters, milters->rcpt_macros);
- for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
- resp = m->rcpt_event(m, argv, macros);
- if (macros)
- argv_free(macros);
+ for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, rcpt_macros);
+ resp = m->rcpt_event(m, argv, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
+ }
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
const char *milter_data_event(MILTERS *milters)
{
- const char *myname = "milter_data_event";
const char *resp;
MILTER *m;
- ARGV *macros = 0;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
if (msg_verbose)
msg_info("report data to all milters");
for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
- if (m->data_event) {
- if (macros == 0 && milters->data_macros)
- macros = milter_macro_lookup(milters, milters->data_macros);
- resp = m->data_event(m, macros);
- } else {
- if (msg_verbose)
- msg_info("%s: skip milter %s (command unimplemented)",
- myname, m->name);
- }
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, data_macros);
+ resp = m->data_event(m, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
}
- if (macros)
- argv_free(macros);
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
const char *milter_unknown_event(MILTERS *milters, const char *command)
{
- const char *myname = "milter_unknown_event";
const char *resp;
MILTER *m;
- ARGV *macros = 0;
+ ARGV *global_macros = 0;
+ ARGV *any_macros;
if (msg_verbose)
msg_info("report unknown command to all milters");
for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
- if (m->unknown_event) {
- if (macros == 0 && milters->unk_macros)
- macros = milter_macro_lookup(milters, milters->unk_macros);
- resp = m->unknown_event(m, command, macros);
- } else {
- if (msg_verbose)
- msg_info("%s: skip milter %s (command unimplemented)",
- myname, m->name);
- }
+ any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, unk_macros);
+ resp = m->unknown_event(m, command, any_macros);
+ if (any_macros != global_macros)
+ argv_free(any_macros);
}
- if (macros)
- argv_free(macros);
+ if (global_macros)
+ argv_free(global_macros);
return (resp);
}
{
const char *resp;
MILTER *m;
- ARGV *eoh_macros;
- ARGV *eod_macros;
+ ARGV *global_eoh_macros = 0;
+ ARGV *global_eod_macros = 0;
+ ARGV *any_eoh_macros;
+ ARGV *any_eod_macros;
if (msg_verbose)
msg_info("inspect content by all milters");
- eoh_macros = milters->eoh_macros == 0 ? 0 :
- milter_macro_lookup(milters, milters->eoh_macros);
- eod_macros = milters->eod_macros == 0 ? 0 :
- milter_macro_lookup(milters, milters->eod_macros);
- for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
- resp = m->message(m, fp, data_offset, eoh_macros, eod_macros);
- if (eoh_macros)
- argv_free(eoh_macros);
- if (eod_macros)
- argv_free(eod_macros);
+ for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+ any_eoh_macros = MILTER_MACRO_EVAL(global_eoh_macros, m, milters, eoh_macros);
+ any_eod_macros = MILTER_MACRO_EVAL(global_eod_macros, m, milters, eod_macros);
+ resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros);
+ if (any_eoh_macros != global_eoh_macros)
+ argv_free(any_eoh_macros);
+ if (any_eod_macros != global_eod_macros)
+ argv_free(any_eod_macros);
+ }
+ if (global_eoh_macros)
+ argv_free(global_eoh_macros);
+ if (global_eod_macros)
+ argv_free(global_eod_macros);
return (resp);
}
m->disc_event(m);
}
-/* milter_create - create milter list */
-
-MILTERS *milter_create(const char *names,
- int conn_timeout,
- int cmd_timeout,
- int msg_timeout,
- const char *protocol,
- const char *def_action,
- const char *conn_macros,
- const char *helo_macros,
- const char *mail_macros,
- const char *rcpt_macros,
- const char *data_macros,
- const char *eoh_macros,
- const char *eod_macros,
- const char *unk_macros)
+/* milter_new - create milter list */
+
+MILTERS *milter_new(const char *names,
+ int conn_timeout,
+ int cmd_timeout,
+ int msg_timeout,
+ const char *protocol,
+ const char *def_action,
+ MILTER_MACROS *macros)
{
MILTERS *milters;
MILTER *head = 0;
milters->milter_list = head;
milters->mac_lookup = 0;
milters->mac_context = 0;
- milters->conn_macros = mystrdup(conn_macros);
- milters->helo_macros = mystrdup(helo_macros);
- milters->mail_macros = mystrdup(mail_macros);
- milters->rcpt_macros = mystrdup(rcpt_macros);
- milters->data_macros = mystrdup(data_macros);
- milters->eoh_macros = mystrdup(eoh_macros);
- milters->eod_macros = mystrdup(eod_macros);
- milters->unk_macros = mystrdup(unk_macros);
+ milters->macros = macros;
milters->add_header = 0;
milters->upd_header = milters->ins_header = 0;
milters->del_header = 0;
msg_info("free all milters");
for (m = milters->milter_list; m != 0; m = next)
next = m->next, m->free(m);
- if (milters->conn_macros)
- myfree(milters->conn_macros);
- if (milters->helo_macros)
- myfree(milters->helo_macros);
- if (milters->mail_macros)
- myfree(milters->mail_macros);
- if (milters->rcpt_macros)
- myfree(milters->rcpt_macros);
- if (milters->rcpt_macros)
- myfree(milters->data_macros);
- if (milters->eoh_macros)
- myfree(milters->eoh_macros);
- if (milters->eod_macros)
- myfree(milters->eod_macros);
- if (milters->unk_macros)
- myfree(milters->unk_macros);
+ if (milters->macros)
+ milter_macros_free(milters->macros);
myfree((char *) milters);
}
- /*
- * Temporary protocol to send /receive milter instances. This needs to be
- * extended with type information when we support both Sendmail8 and
- * Sendmail X protocols.
- */
-#define MAIL_ATTR_MILT_CONN "conn_macros"
-#define MAIL_ATTR_MILT_HELO "helo_macros"
-#define MAIL_ATTR_MILT_MAIL "mail_macros"
-#define MAIL_ATTR_MILT_RCPT "rcpt_macros"
-#define MAIL_ATTR_MILT_DATA "data_macros"
-#define MAIL_ATTR_MILT_EOH "eoh_macros"
-#define MAIL_ATTR_MILT_EOD "eod_macros"
-#define MAIL_ATTR_MILT_UNK "unk_macros"
-
/* milter_dummy - send empty milter list */
int milter_dummy(MILTERS *milters, VSTREAM *stream)
* Send the filter macro names.
*/
(void) attr_print(stream, ATTR_FLAG_MORE,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_CONN, milters->conn_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_HELO, milters->helo_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, milters->mail_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, milters->rcpt_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, milters->data_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, milters->eoh_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, milters->eod_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, milters->unk_macros,
+ ATTR_TYPE_FUNC, milter_macros_print,
+ (void *) milters->macros,
ATTR_TYPE_END);
/*
MILTER *head = 0;
MILTER *tail = 0;
MILTER *milter = 0;
- VSTRING *conn_macros;
- VSTRING *helo_macros;
- VSTRING *mail_macros;
- VSTRING *rcpt_macros;
- VSTRING *data_macros;
- VSTRING *eoh_macros;
- VSTRING *eod_macros;
- VSTRING *unk_macros;
+ MILTER_MACROS *macros = milter_macros_alloc(MILTER_MACROS_ALLOC_ZERO);
- /*
- * Receive filter macros.
- */
-#define FREE_BUFFERS() do { \
- vstring_free(conn_macros); vstring_free(helo_macros); \
- vstring_free(mail_macros); vstring_free(rcpt_macros); \
- vstring_free(data_macros); vstring_free(eoh_macros); \
- vstring_free(eod_macros); vstring_free(unk_macros); \
- } while (0)
-
- conn_macros = vstring_alloc(10);
- helo_macros = vstring_alloc(10);
- mail_macros = vstring_alloc(10);
- rcpt_macros = vstring_alloc(10);
- data_macros = vstring_alloc(10);
- eoh_macros = vstring_alloc(10);
- eod_macros = vstring_alloc(10);
- unk_macros = vstring_alloc(10);
if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_CONN, conn_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_HELO, helo_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, mail_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, rcpt_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, data_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, eoh_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, eod_macros,
- ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, unk_macros,
- ATTR_TYPE_END) != 8) {
- FREE_BUFFERS();
+ ATTR_TYPE_FUNC, milter_macros_scan, (void *) macros,
+ ATTR_TYPE_END) != 1) {
+ milter_macros_free(macros);
return (0);
}
#define NO_MILTERS ((char *) 0)
#define NO_PROTOCOL ((char *) 0)
#define NO_ACTION ((char *) 0)
- milters = milter_create(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION,
- STR(conn_macros), STR(helo_macros),
- STR(mail_macros), STR(rcpt_macros),
- STR(data_macros), STR(eoh_macros),
- STR(eod_macros), STR(unk_macros));
- FREE_BUFFERS();
+ milters = milter_new(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION, macros);
/*
* Receive the filters.
#include <vstream.h>
#include <argv.h>
+ /*
+ * Global library.
+ */
+#include <attr.h>
+
/*
* Each Milter handle is an element of a null-terminated linked list. The
* functions are virtual so that we can support multiple MTA-side Milter
char *name; /* full name including transport */
struct MILTER *next; /* linkage */
struct MILTERS *parent; /* parent information */
+ struct MILTER_MACROS *macros; /* private macros */
const char *(*conn_event) (struct MILTER *, const char *, const char *, const char *, unsigned, ARGV *);
const char *(*helo_event) (struct MILTER *, const char *, int, ARGV *);
const char *(*mail_event) (struct MILTER *, const char **, ARGV *);
extern MILTER *milter8_create(const char *, int, int, int, const char *, const char *, struct MILTERS *);
extern MILTER *milter8_receive(VSTREAM *, struct MILTERS *);
+ /*
+ * As of Sendmail 8.14 each milter can override the default macro list. If a
+ * Milter has its own macro list, a null member means use the global
+ * definition.
+ */
+typedef struct MILTER_MACROS {
+ char *conn_macros; /* macros for connect event */
+ char *helo_macros; /* macros for HELO/EHLO command */
+ char *mail_macros; /* macros for MAIL FROM command */
+ char *rcpt_macros; /* macros for RCPT TO command */
+ char *data_macros; /* macros for DATA command */
+ char *eoh_macros; /* macros for end-of-headers */
+ char *eod_macros; /* macros for END-OF-DATA command */
+ char *unk_macros; /* macros for unknown command */
+} MILTER_MACROS;
+
+extern MILTER_MACROS *milter_macros_create(const char *, const char *,
+ const char *, const char *,
+ const char *, const char *,
+ const char *, const char *);
+extern MILTER_MACROS *milter_macros_alloc(int);
+extern void milter_macros_free(MILTER_MACROS *);
+extern int milter_macros_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int milter_macros_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+
+#define MILTER_MACROS_ALLOC_ZERO 1 /* null pointer */
+#define MILTER_MACROS_ALLOC_EMPTY 2 /* mystrdup(""); */
+
+#define milter_macros_wipe(mp) do { \
+ MILTER_MACROS *__mp = mp; \
+ if (__mp->conn_macros) \
+ myfree(__mp->conn_macros); \
+ if (__mp->helo_macros) \
+ myfree(__mp->helo_macros); \
+ if (__mp->mail_macros) \
+ myfree(__mp->mail_macros); \
+ if (__mp->rcpt_macros) \
+ myfree(__mp->rcpt_macros); \
+ if (__mp->data_macros) \
+ myfree(__mp->data_macros); \
+ if (__mp->eoh_macros) \
+ myfree(__mp->eoh_macros); \
+ if (__mp->eod_macros) \
+ myfree(__mp->eod_macros); \
+ if (__mp->unk_macros) \
+ myfree(__mp->unk_macros); \
+ } while (0)
+
+#define milter_macros_zero(mp) milter_macros_init(mp, 0)
+
+#define milter_macros_init(mp, expr) do { \
+ MILTER_MACROS *__mp = (mp); \
+ char *__expr = (expr); \
+ __mp->conn_macros = __expr; \
+ __mp->helo_macros = __expr; \
+ __mp->mail_macros = __expr; \
+ __mp->rcpt_macros = __expr; \
+ __mp->data_macros = __expr; \
+ __mp->eoh_macros = __expr; \
+ __mp->eod_macros = __expr; \
+ __mp->unk_macros = __expr; \
+ } while (0)
+
+
/*
* A bunch of Milters.
*/
MILTER *milter_list; /* linked list of Milters */
MILTER_MAC_LOOKUP_FN mac_lookup;
void *mac_context; /* macro lookup context */
- char *conn_macros; /* macros for connect event */
- char *helo_macros; /* macros for HELO/EHLO command */
- char *mail_macros; /* macros for MAIL FROM command */
- char *rcpt_macros; /* macros for RCPT TO command */
- char *data_macros; /* macros for DATA command */
- char *eoh_macros; /* macros for end-of-headers */
- char *eod_macros; /* macros for END-OF-DATA command */
- char *unk_macros; /* macros for unknown command */
+ struct MILTER_MACROS *macros;
void *chg_context; /* context for queue file changes */
MILTER_ADD_HEADER_FN add_header;
MILTER_EDIT_HEADER_FN upd_header;
MILTER_EDIT_BODY_FN repl_body;
} MILTERS;
-extern MILTERS *milter_create(const char *, int, int, int,
- const char *, const char *,
- const char *, const char *,
- const char *, const char *,
- const char *, const char *,
- const char *, const char *);
+#define milter_create(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
+ protocol, def_action, conn_macros, helo_macros, \
+ mail_macros, rcpt_macros, data_macros, eoh_macros, \
+ eod_macros, unk_macros) \
+ milter_new(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
+ protocol, def_action, milter_macros_create(conn_macros, \
+ helo_macros, mail_macros, rcpt_macros, data_macros, \
+ eoh_macros, eod_macros, unk_macros))
+
+extern MILTERS *milter_new(const char *, int, int, int, const char *,
+ const char *, MILTER_MACROS *);
extern void milter_macro_callback(MILTERS *, MILTER_MAC_LOOKUP_FN, void *);
extern void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN,
MILTER_EDIT_HEADER_FN, MILTER_EDIT_HEADER_FN,
* members, without using a switch statement.
*/
static size_t milter8_macro_offsets[] = {
- offsetof(MILTERS, conn_macros), /* SMFIM_CONNECT */
- offsetof(MILTERS, helo_macros), /* SMFIM_HELO */
- offsetof(MILTERS, mail_macros), /* SMFIM_ENVFROM */
- offsetof(MILTERS, rcpt_macros), /* SMFIM_ENVRCPT */
- offsetof(MILTERS, data_macros), /* SMFIM_DATA */
- offsetof(MILTERS, eod_macros), /* Note: SMFIM_EOM < SMFIM_EOH */
- offsetof(MILTERS, eoh_macros), /* Note: SMFIM_EOH > SMFIM_EOM */
+ offsetof(MILTER_MACROS, conn_macros), /* SMFIM_CONNECT */
+ offsetof(MILTER_MACROS, helo_macros), /* SMFIM_HELO */
+ offsetof(MILTER_MACROS, mail_macros), /* SMFIM_ENVFROM */
+ offsetof(MILTER_MACROS, rcpt_macros), /* SMFIM_ENVRCPT */
+ offsetof(MILTER_MACROS, data_macros), /* SMFIM_DATA */
+ offsetof(MILTER_MACROS, eod_macros),/* Note: SMFIM_EOM < SMFIM_EOH */
+ offsetof(MILTER_MACROS, eoh_macros),/* Note: SMFIM_EOH > SMFIM_EOM */
};
-#define MILTER8_MACRO_PTR(__milters, __type) \
- ((char **) (((char *) (__milters)) + milter8_macro_offsets[(__type)]))
+#define MILTER8_MACRO_PTR(__macros, __type) \
+ ((char **) (((char *) (__macros)) + milter8_macro_offsets[(__type)]))
/*
* How much buffer space is available for sending body content.
const char *smfim_name;
char **mac_value_ptr;
+ milter->m.macros = milter_macros_alloc(MILTER_MACROS_ALLOC_EMPTY);
+
while (data_len > 0
&& milter8_read_data(milter, &data_len,
MILTER8_DATA_HLONG, &mac_type,
if (msg_verbose)
msg_info("override %s macro list with \"%s\"",
smfim_name, STR(buf));
- mac_value_ptr = MILTER8_MACRO_PTR(milter->m.parent, mac_type);
+ mac_value_ptr = MILTER8_MACRO_PTR(milter->m.macros, mac_type);
if (*mac_value_ptr != 0)
myfree(*mac_value_ptr);
*mac_value_ptr = mystrdup(STR(buf));
#define MAIL_ATTR_MILT_CMD "milter_cmd_timeout"
#define MAIL_ATTR_MILT_MSG "milter_msg_timeout"
#define MAIL_ATTR_MILT_ACT "milter_action"
+#define MAIL_ATTR_MILT_MAC "milter_macro_list"
/* milter8_active - report if this milter still wants events */
if (msg_verbose)
msg_info("%s: milter %s", myname, milter->m.name);
- if (attr_print(stream, ATTR_FLAG_NONE,
+ if (attr_print(stream, ATTR_FLAG_MORE,
ATTR_TYPE_STR, MAIL_ATTR_MILT_NAME, milter->m.name,
ATTR_TYPE_INT, MAIL_ATTR_MILT_VERS, milter->version,
ATTR_TYPE_INT, MAIL_ATTR_MILT_ACTS, milter->rq_mask,
ATTR_TYPE_INT, MAIL_ATTR_MILT_CMD, milter->cmd_timeout,
ATTR_TYPE_INT, MAIL_ATTR_MILT_MSG, milter->msg_timeout,
ATTR_TYPE_STR, MAIL_ATTR_MILT_ACT, milter->def_action,
+ ATTR_TYPE_INT, MAIL_ATTR_MILT_MAC, milter->m.macros != 0,
ATTR_TYPE_END) != 0
+ || (milter->m.macros != 0
+ && attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_FUNC, milter_macros_print,
+ (void *) milter->m.macros,
+ ATTR_TYPE_END) != 0)
+ || (milter->m.macros == 0
+ && attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_END) != 0)
|| vstream_fflush(stream) != 0) {
return (-1);
#ifdef CANT_WRITE_BEFORE_SENDING_FD
}
static MILTER8 *milter8_alloc(const char *, int, int, int, const char *,
- const char *, MILTERS *);
+ const char *, MILTERS *);
/* milter8_receive - receive milter instance */
int cmd_timeout;
int msg_timeout;
int fd;
+ int has_macros;
+ MILTER_MACROS *macros = 0;
+
+#define FREE_MACROS_AND_RETURN(x) do { \
+ if (macros) \
+ milter_macros_free(macros); \
+ return (x); \
+ } while (0)
if (name_buf == 0) {
name_buf = vstring_alloc(10);
act_buf = vstring_alloc(10);
}
- if (attr_scan(stream, ATTR_FLAG_STRICT,
+ if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
ATTR_TYPE_STR, MAIL_ATTR_MILT_NAME, name_buf,
ATTR_TYPE_INT, MAIL_ATTR_MILT_VERS, &version,
ATTR_TYPE_INT, MAIL_ATTR_MILT_ACTS, &rq_mask,
ATTR_TYPE_INT, MAIL_ATTR_MILT_CMD, &cmd_timeout,
ATTR_TYPE_INT, MAIL_ATTR_MILT_MSG, &msg_timeout,
ATTR_TYPE_STR, MAIL_ATTR_MILT_ACT, act_buf,
- ATTR_TYPE_END) < 9) {
- return (0);
+ ATTR_TYPE_INT, MAIL_ATTR_MILT_MAC, &has_macros,
+ ATTR_TYPE_END) < 10
+ || (has_macros != 0
+ && attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_FUNC, milter_macros_scan,
+ (void *) (macros =
+ milter_macros_alloc(MILTER_MACROS_ALLOC_ZERO)),
+ ATTR_TYPE_END) < 1)
+ || (has_macros == 0
+ && attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_END) < 0)) {
+ FREE_MACROS_AND_RETURN(0);
#ifdef CANT_WRITE_BEFORE_SENDING_FD
} else if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
ATTR_TYPE_END) != 0
|| vstream_fflush(stream) != 0) {
- return (0);
+ FREE_MACROS_AND_RETURN(0);
#endif
} else if ((fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
- return (0);
+ FREE_MACROS_AND_RETURN(0);
#ifdef MUST_READ_AFTER_SENDING_FD
} else if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
ATTR_TYPE_END) != 0) {
- return (0);
+ FREE_MACROS_AND_RETURN(0);
#endif
} else {
#define NO_PROTOCOL ((char *) 0)
milter = milter8_alloc(STR(name_buf), conn_timeout, cmd_timeout,
msg_timeout, NO_PROTOCOL, STR(act_buf), parent);
milter->fp = vstream_fdopen(fd, O_RDWR);
+ milter->m.macros = macros;
vstream_control(milter->fp, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_END);
/* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */
vstream_tweak_sock(milter->fp);
myfree(milter->def_action);
if (milter->def_reply)
myfree(milter->def_reply);
+ if (milter->m.macros)
+ milter_macros_free(milter->m.macros);
myfree((char *) milter);
}
milter->m.name = mystrdup(name);
milter->m.next = 0;
milter->m.parent = parent;
+ milter->m.macros = 0;
milter->m.conn_event = milter8_conn_event;
milter->m.helo_event = milter8_helo_event;
milter->m.mail_event = milter8_mail_event;
* Fill in the structure.
*/
milter = milter8_alloc(name, conn_timeout, cmd_timeout, msg_timeout,
- protocol, def_action, parent);
+ protocol, def_action, parent);
/*
* XXX Sendmail 8 libmilter closes the MTA-to-filter socket when it finds
--- /dev/null
+/*++
+/* NAME
+/* milter_macros
+/* SUMMARY
+/* manipulate MILTER_MACROS structures
+/* SYNOPSIS
+/* #include <milter.h>
+/*
+/* MILTER_MACROS *milter_macros_create(conn_macros, helo_macros,
+/* mail_macros, rcpt_macros,
+/* data_macros, eoh_macros,
+/* eod_macros, unk_macros)
+/* const char *conn_macros;
+/* const char *helo_macros;
+/* const char *mail_macros;
+/* const char *rcpt_macrps;
+/* const char *data_macros;
+/* const char *eoh_macros;
+/* const char *eod_macros;
+/* const char *unk_macros;
+/*
+/* MILTER_MACROS *milter_macros_alloc(init_mode)
+/* int init_mode;
+/*
+/* void milter_macros_free(mp)
+/* MILTER_MACROS *mp;
+/*
+/* int milter_macros_print(print_fn, stream, flags, ptr)
+/* ATTR_PRINT_MASTER_FN print_fn;
+/* VSTREAM *stream;
+/* int flags;
+/* void *ptr;
+/*
+/* int milter_macros_scan(scan_fn, fp, flags, ptr)
+/* ATTR_SCAN_MASTER_FN scan_fn;
+/* VSTREAM *fp;
+/* int flags;
+/* void *ptr;
+/* DESCRIPTION
+/* Sendmail mail filter (Milter) applications receive sets of
+/* macro (name=value) pairs with each SMTP or content event.
+/* In Postfix, the lists of names are stored in MILTER_MACROS
+/* structures. By default, the same structure is shared by all
+/* Milter applications; it is initialized with information
+/* from main.cf. With Sendmail 8.14 a Milter can override one
+/* or more lists of macro names, and individual filters may
+/* have their own partial list.
+/*
+/* This module maintains the macro name lists as mystrdup()'ed
+/* values. The user is explicitly allowed to update these
+/* values directly, as long as they respect the mystrdup()
+/* interface.
+/*
+/* milter_macros_create() creates a MILTER_MACROS structure
+/* and initializes it with copies of its string arguments.
+/*
+/* milter_macros_alloc() creates a MILTER_MACROS structure
+/* that is initialized according to its init_mode argument.
+/* .IP MILTER_MACROS_ALLOC_ZERO
+/* Initialize all members as null pointers. This mode is
+/* recommended for applications that use milter_macros_scan().
+/* .IP MILTER_MACROS_ALLOC_EMPTY
+/* Initialize all members with mystrdup(""). This is not as
+/* expensive as it appears to be. This mode is recommend for
+/* applications that update individual MILTER_MACROS members
+/* directly.
+/* .PP
+/* milter_macros_free() destroys a MILTER_MACROS structure and
+/* frees any strings referenced by it.
+/*
+/* milter_macros_print() writes the contents of a MILTER_MACROS
+/* structure to the named stream using the specified attribute
+/* print routine. milter_macros_print() is meant to be passed
+/* as a call-back to attr_print*(), thusly:
+/*
+/* ATTR_TYPE_FUNC, milter_macros_print, (void *) macros,
+/*
+/* milter_macros_scan() reads a MILTER_MACROS structure from
+/* the named stream using the specified attribute scan routine.
+/* milter_macros_scan() is meant to be passed as a call-back
+/* to attr_scan*(), thusly:
+/*
+/* ATTR_TYPE_FUNC, milter_macros_scan, (void *) macros,
+/* DIAGNOSTICS
+/* Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this
+/* software.
+/* AUTHOR(S)
+/* Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown
+/* Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <attr.h>
+#include <mymalloc.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <milter.h>
+
+ /*
+ * Ad-hoc protocol to send/receive milter macro name lists.
+ */
+#define MAIL_ATTR_MILT_MAC_CONN "conn_macros"
+#define MAIL_ATTR_MILT_MAC_HELO "helo_macros"
+#define MAIL_ATTR_MILT_MAC_MAIL "mail_macros"
+#define MAIL_ATTR_MILT_MAC_RCPT "rcpt_macros"
+#define MAIL_ATTR_MILT_MAC_DATA "data_macros"
+#define MAIL_ATTR_MILT_MAC_EOH "eoh_macros"
+#define MAIL_ATTR_MILT_MAC_EOD "eod_macros"
+#define MAIL_ATTR_MILT_MAC_UNK "unk_macros"
+
+/* milter_macros_print - write recipient to stream */
+
+int milter_macros_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+ int flags, void *ptr)
+{
+ MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
+ int ret;
+
+ /*
+ * The attribute order does not matter, except that it must be the same
+ * as in the milter_macros_scan() function.
+ */
+ ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, mp->conn_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, mp->helo_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mp->mail_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, mp->rcpt_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, mp->data_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, mp->eoh_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, mp->eod_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, mp->unk_macros,
+ ATTR_TYPE_END);
+ return (ret);
+}
+
+/* milter_macros_scan - receive milter macro name list */
+
+int milter_macros_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+ int flags, void *ptr)
+{
+ MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
+ int ret;
+ VSTRING *conn_macros = vstring_alloc(10);
+ VSTRING *helo_macros = vstring_alloc(10);
+ VSTRING *mail_macros = vstring_alloc(10);
+ VSTRING *rcpt_macros = vstring_alloc(10);
+ VSTRING *data_macros = vstring_alloc(10);
+ VSTRING *eoh_macros = vstring_alloc(10);
+ VSTRING *eod_macros = vstring_alloc(10);
+ VSTRING *unk_macros = vstring_alloc(10);
+
+ /*
+ * The attribute order does not matter, except that it must be the same
+ * as in the milter_macros_print() function.
+ */
+ ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, conn_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, helo_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mail_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, rcpt_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, data_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, eoh_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, eod_macros,
+ ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, unk_macros,
+ ATTR_TYPE_END);
+
+ /*
+ * Don't optimize for error.
+ */
+ mp->conn_macros = vstring_export(conn_macros);
+ mp->helo_macros = vstring_export(helo_macros);
+ mp->mail_macros = vstring_export(mail_macros);
+ mp->rcpt_macros = vstring_export(rcpt_macros);
+ mp->data_macros = vstring_export(data_macros);
+ mp->eoh_macros = vstring_export(eoh_macros);
+ mp->eod_macros = vstring_export(eod_macros);
+ mp->unk_macros = vstring_export(unk_macros);
+
+ return (ret == 8 ? 1 : -1);
+}
+
+/* milter_macros_create - create and initialize macros structure */
+
+MILTER_MACROS *milter_macros_create(const char *conn_macros,
+ const char *helo_macros,
+ const char *mail_macros,
+ const char *rcpt_macros,
+ const char *data_macros,
+ const char *eoh_macros,
+ const char *eod_macros,
+ const char *unk_macros)
+{
+ MILTER_MACROS *mp;
+
+ mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
+ mp->conn_macros = mystrdup(conn_macros);
+ mp->helo_macros = mystrdup(helo_macros);
+ mp->mail_macros = mystrdup(mail_macros);
+ mp->rcpt_macros = mystrdup(rcpt_macros);
+ mp->data_macros = mystrdup(data_macros);
+ mp->eoh_macros = mystrdup(eoh_macros);
+ mp->eod_macros = mystrdup(eod_macros);
+ mp->unk_macros = mystrdup(unk_macros);
+
+ return (mp);
+}
+
+/* milter_macros_alloc - allocate memory for structure with simple initialization */
+
+MILTER_MACROS *milter_macros_alloc(int mode)
+{
+ MILTER_MACROS *mp;
+
+ mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
+ switch (mode) {
+ case MILTER_MACROS_ALLOC_ZERO:
+ milter_macros_init(mp, 0);
+ break;
+ case MILTER_MACROS_ALLOC_EMPTY:
+ milter_macros_init(mp, mystrdup(""));
+ break;
+ default:
+ msg_panic("milter_macros_alloc: unknown mode %d", mode);
+ }
+ return (mp);
+}
+
+/* milter_macros_free - destroy memory for MILTER_MACROS structure */
+
+void milter_macros_free(MILTER_MACROS *mp)
+{
+ milter_macros_wipe(mp);
+ myfree((char *) mp);
+}