levels, because changing the level alone is not sufficient.
Server-side TLS requires that at least one private key and
corresponding public-key certificate chain are configured.
+
+20250624
+
+ Feature: a new debug: pseudo lookup table. Specify
+ debug:maptype:mapname to encapsulate a maptype:mapname
+ lookup table and log all access. This builds on existing
+ but unused code to log table access. Richard Hansen
+ (rhansen@rhansen.org). Files: proto/DATABASE_README.html,
+ postconf/Makefile.in, /postconf/postconf.c,
+ postconf/postconf_dbms.c, postconf/test77-main.cf,
+ postconf/test77.ref, util/Makefile.in, util/dict_debug.c,
+ util/dict_debug.h, util/dict_debug_test.ref,
+ util/dict_debug_test.sh, util/dict_open.c.
+
+ Cleanup: To keep the dict_debug: code clean, Wietse removed
+ support for the DICT_FLAG_DEBUG feature that had not been
+ used for decades. Files: util/dict_debug.c, util/dict.c,
+ util/dict.h, src/global/dict_ldap.c, global/dict_mongodb.c,
+ global/dict_mysql.c, global/dict_pgsql.c, global/dict_proxy.c,
+ global/dict_sqlite.c, util/dict_cdb.c, util/dict_cidr.c,
+ util/dict_db.c, util/dict_dbm.c, util/dict_env.c,
+ util/dict_fail.c, util/dict_inline.c, util/dict_lmdb.c,
+ util/dict_ni.c, util/dict_nis.c, util/dict_nisplus.c,
+ util/dict_pcre.c, util/dict_pipe.c, util/dict_random.c,
+ util/dict_regexp.c, util/dict_sdbm.c, util/dict_sockmap.c,
+ util/dict_static.c, util/dict_surrogate.c, util/dict_tcp.c,
+ util/dict_thash.c, util/dict_union.c, util/dict_unix.c.
databases are maintained by Postfix daemons. The lookup table name as
used in "dbm:table" is the database file name without the ".dir" or
".pag" suffix.
+ d\bde\beb\bbu\bug\bg
+ An adapter for another table that causes all accesses to be logged.
+ Example usage: "debug:hash:/etc/postfix/example". The formats of the
+ log messages are unspecified and subject to change. Warning: If a query
+ or the underlying table contains sensitive information (such as a
+ password), that information might be logged.
+
+ This feature is available with Postfix 3.11 and later.
+
e\ben\bnv\bvi\bir\bro\bon\bn
The UNIX process environment array. The lookup key is the variable
name. The lookup table name in "environ:table" is ignored.
as used in "<a href="DATABASE_README.html#types">dbm</a>:table" is the database file name without the ".dir"
or ".pag" suffix. </dd>
+<dt> <b>debug</b> </dt>
+
+<dd>
+<p> An adapter for another table that causes all accesses to be
+logged. Example usage: "debug:<a href="DATABASE_README.html#types">hash</a>:/etc/postfix/example". The
+formats of the log messages are unspecified and subject to change.
+Warning: If a query or the underlying table contains sensitive
+information (such as a password), that information might be
+logged. </p>
+
+<p> This feature is available with Postfix 3.11 and later. </p>
+</dd>
+
<dt> <b>environ</b> </dt>
<dd> The UNIX process environment array. The lookup key is the
<b>dbm</b> An indexed file type based on hashing. Available on sys-
tems with support for DBM databases.
+ <b>debug</b> An adapter for another table that causes all accesses to
+ be logged. The table name syntax is <i>type</i><b>:</b><i>name</i>. Example
+ usage: <b>debug:<a href="DATABASE_README.html#types">hash</a>:/etc/postfix/example</b>. The formats of
+ the log messages are unspecified and subject to change.
+ Warning: If a query or the underlying table contains sen-
+ sitive information (such as a password), that information
+ might be logged.
+
+ This feature is available with Postfix 3.11 and later.
+
<b>environ</b>
The UNIX process environment array. The lookup key is the
environment variable name; the table name is ignored.
.IP \fBdbm\fR
An indexed file type based on hashing. Available on systems
with support for DBM databases.
+.IP \fBdebug\fR
+An adapter for another table that causes all accesses to be
+logged. The table name syntax is \fItype\fB:\fIname\fR.
+Example usage: \fBdebug:hash:/etc/postfix/example\fR. The
+formats of the log messages are unspecified and subject to
+change. Warning: If a query or the underlying table contains
+sensitive information (such as a password), that information
+might be logged.
+
+This feature is available with Postfix 3.11 and later.
.IP \fBenviron\fR
The UNIX process environment array. The lookup key is the
environment variable name; the table name is ignored. Originally
as used in "dbm:table" is the database file name without the ".dir"
or ".pag" suffix. </dd>
+<dt> <b>debug</b> </dt>
+
+<dd>
+<p> An adapter for another table that causes all accesses to be
+logged. Example usage: "debug:hash:/etc/postfix/example". The
+formats of the log messages are unspecified and subject to change.
+Warning: If a query or the underlying table contains sensitive
+information (such as a password), that information might be
+logged. </p>
+
+<p> This feature is available with Postfix 3.11 and later. </p>
+</dd>
+
<dt> <b>environ</b> </dt>
<dd> The UNIX process environment array. The lookup key is the
typofix
LD
PRELOAD
+rhansen
USE_TLSRPT USE_TLSRPT
encoded encoded text can contain only alpha digit
ossl_digest_new ossl_digest_new returns NULL after error ossl_digest_data
+ Richard Hansen rhansen rhansen org
Files smtp smtp h
proto proto COMPATIBILITY_README html
smtp smtp c tlsproxy tlsproxy c proto postconf proto
+ rhansen rhansen org Files proto DATABASE_README html
+ postconf Makefile in postconf postconf c
* Return the new dict_ldap structure.
*/
dict_ldap->dict.owner = cfg_get_owner(dict_ldap->parser);
- return (DICT_DEBUG (&dict_ldap->dict));
+ return (&dict_ldap->dict);
}
#endif
mongoc_uri_destroy(uri);
mongoc_client_set_error_api(dict_mongodb->client, MONGOC_ERROR_API_VERSION_2);
- return (DICT_DEBUG (&dict_mongodb->dict));
+ return (&dict_mongodb->dict);
}
#endif
}
/* Don't blacklist the load balancer! */
if (dict_mysql->hosts->argc == 1)
- argv_add(dict_mysql->hosts, dict_mysql->hosts->argv[0], (char *) 0);
+ argv_add(dict_mysql->hosts, dict_mysql->hosts->argv[0], (char *) 0);
myfree(hosts);
}
if (dict_mysql->pldb == NULL)
msg_fatal("couldn't initialize pldb!\n");
dict_mysql->dict.owner = cfg_get_owner(dict_mysql->parser);
- return (DICT_DEBUG (&dict_mysql->dict));
+ return (&dict_mysql->dict);
}
/*
return (ret);
}
dict_pgsql->dict.owner = cfg_get_owner(dict_pgsql->parser);
- return (DICT_DEBUG (&dict_pgsql->dict));
+ return (&dict_pgsql->dict);
}
/* plpgsql_init - initialize a PGSQL database */
case PROXY_STAT_OK:
dict_proxy->dict.flags = (dict_flags & ~DICT_FLAG_IMPL_MASK)
| (server_flags & DICT_FLAG_IMPL_MASK);
- return (DICT_DEBUG (&dict_proxy->dict));
+ return (&dict_proxy->dict);
default:
msg_warn("%s open failed for table \"%s\": unexpected status %d",
dict_proxy->service, dict_proxy->dict.name, status);
}
dict_sqlite->dict.owner = cfg_get_owner(dict_sqlite->parser);
- return (DICT_DEBUG (&dict_sqlite->dict));
+ return (&dict_sqlite->dict);
}
#endif
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20250623"
+#define MAIL_RELEASE_DATE "20250624"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT
diff /dev/null test76.tmp
rm -f main.cf master.cf test76.tmp
+test77: $(PROG) test77-main.cf test77.ref
+ rm -f main.cf master.cf
+ cp test77-main.cf main.cf
+ touch master.cf
+ touch -t 197701010000 main.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc . >test77.tmp 2>&1
+ diff test77.ref test77.tmp
+ rm -f main.cf master.cf test77.tmp
+
# Warn about unused, deprecated, or deleted parameters.
test78: $(PROG) test78.ref
rm -f main.cf master.cf
postconf_dbms.o: ../../include/argv.h
postconf_dbms.o: ../../include/check_arg.h
postconf_dbms.o: ../../include/dict.h
+postconf_dbms.o: ../../include/dict_debug.h
postconf_dbms.o: ../../include/dict_ht.h
postconf_dbms.o: ../../include/dict_ldap.h
postconf_dbms.o: ../../include/dict_memcache.h
/* .IP \fBdbm\fR
/* An indexed file type based on hashing. Available on systems
/* with support for DBM databases.
+/* .IP \fBdebug\fR
+/* An adapter for another table that causes all accesses to be
+/* logged. The table name syntax is \fItype\fB:\fIname\fR.
+/* Example usage: \fBdebug:hash:/etc/postfix/example\fR. The
+/* formats of the log messages are unspecified and subject to
+/* change. Warning: If a query or the underlying table contains
+/* sensitive information (such as a password), that information
+/* might be logged.
+/*
+/* This feature is available with Postfix 3.11 and later.
/* .IP \fBenviron\fR
/* The UNIX process environment array. The lookup key is the
/* environment variable name; the table name is ignored. Originally
#include <mail_conf.h>
#include <mail_params.h>
+#include <dict_debug.h>
#include <dict_ht.h>
#include <dict_proxy.h>
#include <dict_ldap.h>
}
/*
- * Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
- * behavior when opening a local database configuration file.
+ * Skip over adapter maptypes "proxy:" and "debug:", to emulate their
+ * behavior when wrapping a local database configuration file.
*/
while ((prefix = split_at(db_type, ':')) != 0
- && strcmp(db_type, DICT_TYPE_PROXY) == 0)
+ && (strcmp(db_type, DICT_TYPE_PROXY) == 0 ||
+ strcmp(db_type, DICT_TYPE_DEBUG) == 0))
db_type = prefix;
if (prefix == 0)
--- /dev/null
+# Test that debug:$dbtype:$dbname in a parameter value is processed like
+# $dbtype:$dbname. Specifically, all $dbname_$dbparamsuffix parameters (where
+# $dbparamsuffix is a recognized parameter suffix for $dbtype) should be marked
+# as used if debug:$dbtype:$dbname is in a used parameter.
+#
+# See also: test28, test29
+
+_debug = debug
+
+header_checks =
+ ldap:_baseline
+ debug:ldap:_debug
+ ${_debug}:ldap:_debugvar
+ proxy:debug:ldap:_proxy_debug
+ debug:proxy:ldap:_debug_proxy
+ pipemap:{debug:ldap:_pipemap_debug}
+ debug:pipemap:{ldap:_debug_pipemap}
+ unionmap:{debug:ldap:_unionmap_debug}
+ debug:unionmap:{ldap:_debug_unionmap}
+
+# The following parameters should be considered in-use because *_domain is a
+# recognized parameter suffix for the ldap: table type.
+_baseline_domain = whatever
+_debug_domain = whatever
+_debugvar_domain = whatever
+_debug_proxy_domain = whatever
+_proxy_debug_domain = whatever
+_pipemap_debug_domain = whatever
+_debug_pipemap_domain = whatever
+_unionmap_debug_domain = whatever
+_debug_unionmap_domain = whatever
+
+# These parameters should cause unused warnings because *_foo is not a
+# recognized parameter suffix for the ldap: table type.
+_baseline_foo = whatever
+_debug_foo = whatever
+_debugvar_foo = whatever
+_debug_proxy_foo = whatever
+_proxy_debug_foo = whatever
+_pipemap_debug_foo = whatever
+_debug_pipemap_foo = whatever
+_unionmap_debug_foo = whatever
+_debug_unionmap_foo = whatever
+
+# $_unused_tables is an unused parameter, so none of the tables mentioned in its
+# value should cause any $dbname_$dbparamsuffix parameter to be marked as
+# in-use.
+_unused_tables =
+ ldap:_unused_baseline
+ debug:ldap:_unused_debug
+ ${_debug}:ldap:_unused_debugvar
+ proxy:debug:ldap:_unused_proxy_debug
+ debug:proxy:ldap:_unused_debug_proxy
+ pipemap:{debug:ldap:_unused_pipemap_debug}
+ debug:pipemap:{ldap:_unused_debug_pipemap}
+ unionmap:{debug:ldap:_unused_unionmap_debug}
+ debug:unionmap:{ldap:_unused_debug_unionmap}
+
+_unused_baseline_domain = whatever
+_unused_debug_domain = whatever
+_unused_debugvar_domain = whatever
+_unused_debug_proxy_domain = whatever
+_unused_proxy_debug_domain = whatever
+_unused_pipemap_debug_domain = whatever
+_unused_debug_pipemap_domain = whatever
+_unused_unionmap_debug_domain = whatever
+_unused_debug_unionmap_domain = whatever
--- /dev/null
+_baseline_domain = whatever
+_debug = debug
+_debug_domain = whatever
+_debug_pipemap_domain = whatever
+_debug_proxy_domain = whatever
+_debug_unionmap_domain = whatever
+_debugvar_domain = whatever
+_pipemap_debug_domain = whatever
+_proxy_debug_domain = whatever
+_unionmap_debug_domain = whatever
+config_directory = .
+header_checks = ldap:_baseline debug:ldap:_debug ${_debug}:ldap:_debugvar proxy:debug:ldap:_proxy_debug debug:proxy:ldap:_debug_proxy pipemap:{debug:ldap:_pipemap_debug} debug:pipemap:{ldap:_debug_pipemap} unionmap:{debug:ldap:_unionmap_debug} debug:unionmap:{ldap:_debug_unionmap}
+./postconf: warning: ./main.cf: unused parameter: _unused_debug_pipemap_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_pipemap_debug_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _unionmap_debug_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_unionmap_debug_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_baseline_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _debugvar_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_tables=ldap:_unused_baseline debug:ldap:_unused_debug ${_debug}:ldap:_unused_debugvar proxy:debug:ldap:_unused_proxy_debug debug:proxy:ldap:_unused_debug_proxy pipemap:{debug:ldap:_unused_pipemap_debug} debug:pipemap:{ldap:_unused_debug_pipemap} unionmap:{debug:ldap:_unused_unionmap_debug} debug:unionmap:{ldap:_unused_debug_unionmap}
+./postconf: warning: ./main.cf: unused parameter: _debug_pipemap_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _pipemap_debug_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_debug_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_proxy_debug_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_proxy_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_debugvar_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_debug_unionmap_domain=whatever
+./postconf: warning: ./main.cf: unused parameter: _baseline_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _proxy_debug_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_unionmap_foo=whatever
+./postconf: warning: ./main.cf: unused parameter: _unused_debug_proxy_domain=whatever
mkmap_cdb.o mkmap_lmdb.o mkmap_sdbm.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
- dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
+ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_debug.h dict_env.h \
+ dict_ht.h \
dict_lmdb.h dict_ni.h dict_nis.h dict_nisplus.h dict_pcre.h dict_regexp.h \
dict_sdbm.h dict_static.h dict_tcp.h dict_unix.h dir_forest.h \
events.h exec_command.h find_inet.h fsspace.h fullname.h \
dict_regexp_file_test dict_cidr_file_test \
dict_static_file_test dict_random_test dict_random_file_test \
dict_inline_file_test dict_stream_test dict_inline_regexp_test \
- dict_inline_cidr_test
+ dict_inline_cidr_test dict_debug_test
dict_pcre_tests: dict_pcre_test miss_endif_pcre_test dict_pcre_file_test \
dict_inline_pcre_test
diff dict_inline_cidr.ref dict_inline_cidr.tmp
rm -f dict_inline_cidr.tmp
+dict_debug_test: dict_open dict_debug_test.sh dict_debug_test.ref
+ $(SHLIB_ENV) ./dict_debug_test.sh >dict_debug_test.tmp 2>&1
+ diff dict_debug_test.ref dict_debug_test.tmp
+ rm -f dict_debug_test.tmp
+
find_inet_test: find_inet find_inet.ref
$(SHLIB_ENV) ${VALGRIND} ./find_inet >find_inet.tmp 2>&1
diff find_inet.ref find_inet.tmp
dict_debug.o: check_arg.h
dict_debug.o: dict.h
dict_debug.o: dict_debug.c
+dict_debug.o: dict_debug.h
dict_debug.o: msg.h
dict_debug.o: myflock.h
dict_debug.o: mymalloc.h
dict_open.o: dict_cidr.h
dict_open.o: dict_db.h
dict_open.o: dict_dbm.h
+dict_open.o: dict_debug.h
dict_open.o: dict_env.h
dict_open.o: dict_fail.h
dict_open.o: dict_ht.h
"lock", DICT_FLAG_LOCK, /* lock before access */
"replace", DICT_FLAG_DUP_REPLACE, /* if file, replace dups */
"sync_update", DICT_FLAG_SYNC_UPDATE, /* if file, sync updates */
- "debug", DICT_FLAG_DEBUG, /* log access */
+ /*"debug", DICT_FLAG_DEBUG, /* log access */
"no_regsub", DICT_FLAG_NO_REGSUB, /* disallow regexp substitution */
"no_proxy", DICT_FLAG_NO_PROXY, /* disallow proxy mapping */
"no_unauth", DICT_FLAG_NO_UNAUTH, /* disallow unauthenticated data */
extern DICT *dict_alloc(const char *, const char *, ssize_t);
extern void dict_free(DICT *);
-extern DICT *dict_debug(DICT *);
-
-#define DICT_DEBUG(d) ((d)->flags & DICT_FLAG_DEBUG ? dict_debug(d) : (d))
-
/*
* See dict_open.c embedded manpage for flag definitions.
*/
#define DICT_FLAG_LOCK (1<<6) /* use temp lock before access */
#define DICT_FLAG_DUP_REPLACE (1<<7) /* replace dups if supported */
#define DICT_FLAG_SYNC_UPDATE (1<<8) /* sync updates if supported */
-#define DICT_FLAG_DEBUG (1<<9) /* log access */
+/*#define DICT_FLAG_DEBUG (1<<9) /* log access */
/*#define DICT_FLAG_FOLD_KEY (1<<10) /* lowercase the lookup key */
#define DICT_FLAG_NO_REGSUB (1<<11) /* disallow regexp substitution */
#define DICT_FLAG_NO_PROXY (1<<12) /* disallow proxy mapping */
if (dict_flags & DICT_FLAG_FOLD_FIX)
dict_cdbq->dict.fold_buf = vstring_alloc(10);
- DICT_CDBQ_OPEN_RETURN(DICT_DEBUG (&dict_cdbq->dict));
+ DICT_CDBQ_OPEN_RETURN(&dict_cdbq->dict);
}
/* dict_cdbm_update - add database entry, create mode */
if (dict_flags & DICT_FLAG_FOLD_FIX)
dict_cdbm->dict.fold_buf = vstring_alloc(10);
- DICT_CDBM_OPEN_RETURN(DICT_DEBUG (&dict_cdbm->dict));
+ DICT_CDBM_OPEN_RETURN(&dict_cdbm->dict);
}
/* dict_cdb_open - open data base for query mode or create mode */
DICT *dict_cdb_open(const char *path, int open_flags, int dict_flags)
{
switch (open_flags & (O_RDONLY | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) {
- case O_RDONLY: /* query mode */
+ case O_RDONLY: /* query mode */
return dict_cdbq_open(path, dict_flags);
case O_WRONLY | O_CREAT | O_TRUNC: /* create mode */
case O_RDWR | O_CREAT | O_TRUNC: /* sloppiness */
(void) mvect_free(&mvect);
dict_file_purge_buffers(&dict_cidr->dict);
- DICT_CIDR_OPEN_RETURN(DICT_DEBUG (&dict_cidr->dict));
+ DICT_CIDR_OPEN_RETURN(&dict_cidr->dict);
}
dict_db->val_buf = 0;
myfree(db_path);
- return (DICT_DEBUG (&dict_db->dict));
+ return (&dict_db->dict);
}
/* dict_hash_open - create association with data base */
dict_dbm->key_buf = 0;
dict_dbm->val_buf = 0;
- DICT_DBM_OPEN_RETURN(DICT_DEBUG (&dict_dbm->dict));
+ DICT_DBM_OPEN_RETURN(&dict_dbm->dict);
}
#endif
/* SUMMARY
/* dictionary manager, logging proxy
/* SYNOPSIS
-/* #include <dict.h>
+/* #include <dict_debug.h>
/*
-/* DICT *dict_debug(dict_handle)
-/* DICT *dict_handle;
-/*
-/* DICT *DICT_DEBUG(dict_handle)
-/* DICT *dict_handle;
+/* DICT *dict_debug_open(name, open_flags, dict_flags);
+/* const char *name;
+/* int open_flags;
+/* int dict_flags;
/* DESCRIPTION
-/* dict_debug() encapsulates the given dictionary object and returns
-/* a proxy object that logs all access to the encapsulated object.
-/* This is more convenient than having to add logging capability
-/* to each individual dictionary access method.
+/* dict_debug_open() encapsulates the named dictionary object and
+/* returns a proxy object that logs all access to the encapsulated
+/* object.
/*
-/* DICT_DEBUG() is an unsafe macro that returns the original object if
-/* the object's debugging flag is not set, and that otherwise encapsulates
-/* the object with dict_debug(). This macro simplifies usage by avoiding
-/* clumsy expressions. The macro evaluates its argument multiple times.
+/* If the encapsulated dictionary is not already registered, it is
+/* opened with a call to dict_open(\fIname\fR, \fIopen_flags\fR,
+/* \fIdict_flags\fR) before registering it.
/* DIAGNOSTICS
/* Fatal errors: out of memory.
/* LICENSE
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Richard Hansen <rhansen@rhansen.org>
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System libraries. */
#include <sys_defs.h>
+#include <string.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <dict.h>
+#include <dict_debug.h>
/* Application-specific. */
real_dict->flags = dict->flags;
result = dict_get(real_dict, key);
dict->flags = real_dict->flags;
- msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key,
+ msg_info("%s lookup: \"%s\" = \"%s\"", dict->name, key,
result ? result : real_dict->error ? "error" : "not_found");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
}
real_dict->flags = dict->flags;
result = dict_put(real_dict, key, value);
dict->flags = real_dict->flags;
- msg_info("%s:%s update: \"%s\" = \"%s\": %s", dict->type, dict->name,
+ msg_info("%s update: \"%s\" = \"%s\": %s", dict->name,
key, value, result == 0 ? "success" : real_dict->error ?
"error" : "failed");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
real_dict->flags = dict->flags;
result = dict_del(real_dict, key);
dict->flags = real_dict->flags;
- msg_info("%s:%s delete: \"%s\": %s", dict->type, dict->name, key,
+ msg_info("%s delete: \"%s\": %s", dict->name, key,
result == 0 ? "success" : real_dict->error ?
"error" : "failed");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
result = dict_seq(real_dict, function, key, value);
dict->flags = real_dict->flags;
if (result == 0)
- msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name,
- *key, *value);
+ msg_info("%s sequence: \"%s\" = \"%s\"", dict->name, *key, *value);
else
- msg_info("%s:%s sequence: found EOF", dict->type, dict->name);
+ msg_info("%s sequence: found EOF", dict->name);
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
}
static void dict_debug_close(DICT *dict)
{
- DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
-
- dict_close(dict_debug->real_dict);
+ /* TODO(wietse) use the annotated name from dict_make_registered_name(). */
+ dict_unregister(dict->name);
dict_free(dict);
}
-/* dict_debug - encapsulate dictionary object and install proxies */
+/* dict_debug_open - encapsulate dictionary object and install proxies */
-DICT *dict_debug(DICT *real_dict)
+DICT *dict_debug_open(const char *name, int open_flags, int dict_flags)
{
- DICT_DEBUG *dict_debug;
+ static const char myname[] = "dict_debug_open";
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, name);
+
+ /*
+ * Reuse a previously registered table if present. This prevents a config
+ * containing both debug:foo:bar and foo:bar from creating two DICT
+ * objects for foo:bar.
+ *
+ * TODO(wietse) use the annotated name from dict_make_registered_name().
+ */
+ DICT *real_dict = dict_handle(name);
+
+ if (real_dict == 0)
+ real_dict = dict_open(name, open_flags, dict_flags);
+ dict_register(name, real_dict);
+
+ /*
+ * Encapsulate the real dictionary.
+ */
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict_alloc(DICT_TYPE_DEBUG, name,
+ sizeof(*dict_debug));
- dict_debug = (DICT_DEBUG *) dict_alloc(real_dict->type,
- real_dict->name, sizeof(*dict_debug));
dict_debug->dict.flags = real_dict->flags; /* XXX not synchronized */
dict_debug->dict.lookup = dict_debug_lookup;
dict_debug->dict.update = dict_debug_update;
dict_debug->dict.sequence = dict_debug_sequence;
dict_debug->dict.close = dict_debug_close;
dict_debug->real_dict = real_dict;
+ dict_debug->dict.owner = real_dict->owner;
return (&dict_debug->dict);
}
--- /dev/null
+#ifndef _DICT_DEBUG_H_INCLUDED_
+#define _DICT_DEBUG_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_debug 3h
+/* SUMMARY
+/* dictionary manager interface for "debug" tables
+/* SYNOPSIS
+/* #include <dict_debug.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_DEBUG "debug"
+
+extern DICT *dict_debug_open(const char *, int, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Richard Hansen <rhansen@rhansen.org>
+/*--*/
+
+#endif
--- /dev/null
++ ./dict_open debug: read
+./dict_open: fatal: open dictionary: expecting "type:name" form instead of "debug:"
++ ./dict_open debug:missing_colon_and_name read
+./dict_open: fatal: open dictionary: expecting "type:name" form instead of "missing_colon_and_name"
++ ./dict_open 'debug:static:{space in name}' read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: static:{space in name} lookup: "k" = "space in name"
+k=space in name
++ ./dict_open debug:debug:static:value read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: static:value lookup: "k" = "value"
+./dict_open: debug:static:value lookup: "k" = "value"
+k=value
++ ./dict_open debug:internal:name write
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: internal:name lookup: "k" = "not_found"
+k: not found
+> put k=v
+./dict_open: internal:name update: "k" = "v": success
+> get k
+./dict_open: internal:name lookup: "k" = "v"
+k=v
+> first
+./dict_open: internal:name sequence: "k" = "v"
+k=v
+> next
+./dict_open: internal:name sequence: found EOF
+not found
+> del k
+./dict_open: internal:name delete: "k": success
+k: deleted
+> get k
+./dict_open: internal:name lookup: "k" = "not_found"
+k: not found
+> del k
+./dict_open: internal:name delete: "k": failed
+k: not found
+> first
+./dict_open: internal:name sequence: found EOF
+not found
++ ./dict_open 'debug:fail:{oh no}' read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: fail:{oh no} lookup: "k" = "error"
+k: error
+> first
+./dict_open: fail:{oh no} sequence: found EOF
+error
--- /dev/null
+#!/bin/sh
+set -ex
+! ${VALGRIND} ./dict_open 'debug:' read </dev/null || exit 1
+! ${VALGRIND} ./dict_open 'debug:missing_colon_and_name' read </dev/null || exit 1
+${VALGRIND} ./dict_open 'debug:static:{space in name}' read <<EOF
+get k
+EOF
+${VALGRIND} ./dict_open 'debug:debug:static:value' read <<EOF
+get k
+EOF
+${VALGRIND} ./dict_open 'debug:internal:name' write <<EOF
+get k
+put k=v
+get k
+first
+next
+del k
+get k
+del k
+first
+EOF
+${VALGRIND} ./dict_open 'debug:fail:{oh no}' read <<EOF
+get k
+first
+EOF
if (dict_flags & DICT_FLAG_FOLD_FIX)
dict->fold_buf = vstring_alloc(10);
dict->owner.status = DICT_OWNER_TRUSTED;
- return (DICT_DEBUG (dict));
+ return (dict);
}
dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dp->dict_errno = DICT_ERR_RETRY;
dp->dict.owner.status = DICT_OWNER_TRUSTED;
- return (DICT_DEBUG (&dp->dict));
+ return (&dp->dict);
}
dict->owner.status = DICT_OWNER_TRUSTED;
dict_file_purge_buffers(dict);
- DICT_INLINE_RETURN(DICT_DEBUG (dict));
+ DICT_INLINE_RETURN(dict);
}
dict_lmdb_notify((void *) dict_lmdb, MDB_SUCCESS,
slmdb_curr_limit(&dict_lmdb->slmdb));
- DICT_LMDB_OPEN_RETURN(DICT_DEBUG (&dict_lmdb->dict));
+ DICT_LMDB_OPEN_RETURN(&dict_lmdb->dict);
}
#endif
d->dict.fold_buf = vstring_alloc(10);
d->dict.owner.status = DICT_OWNER_TRUSTED;
- return (DICT_DEBUG (&d->dict));
+ return (&d->dict);
}
#endif
if (dict_nis_domain == 0)
dict_nis_init();
dict_nis->dict.owner.status = DICT_OWNER_TRUSTED;
- return (DICT_DEBUG (&dict_nis->dict));
+ return (&dict_nis->dict);
}
#endif
if (msg_verbose)
msg_info("%s: opened NIS+ table %s for column %d",
myname, dict_nisplus->template, dict_nisplus->column);
- return (DICT_DEBUG (&dict_nisplus->dict));
+ return (&dict_nisplus->dict);
}
#endif
#include <msg.h>
#include <dict.h>
#include <dict_cdb.h>
+#include <dict_debug.h>
#include <dict_env.h>
#include <dict_unix.h>
#include <dict_tcp.h>
DICT_TYPE_LMDB, dict_lmdb_open, mkmap_lmdb_open,
#endif
#endif /* !USE_DYNAMIC_MAPS */
+ DICT_TYPE_DEBUG, dict_debug_open, 0,
0,
};
(void) mvect_free(&mvect);
dict_file_purge_buffers(&dict_pcre->dict);
- DICT_PCRE_OPEN_RETURN(DICT_DEBUG (&dict_pcre->dict));
+ DICT_PCRE_OPEN_RETURN(&dict_pcre->dict);
}
#endif /* HAS_PCRE */
reg_name_buf = 0;
dict_pipe->map_pipe = argv;
argv = 0;
- DICT_PIPE_RETURN(DICT_DEBUG (&dict_pipe->dict));
+ DICT_PIPE_RETURN(&dict_pipe->dict);
}
"%s", err));
}
dict_file_purge_buffers(&dict_random->dict);
- DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict));
+ DICT_RANDOM_RETURN(&dict_random->dict);
}
(regmatch_t *) mymalloc(sizeof(regmatch_t) * (max_sub + 1));
dict_file_purge_buffers(&dict_regexp->dict);
- DICT_REGEXP_OPEN_RETURN(DICT_DEBUG (&dict_regexp->dict));
+ DICT_REGEXP_OPEN_RETURN(&dict_regexp->dict);
}
#endif
if ((dict_flags & DICT_FLAG_LOCK))
myfree(dbm_path);
- return (DICT_DEBUG (&dict_sdbm->dict));
+ return (&dict_sdbm->dict);
}
#endif
/* Don't look up parent domains or network superblocks. */
dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
- DICT_SOCKMAP_OPEN_RETURN(DICT_DEBUG (&dp->dict));
+ DICT_SOCKMAP_OPEN_RETURN(&dp->dict);
}
dict_static->value = mystrdup(value);
dict_file_purge_buffers(&dict_static->dict);
- DICT_STATIC_OPEN_RETURN(DICT_DEBUG (&(dict_static->dict)));
+ DICT_STATIC_OPEN_RETURN(&(dict_static->dict));
}
vstring_vsprintf(buf, fmt, ap2);
va_end(ap2);
dp->reason = vstring_export(buf);
- return (DICT_DEBUG (&dp->dict));
+ return (&dp->dict);
}
if (dict_flags & DICT_FLAG_FOLD_MUL)
dict_tcp->dict.fold_buf = vstring_alloc(10);
- return (DICT_DEBUG (&dict_tcp->dict));
+ return (&dict_tcp->dict);
}
dict->owner.uid = st.st_uid;
dict->owner.status = (st.st_uid != 0);
- DICT_THASH_OPEN_RETURN(DICT_DEBUG (dict));
+ DICT_THASH_OPEN_RETURN(dict);
}
reg_name_buf = 0;
dict_union->map_union = argv;
argv = 0;
- DICT_UNION_RETURN(DICT_DEBUG (&dict_union->dict));
+ DICT_UNION_RETURN(&dict_union->dict);
}
dict_unix->dict.fold_buf = vstring_alloc(10);
dict_unix->dict.owner.status = DICT_OWNER_TRUSTED;
- return (DICT_DEBUG (&dict_unix->dict));
+ return (&dict_unix->dict);
}