]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.4-20181228-nonprod
authorWietse Venema <wietse@porcupine.org>
Fri, 28 Dec 2018 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 29 Dec 2018 00:51:49 +0000 (19:51 -0500)
24 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/global/maps.c
postfix/src/global/mkmap_open.c
postfix/src/postmap/file_test.ref
postfix/src/postmap/postmap.c
postfix/src/tls/tls_certkey.c
postfix/src/util/Makefile.in
postfix/src/util/dict.c
postfix/src/util/dict.h
postfix/src/util/dict_alloc.c
postfix/src/util/dict_cidr_file.ref
postfix/src/util/dict_file.c
postfix/src/util/dict_inline_file.ref
postfix/src/util/dict_open.c
postfix/src/util/dict_pcre_file.ref
postfix/src/util/dict_pipe.c
postfix/src/util/dict_random_file.ref
postfix/src/util/dict_regexp_file.ref
postfix/src/util/dict_static_file.ref
postfix/src/util/dict_union.c
postfix/src/util/dict_utf8.c
postfix/src/util/dict_wrapper.c [new file with mode: 0644]

index 40ba2bc9d47d45e22a8ffc48ef1126b129d68728..5a1c44e5bb20c7e4172dc20a0a1f3ea7a3440800 100644 (file)
@@ -81,6 +81,7 @@
 -TDICT_DEBUG
 -TDICT_ENV
 -TDICT_FAIL
+-TDICT_FINAL_WRAPPER
 -TDICT_HT
 -TDICT_INLINE
 -TDICT_LDAP
 -TDICT_THASH
 -TDICT_UNION
 -TDICT_UNIX
--TDICT_UTF8_BACKUP
+-TDICT_WRAPPER
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
index 3b5d3fdfdd04a4bca871cc8173d9d8b18d87f81a..c2ee393455f85736a81ebe7572c53478cb006a1a 100644 (file)
@@ -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.
index f1165b348ecc18f76b4447ba0ee8701e3dba6bf5..882c9c4717f311289d8fa80c58f4493bac484423 100644 (file)
@@ -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
index df25e84ad48dbc42320b2cbce83d2c038c5f58d5..8a1dc9e881828fa1828cb94cbe5e810b94e1cb53 100644 (file)
@@ -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\"",
index 9d15eec30a27f0557c590458e1cddc165ad45e01..32dfc9ea6b8144b26bb3d1a91b9109d27689fa12 100644 (file)
@@ -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.
index aa676441dff570ec70e5c18e32677a5e41397def..1e808abbe5e48787f2d5de4fb8fd55dea35d0899 100644 (file)
@@ -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
index 16bbef942d7ec79d5413be971ee0502988ee1d98..2077335734949ef73b34a9ce22db09f4ae61ae81 100644 (file)
@@ -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)
index 1e7fbf33e941689d2b303eb07598cb28307bc82d..997e26830703a8ac220345a1bddd83c98702d78e 100644 (file)
@@ -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;
index f0715959c07a11a75e28b624cfd34f4f39fbbada..a1bd8bcba2883371159a63f8a3fcbec6318d3d14 100644 (file)
@@ -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
index 5d53860f17d57e3f1fa52b47389dad0f8cc667aa..84e413eb028537292f1620550e8e04a1f340c064 100644 (file)
@@ -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,
 };
 
index a89f0ea5d122d0f3f61cc8d5582a34423d487c95..8c03477e3b52f2cc4d90583c6300ebfa6ac7d0ea 100644 (file)
@@ -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.
index 3285a38e35758ecdcf036d83db5bb5be98616bd1..384defbf69446ef25732dc47e602c5ebd13ad1b2 100644 (file)
@@ -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)
index 3e9e79205c7aa56f1e73a733ce7c84a67b4f695d..537805e240ce353b257a3c569084de48ed86fde9 100644 (file)
@@ -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
index e59842a31a4ea771c85515d386c351fd5108ff33..ebfbb3f16109e9b0646c62fe55bd085923ba05b5 100644 (file)
@@ -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;
+}
index 9d49e95f42010cca2a00062f3487c3c8ee0e3e0c..2aed9bd57a18ef14c8d67395f30a73c84c9c7796 100644 (file)
@@ -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
index ca8df67eea5abd2ce6a5c1892ec56f0efec23501..ad95f1255381b7d3d93614bcdda0f1170d232b9e 100644 (file)
@@ -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);
 }
 
index 727306d91c37a56f0d01ceaf8cbc31e5a29d7a71..7021c337049e1fcaa76cf5346470e545f2a5f614 100644 (file)
@@ -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
+
index 8ce0faad728d5f973fc2718bbe2917b6670997a5..9940c4be660d83e0d073269ba774d54755473c81 100644 (file)
@@ -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)
index cb0187379fa017c699dae857d58c77acdf77505f..7622c1f9cc70ed9e13ddba2412944447dc98f7ae 100644 (file)
@@ -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
+
index 2218143623fae5def96bd69c8d5bf51fe9733083..2a2ba7f52282cdc76dc490132aeb87a4d60438cb 100644 (file)
@@ -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
index 259f9fb67a05918dc27e6ad41a051b7503795a29..47048a29780ff46184253ad88fc33e00fd38fa46 100644 (file)
@@ -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
+
index 80df03b61717d7ea943ef5768de361789d63e7c7..5c3b08af8679be38b838dd85cad1981425aeaae0 100644 (file)
@@ -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)
index f1fc65a5920ccec21a47a04ac7f465093a19b57f..e7dc4757856f9c2c478f3abe8d2c58fdc5e66666 100644 (file)
@@ -6,13 +6,13 @@
 /* SYNOPSIS
 /*     #include <dict.h>
 /*
-/*     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 (file)
index 0000000..3a54c6b
--- /dev/null
@@ -0,0 +1,243 @@
+/*++
+/* NAME
+/*     dict_wrapper 3
+/* SUMMARY
+/*     dictionary method wrappers
+/* SYNOPSIS
+/*     #include <dict.h>
+/*
+/*     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 <sys_defs.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <stringops.h>
+#include <dict.h>
+#include <mymalloc.h>
+#include <msg.h>
+
+ /*
+  * 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);
+}