diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 30e466857..3b8209c42 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -143,6 +143,7 @@ -TMILTER -TMILTER8 -TMILTERS +-TMILTER_MACROS -TMILTER_MSG_CONTEXT -TMIME_ENCODING -TMIME_INFO diff --git a/postfix/HISTORY b/postfix/HISTORY index ebc0f1657..5e90db6fd 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -14053,3 +14053,12 @@ Apologies for any names omitted. 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. diff --git a/postfix/src/global/dsb_scan.c b/postfix/src/global/dsb_scan.c index 0693d5887..8331022c5 100644 --- a/postfix/src/global/dsb_scan.c +++ b/postfix/src/global/dsb_scan.c @@ -16,7 +16,7 @@ /* 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 diff --git a/postfix/src/global/dsn_print.c b/postfix/src/global/dsn_print.c index 9b21a6904..58f06a34c 100644 --- a/postfix/src/global/dsn_print.c +++ b/postfix/src/global/dsn_print.c @@ -16,7 +16,7 @@ /* 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 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index e6708f71a..70c942d3c 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * 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 diff --git a/postfix/src/global/msg_stats_print.c b/postfix/src/global/msg_stats_print.c index 98d468dcd..f39b73c99 100644 --- a/postfix/src/global/msg_stats_print.c +++ b/postfix/src/global/msg_stats_print.c @@ -17,7 +17,7 @@ /* 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 diff --git a/postfix/src/global/rcpt_buf.c b/postfix/src/global/rcpt_buf.c index 3c8edddad..798929d84 100644 --- a/postfix/src/global/rcpt_buf.c +++ b/postfix/src/global/rcpt_buf.c @@ -41,7 +41,7 @@ /* 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. diff --git a/postfix/src/global/rcpt_print.c b/postfix/src/global/rcpt_print.c index 985f42c32..1c8b0cfa7 100644 --- a/postfix/src/global/rcpt_print.c +++ b/postfix/src/global/rcpt_print.c @@ -17,7 +17,7 @@ /* 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 diff --git a/postfix/src/milter/Makefile.in b/postfix/src/milter/Makefile.in index 3aba26635..8bb27c08a 100644 --- a/postfix/src/milter/Makefile.in +++ b/postfix/src/milter/Makefile.in @@ -1,6 +1,6 @@ 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) @@ -117,4 +117,15 @@ milter8.o: ../../include/vstream.h 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 diff --git a/postfix/src/milter/milter.c b/postfix/src/milter/milter.c index e9024f721..54871653d 100644 --- a/postfix/src/milter/milter.c +++ b/postfix/src/milter/milter.c @@ -310,15 +310,27 @@ const char *milter_conn_event(MILTERS *milters, { 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); } @@ -329,16 +341,19 @@ const char *milter_helo_event(MILTERS *milters, const char *helo_name, { 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); } @@ -348,16 +363,19 @@ const char *milter_mail_event(MILTERS *milters, const char **argv) { 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); } @@ -367,16 +385,19 @@ const char *milter_rcpt_event(MILTERS *milters, const char **argv) { 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); } @@ -384,26 +405,21 @@ const char *milter_rcpt_event(MILTERS *milters, const char **argv) 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); } @@ -411,26 +427,21 @@ const char *milter_data_event(MILTERS *milters) 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); } @@ -454,21 +465,26 @@ const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset) { 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); } @@ -496,22 +512,15 @@ void milter_disc_event(MILTERS *milters) m->disc_event(m); } -/* milter_create - create milter list */ +/* milter_new - 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) +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; @@ -544,14 +553,7 @@ MILTERS *milter_create(const char *names, 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; @@ -572,39 +574,11 @@ void milter_free(MILTERS *milters) 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) @@ -640,14 +614,8 @@ int milter_send(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); /* @@ -675,44 +643,12 @@ MILTERS *milter_receive(VSTREAM *stream, int count) 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) @@ -720,12 +656,7 @@ MILTERS *milter_receive(VSTREAM *stream, int count) #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. diff --git a/postfix/src/milter/milter.h b/postfix/src/milter/milter.h index b47efb959..1f9b7f629 100644 --- a/postfix/src/milter/milter.h +++ b/postfix/src/milter/milter.h @@ -18,6 +18,11 @@ #include #include + /* + * Global library. + */ +#include + /* * 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 @@ -28,6 +33,7 @@ typedef struct 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 *); @@ -46,6 +52,70 @@ typedef struct MILTER { 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. */ @@ -60,14 +130,7 @@ typedef struct 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; @@ -78,12 +141,17 @@ typedef struct MILTERS { 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, diff --git a/postfix/src/milter/milter8.c b/postfix/src/milter/milter8.c index 43d2d7800..fc2cccc33 100644 --- a/postfix/src/milter/milter8.c +++ b/postfix/src/milter/milter8.c @@ -322,17 +322,17 @@ static NAME_CODE smfim_table[] = { * 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. @@ -1734,6 +1734,8 @@ static void milter8_connect(MILTER8 *milter) 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, @@ -1747,7 +1749,7 @@ static void milter8_connect(MILTER8 *milter) 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)); @@ -2467,6 +2469,7 @@ static const char *milter8_message(MILTER *m, VSTREAM *qfile, #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 */ @@ -2489,7 +2492,7 @@ static int milter8_send(MILTER *m, VSTREAM *stream) 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, @@ -2500,7 +2503,16 @@ static int milter8_send(MILTER *m, VSTREAM *stream) 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 @@ -2524,7 +2536,7 @@ static int milter8_send(MILTER *m, VSTREAM *stream) } static MILTER8 *milter8_alloc(const char *, int, int, int, const char *, - const char *, MILTERS *); + const char *, MILTERS *); /* milter8_receive - receive milter instance */ @@ -2543,12 +2555,20 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent) 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, @@ -2559,22 +2579,32 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent) 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) @@ -2585,6 +2615,7 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent) 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); @@ -2615,6 +2646,8 @@ static void milter8_free(MILTER *m) 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); } @@ -2635,6 +2668,7 @@ static MILTER8 *milter8_alloc(const char *name, int conn_timeout, 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; @@ -2678,7 +2712,7 @@ MILTER *milter8_create(const char *name, int conn_timeout, int cmd_timeout, * 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 diff --git a/postfix/src/milter/milter_macros.c b/postfix/src/milter/milter_macros.c new file mode 100644 index 000000000..db5c36db9 --- /dev/null +++ b/postfix/src/milter/milter_macros.c @@ -0,0 +1,247 @@ +/*++ +/* NAME +/* milter_macros +/* SUMMARY +/* manipulate MILTER_MACROS structures +/* SYNOPSIS +/* #include +/* +/* 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 + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + + /* + * 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); +}