]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-19990329
authorWietse Venema <wietse@porcupine.org>
Mon, 29 Mar 1999 05:00:00 +0000 (00:00 -0500)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 03:34:03 +0000 (22:34 -0500)
30 files changed:
postfix/HISTORY
postfix/cleanup/Makefile.in
postfix/cleanup/cleanup.c
postfix/global/mail_addr_find.c
postfix/global/mail_addr_map.c
postfix/global/mail_version.h
postfix/global/maps.c
postfix/global/maps.h
postfix/local/alias.c
postfix/qmgr/Makefile.in
postfix/qmgr/qmgr.c
postfix/qmgr/qmgr_message.c
postfix/smtpd/smtpd_check.c
postfix/trivial-rewrite/transport.c
postfix/util/Makefile.in
postfix/util/dict.c
postfix/util/dict.h
postfix/util/dict_db.c
postfix/util/dict_dbm.c
postfix/util/dict_env.c
postfix/util/dict_ht.c
postfix/util/dict_ldap.c
postfix/util/dict_ni.c
postfix/util/dict_nisplus.c
postfix/util/dict_open.c
postfix/util/dict_pcre.c
postfix/util/dict_regexp.c
postfix/util/dict_unix.c
postfix/util/match_list.c
postfix/util/sys_defs.h

index cf850012deae0bdc9cb5d7caf155e3384d78c5ef..bce74a964b1fc8c32c34c172ed5bb0dfaebaca9e 100644 (file)
@@ -2458,11 +2458,41 @@ Apologies for any names omitted.
 
        Cleanup: the dictionary routines now take an extra flag
        argument to control such things as warning about duplicates,
-       and appending null bytes to key/value. This was needed for
-       a clean implementation of NIS master alias maps support.
+       and appending null bytes to key/value. The latter was needed
+       for a clean implementation of NIS master alias maps support.
 
        Feature: POSIX regular expressions by Lamont Jones.
 
+19990328
+
+       Code cleanup: dictionaries now have flags that say whether
+       lookup keys are fixed strings or whether keys are subjected
+       to pattern matching. This is needed to avoid passing partial
+       addresses to regexp-based lookup tables (user, @domain,
+       user@, domain). Files: util/dict*.c.
+
+       Bugfix: fixed memory leaks and core dumps in the regexp
+       and pcre routines (neither handled an empty pattern file).
+
+19990329
+
+       Code cleanup: the dictionary I/O routines now do their own
+       locking depending on dictionary flag settings. This means
+       that the low-level dict_get() interface can now be used
+       for safe dictionary lookups. This is needed for 19990328's
+       partial lookup key support. Files: util/dict*.c. global/maps.c.
+
+       Feature: regular expression matches are no longer limited
+       to user@domain address forms in access/canonical/virtual
+       maps, but can also be used for domains in transport maps.
+       This needed the partial lookup key support to avoid passing
+       partial addresses to regexp-based lookup tables (user,
+       @domain, user@, domain). Files: global/maps.c
+       globl/mail_addr_find.c.
+
+       Feature: new dictionary types can be registered with
+       dict_open_register(). File: util/dict_open.c.
+
 Future:
 
        Planned: must be able to list the same hash table in
index 1eb83bc7ab207d05d30c0c138e4efecfdb94ac5e..391f409ffb37b2cb558142506f119b4c162f74a6 100644 (file)
@@ -81,6 +81,7 @@ cleanup.o: ../include/mail_server.h
 cleanup.o: cleanup.h
 cleanup.o: ../include/argv.h
 cleanup.o: ../include/maps.h
+cleanup.o: ../include/dict.h
 cleanup.o: ../include/tok822.h
 cleanup.o: ../include/resolve_clnt.h
 cleanup.o: ../include/been_here.h
@@ -100,6 +101,7 @@ cleanup_envelope.o: ../include/mail_params.h
 cleanup_envelope.o: cleanup.h
 cleanup_envelope.o: ../include/argv.h
 cleanup_envelope.o: ../include/maps.h
+cleanup_envelope.o: ../include/dict.h
 cleanup_envelope.o: ../include/been_here.h
 cleanup_envelope.o: ../include/mail_stream.h
 cleanup_extracted.o: cleanup_extracted.c
@@ -115,6 +117,7 @@ cleanup_extracted.o: ../include/record.h
 cleanup_extracted.o: ../include/rec_type.h
 cleanup_extracted.o: cleanup.h
 cleanup_extracted.o: ../include/maps.h
+cleanup_extracted.o: ../include/dict.h
 cleanup_extracted.o: ../include/tok822.h
 cleanup_extracted.o: ../include/resolve_clnt.h
 cleanup_extracted.o: ../include/been_here.h
@@ -171,6 +174,7 @@ cleanup_masquerade.o: ../include/quote_822_local.h
 cleanup_masquerade.o: cleanup.h
 cleanup_masquerade.o: ../include/vstream.h
 cleanup_masquerade.o: ../include/maps.h
+cleanup_masquerade.o: ../include/dict.h
 cleanup_masquerade.o: ../include/been_here.h
 cleanup_masquerade.o: ../include/mail_stream.h
 cleanup_message.o: cleanup_message.c
@@ -195,6 +199,7 @@ cleanup_message.o: ../include/mail_addr.h
 cleanup_message.o: ../include/is_header.h
 cleanup_message.o: cleanup.h
 cleanup_message.o: ../include/maps.h
+cleanup_message.o: ../include/dict.h
 cleanup_message.o: ../include/been_here.h
 cleanup_message.o: ../include/mail_stream.h
 cleanup_out.o: cleanup_out.c
@@ -209,6 +214,7 @@ cleanup_out.o: ../include/cleanup_user.h
 cleanup_out.o: cleanup.h
 cleanup_out.o: ../include/argv.h
 cleanup_out.o: ../include/maps.h
+cleanup_out.o: ../include/dict.h
 cleanup_out.o: ../include/tok822.h
 cleanup_out.o: ../include/resolve_clnt.h
 cleanup_out.o: ../include/been_here.h
@@ -224,6 +230,7 @@ cleanup_out_recipient.o: ../include/vstring.h
 cleanup_out_recipient.o: ../include/vbuf.h
 cleanup_out_recipient.o: ../include/vstream.h
 cleanup_out_recipient.o: ../include/maps.h
+cleanup_out_recipient.o: ../include/dict.h
 cleanup_out_recipient.o: ../include/tok822.h
 cleanup_out_recipient.o: ../include/resolve_clnt.h
 cleanup_out_recipient.o: ../include/mail_stream.h
@@ -240,6 +247,7 @@ cleanup_rewrite.o: cleanup.h
 cleanup_rewrite.o: ../include/vstream.h
 cleanup_rewrite.o: ../include/argv.h
 cleanup_rewrite.o: ../include/maps.h
+cleanup_rewrite.o: ../include/dict.h
 cleanup_rewrite.o: ../include/been_here.h
 cleanup_rewrite.o: ../include/mail_stream.h
 cleanup_skip.o: cleanup_skip.c
@@ -253,6 +261,7 @@ cleanup_skip.o: ../include/rec_type.h
 cleanup_skip.o: cleanup.h
 cleanup_skip.o: ../include/argv.h
 cleanup_skip.o: ../include/maps.h
+cleanup_skip.o: ../include/dict.h
 cleanup_skip.o: ../include/tok822.h
 cleanup_skip.o: ../include/resolve_clnt.h
 cleanup_skip.o: ../include/been_here.h
@@ -268,6 +277,7 @@ cleanup_state.o: ../include/mail_params.h
 cleanup_state.o: cleanup.h
 cleanup_state.o: ../include/argv.h
 cleanup_state.o: ../include/maps.h
+cleanup_state.o: ../include/dict.h
 cleanup_state.o: ../include/tok822.h
 cleanup_state.o: ../include/resolve_clnt.h
 cleanup_state.o: ../include/mail_stream.h
index ef6a62d418c4cb74f9c1da8eff5a3efa293e422e..7666077f90ef3481195ccce6af3d053e73eaef38 100644 (file)
@@ -375,15 +375,18 @@ static void pre_jail_init(void)
 {
     if (*var_canonical_maps)
        cleanup_comm_canon_maps =
-       maps_create(VAR_CANONICAL_MAPS, var_canonical_maps);
+       maps_create(VAR_CANONICAL_MAPS, var_canonical_maps, DICT_FLAG_LOCK);
     if (*var_send_canon_maps)
        cleanup_send_canon_maps =
-           maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps);
+           maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps,
+                       DICT_FLAG_LOCK);
     if (*var_rcpt_canon_maps)
        cleanup_rcpt_canon_maps =
-           maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps);
+           maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
+                       DICT_FLAG_LOCK);
     if (*var_virtual_maps)
-       cleanup_virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps);
+       cleanup_virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps,
+                                          DICT_FLAG_LOCK);
     if (*var_masq_domains)
        cleanup_masq_domains = argv_split(var_masq_domains, " ,\t\r\n");
 }
index eac16825854fff38ce5bd6dff52d7e21b0ae840f..de8b7fe7e73d4343a3e8453ea938b584bd58cc65 100644 (file)
@@ -127,9 +127,15 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
 
     /*
      * Try user+foo@domain and user@domain.
+     * 
+     * Specify what keys are partial or full, to avoid matching partial
+     * addresses with regular expressions.
      */
-    if ((result = maps_find(path, full_key)) == 0 && dict_errno == 0
-       && bare_key != 0 && (result = maps_find(path, bare_key)) != 0
+#define FULL   0
+#define PARTIAL        DICT_FLAG_FIXED
+
+    if ((result = maps_find(path, full_key, FULL)) == 0 && dict_errno == 0
+      && bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0
        && extp != 0) {
        *extp = saved_ext;
        saved_ext = 0;
@@ -144,12 +150,12 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
        && (strcasecmp(ratsign + 1, var_myorigin) == 0
            || resolve_local(ratsign + 1))) {
        *ratsign = 0;
-       result = maps_find(path, full_key);
+       result = maps_find(path, full_key, PARTIAL);
        if (result == 0 && dict_errno == 0 && bare_key != 0) {
            if ((ratsign = strrchr(bare_key, '@')) == 0)
                msg_panic("%s: bare key botch", myname);
            *ratsign = 0;
-           if ((result = maps_find(path, bare_key)) != 0 && extp != 0) {
+           if ((result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) {
                *extp = saved_ext;
                saved_ext = 0;
            }
@@ -161,7 +167,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
      * Try @domain.
      */
     if (result == 0 && dict_errno == 0 && ratsign)
-       result = maps_find(path, ratsign);
+       result = maps_find(path, ratsign, PARTIAL);
 
     /*
      * Clean up.
@@ -202,18 +208,19 @@ int     main(int argc, char **argv)
      */
     if (argc != 2)
        msg_fatal("usage: %s database", argv[0]);
+    msg_verbose = 1;
 
     /*
      * Initialize.
      */
     read_config();
-    path = maps_create(argv[0], argv[1]);
+    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK);
     while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
        extent = 0;
        result = mail_addr_find(path, STR(buffer), &extent);
        vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result :
                       dict_errno ? "(try again)" :
-                      "(not found)", extent ? extent : "null");
+                      "(not found)", extent ? extent : "null extension");
        vstream_fflush(VSTREAM_OUT);
        if (extent)
            myfree(extent);
index 00fba564e5cdb2bb93ed2addde28c97fdecf7595..6949f5fd94a99c9e2bd202e6356b6a0d0afad3ca 100644 (file)
@@ -159,7 +159,7 @@ int     main(int argc, char **argv)
     msg_verbose = 1;
     if (chdir(var_queue_dir) < 0)
        msg_fatal("chdir %s: %m", var_queue_dir);
-    path = maps_create(argv[0], argv[1]);
+    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK);
     while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
        if ((result = mail_addr_map(path, STR(buffer))) != 0)
            argv_free(result);
index cd0a40af2423b23aa65bdc7b0f8f6dac39aab0c5..e1976f88ea1693bc0b779988704b18298cfedc4a 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-19990328"
+#define DEF_MAIL_VERSION       "Snapshot-19990329"
 extern char *var_mail_version;
 
 /* LICENSE
index 71cf6b337cfaab8c4dc40bf9a1c6fe5ac1e9189f..02af45d4c6439eddd277cf8db497b83b40b36d50 100644 (file)
@@ -28,7 +28,7 @@
 /*     named dictionaries.
 /*     The result is a handle that must be specified along with all
 /*     other maps_xxx() operations.
-/*     see dict_open(3) for a description of flags.
+/*     See dict_open(3) for a description of flags.
 /*
 /*     maps_find() searches the specified list of dictionaries
 /*     in the specified order for the named key. The result is in
 
 /* maps_create - initialize */
 
-MAPS   *maps_create(const char *title, const char *map_names)
+MAPS   *maps_create(const char *title, const char *map_names, int flags)
 {
     char   *myname = "maps_create";
     char   *temp = mystrdup(map_names);
@@ -127,7 +127,10 @@ MAPS   *maps_create(const char *title, const char *map_names)
        if (msg_verbose)
            msg_info("%s: %s", myname, map_type_name);
        if ((dict = dict_handle(map_type_name)) == 0)
-           dict = dict_open(map_type_name, O_RDONLY, 0);
+           dict = dict_open(map_type_name, O_RDONLY, flags);
+       else if ((dict->flags & flags) != flags)
+           msg_warn("%s: map %s has flags 0%o, want flags 0%o",
+                    myname, map_type_name, dict->flags, flags);
        dict_register(map_type_name, dict);
        argv_add(maps->argv, map_type_name, ARGV_END);
     }
@@ -138,14 +141,19 @@ MAPS   *maps_create(const char *title, const char *map_names)
 
 /* maps_find - search a list of dictionaries */
 
-const char *maps_find(MAPS *maps, const char *name)
+const char *maps_find(MAPS *maps, const char *name, int flags)
 {
     char   *myname = "maps_find";
     char  **map_name;
     const char *expansion;
+    DICT   *dict;
 
     for (map_name = maps->argv->argv; *map_name; map_name++) {
-       if ((expansion = dict_lookup(*map_name, name)) != 0) {
+       if ((dict = dict_handle(*map_name)) == 0)
+           msg_panic("%s: dictionary not found: %s", myname, *map_name);
+       if (flags != 0 && (dict->flags & flags) == 0)
+           continue;
+       if ((expansion = dict_get(dict, name)) != 0) {
            if (msg_verbose)
                msg_info("%s: %s: %s = %s", myname, *map_name, name, expansion);
            return (expansion);
@@ -191,10 +199,10 @@ main(int argc, char **argv)
     if (argc != 2)
        msg_fatal("usage: %s maps", argv[0]);
     msg_verbose = 2;
-    maps = maps_create("whatever", argv[1]);
+    maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK);
 
     while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
-       if ((result = maps_find(maps, vstring_str(buf))) != 0) {
+       if ((result = maps_find(maps, vstring_str(buf), 0)) != 0) {
            vstream_printf("%s\n", result);
        } else if (dict_errno != 0) {
            msg_fatal("lookup error: %m");
index dd0787b7d212ae398c84e3e35a2ec3ec396b49e5..015811f699ebc7e1363b9f8e86ef38e77d111103 100644 (file)
 /* DESCRIPTION
 /* .nf
 
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
  /*
   * Dictionary name storage. We're borrowing from the argv(3) module.
   */
@@ -19,8 +24,8 @@ typedef struct MAPS {
     struct ARGV *argv;
 } MAPS;
 
-extern MAPS *maps_create(const char *, const char *);
-extern const char *maps_find(MAPS *, const char *);
+extern MAPS *maps_create(const char *, const char *, int);
+extern const char *maps_find(MAPS *, const char *, int);
 extern MAPS *maps_free(MAPS *);
 
 /* LICENSE
index 90bfe4f9a86c323bcdad84543b2cf08d4e5db7f9..bbbbe9df0b36883ed7313b067833c7bfce076bba 100644 (file)
@@ -142,7 +142,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      * Do this only once.
      */
     if (maps == 0)
-       maps = maps_create("aliases", var_alias_maps);
+       maps = maps_create("aliases", var_alias_maps, DICT_FLAG_LOCK);
 
     /*
      * DUPLICATE/LOOP ELIMINATION
@@ -235,7 +235,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
            concatenate("owner-", state.msg_attr.local, (char *) 0)))
 
            expansion = mystrdup(alias_result);
-           if (OWNER_ASSIGN(owner) != 0 && maps_find(maps, owner)) {
+           if (OWNER_ASSIGN(owner) != 0 && maps_find(maps, owner, 0)) {
                canon_owner = canon_addr_internal(vstring_alloc(10), owner);
                SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
            } else {
index 4219845f01a441e6aad3a7ad0bd1adb4f1df349e..fe93507008ff935999e70e6f4e07fb7da1d3cc67 100644 (file)
@@ -76,6 +76,7 @@ qmgr.o: ../include/mail_server.h
 qmgr.o: qmgr.h
 qmgr.o: ../include/scan_dir.h
 qmgr.o: ../include/maps.h
+qmgr.o: ../include/dict.h
 qmgr_active.o: qmgr_active.c
 qmgr_active.o: ../include/sys_defs.h
 qmgr_active.o: ../include/msg.h
@@ -94,6 +95,7 @@ qmgr_active.o: ../include/rec_type.h
 qmgr_active.o: qmgr.h
 qmgr_active.o: ../include/scan_dir.h
 qmgr_active.o: ../include/maps.h
+qmgr_active.o: ../include/dict.h
 qmgr_bounce.o: qmgr_bounce.c
 qmgr_bounce.o: ../include/sys_defs.h
 qmgr_bounce.o: ../include/bounce.h
@@ -103,6 +105,7 @@ qmgr_bounce.o: ../include/vbuf.h
 qmgr_bounce.o: qmgr.h
 qmgr_bounce.o: ../include/scan_dir.h
 qmgr_bounce.o: ../include/maps.h
+qmgr_bounce.o: ../include/dict.h
 qmgr_defer.o: qmgr_defer.c
 qmgr_defer.o: ../include/sys_defs.h
 qmgr_defer.o: ../include/msg.h
@@ -113,6 +116,7 @@ qmgr_defer.o: ../include/bounce.h
 qmgr_defer.o: qmgr.h
 qmgr_defer.o: ../include/scan_dir.h
 qmgr_defer.o: ../include/maps.h
+qmgr_defer.o: ../include/dict.h
 qmgr_deliver.o: qmgr_deliver.c
 qmgr_deliver.o: ../include/sys_defs.h
 qmgr_deliver.o: ../include/msg.h
@@ -129,6 +133,7 @@ qmgr_deliver.o: ../include/mail_params.h
 qmgr_deliver.o: qmgr.h
 qmgr_deliver.o: ../include/scan_dir.h
 qmgr_deliver.o: ../include/maps.h
+qmgr_deliver.o: ../include/dict.h
 qmgr_enable.o: qmgr_enable.c
 qmgr_enable.o: ../include/sys_defs.h
 qmgr_enable.o: ../include/msg.h
@@ -137,6 +142,7 @@ qmgr_enable.o: ../include/vbuf.h
 qmgr_enable.o: qmgr.h
 qmgr_enable.o: ../include/scan_dir.h
 qmgr_enable.o: ../include/maps.h
+qmgr_enable.o: ../include/dict.h
 qmgr_entry.o: qmgr_entry.c
 qmgr_entry.o: ../include/sys_defs.h
 qmgr_entry.o: ../include/msg.h
@@ -148,6 +154,7 @@ qmgr_entry.o: ../include/mail_params.h
 qmgr_entry.o: qmgr.h
 qmgr_entry.o: ../include/scan_dir.h
 qmgr_entry.o: ../include/maps.h
+qmgr_entry.o: ../include/dict.h
 qmgr_message.o: qmgr_message.c
 qmgr_message.o: ../include/sys_defs.h
 qmgr_message.o: ../include/msg.h
@@ -185,6 +192,7 @@ qmgr_move.o: ../include/vstream.h
 qmgr_move.o: ../include/mail_scan_dir.h
 qmgr_move.o: qmgr.h
 qmgr_move.o: ../include/maps.h
+qmgr_move.o: ../include/dict.h
 qmgr_queue.o: qmgr_queue.c
 qmgr_queue.o: ../include/sys_defs.h
 qmgr_queue.o: ../include/msg.h
@@ -198,6 +206,7 @@ qmgr_queue.o: ../include/vstream.h
 qmgr_queue.o: ../include/vbuf.h
 qmgr_queue.o: ../include/scan_dir.h
 qmgr_queue.o: ../include/maps.h
+qmgr_queue.o: ../include/dict.h
 qmgr_rcpt_list.o: qmgr_rcpt_list.c
 qmgr_rcpt_list.o: ../include/sys_defs.h
 qmgr_rcpt_list.o: ../include/mymalloc.h
@@ -206,6 +215,7 @@ qmgr_rcpt_list.o: ../include/vstream.h
 qmgr_rcpt_list.o: ../include/vbuf.h
 qmgr_rcpt_list.o: ../include/scan_dir.h
 qmgr_rcpt_list.o: ../include/maps.h
+qmgr_rcpt_list.o: ../include/dict.h
 qmgr_scan.o: qmgr_scan.c
 qmgr_scan.o: ../include/sys_defs.h
 qmgr_scan.o: ../include/msg.h
@@ -216,6 +226,7 @@ qmgr_scan.o: qmgr.h
 qmgr_scan.o: ../include/vstream.h
 qmgr_scan.o: ../include/vbuf.h
 qmgr_scan.o: ../include/maps.h
+qmgr_scan.o: ../include/dict.h
 qmgr_transport.o: qmgr_transport.c
 qmgr_transport.o: ../include/sys_defs.h
 qmgr_transport.o: ../include/msg.h
@@ -232,3 +243,4 @@ qmgr_transport.o: ../include/mail_params.h
 qmgr_transport.o: qmgr.h
 qmgr_transport.o: ../include/scan_dir.h
 qmgr_transport.o: ../include/maps.h
+qmgr_transport.o: ../include/dict.h
index 007f298dd7fa705effaac222d660b719702e36ab..b90ef97e7fd6d5ec2c433db6a742808fc08ccbb5 100644 (file)
@@ -392,9 +392,11 @@ static int qmgr_loop(void)
 static void qmgr_pre_init(void)
 {
     if (*var_relocated_maps)
-       qmgr_relocated = maps_create("relocated", var_relocated_maps);
+       qmgr_relocated = maps_create("relocated", var_relocated_maps,
+                                    DICT_FLAG_LOCK);
     if (*var_virtual_maps)
-       qmgr_virtual = maps_create("virtual", var_virtual_maps);
+       qmgr_virtual = maps_create("virtual", var_virtual_maps,
+                                  DICT_FLAG_LOCK);
 }
 
 /* qmgr_post_init - post-jail initialization */
index c636890483c09c9f310613732ef1f912dfc9ec77..56041d86e68a7507e58410b79b9fcba520bb80f7 100644 (file)
@@ -478,7 +478,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            && qmgr_virtual != 0
            && (at = strrchr(recipient->address, '@')) != 0) {
            domain = lowercase(mystrdup(at + 1));
-           junk = maps_find(qmgr_virtual, domain);
+           junk = maps_find(qmgr_virtual, domain, 0);
            myfree(domain);
            if (junk) {
                qmgr_bounce_recipient(message, recipient,
index 98daaecf46631bbaba1f9a97cfe34d76547c96f9..5dc20d6380ac2d6fec9ddf0eaa7393eaeb306ee1 100644 (file)
@@ -312,7 +312,7 @@ static ARGV *smtpd_check_parse(char *checks)
     while ((name = mystrtok(&bp, " \t\r\n,")) != 0) {
        argv_add(argv, name, (char *) 0);
        if (strchr(name, ':') && dict_handle(name) == 0)
-           dict_register(name, dict_open(name, 0, 0));
+           dict_register(name, dict_open(name, O_RDONLY, DICT_FLAG_LOCK));
     }
     argv_terminate(argv);
 
@@ -877,33 +877,42 @@ static int check_table_result(SMTPD_STATE *state, char *table,
 
 /* check_access - table lookup without substring magic */
 
-static int check_access(SMTPD_STATE *state, char *table, char *name)
+static int check_access(SMTPD_STATE *state, char *table, char *name, int flags)
 {
     char   *myname = "check_access";
     char   *low_name = lowercase(mystrdup(name));
     const char *value;
+    DICT   *dict;
 
 #define CHK_ACCESS_RETURN(x) { myfree(low_name); return(x); }
+#define FULL   0
+#define PARTIAL        DICT_FLAG_FIXED
 
     if (msg_verbose)
        msg_info("%s: %s", myname, name);
 
-    if ((value = dict_lookup(table, low_name)) != 0)
-       CHK_ACCESS_RETURN(check_table_result(state, table, value, name));
-    if (dict_errno != 0)
-       msg_fatal("%s: table lookup problem", table);
+    if ((dict = dict_handle(table)) == 0)
+       msg_panic("%s: dictionary not found: %s", myname, table);
+    if (flags == 0 || (flags & dict->flags) != 0) {
+       if ((value = dict_get(dict, low_name)) != 0)
+           CHK_ACCESS_RETURN(check_table_result(state, table, value, name));
+       if (dict_errno != 0)
+           msg_fatal("%s: table lookup problem", table);
+    }
     CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO);
 }
 
 /* check_domain_access - domainname-based table lookup */
 
-static int check_domain_access(SMTPD_STATE *state, char *table, char *domain)
+static int check_domain_access(SMTPD_STATE *state, char *table,
+                                      char *domain, int flags)
 {
     char   *myname = "check_domain_access";
     char   *low_domain = lowercase(mystrdup(domain));
     char   *name;
     char   *next;
     const char *value;
+    DICT   *dict;
 
     if (msg_verbose)
        msg_info("%s: %s", myname, domain);
@@ -914,21 +923,28 @@ static int check_domain_access(SMTPD_STATE *state, char *table, char *domain)
 #define CHK_DOMAIN_RETURN(x) { myfree(low_domain); return(x); }
 
     for (name = low_domain; (next = strchr(name, '.')) != 0; name = next + 1) {
-       if ((value = dict_lookup(table, name)) != 0)
+       if ((dict = dict_handle(table)) == 0)
+           msg_panic("%s: dictionary not found: %s", myname, table);
+       if (flags != 0 && (flags & dict->flags) == 0)
+           continue;
+       if ((value = dict_get(dict, name)) != 0)
            CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain));
        if (dict_errno != 0)
            msg_fatal("%s: table lookup problem", table);
+       flags = PARTIAL;
     }
     CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO);
 }
 
 /* check_addr_access - address-based table lookup */
 
-static int check_addr_access(SMTPD_STATE *state, char *table, char *address)
+static int check_addr_access(SMTPD_STATE *state, char *table, char *address,
+                                    int flags)
 {
     char   *myname = "check_addr_access";
     char   *addr;
     const char *value;
+    DICT   *dict;
 
     if (msg_verbose)
        msg_info("%s: %s", myname, address);
@@ -939,10 +955,15 @@ static int check_addr_access(SMTPD_STATE *state, char *table, char *address)
     addr = STR(vstring_strcpy(error_text, address));
 
     do {
-       if ((value = dict_lookup(table, addr)) != 0)
+       if ((dict = dict_handle(table)) == 0)
+           msg_panic("%s: dictionary not found: %s", myname, table);
+       if (flags != 0 && (flags & dict->flags) == 0)
+           continue;
+       if ((value = dict_get(dict, addr)) != 0)
            return (check_table_result(state, table, value, address));
        if (dict_errno != 0)
            msg_fatal("%s: table lookup problem", table);
+       flags = PARTIAL;
     } while (split_at_right(addr, '.'));
 
     return (SMTPD_CHECK_DUNNO);
@@ -951,7 +972,7 @@ static int check_addr_access(SMTPD_STATE *state, char *table, char *address)
 /* check_namadr_access - OK/FAIL based on host name/address lookup */
 
 static int check_namadr_access(SMTPD_STATE *state, char *table,
-                                      char *name, char *addr)
+                                      char *name, char *addr, int flags)
 {
     char   *myname = "check_namadr_access";
     int     status;
@@ -963,13 +984,13 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
      * Look up the host name, or parent domains thereof. XXX A domain
      * wildcard may pre-empt a more specific address table entry.
      */
-    if ((status = check_domain_access(state, table, name)) != 0)
+    if ((status = check_domain_access(state, table, name, flags)) != 0)
        return (status);
 
     /*
      * Look up the network address, or parent networks thereof.
      */
-    if ((status = check_addr_access(state, table, addr)) != 0)
+    if ((status = check_addr_access(state, table, addr, flags)) != 0)
        return (status);
 
     /*
@@ -1008,13 +1029,13 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
     /*
      * Look up the full address.
      */
-    if ((status = check_access(state, table, STR(reply.recipient))) != 0)
+    if ((status = check_access(state, table, STR(reply.recipient), FULL)) != 0)
        return (status);
 
     /*
      * Look up the domain name, or parent domains thereof.
      */
-    if ((status = check_domain_access(state, table, ratsign + 1)) != 0)
+    if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL)) != 0)
        return (status);
 
     /*
@@ -1022,7 +1043,7 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
      */
     local_at = mystrndup(STR(reply.recipient),
                         ratsign - STR(reply.recipient) + 1);
-    status = check_access(state, table, local_at);
+    status = check_access(state, table, local_at, PARTIAL);
     myfree(local_at);
     if (status != 0)
        return (status);
@@ -1147,7 +1168,7 @@ static int generic_checks(SMTPD_STATE *state, char *name,
        return (1);
     }
     if (is_map_command(name, CHECK_CLIENT_ACL, cpp)) {
-       *status = check_namadr_access(state, **cpp, state->name, state->addr);
+       *status = check_namadr_access(state, **cpp, state->name, state->addr, FULL);
        return (1);
     }
     if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
@@ -1160,7 +1181,7 @@ static int generic_checks(SMTPD_STATE *state, char *name,
      */
     if (state->helo_name) {
        if (is_map_command(name, CHECK_HELO_ACL, cpp) && state->helo_name) {
-           *status = check_domain_access(state, **cpp, state->helo_name);
+           *status = check_domain_access(state, **cpp, state->helo_name, FULL);
            return (1);
        }
        if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
@@ -1237,7 +1258,7 @@ char   *smtpd_check_client(SMTPD_STATE *state)
      */
     for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) {
        if (strchr(name, ':') != 0) {
-           status = check_namadr_access(state, name, state->name, state->addr);
+           status = check_namadr_access(state, name, state->name, state->addr, FULL);
        } else if (generic_checks(state, name, &cpp, &status, state->addr) == 0) {
            msg_warn("unknown %s check: \"%s\"", VAR_CLIENT_CHECKS, name);
            break;
@@ -1271,7 +1292,7 @@ char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
     state->helo_name = mystrdup(helohost);
     for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) {
        if (strchr(name, ':') != 0) {
-           status = check_domain_access(state, name, helohost);
+           status = check_domain_access(state, name, helohost, FULL);
        } else if (generic_checks(state, name, &cpp, &status, helohost) == 0) {
            msg_warn("unknown %s check: \"%s\"", VAR_HELO_CHECKS, name);
            break;
@@ -1381,9 +1402,9 @@ char   *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
      */
     for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) {
        if (strchr(name, ':') != 0) {
-           status = check_domain_access(state, name, domain);
+           status = check_domain_access(state, name, domain, FULL);
        } else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
-           status = check_domain_access(state, *cpp, domain);
+           status = check_domain_access(state, *cpp, domain, FULL);
        } else if (generic_checks(state, name, &cpp, &status, domain) == 0) {
            msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
            break;
index 4b6eabcd18b3ccd9237d6a94c93e94e52ec5a43f..e8ceee266d3ab929c638165cf737d6cf7e28bd2a 100644 (file)
@@ -75,7 +75,8 @@ void    transport_init(void)
 {
     if (transport_path)
        msg_panic("transport_init: repeated call");
-    transport_path = maps_create("transport", var_transport_maps);
+    transport_path = maps_create("transport", var_transport_maps,
+                                DICT_FLAG_LOCK);
 }
 
 /* transport_lookup - map a transport domain */
@@ -90,6 +91,11 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
     char   *transport;
     int     found = 0;
 
+#define FULL   0
+#define PARTIAL                DICT_FLAG_FIXED
+
+    int     maps_flag = FULL;
+
     if (transport_path == 0)
        msg_panic("transport_lookup: missing initialization");
 
@@ -103,9 +109,12 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
      * 
      * Before changing the DB lookup result, make a copy first, in order to
      * avoid DB cache corruption.
+     * 
+     * Specify if a key is partial or full, to avoid matching partial keys with
+     * regular expressions.
      */
     for (name = low_domain; name != 0; name = strchr(name + 1, '.')) {
-       if ((value = maps_find(transport_path, name)) != 0) {
+       if ((value = maps_find(transport_path, name, maps_flag)) != 0) {
            saved_value = mystrdup(value);
            if ((host = split_at(saved_value, ':')) == 0 || *host == 0)
                host = domain;
@@ -119,6 +128,7 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
        } else if (dict_errno != 0) {
            msg_fatal("transport table lookup problem");
        }
+       maps_flag = PARTIAL;
     }
     myfree(low_domain);
     return (found);
index 3ac316ab10763a50550e5ac7cd379f50bcd23de4..1c2784b162cd2dbc4da0bc58e8d1c496b33b5377 100644 (file)
@@ -291,7 +291,6 @@ dict.o: vstream.h
 dict.o: vbuf.h
 dict.o: vstring.h
 dict.o: readline.h
-dict.o: myflock.h
 dict.o: mac_parse.h
 dict.o: dict.h
 dict.o: dict_ht.h
@@ -303,6 +302,7 @@ dict_db.o: vstring.h
 dict_db.o: vbuf.h
 dict_db.o: stringops.h
 dict_db.o: iostuff.h
+dict_db.o: myflock.h
 dict_db.o: dict.h
 dict_db.o: vstream.h
 dict_db.o: dict_db.h
index 82347ddfb40a59aef9099e726a805ba368ce6511..1555159945d557a67fe43038f3433da1d1076539 100644 (file)
 /*
 /*     dict_update() updates the value of the named dictionary member.
 /*     The dictionary member and the named dictionary are instantiated
-/*     on the fly.  During the update, a file-based dictionary is locked
-/*     for exclusive access. With file-based dictionaries, duplicate
-/*     of duplicate entries depends on dictionary flag settings:
-/* .IP DICT_FLAG_DUP_WARN
-/*     Log a warning and ignore the duplicate.
-/* .IP DICT_FLAG_DUP_IGNORE
-/*     Silently ignore the duplicate.
-/* .PP
-/*     The default is to terminate the program with a fatal error.
+/*     on the fly.
 /*
 /*     dict_lookup() returns the value of the named member (i.e. without
 /*     expanding macros in the member value).  The \fIdict_name\fR argument
-/*     specifies the dictionary to search. The dictionary is locked for
-/*     shared access, when it is file based.  The result is a null pointer
+/*     specifies the dictionary to search. The result is a null pointer
 /*     when no value is found, otherwise the result is owned by the
 /*     underlying dictionary method. Make a copy if the result is to be
 /*     modified, or if the result is to survive multiple dict_lookup() calls.
 #include "vstream.h"
 #include "vstring.h"
 #include "readline.h"
-#include "myflock.h"
 #include "mac_parse.h"
 #include "dict.h"
 #include "dict_ht.h"
@@ -252,11 +242,7 @@ void    dict_update(const char *dict_name, const char *member, const char *value
        dict = node->dict;
     if (msg_verbose > 1)
        msg_info("%s: %s = %s", myname, member, value);
-    if (dict->fd >= 0 && myflock(dict->fd, MYFLOCK_EXCLUSIVE) < 0)
-       msg_fatal("%s: lock dictionary %s: %m", myname, dict_name);
     dict->update(dict, member, value);
-    if (dict->fd >= 0 && myflock(dict->fd, MYFLOCK_NONE) < 0)
-       msg_fatal("%s: unlock dictionary %s: %m", myname, dict_name);
 }
 
 /* dict_lookup - look up dictionary entry */
@@ -268,18 +254,12 @@ const char *dict_lookup(const char *dict_name, const char *member)
     DICT   *dict;
     const char *ret = 0;
 
-    dict_errno = 0;
-
     if ((node = dict_node(dict_name)) == 0) {
        if (dict_unknown_allowed == 0)
            msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
     } else {
        dict = node->dict;
-       if (dict->fd >= 0 && myflock(dict->fd, MYFLOCK_SHARED) < 0)
-           msg_fatal("%s: lock dictionary %s: %m", myname, dict_name);
        ret = dict->lookup(dict, member);
-       if (dict->fd >= 0 && myflock(dict->fd, MYFLOCK_NONE) < 0)
-           msg_fatal("%s: unlock dictionary %s: %m", myname, dict_name);
        if (ret == 0 && dict_unknown_allowed == 0)
            msg_fatal("dictionary %s: unknown member: %s", dict_name, member);
     }
index 23c0a39170f7f2eca21cd5786549537fb3f080bf..dc279298d16584a779f1c5fb820a99d026972d84 100644 (file)
@@ -39,6 +39,7 @@ typedef struct DICT {
 #define DICT_FLAG_TRY1NULL     (1<<3)  /* append 0 to key/value */
 #define DICT_FLAG_FIXED                (1<<4)  /* fixed key map */
 #define DICT_FLAG_PATTERN      (1<<5)  /* keys are patterns */
+#define DICT_FLAG_LOCK         (1<<6)  /* lock before access */
 
 extern int dict_unknown_allowed;
 extern int dict_errno;
@@ -64,7 +65,7 @@ extern const char *dict_eval(const char *, const char *, int);
   */
 extern DICT *dict_open(const char *, int, int);
 extern DICT *dict_open3(const char *, const char *, int, int);
-
+extern void dict_open_register(const char *, DICT *(*)(const char *, int, int));
 #define dict_get(dp, key)      (dp)->lookup((dp), (key))
 #define dict_put(dp, key, val) (dp)->update((dp), (key), (val))
 #define dict_close(dp)         (dp)->close(dp)
index c188d5f28acf467f3bc92459ee1822c91487b5a8..4603f066dcda41d94fda611e5a8a3f1996c3d8ea 100644 (file)
@@ -63,6 +63,7 @@
 #include "vstring.h"
 #include "stringops.h"
 #include "iostuff.h"
+#include "myflock.h"
 #include "dict.h"
 #include "dict_db.h"
 
@@ -70,7 +71,6 @@
 
 typedef struct {
     DICT    dict;                      /* generic members */
-    int     flags;                     /* see below */
     DB     *db;                                /* open db file */
     char   *path;                      /* pathname */
 } DICT_DB;
@@ -88,19 +88,28 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
     DBT     db_value;
     int     status;
     static VSTRING *buf;
+    const char *result = 0;
+
+    dict_errno = 0;
+
+    /*
+     * Acquire a shared lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_SHARED) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_db->path);
 
     /*
      * See if this DB file was written with one null byte appended to key and
      * value.
      */
-    if (dict_db->flags & DICT_FLAG_TRY1NULL) {
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
        db_key.data = (void *) name;
        db_key.size = strlen(name) + 1;
        if ((status = db->get(db, &db_key, &db_value, 0)) < 0)
            msg_fatal("error reading %s: %m", dict_db->path);
        if (status == 0) {
-           dict_db->flags &= ~DICT_FLAG_TRY0NULL;
-           return (db_value.data);
+           dict->flags &= ~DICT_FLAG_TRY0NULL;
+           result = db_value.data;
        }
     }
 
@@ -108,7 +117,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
      * See if this DB file was written with no null byte appended to key and
      * value.
      */
-    if (dict_db->flags & DICT_FLAG_TRY0NULL) {
+    if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
        db_key.data = (void *) name;
        db_key.size = strlen(name);
        if ((status = db->get(db, &db_key, &db_value, 0)) < 0)
@@ -117,11 +126,18 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
            if (buf == 0)
                buf = vstring_alloc(10);
            vstring_strncpy(buf, db_value.data, db_value.size);
-           dict_db->flags &= ~DICT_FLAG_TRY1NULL;
-           return (vstring_str(buf));
+           dict->flags &= ~DICT_FLAG_TRY1NULL;
+           result = vstring_str(buf);
        }
     }
-    return (0);
+
+    /*
+     * Release the shared lock.
+     */
+    if ((dict->fd & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_db->path);
+
+    return (result);
 }
 
 /* dict_db_update - add or update database entry */
@@ -143,23 +159,31 @@ static void dict_db_update(DICT *dict, const char *name, const char *value)
      * If undecided about appending a null byte to key and value, choose a
      * default depending on the platform.
      */
-    if ((dict_db->flags & DICT_FLAG_TRY1NULL)
-       && (dict_db->flags & DICT_FLAG_TRY0NULL)) {
+    if ((dict->flags & DICT_FLAG_TRY1NULL)
+       && (dict->flags & DICT_FLAG_TRY0NULL)) {
 #ifdef DB_NO_TRAILING_NULL
-       dict_db->flags = DICT_FLAG_TRY0NULL;
+       dict->flags &= ~DICT_FLAG_TRY1NULL;
+       dict->flags |= DICT_FLAG_TRY0NULL;
 #else
-       dict_db->flags = DICT_FLAG_TRY1NULL;
+       dict->flags &= ~DICT_FLAG_TRY0NULL;
+       dict->flags |= DICT_FLAG_TRY1NULL;
 #endif
     }
 
     /*
      * Optionally append a null byte to key and value.
      */
-    if (dict_db->flags & DICT_FLAG_TRY1NULL) {
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
        db_key.size++;
        db_value.size++;
     }
 
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_EXCLUSIVE) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_db->path);
+
     /*
      * Do the update.
      */
@@ -173,6 +197,12 @@ static void dict_db_update(DICT *dict, const char *name, const char *value)
        else
            msg_fatal("%s: duplicate entry: \"%s\"", dict_db->path, name);
     }
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_db->path);
 }
 
 /* dict_db_close - close data base */
@@ -237,5 +267,6 @@ DICT   *dict_btree_open(const char *path, int open_flags, int dict_flags)
 
     return (dict_db_open(path, open_flags, DB_BTREE, (void *) &tweak, dict_flags));
 }
+/**INDENT** Error@188: Unmatched #endif */
 
 #endif
index 33b802a061c2c999d44ee0d94ef27fad09adfa5a..1798202ff14fe6594ee1eda33ed7dddafdd4b3f9 100644 (file)
@@ -46,6 +46,7 @@
 #include "htable.h"
 #include "iostuff.h"
 #include "vstring.h"
+#include "myflock.h"
 #include "dict.h"
 #include "dict_dbm.h"
 
@@ -53,7 +54,6 @@
 
 typedef struct {
     DICT    dict;                      /* generic members */
-    int     flags;                     /* see below */
     DBM    *dbm;                       /* open database */
     char   *path;                      /* pathname */
 } DICT_DBM;
@@ -66,18 +66,27 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
     datum   dbm_key;
     datum   dbm_value;
     static VSTRING *buf;
+    const char *result = 0;
+
+    dict_errno = 0;
+
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_SHARED) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
 
     /*
      * See if this DBM file was written with one null byte appended to key
      * and value.
      */
-    if (dict_dbm->flags & DICT_FLAG_TRY1NULL) {
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
        dbm_key.dptr = (void *) name;
        dbm_key.dsize = strlen(name) + 1;
        dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
        if (dbm_value.dptr != 0) {
-           dict_dbm->flags &= ~DICT_FLAG_TRY0NULL;
-           return (dbm_value.dptr);
+           dict->flags &= ~DICT_FLAG_TRY0NULL;
+           result = dbm_value.dptr;
        }
     }
 
@@ -85,7 +94,7 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
      * See if this DBM file was written with no null byte appended to key and
      * value.
      */
-    if (dict_dbm->flags & DICT_FLAG_TRY0NULL) {
+    if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
        dbm_key.dptr = (void *) name;
        dbm_key.dsize = strlen(name);
        dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
@@ -93,11 +102,18 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
            if (buf == 0)
                buf = vstring_alloc(10);
            vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
-           dict_dbm->flags &= ~DICT_FLAG_TRY1NULL;
-           return (vstring_str(buf));
+           dict->flags &= ~DICT_FLAG_TRY1NULL;
+           result = vstring_str(buf);
        }
     }
-    return (0);
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
+
+    return (result);
 }
 
 /* dict_dbm_update - add or update database entry */
@@ -118,23 +134,31 @@ static void dict_dbm_update(DICT *dict, const char *name, const char *value)
      * If undecided about appending a null byte to key and value, choose a
      * default depending on the platform.
      */
-    if ((dict_dbm->flags & DICT_FLAG_TRY1NULL)
-       && (dict_dbm->flags & DICT_FLAG_TRY0NULL)) {
+    if ((dict->flags & DICT_FLAG_TRY1NULL)
+       && (dict->flags & DICT_FLAG_TRY0NULL)) {
 #ifdef DBM_NO_TRAILING_NULL
-       dict_dbm->flags = DICT_FLAG_TRY0NULL;
+       dict->flags &= ~DICT_FLAG_TRY1NULL;
+       dict->flags |= DICT_FLAG_TRY0NULL;
 #else
-       dict_dbm->flags = DICT_FLAG_TRY1NULL;
+       dict->flags &= ~DICT_FLAG_TRY0NULL;
+       dict->flags |= DICT_FLAG_TRY1NULL;
 #endif
     }
 
     /*
      * Optionally append a null byte to key and value.
      */
-    if (dict_dbm->flags & DICT_FLAG_TRY1NULL) {
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
        dbm_key.dsize++;
        dbm_value.dsize++;
     }
 
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_EXCLUSIVE) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
+
     /*
      * Do the update.
      */
@@ -148,6 +172,12 @@ static void dict_dbm_update(DICT *dict, const char *name, const char *value)
        else
            msg_fatal("%s: duplicate entry: \"%s\"", dict_dbm->path, name);
     }
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->fd, MYFLOCK_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
 }
 
 /* dict_dbm_close - disassociate from data base */
index f9f41506d673bd2085046fbd54c86de95c29c625..1f906c7d75c9b2470c79ba3ea4dce92b8a34c12d 100644 (file)
@@ -57,6 +57,8 @@ static void dict_env_update(DICT *unused_dict, const char *name, const char *val
 
 static const char *dict_env_lookup(DICT *unused_dict, const char *name)
 {
+    dict_errno = 0;
+
     return (safe_getenv(name));
 }
 
index f9baad406b3ffa6d364fce9fbcaf6f1336130655..a3f51e6f3182902f681204620f9add06c0cb9efc 100644 (file)
@@ -54,6 +54,8 @@ static const char *dict_ht_lookup(DICT *dict, const char *name)
 {
     DICT_HT *dict_ht = (DICT_HT *) dict;
 
+    dict_errno = 0;
+
     return (htable_find(dict_ht->table, name));
 }
 
index a155f84423364d9347651c3b0cd54cac90c5af76..10dcc6cc9ee5b98ed773ad0813935d308ee4361d 100644 (file)
@@ -143,6 +143,8 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     int rc = 0;
     void    (*saved_alarm) (int);
 
+    dict_errno = 0;
+
     /*
      * Initialize.
      */
index cb2a09fe0a5fcac1d5bb28df8f7566e21ec74e52..b3737d8209a8c51ffbe3e825a7026eceb323701f 100644 (file)
@@ -79,6 +79,8 @@ static const char *dict_ni_do_lookup(char *path, char *key_prop,
     ni_status r;
     ni_id   dir;
 
+    dict_errno = 0;
+
     if (msg_verbose)
        msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
 
index 83a81393636c9c1b4b191d1f994f29aeb901d2d9..06c9d2fcd1b292736611694cb604000db50961fa 100644 (file)
@@ -51,6 +51,7 @@ typedef struct {
 
 static const char *dict_nisplus_lookup(DICT *unused_dict, const char *unused_name)
 {
+    dict_errno = 0;
     msg_warn("dict_nisplus_lookup: NISPLUS lookup not implemented");
     return (0);
 }
index 3f91b647a4a4bdd6f404d38012450300c11f8308..ff65b7d2e4f51e07b3b84ba60496e4caddb6a7b4 100644 (file)
 /*
 /*     void    dict_close(dict)
 /*     DICT    *dict;
+/*
+/*     dict_open_register(type, open)
+/*     char    *type;
+/*     DICT    *(*open) (const char *, int, int);
 /* DESCRIPTION
 /*     This module implements a low-level interface to multiple
 /*     physical dictionary types.
 /*     Ignore duplicate keys if the underlying database does not
 /*     support duplicate keys. The default is to terminate with a fatal
 /*     error.
+/* .IP DICT_FLAG_TRY0NULL
+/*      With maps where this is appropriate, append no null byte to
+/*     keys and values.
+/*     When neither DICT_FLAG_TRY0NULL nor DICT_FLAG_TRY1NULL are
+/*     specified, the software guesses what format to use for reading;
+/*     and in the absence of definite information, a system-dependent
+/*     default is chosen for writing.
+/* .IP DICT_FLAG_TRY1NULL
+/*      With maps where this is appropriate, append one null byte to
+/*     keys and values.
+/*     When neither DICT_FLAG_TRY0NULL nor DICT_FLAG_TRY1NULL are
+/*     specified, the software guesses what format to use for reading;
+/*     and in the absence of definite information, a system-dependent
+/*     default is chosen for writing.
+/* .IP DICT_FLAG_LOCK
+/*     With maps where this is appropriate, acquire an exclusive lock
+/*     before writing, and acquire a shared lock before reading.
 /* .PP
 /*     The dictionary types are as follows:
 /* .IP environ
 /*
 /*     dict_get() retrieves the value stored in the named dictionary
 /*     under the given key. A null pointer means the value was not found.
-/*     This routine does not manipulate any locks.
 /*
 /*     dict_put() stores the specified key and value into the named
-/*     dictionary. This routine does not manipulate any locks.
+/*     dictionary.
 /*
 /*     dict_close() closes the specified dictionary and cleans up the
 /*     associated data structures.
+/*
+/*     dict_open_register() adds support for a new dictionary type.
 /* DIAGNOSTICS
 /*     Fatal error: open error, unsupported dictionary type, attempt to
 /*     update non-writable dictionary.
 #include <dict_regexp.h>
 #include <stringops.h>
 #include <split_at.h>
+#include <htable.h>
 
  /*
   * lookup table for available map types.
@@ -160,6 +183,23 @@ static DICT_OPEN_INFO dict_open_info[] = {
     0,
 };
 
+static HTABLE *dict_open_hash;
+
+/* dict_open_init - one-off initialization */
+
+static void dict_open_init(void)
+{
+    char   *myname = "dict_open_init";
+    DICT_OPEN_INFO *dp;
+
+    if (dict_open_hash != 0)
+       msg_panic("%s: multiple initialization", myname);
+    dict_open_hash = htable_create(10);
+
+    for (dp = dict_open_info; dp->type; dp++)
+       htable_enter(dict_open_hash, dp->type, (char *) dp);
+}
+
 /* dict_open - open dictionary */
 
 DICT   *dict_open(const char *dict_spec, int open_flags, int dict_flags)
@@ -184,22 +224,37 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
 {
     char   *myname = "dict_open";
     DICT_OPEN_INFO *dp;
-    DICT   *dict = 0;
-
-    for (dp = dict_open_info; dp->type; dp++) {
-       if (strcasecmp(dp->type, dict_type) == 0) {
-           if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
-               msg_fatal("opening %s:%s %m", dict_type, dict_name);
-           if (msg_verbose)
-               msg_info("%s: %s:%s", myname, dict_type, dict_name);
-           break;
-       }
-    }
-    if (dp->type == 0)
+    DICT   *dict;
+
+    if (dict_open_hash == 0)
+       dict_open_init();
+    if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0)
        msg_fatal("unsupported dictionary type: %s", dict_type);
+    if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
+       msg_fatal("opening %s:%s %m", dict_type, dict_name);
+    if (msg_verbose)
+       msg_info("%s: %s:%s", myname, dict_type, dict_name);
     return (dict);
 }
 
+/* dict_open_register - register dictionary type */
+
+void    dict_open_register(const char *type,
+                                  DICT *(*open) (const char *, int, int))
+{
+    char   *myname = "dict_open_register";
+    DICT_OPEN_INFO *dp;
+
+    if (dict_open_hash == 0)
+       dict_open_init();
+    if (htable_find(dict_open_hash, type))
+       msg_panic("%s: dictionary type exists: %s", myname, type);
+    dp = (DICT_OPEN_INFO *) mymalloc(sizeof(*dp));
+    dp->type = mystrdup(type);
+    dp->open = open;
+    htable_enter(dict_open_hash, dp->type, (char *) dp);
+}
+
 #ifdef TEST
 
  /*
@@ -221,6 +276,11 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
 #include "msg_vstream.h"
 #include "vstring_vstream.h"
 
+static NORETURN usage(char *myname)
+{
+    msg_fatal("usage: %s type:file read|write|create", myname);
+}
+
 main(int argc, char **argv)
 {
     VSTRING *keybuf = vstring_alloc(1);
@@ -229,19 +289,30 @@ main(int argc, char **argv)
     int     open_flags;
     char   *key;
     const char *value;
+    int     ch;
 
     msg_vstream_init(argv[0], VSTREAM_ERR);
-    if (argc != 3)
-       msg_fatal("usage: %s type:file read|write|create", argv[0]);
-    if (strcasecmp(argv[2], "create") == 0)
+    while ((ch = GETOPT(argc, argv, "v")) > 0) {
+       switch (ch) {
+       default:
+           usage(argv[0]);
+       case 'v':
+           msg_verbose++;
+           break;
+       }
+    }
+    optind = OPTIND;
+    if (argc - optind != 2)
+       usage(argv[0]);
+    if (strcasecmp(argv[optind + 1], "create") == 0)
        open_flags = O_CREAT | O_RDWR | O_TRUNC;
-    else if (strcasecmp(argv[2], "write") == 0)
+    else if (strcasecmp(argv[optind + 1], "write") == 0)
        open_flags = O_RDWR;
-    else if (strcasecmp(argv[2], "read") == 0)
+    else if (strcasecmp(argv[optind + 1], "read") == 0)
        open_flags = O_RDONLY;
     else
        msg_fatal("unknown access mode: %s", argv[2]);
-    dict_name = argv[1];
+    dict_name = argv[optind];
     dict = dict_open(dict_name, open_flags, 0);
     while (vstring_fgets_nonl(keybuf, VSTREAM_IN)) {
        if ((key = strtok(vstring_str(keybuf), " =")) == 0)
index f6803dd4c92ec54291b4c60aa87a2cd6c136fa69..6657b03c53c5e01f85d3d3fdef054e47911fdcc4 100644 (file)
@@ -146,16 +146,10 @@ static const char *dict_pcre_lookup(DICT *dict, const char *name)
     static VSTRING *buf;
     char   *at;
 
-/*    msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name );*/
-
-    /*
-     * XXX Require user@domain, to defeat partial address matching for smtp
-     * access control, canonical and virtual mappings, and to prevent regexps
-     * from being used as alias databases because one might inadvertantly
-     * copy "|command" or /file/name or :include: to the result.
-     */
-    if (name[0] == '@' || (at = strrchr(name, '@')) == 0 || at[1] == 0)
-       return (0);
+    dict_errno = 0;
+
+    if (msg_verbose)
+       msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name);
 
     /* Search for a matching expression */
     ctxt.matches = 0;
index 7fe2cbf40fac83e1d414333b831b2ce73ef2b453..099ac4c1015365b85e85dbef6d7c02eef20e2972 100644 (file)
@@ -139,16 +139,10 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
     char   *at;
     int     error;
 
-    /* msg_info("dict_regexp_lookup: %s: %s", dict_regexp->map, name ); */
-
-    /*
-     * XXX Require user@domain, to defeat partial address matching for smtp
-     * access control, canonical and virtual mappings, and to prevent regexps
-     * from being used as alias databases because one might inadvertently
-     * copy "|command" or /file/name or :include: to the result.
-     */
-    if (name[0] == '@' || (at = strrchr(name, '@')) == 0 || at[1] == 0)
-       return (0);
+    dict_errno = 0;
+
+    if (msg_verbose)
+       msg_info("dict_regexp_lookup: %s: %s", dict_regexp->map, name);
 
     /* Search for a matching expression */
     for (rule = dict_regexp->head; rule; rule = rule->next) {
index 00b775b7ba5532c9d4f1444efa9af36c8be152da..89a9d720482af4c90a884d5b603b1f688f78bcff 100644 (file)
@@ -110,6 +110,8 @@ DICT   *dict_unix_open(const char *map, int unused_flags, int dict_flags)
     };
     struct dict_unix_lookup *lp;
 
+    dict_errno = 0;
+
     dict_unix = (DICT_UNIX *) mymalloc(sizeof(*dict_unix));
     for (lp = dict_unix_lookup; /* void */ ; lp++) {
        if (lp->name == 0)
index 22f0a16ba18a74e908f31556e2e56a63b4065a9c..4f406458a67123fefb123189cbaac7e4a901a6c1 100644 (file)
@@ -109,7 +109,9 @@ static ARGV *match_list_parse(ARGV *list, char *string)
        } else if (strchr(pattern, ':') != 0) { /* type:table */
            for (cp = pattern; *cp == '!'; cp++)
                 /* void */ ;
-           dict_register(pattern, dict_open(pattern, 0, 0));
+           if (dict_handle(pattern) == 0)
+               dict_register(pattern,
+                             dict_open(pattern, O_RDONLY, DICT_FLAG_LOCK));
            argv_add(list, pattern, (char *) 0);
        } else {                                /* other pattern */
            argv_add(list, pattern, (char *) 0);
index f0bbee356f833447f10cbd75c1083360c3a68cde..3c13963486976f8bffff521e6d133ab293838aad 100644 (file)
@@ -484,6 +484,7 @@ extern int opterr;
 #else
 #define GETOPT(argc, argv, str) getopt((argc), (argv), (str))
 #endif
+#define OPTIND  (optind > 0 ? optind : 1)
 
 #if defined(USE_FCNTL_LOCK) && defined(USE_FLOCK_LOCK)
 #error "define USE_FCNTL_LOCK or USE_FLOCK_LOCK, not both"