From: Wietse Venema Date: Fri, 28 Dec 2018 05:00:00 +0000 (-0500) Subject: postfix-3.4-20181228-nonprod X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5436ba9f299ecc7ee12a50813354292346c50d1a;p=thirdparty%2Fpostfix.git postfix-3.4-20181228-nonprod --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 40ba2bc9d..5a1c44e5b 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -81,6 +81,7 @@ -TDICT_DEBUG -TDICT_ENV -TDICT_FAIL +-TDICT_FINAL_WRAPPER -TDICT_HT -TDICT_INLINE -TDICT_LDAP @@ -126,7 +127,7 @@ -TDICT_THASH -TDICT_UNION -TDICT_UNIX --TDICT_UTF8_BACKUP +-TDICT_WRAPPER -TDNS_FIXED -TDNS_REPLY -TDNS_RR diff --git a/postfix/HISTORY b/postfix/HISTORY index 3b5d3fdfd..c2ee39345 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23916,3 +23916,17 @@ Apologies for any names omitted. postscreen_post_queue_limit, and attributed the wrong reject message to the postscreen_pre_queue_limit. Problem reported by Michael Orlitzky. File: proto/POSTSCREEN_README.html. + + Compatibility: removed support for OpenSSL 1.0.1 and earlier. + + Feature: TLS support for client-side and server-side SNI + in the Postfix SMTP server, SMTP client, and tlsproxy. + +20181228 + + Cleanup: generic wrapper infrastructure for Postfix maps + (dictionaries) that is the basis for UTF8 checks and for + base64 decoding of lookup results. Files: global/mkmap_open.c, + postmap/postmap.c, util/dict.c, util/dict.h, util/dict_alloc.c, + util/dict_file.c, util/dict_open.c, util/dict_pipe.c, + util/dict_union.c, util/dict_utf8.c, util/dict_wrapper.c. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index f1165b348..882c9c471 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 "20181226" +#define MAIL_RELEASE_DATE "20181228" #define MAIL_VERSION_NUMBER "3.4" #ifdef SNAPSHOT diff --git a/postfix/src/global/maps.c b/postfix/src/global/maps.c index df25e84ad..8a1dc9e88 100644 --- a/postfix/src/global/maps.c +++ b/postfix/src/global/maps.c @@ -165,14 +165,6 @@ const char *maps_find(MAPS *maps, const char *name, int flags) char **map_name; const char *expansion; DICT *dict; - int rhs_is_file; - - /* - * For now, handled at this layer, rather rather than implicitly in - * dict_get(). - */ - rhs_is_file = flags & DICT_FLAG_SRC_RHS_IS_FILE; - flags &= ~DICT_FLAG_SRC_RHS_IS_FILE; /* * In case of return without map lookup (empty name or no maps). @@ -200,23 +192,9 @@ const char *maps_find(MAPS *maps, const char *name, int flags) maps->error = DICT_ERR_RETRY; return (0); } - /* Log raw value, prior to base64 decoding */ if (msg_verbose) msg_info("%s: %s: %s: %s = %s", myname, maps->title, *map_name, name, expansion); - if (rhs_is_file) { - VSTRING *unb64; - char *err; - - if ((unb64 = dict_file_from_b64(dict, expansion)) == 0) { - err = dict_file_get_error(dict); - msg_warn("table %s:%s: key %s: %s", - dict->type, dict->name, name, err); - maps->error = DICT_ERR_RETRY; - return (0); - } - expansion = vstring_str(unb64); - } return (expansion); } else if ((maps->error = dict->error) != 0) { msg_warn("%s:%s lookup error for \"%.100s\"", diff --git a/postfix/src/global/mkmap_open.c b/postfix/src/global/mkmap_open.c index 9d15eec30..32dfc9ea6 100644 --- a/postfix/src/global/mkmap_open.c +++ b/postfix/src/global/mkmap_open.c @@ -301,7 +301,12 @@ MKMAP *mkmap_open(const char *type, const char *path, */ if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0 && DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags)) - mkmap->dict = dict_utf8_activate(mkmap->dict); + dict_utf8_wrapper_activate(mkmap->dict); + + /* Insert wrapper for base64 decoding file content. */ + if ((mkmap->dict->flags & DICT_FLAG_UNB64_ACTIVE) == 0 + && (mkmap->dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) != 0) + dict_file_wrapper_activate(mkmap->dict); /* * Resume signal delivery if multi-writer safe. diff --git a/postfix/src/postmap/file_test.ref b/postfix/src/postmap/file_test.ref index aa676441d..1e808abbe 100644 --- a/postfix/src/postmap/file_test.ref +++ b/postfix/src/postmap/file_test.ref @@ -10,4 +10,5 @@ file-1 this-is-file1 file-2 this-is-file2 this-is-file1 this-is-file2 -postmap: fatal: table hash:file_test_map.db: key entry-4: malformed BASE64 value: postmap-entry-4 +postmap: warning: table hash:file_test_map.db: key entry-4: malformed BASE64 value: postmap-entry-4 +postmap: fatal: table hash:file_test_map.db: query error: No such file or directory diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c index 16bbef942..207733573 100644 --- a/postfix/src/postmap/postmap.c +++ b/postfix/src/postmap/postmap.c @@ -658,6 +658,7 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count, msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND", dicts[n]->type, dicts[n]->name); } +#if 0 if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) { VSTRING *unb64; char *err; @@ -670,6 +671,7 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count, } value = STR(unb64); } +#endif vstream_printf("%s %s\n", STR(keybuf), value); found = 1; break; @@ -757,6 +759,7 @@ static int postmap_query(const char *map_type, const char *map_name, msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND", map_type, map_name); } +#if 0 if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) { VSTRING *unb64; char *err; @@ -769,6 +772,7 @@ static int postmap_query(const char *map_type, const char *map_name, } value = STR(unb64); } +#endif vstream_printf("%s\n", value); } if (dict->error) @@ -881,6 +885,7 @@ static void postmap_seq(const char *map_type, const char *map_name, msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND", map_type, map_name); } +#if 1 if (dict_flags & DICT_FLAG_SRC_RHS_IS_FILE) { VSTRING *unb64; char *err; @@ -895,6 +900,7 @@ static void postmap_seq(const char *map_type, const char *map_name, } value = STR(unb64); } +#endif vstream_printf("%s %s\n", key, value); } if (dict->error) diff --git a/postfix/src/tls/tls_certkey.c b/postfix/src/tls/tls_certkey.c index 1e7fbf33e..997e26830 100644 --- a/postfix/src/tls/tls_certkey.c +++ b/postfix/src/tls/tls_certkey.c @@ -143,7 +143,7 @@ static void init_pem_load_state(pem_load_state *st, SSL_CTX *ctx, SSL *ssl, /* use_chain - load cert, key and chain into ctx or ssl */ -#if OPENSSL_VERSION_NUMBER >= 0x1010000fUL +#if OPENSSL_VERSION_NUMBER >= 0x1010100fUL static int use_chain(pem_load_state *st) { int ret; @@ -177,7 +177,7 @@ static int use_chain(pem_load_state *st) #else -/* Legacy OpenSSL 1.0.2 interface */ +/* Legacy OpenSSL 1.0.2 and 1.1.0 interface */ static int use_chain(pem_load_state *st) { int ret = 1; diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index f0715959c..a1bd8bcba 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -40,7 +40,8 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ poll_fd.c timecmp.c slmdb.c dict_pipe.c dict_random.c \ valid_utf8_hostname.c midna_domain.c argv_splitq.c balpar.c dict_union.c \ extpar.c dict_inline.c casefold.c dict_utf8.c strcasecmp_utf8.c \ - split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c + split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c \ + dict_wrapper.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ @@ -82,7 +83,8 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ poll_fd.o timecmp.o $(NON_PLUGIN_MAP_OBJ) dict_pipe.o dict_random.o \ valid_utf8_hostname.o midna_domain.o argv_splitq.o balpar.o dict_union.o \ extpar.o dict_inline.o casefold.o dict_utf8.o strcasecmp_utf8.o \ - split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o + split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o \ + dict_wrapper.o # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), # otherwise it sets the PLUGIN_* macros. @@ -1340,7 +1342,6 @@ dict_ht.o: sys_defs.h dict_ht.o: vbuf.h dict_ht.o: vstream.h dict_ht.o: vstring.h -dict_inline.cdict_static.o: dict_inline.cdict_static.c dict_inline.o: argv.h dict_inline.o: check_arg.h dict_inline.o: dict.h @@ -1647,6 +1648,18 @@ dict_utf8.o: sys_defs.h dict_utf8.o: vbuf.h dict_utf8.o: vstream.h dict_utf8.o: vstring.h +dict_wrapper.o: argv.h +dict_wrapper.o: check_arg.h +dict_wrapper.o: dict.h +dict_wrapper.o: dict_wrapper.c +dict_wrapper.o: msg.h +dict_wrapper.o: myflock.h +dict_wrapper.o: mymalloc.h +dict_wrapper.o: stringops.h +dict_wrapper.o: sys_defs.h +dict_wrapper.o: vbuf.h +dict_wrapper.o: vstream.h +dict_wrapper.o: vstring.h dir_forest.o: check_arg.h dir_forest.o: dir_forest.c dir_forest.o: dir_forest.h @@ -1904,8 +1917,6 @@ load_file.o: vbuf.h load_file.o: vstream.h load_file.o: warn_stat.h load_lib.o: load_lib.c -load_lib.o: load_lib.h -load_lib.o: msg.h load_lib.o: sys_defs.h lowercase.o: check_arg.h lowercase.o: lowercase.c diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 5d53860f1..84e413eb0 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -640,6 +640,7 @@ static const NAME_MASK dict_mask[] = { "utf8_request", DICT_FLAG_UTF8_REQUEST, /* request UTF-8 activation */ "utf8_active", DICT_FLAG_UTF8_ACTIVE, /* UTF-8 is activated */ "src_rhs_is_file", DICT_FLAG_SRC_RHS_IS_FILE, /* value from file */ + "unb64_active", DICT_FLAG_UNB64_ACTIVE, /* base64 decode activated */ 0, }; diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h index a89f0ea5d..8c03477e3 100644 --- a/postfix/src/util/dict.h +++ b/postfix/src/util/dict.h @@ -93,7 +93,7 @@ typedef struct DICT { DICT_OWNER owner; /* provenance */ int error; /* last operation only */ DICT_JMP_BUF *jbuf; /* exception handling */ - struct DICT_UTF8_BACKUP *utf8_backup; /* see below */ + struct DICT_WRAPPER *wrapper; /* see below */ struct VSTRING *file_buf; /* dict_file_to_buf() */ struct VSTRING *file_b64; /* dict_file_to_b64() */ } DICT; @@ -133,6 +133,7 @@ extern DICT *dict_debug(DICT *); #define DICT_FLAG_UTF8_ACTIVE (1<<20) /* UTF-8 proxy layer is present */ #define DICT_FLAG_SRC_RHS_IS_FILE \ (1<<21) /* Map source RHS is a file */ +#define DICT_FLAG_UNB64_ACTIVE (1<<22) /* File decode proxy layer is present */ #define DICT_FLAG_UTF8_MASK (DICT_FLAG_UTF8_REQUEST) @@ -251,15 +252,29 @@ extern int dict_flags_mask(const char *); extern void dict_type_override(DICT *, const char *); /* - * Check and convert UTF-8 keys and values. + * Wrappers for DICT methods. Usage: create an "trivial" wrapper object with + * dict_wrapper_alloc(), then for each method that requires special + * processing, specify a pointer to function that calls the 'next' wrapper's + * method of the same type, with the 'next' wrapper as the first argument + * (the 'self' pointer). */ -typedef struct DICT_UTF8_BACKUP { - const char *(*lookup) (struct DICT *, const char *); - int (*update) (struct DICT *, const char *, const char *); - int (*delete) (struct DICT *, const char *); -} DICT_UTF8_BACKUP; +typedef struct DICT_WRAPPER { + const char *name; /* for literal constant */ + const char *(*lookup) (struct DICT_WRAPPER *, DICT *, const char *); + int (*update) (struct DICT_WRAPPER *, DICT *, const char *, const char *); + int (*delete) (struct DICT_WRAPPER *, DICT *, const char *); + struct DICT_WRAPPER *next; +} DICT_WRAPPER; + +extern void dict_wrapper_prepend(DICT *, DICT_WRAPPER *); +extern DICT_WRAPPER *dict_wrapper_alloc(ssize_t); +extern void dict_wrapper_free(DICT_WRAPPER *); -extern DICT *dict_utf8_activate(DICT *); + /* + * Things that build on DICT_WRAPPER. + */ +extern void dict_utf8_wrapper_activate(DICT *); +extern void dict_file_wrapper_activate(DICT *); /* * Driver for interactive or scripted tests. diff --git a/postfix/src/util/dict_alloc.c b/postfix/src/util/dict_alloc.c index 3285a38e3..384defbf6 100644 --- a/postfix/src/util/dict_alloc.c +++ b/postfix/src/util/dict_alloc.c @@ -159,7 +159,7 @@ DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size) dict->owner.uid = INT_MAX; dict->error = DICT_ERR_NONE; dict->jbuf = 0; - dict->utf8_backup = 0; + dict->wrapper = 0; dict->file_buf = 0; dict->file_b64 = 0; return dict; @@ -173,8 +173,8 @@ void dict_free(DICT *dict) myfree(dict->name); if (dict->jbuf) myfree((void *) dict->jbuf); - if (dict->utf8_backup) - myfree((void *) dict->utf8_backup); + if (dict->wrapper) + dict_wrapper_free(dict->wrapper); if (dict->file_buf) vstring_free(dict->file_buf); if (dict->file_b64) diff --git a/postfix/src/util/dict_cidr_file.ref b/postfix/src/util/dict_cidr_file.ref index 3e9e79205..537805e24 100644 --- a/postfix/src/util/dict_cidr_file.ref +++ b/postfix/src/util/dict_cidr_file.ref @@ -1,8 +1,10 @@ ./dict_open: warning: cidr map dict_cidr_file.map, line 3: open dict_cidr_file3: No such file or directory: skipping this rule owner=untrusted (uid=USER) > get 1.1.1.1 -1.1.1.1=dGhpcy1pcy1maWxlMQo= +1.1.1.1=this-is-file1 + > get 2.2.2.2 -2.2.2.2=dGhpcy1pcy1maWxlMgo= +2.2.2.2=this-is-file2 + > get 3.3.3.3 3.3.3.3: not found diff --git a/postfix/src/util/dict_file.c b/postfix/src/util/dict_file.c index e59842a31..ebfbb3f16 100644 --- a/postfix/src/util/dict_file.c +++ b/postfix/src/util/dict_file.c @@ -23,6 +23,9 @@ /* /* void dict_file_purge_buffers( /* DICT *dict) +/* +/* void dict_file_wrapper_activate( +/* DICT *dict) /* DESCRIPTION /* dict_file_to_buf() reads the content of the specified files, /* with names separated by CHARS_COMMA_SP, while inserting a @@ -44,6 +47,9 @@ /* dict_file_get_error() should be called only after error; /* it returns a desciption of the problem. Storage is owned /* by the caller. +/* +/* dict_file_wrapper_activate() activates a wrapper that +/* automatically base64-decodes lookup results. /* DIAGNOSTICS /* In case of error the result value is a null pointer, and /* an error description can be retrieved with dict_file_get_error(). @@ -192,3 +198,57 @@ void dict_file_purge_buffers(DICT *dict) dict->file_b64 = 0; } } + +/* dict_file_wrapper_lookup - wrap the lookup method */ + +static const char *dict_file_wrapper_lookup(DICT_WRAPPER *wrapper, + DICT *dict, const char *key) +{ + DICT_WRAPPER *next_wrapper; + const char *res; + VSTRING *unb64; + char *err; + + next_wrapper = wrapper->next; + if ((res = next_wrapper->lookup(next_wrapper, dict, key)) != 0) { + if ((unb64 = dict_file_from_b64(dict, res)) == 0) { + err = dict_file_get_error(dict); + msg_warn("table %s:%s: key %s: %s", + dict->type, dict->name, key, err); + myfree(err); + dict->error = DICT_ERR_CONFIG; + res = 0; + } else { + res = vstring_str(unb64); + } + } + return (res); +} + +/* dict_file_wrapper_activate - wrap the lookup method */ + +void dict_file_wrapper_activate(DICT *dict) +{ + const char myname[] = "dict_file_wrapper_activate"; + DICT_WRAPPER *wrapper; + + /* + * Sanity check. + */ + if ((dict->flags & DICT_FLAG_UNB64_ACTIVE)) + msg_panic("%s: %s:%s Base64 decoding support is already activated", + myname, dict->type, dict->name); + + /* + * Interpose on the lookup method. + */ + wrapper = dict_wrapper_alloc(sizeof(*wrapper)); + wrapper->name = "file"; + wrapper->lookup = dict_file_wrapper_lookup; + dict_wrapper_prepend(dict, wrapper); + + /* + * Leave our mark. See sanity check above. + */ + dict->flags |= DICT_FLAG_UNB64_ACTIVE; +} diff --git a/postfix/src/util/dict_inline_file.ref b/postfix/src/util/dict_inline_file.ref index 9d49e95f4..2aed9bd57 100644 --- a/postfix/src/util/dict_inline_file.ref +++ b/postfix/src/util/dict_inline_file.ref @@ -5,8 +5,10 @@ owner=trusted (uid=2147483647) foo: error owner=trusted (uid=2147483647) > get file1 -file1=dGhpcy1pcy1maWxlMQo= +file1=this-is-file1 + > get file2 -file2=dGhpcy1pcy1maWxlMgo= +file2=this-is-file2 + > get file3 file3: not found diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index ca8df67ee..ad95f1255 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -479,10 +479,16 @@ DICT *dict_open3(const char *dict_type, const char *dict_name, msg_fatal("%s:%s: unable to get exclusive lock: %m", dict_type, dict_name); } - /* Last step: insert proxy for UTF-8 syntax checks and casefolding. */ + /* Insert wrapper for UTF-8 syntax checks and casefolding. */ if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0 && DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags)) - dict = dict_utf8_activate(dict); + dict_utf8_wrapper_activate(dict); + + /* Insert wrapper for base64 decoding file content. */ + if ((dict->flags & DICT_FLAG_UNB64_ACTIVE) == 0 + && dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) + dict_file_wrapper_activate(dict); + return (dict); } diff --git a/postfix/src/util/dict_pcre_file.ref b/postfix/src/util/dict_pcre_file.ref index 727306d91..7021c3370 100644 --- a/postfix/src/util/dict_pcre_file.ref +++ b/postfix/src/util/dict_pcre_file.ref @@ -3,10 +3,15 @@ ./dict_open: warning: pcre map dict_pcre_file.map, line 6: empty pathname list: >>,<<': skipping this rule owner=untrusted (uid=USER) > get file1 -file1=dGhpcy1pcy1maWxlMQo= +file1=this-is-file1 + > get file2 -file2=dGhpcy1pcy1maWxlMgo= +file2=this-is-file2 + > get file3 file3: not found > get files12 -files12=dGhpcy1pcy1maWxlMQoKdGhpcy1pcy1maWxlMgo= +files12=this-is-file1 + +this-is-file2 + diff --git a/postfix/src/util/dict_pipe.c b/postfix/src/util/dict_pipe.c index 8ce0faad7..9940c4be6 100644 --- a/postfix/src/util/dict_pipe.c +++ b/postfix/src/util/dict_pipe.c @@ -166,7 +166,8 @@ DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags) DICT_TYPE_PIPE, name, DICT_TYPE_PIPE)); if ((dict = dict_handle(dict_type_name)) == 0) - dict = dict_open(dict_type_name, open_flags, dict_flags); + dict = dict_open(dict_type_name, open_flags, + dict_flags & ~DICT_FLAG_SRC_RHS_IS_FILE); dict_register(dict_type_name, dict); DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner); if (cpp == argv->argv) diff --git a/postfix/src/util/dict_random_file.ref b/postfix/src/util/dict_random_file.ref index cb0187379..7622c1f9c 100644 --- a/postfix/src/util/dict_random_file.ref +++ b/postfix/src/util/dict_random_file.ref @@ -5,6 +5,8 @@ owner=trusted (uid=2147483647) foo: error owner=trusted (uid=0) > get foo -foo=dGhpcy1pcy1maWxlMQo= +foo=this-is-file1 + > get bar -bar=dGhpcy1pcy1maWxlMQo= +bar=this-is-file1 + diff --git a/postfix/src/util/dict_regexp_file.ref b/postfix/src/util/dict_regexp_file.ref index 221814362..2a2ba7f52 100644 --- a/postfix/src/util/dict_regexp_file.ref +++ b/postfix/src/util/dict_regexp_file.ref @@ -1,8 +1,10 @@ ./dict_open: warning: regexp map dict_regexp_file.map, line 3: open dict_regexp_file3: No such file or directory: skipping this rule owner=untrusted (uid=USER) > get file1 -file1=dGhpcy1pcy1maWxlMQo= +file1=this-is-file1 + > get file2 -file2=dGhpcy1pcy1maWxlMgo= +file2=this-is-file2 + > get file3 file3: not found diff --git a/postfix/src/util/dict_static_file.ref b/postfix/src/util/dict_static_file.ref index 259f9fb67..47048a297 100644 --- a/postfix/src/util/dict_static_file.ref +++ b/postfix/src/util/dict_static_file.ref @@ -5,6 +5,8 @@ owner=trusted (uid=2147483647) foo: error owner=trusted (uid=2147483647) > get file1 -file1=dGhpcy1pcy1maWxlMQo= +file1=this-is-file1 + > get file2 -file2=dGhpcy1pcy1maWxlMQo= +file2=this-is-file1 + diff --git a/postfix/src/util/dict_union.c b/postfix/src/util/dict_union.c index 80df03b61..5c3b08af8 100644 --- a/postfix/src/util/dict_union.c +++ b/postfix/src/util/dict_union.c @@ -179,7 +179,8 @@ DICT *dict_union_open(const char *name, int open_flags, int dict_flags) DICT_TYPE_UNION, name, DICT_TYPE_UNION)); if ((dict = dict_handle(dict_type_name)) == 0) - dict = dict_open(dict_type_name, open_flags, dict_flags); + dict = dict_open(dict_type_name, open_flags, + dict_flags & ~DICT_FLAG_SRC_RHS_IS_FILE); dict_register(dict_type_name, dict); DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner); if (cpp == argv->argv) diff --git a/postfix/src/util/dict_utf8.c b/postfix/src/util/dict_utf8.c index f1fc65a59..e7dc47578 100644 --- a/postfix/src/util/dict_utf8.c +++ b/postfix/src/util/dict_utf8.c @@ -6,13 +6,13 @@ /* SYNOPSIS /* #include /* -/* DICT *dict_utf8_activate( +/* void dict_utf8_wrapper_activate( /* DICT *dict) /* DESCRIPTION -/* dict_utf8_activate() wraps a dictionary's lookup/update/delete +/* dict_utf8_wrapper_activate() wraps a dictionary's lookup/update/delete /* methods with code that enforces UTF-8 checks on keys and /* values, and that logs a warning when incorrect UTF-8 is -/* encountered. The original dictionary handle becomes invalid. +/* encountered. /* /* The wrapper code enforces a policy that maximizes application /* robustness (it avoids the need for new error-handling code @@ -22,8 +22,6 @@ /* skipped while reporting a non-error status, and lookup /* results that contain a non-UTF-8 value are blocked while /* reporting a configuration error. -/* BUGS -/* dict_utf8_activate() does not nest. /* LICENSE /* .ad /* .fi @@ -133,9 +131,10 @@ static int dict_utf8_check(const char *string, CONST_CHAR_STAR *err) /* dict_utf8_lookup - UTF-8 lookup method wrapper */ -static const char *dict_utf8_lookup(DICT *dict, const char *key) +static const char *dict_utf8_lookup(DICT_WRAPPER *wrapper, DICT *dict, + const char *key) { - DICT_UTF8_BACKUP *backup; + DICT_WRAPPER *next_wrapper; const char *utf8_err; const char *fold_res; const char *value; @@ -156,8 +155,8 @@ static const char *dict_utf8_lookup(DICT *dict, const char *key) */ saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY); dict->flags &= ~DICT_FLAG_FOLD_ANY; - backup = dict->utf8_backup; - value = backup->lookup(dict, fold_res); + next_wrapper = wrapper->next; + value = next_wrapper->lookup(next_wrapper, dict, fold_res); dict->flags |= saved_flags; /* @@ -175,9 +174,10 @@ static const char *dict_utf8_lookup(DICT *dict, const char *key) /* dict_utf8_update - UTF-8 update method wrapper */ -static int dict_utf8_update(DICT *dict, const char *key, const char *value) +static int dict_utf8_update(DICT_WRAPPER *wrapper, DICT *dict, + const char *key, const char *value) { - DICT_UTF8_BACKUP *backup; + DICT_WRAPPER *next_wrapper; const char *utf8_err; const char *fold_res; int saved_flags; @@ -209,8 +209,8 @@ static int dict_utf8_update(DICT *dict, const char *key, const char *value) else { saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY); dict->flags &= ~DICT_FLAG_FOLD_ANY; - backup = dict->utf8_backup; - status = backup->update(dict, fold_res, value); + next_wrapper = wrapper->next; + status = next_wrapper->update(next_wrapper, dict, fold_res, value); dict->flags |= saved_flags; return (status); } @@ -218,9 +218,9 @@ static int dict_utf8_update(DICT *dict, const char *key, const char *value) /* dict_utf8_delete - UTF-8 delete method wrapper */ -static int dict_utf8_delete(DICT *dict, const char *key) +static int dict_utf8_delete(DICT_WRAPPER *wrapper, DICT *dict, const char *key) { - DICT_UTF8_BACKUP *backup; + DICT_WRAPPER *next_wrapper; const char *utf8_err; const char *fold_res; int saved_flags; @@ -242,19 +242,19 @@ static int dict_utf8_delete(DICT *dict, const char *key) else { saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY); dict->flags &= ~DICT_FLAG_FOLD_ANY; - backup = dict->utf8_backup; - status = backup->delete(dict, fold_res); + next_wrapper = wrapper->next; + status = next_wrapper->delete(next_wrapper, dict, fold_res); dict->flags |= saved_flags; return (status); } } -/* dict_utf8_activate - wrap a legacy dict object for UTF-8 processing */ +/* dict_utf8_wrapper_activate - wrap legacy dict object for UTF-8 processing */ -DICT *dict_utf8_activate(DICT *dict) +void dict_utf8_wrapper_activate(DICT *dict) { - const char myname[] = "dict_utf8_activate"; - DICT_UTF8_BACKUP *backup; + const char myname[] = "dict_utf8_wrapper_activate"; + DICT_WRAPPER *wrapper; /* * Sanity check. @@ -264,37 +264,22 @@ DICT *dict_utf8_activate(DICT *dict) if ((dict->flags & DICT_FLAG_UTF8_REQUEST) == 0) msg_panic("%s: %s:%s does not request Unicode support", myname, dict->type, dict->name); - if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) || dict->utf8_backup != 0) + if ((dict->flags & DICT_FLAG_UTF8_ACTIVE)) msg_panic("%s: %s:%s Unicode support is already activated", myname, dict->type, dict->name); /* - * Unlike dict_debug(3) we do not put a proxy dict object in front of the - * encapsulated object, because then we would have to bidirectionally - * propagate changes in the data members (errors, flags, jbuf, and so on) - * between proxy object and encapsulated object. - * - * Instead we attach ourselves behind the encapsulated dict object, and - * redirect some function pointers to ourselves. + * Interpose on the lookup/update/delete methods. */ - backup = dict->utf8_backup = (DICT_UTF8_BACKUP *) mymalloc(sizeof(*backup)); - - /* - * Interpose on the lookup/update/delete methods. It is a conscious - * decision not to tinker with the iterator or destructor. - */ - backup->lookup = dict->lookup; - backup->update = dict->update; - backup->delete = dict->delete; - - dict->lookup = dict_utf8_lookup; - dict->update = dict_utf8_update; - dict->delete = dict_utf8_delete; + wrapper = dict_wrapper_alloc(sizeof(*wrapper)); + wrapper->name = "utf8"; + wrapper->lookup = dict_utf8_lookup; + wrapper->update = dict_utf8_update; + wrapper->delete = dict_utf8_delete; + dict_wrapper_prepend(dict, wrapper); /* * Leave our mark. See sanity check above. */ dict->flags |= DICT_FLAG_UTF8_ACTIVE; - - return (dict); } diff --git a/postfix/src/util/dict_wrapper.c b/postfix/src/util/dict_wrapper.c new file mode 100644 index 000000000..3a54c6b8e --- /dev/null +++ b/postfix/src/util/dict_wrapper.c @@ -0,0 +1,243 @@ +/*++ +/* NAME +/* dict_wrapper 3 +/* SUMMARY +/* dictionary method wrappers +/* SYNOPSIS +/* #include +/* +/* void dict_wrapper_prepend( +/* DICT *dict, +/* DICT_WRAPPER *wrapper) +/* +/* DICT_WRAPPER *dict_wrapper_alloc( +/* ssize_t size) +/* +/* void dict_wrapper_free( +/* DICT_WRAPPER *wrapper) +/* DESCRIPTION +/* dict_wrapper_prepend() prepends the specified dictionary +/* lookup/update/delete wrappers to a chain that is evaluated +/* in reverse order. dict_wrapper_prepend() takes ownership +/* of the wrapper. +/* +/* dict_wrapper_alloc() allocates memory for a dictionary +/* wrapper object and initializes all wrapper methods to +/* empty (no override). +/* +/* dict_wrapper_free() destroys a chain of dictionary wrappers. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + + /* + * System library. + */ +#include +#include + + /* + * Utility library. + */ +#include +#include +#include +#include +#include + + /* + * The final DICT_WRAPPER is installed first, and also contains the original + * DICT's methods. + */ +typedef struct { + DICT_WRAPPER wrapper; /* parent class, must be first */ + const char *(*saved_lookup) (DICT *, const char *); + int (*saved_update) (DICT *, const char *, const char *); + int (*saved_delete) (DICT *, const char *); +} DICT_FINAL_WRAPPER; + + /* + * Functions that override DICT methods, and that call into the head of + * the dict wrapper chain. + */ + +/* dict_wrapper_lookup - DICT method to call into wrapper chain head */ + +static const char *dict_wrapper_lookup(DICT *dict, const char *key) +{ + DICT_WRAPPER *head_wrapper = dict->wrapper; + + return (head_wrapper->lookup(head_wrapper, dict, key)); +} + +/* dict_wrapper_update - DICT method to call into wrapper chain head */ + +static int dict_wrapper_update(DICT *dict, const char *key, const char *value) +{ + DICT_WRAPPER *head_wrapper = dict->wrapper; + + return (head_wrapper->update(head_wrapper, dict, key, value)); +} + +/* dict_wrapper_delete - DICT method to call into wrapper chain head */ + +static int dict_wrapper_delete(DICT *dict, const char *key) +{ + DICT_WRAPPER *head_wrapper = dict->wrapper; + + return (head_wrapper->delete(head_wrapper, dict, key)); +} + + /* + * Empty methods for wrappers that override only some methods. These ensure + * that the next wrapper's methods are called with the right 'self' pointer. + */ + +/* empty_wrapper_lookup - wrapper method to call into next wrapper */ + +static const char *empty_wrapper_lookup(DICT_WRAPPER *wrapper, DICT *dict, + const char *key) +{ + DICT_WRAPPER *next_wrapper = wrapper->next; + + return (next_wrapper->lookup(next_wrapper, dict, key)); +} + +/* empty_wrapper_update - wrapper method to call into next wrapper */ + +static int empty_wrapper_update(DICT_WRAPPER *wrapper, DICT *dict, + const char *key, const char *value) +{ + DICT_WRAPPER *next_wrapper = wrapper->next; + + return (next_wrapper->update(next_wrapper, dict, key, value)); +} + +/* empty_wrapper_delete - wrapper method to call into next wrapper */ + +static int empty_wrapper_delete(DICT_WRAPPER *wrapper, DICT *dict, + const char *key) +{ + DICT_WRAPPER *next_wrapper = wrapper->next; + + return (next_wrapper->delete(next_wrapper, dict, key)); +} + + /* + * Wrapper methods for the final dict wrapper in the chain. These call into + * the saved DICT methods. + */ + +/* final_wrapper_lookup - wrapper method to call saved DICT method */ + +static const char *final_wrapper_lookup(DICT_WRAPPER *wrapper, DICT *dict, + const char *key) +{ + DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper; + + return (final_wrapper->saved_lookup(dict, key)); +} + +/* final_wrapper_update - wrapper method to call saved DICT method */ + +static int final_wrapper_update(DICT_WRAPPER *wrapper, DICT *dict, + const char *key, const char *value) +{ + DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper; + + return (final_wrapper->saved_update(dict, key, value)); +} + +/* final_wrapper_delete - wrapper method to call saved DICT method */ + +static int final_wrapper_delete(DICT_WRAPPER *wrapper, DICT *dict, + const char *key) +{ + DICT_FINAL_WRAPPER *final_wrapper = (DICT_FINAL_WRAPPER *) wrapper; + + return (final_wrapper->saved_delete(dict, key)); +} + + /* + * Finally, the functions that build the wrapper chain. + */ + +/* dict_wrapper_activate - wrap a DICT object for additional processing */ + +static void dict_wrapper_activate(DICT *dict) +{ + const char myname[] = "dict_wrapper_activate"; + DICT_FINAL_WRAPPER *final_wrapper; + + /* + * Sanity check. + */ + if (dict->wrapper != 0) + msg_panic("%s: %s:%s wrapper support is already activated", + myname, dict->type, dict->name); + + /* + * Install the final wrapper object that calls the original DICT's + * methods, and redirect DICT's method calls to ourselves. All other + * dictionary wrappers will be prepended to a chain that ends in the + * final wrapper object. + */ + final_wrapper = (DICT_FINAL_WRAPPER *) mymalloc(sizeof(*final_wrapper)); + final_wrapper->wrapper.name = "final"; + final_wrapper->wrapper.lookup = final_wrapper_lookup; + final_wrapper->wrapper.update = final_wrapper_update; + final_wrapper->wrapper.delete = final_wrapper_delete; + final_wrapper->wrapper.next = 0; + dict->wrapper = &final_wrapper->wrapper; + + /* + * Interpose on the DICT's lookup/update/delete methods. + */ + final_wrapper->saved_lookup = dict->lookup; + final_wrapper->saved_update = dict->update; + final_wrapper->saved_delete = dict->delete; + + dict->lookup = dict_wrapper_lookup; + dict->update = dict_wrapper_update; + dict->delete = dict_wrapper_delete; +} + +/* dict_wrapper_alloc - allocate and initialize dictionary wrapper */ + +DICT_WRAPPER *dict_wrapper_alloc(ssize_t size) +{ + DICT_WRAPPER *wrapper; + + wrapper = (DICT_WRAPPER *) mymalloc(size); + wrapper->lookup = empty_wrapper_lookup; + wrapper->update = empty_wrapper_update; + wrapper->delete = empty_wrapper_delete; + return (wrapper); +} + +/* dict_wrapper_prepend - prepend dict method overrides */ + +void dict_wrapper_prepend(DICT *dict, DICT_WRAPPER *wrapper) +{ + if (dict->wrapper == 0) + dict_wrapper_activate(dict); + + wrapper->next = dict->wrapper; + dict->wrapper = wrapper; +} + +/* dict_wrapper_free - wrapper destructor */ + +void dict_wrapper_free(DICT_WRAPPER *wrapper) +{ + if (wrapper->next) + dict_wrapper_free(wrapper->next); + myfree((void *) wrapper); +}