From 089fe6b742f3ece3b4e5d5b1b8e2cac1d551e3db Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Mon, 29 Mar 1999 00:00:00 -0500 Subject: [PATCH] snapshot-19990329 --- postfix/HISTORY | 34 ++++++++- postfix/cleanup/Makefile.in | 10 +++ postfix/cleanup/cleanup.c | 11 ++- postfix/global/mail_addr_find.c | 21 ++++-- postfix/global/mail_addr_map.c | 2 +- postfix/global/mail_version.h | 2 +- postfix/global/maps.c | 22 ++++-- postfix/global/maps.h | 9 ++- postfix/local/alias.c | 4 +- postfix/qmgr/Makefile.in | 12 +++ postfix/qmgr/qmgr.c | 6 +- postfix/qmgr/qmgr_message.c | 2 +- postfix/smtpd/smtpd_check.c | 65 +++++++++++------ postfix/trivial-rewrite/transport.c | 14 +++- postfix/util/Makefile.in | 2 +- postfix/util/dict.c | 24 +----- postfix/util/dict.h | 3 +- postfix/util/dict_db.c | 57 +++++++++++---- postfix/util/dict_dbm.c | 56 ++++++++++---- postfix/util/dict_env.c | 2 + postfix/util/dict_ht.c | 2 + postfix/util/dict_ldap.c | 2 + postfix/util/dict_ni.c | 2 + postfix/util/dict_nisplus.c | 1 + postfix/util/dict_open.c | 109 +++++++++++++++++++++++----- postfix/util/dict_pcre.c | 12 +-- postfix/util/dict_regexp.c | 12 +-- postfix/util/dict_unix.c | 2 + postfix/util/match_list.c | 4 +- postfix/util/sys_defs.h | 1 + 30 files changed, 364 insertions(+), 141 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index cf850012d..bce74a964 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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 diff --git a/postfix/cleanup/Makefile.in b/postfix/cleanup/Makefile.in index 1eb83bc7a..391f409ff 100644 --- a/postfix/cleanup/Makefile.in +++ b/postfix/cleanup/Makefile.in @@ -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 diff --git a/postfix/cleanup/cleanup.c b/postfix/cleanup/cleanup.c index ef6a62d41..7666077f9 100644 --- a/postfix/cleanup/cleanup.c +++ b/postfix/cleanup/cleanup.c @@ -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"); } diff --git a/postfix/global/mail_addr_find.c b/postfix/global/mail_addr_find.c index eac168258..de8b7fe7e 100644 --- a/postfix/global/mail_addr_find.c +++ b/postfix/global/mail_addr_find.c @@ -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); diff --git a/postfix/global/mail_addr_map.c b/postfix/global/mail_addr_map.c index 00fba564e..6949f5fd9 100644 --- a/postfix/global/mail_addr_map.c +++ b/postfix/global/mail_addr_map.c @@ -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); diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index cd0a40af2..e1976f88e 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -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 diff --git a/postfix/global/maps.c b/postfix/global/maps.c index 71cf6b337..02af45d4c 100644 --- a/postfix/global/maps.c +++ b/postfix/global/maps.c @@ -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 @@ -102,7 +102,7 @@ /* 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"); diff --git a/postfix/global/maps.h b/postfix/global/maps.h index dd0787b7d..015811f69 100644 --- a/postfix/global/maps.h +++ b/postfix/global/maps.h @@ -11,6 +11,11 @@ /* DESCRIPTION /* .nf + /* + * Utility library. + */ +#include + /* * 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 diff --git a/postfix/local/alias.c b/postfix/local/alias.c index 90bfe4f9a..bbbbe9df0 100644 --- a/postfix/local/alias.c +++ b/postfix/local/alias.c @@ -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 { diff --git a/postfix/qmgr/Makefile.in b/postfix/qmgr/Makefile.in index 4219845f0..fe9350700 100644 --- a/postfix/qmgr/Makefile.in +++ b/postfix/qmgr/Makefile.in @@ -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 diff --git a/postfix/qmgr/qmgr.c b/postfix/qmgr/qmgr.c index 007f298dd..b90ef97e7 100644 --- a/postfix/qmgr/qmgr.c +++ b/postfix/qmgr/qmgr.c @@ -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 */ diff --git a/postfix/qmgr/qmgr_message.c b/postfix/qmgr/qmgr_message.c index c63689048..56041d86e 100644 --- a/postfix/qmgr/qmgr_message.c +++ b/postfix/qmgr/qmgr_message.c @@ -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, diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index 98daaecf4..5dc20d638 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -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; diff --git a/postfix/trivial-rewrite/transport.c b/postfix/trivial-rewrite/transport.c index 4b6eabcd1..e8ceee266 100644 --- a/postfix/trivial-rewrite/transport.c +++ b/postfix/trivial-rewrite/transport.c @@ -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); diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index 3ac316ab1..1c2784b16 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -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 diff --git a/postfix/util/dict.c b/postfix/util/dict.c index 82347ddfb..155515994 100644 --- a/postfix/util/dict.c +++ b/postfix/util/dict.c @@ -78,20 +78,11 @@ /* /* 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. @@ -149,7 +140,6 @@ #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); } diff --git a/postfix/util/dict.h b/postfix/util/dict.h index 23c0a3917..dc279298d 100644 --- a/postfix/util/dict.h +++ b/postfix/util/dict.h @@ -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) diff --git a/postfix/util/dict_db.c b/postfix/util/dict_db.c index c188d5f28..4603f066d 100644 --- a/postfix/util/dict_db.c +++ b/postfix/util/dict_db.c @@ -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 diff --git a/postfix/util/dict_dbm.c b/postfix/util/dict_dbm.c index 33b802a06..1798202ff 100644 --- a/postfix/util/dict_dbm.c +++ b/postfix/util/dict_dbm.c @@ -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 */ diff --git a/postfix/util/dict_env.c b/postfix/util/dict_env.c index f9f41506d..1f906c7d7 100644 --- a/postfix/util/dict_env.c +++ b/postfix/util/dict_env.c @@ -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)); } diff --git a/postfix/util/dict_ht.c b/postfix/util/dict_ht.c index f9baad406..a3f51e6f3 100644 --- a/postfix/util/dict_ht.c +++ b/postfix/util/dict_ht.c @@ -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)); } diff --git a/postfix/util/dict_ldap.c b/postfix/util/dict_ldap.c index a155f8442..10dcc6cc9 100644 --- a/postfix/util/dict_ldap.c +++ b/postfix/util/dict_ldap.c @@ -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. */ diff --git a/postfix/util/dict_ni.c b/postfix/util/dict_ni.c index cb2a09fe0..b3737d820 100644 --- a/postfix/util/dict_ni.c +++ b/postfix/util/dict_ni.c @@ -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); diff --git a/postfix/util/dict_nisplus.c b/postfix/util/dict_nisplus.c index 83a813936..06c9d2fcd 100644 --- a/postfix/util/dict_nisplus.c +++ b/postfix/util/dict_nisplus.c @@ -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); } diff --git a/postfix/util/dict_open.c b/postfix/util/dict_open.c index 3f91b647a..ff65b7d2e 100644 --- a/postfix/util/dict_open.c +++ b/postfix/util/dict_open.c @@ -28,6 +28,10 @@ /* /* 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. @@ -44,6 +48,23 @@ /* 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 @@ -72,13 +93,14 @@ /* /* 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. @@ -120,6 +142,7 @@ #include #include #include +#include /* * 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; + DICT *dict; - 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) + 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) diff --git a/postfix/util/dict_pcre.c b/postfix/util/dict_pcre.c index f6803dd4c..6657b03c5 100644 --- a/postfix/util/dict_pcre.c +++ b/postfix/util/dict_pcre.c @@ -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 );*/ + dict_errno = 0; - /* - * 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); + if (msg_verbose) + msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name); /* Search for a matching expression */ ctxt.matches = 0; diff --git a/postfix/util/dict_regexp.c b/postfix/util/dict_regexp.c index 7fe2cbf40..099ac4c10 100644 --- a/postfix/util/dict_regexp.c +++ b/postfix/util/dict_regexp.c @@ -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 ); */ + dict_errno = 0; - /* - * 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); + 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) { diff --git a/postfix/util/dict_unix.c b/postfix/util/dict_unix.c index 00b775b7b..89a9d7204 100644 --- a/postfix/util/dict_unix.c +++ b/postfix/util/dict_unix.c @@ -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) diff --git a/postfix/util/match_list.c b/postfix/util/match_list.c index 22f0a16ba..4f406458a 100644 --- a/postfix/util/match_list.c +++ b/postfix/util/match_list.c @@ -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); diff --git a/postfix/util/sys_defs.h b/postfix/util/sys_defs.h index f0bbee356..3c1396348 100644 --- a/postfix/util/sys_defs.h +++ b/postfix/util/sys_defs.h @@ -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"