summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2022-03-20 14:20:13 +0000
committerJeremy Harris <jgh146exb@wizmail.org>2022-03-28 12:32:47 +0100
commit0cc804c87799fb5902e66d5bd537a762f786dc2a (patch)
tree326d1999bab0b060d3abf4a4f7aa8b65426a9ae0
parentc3d6f1ff09458b3e7619f9bc4799aec0ab5fc2f2 (diff)
downloadexim4-0cc804c87799fb5902e66d5bd537a762f786dc2a.tar.gz
Hints DB interface: convert from macros to inlinable functions.
Testing status: tdb, dbm, gdbm & ndbm build and pass testsuite.
-rw-r--r--src/Makefile1
-rw-r--r--src/OS/Makefile-Base6
-rw-r--r--src/exim_monitor/em_hdr.h3
-rwxr-xr-xsrc/scripts/MakeLinks4
-rw-r--r--src/src/buildconfig.c5
-rw-r--r--src/src/dbfn.c85
-rw-r--r--src/src/dbfunctions.h9
-rw-r--r--src/src/dbstuff.h724
-rw-r--r--src/src/exim.h3
-rw-r--r--src/src/exim_dbmbuild.c62
-rw-r--r--src/src/exim_dbutil.c83
-rw-r--r--src/src/filter.c10
-rw-r--r--src/src/hintsdb.h805
-rw-r--r--src/src/hintsdb_structs.h189
-rw-r--r--src/src/lookups/dbmdb.c21
-rw-r--r--src/src/perl.c4
-rw-r--r--src/src/transports/autoreply.c37
17 files changed, 1128 insertions, 923 deletions
diff --git a/src/Makefile b/src/Makefile
index 3aa3cc374..a48938023 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -102,6 +102,7 @@ distclean:; $(RM_COMMAND) -rf build-* cscope*
cscope.files: FRC
echo "-q" > $@
echo "-p3" >> $@
+ -bd=build-$(buildname); [ -d $$bd ] && echo -e "$$bd/config.h\n$$bd/Makefile" >> $@
find src Local OS exim_monitor -name "*.[cshyl]" -print \
-o -name "os.[ch]*" -print \
-o -name "*akefile*" -print \
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index 612db7a9c..cab56cc38 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -635,11 +635,12 @@ eximon.bin: $(EXIMON_EDITME) eximon $(OBJ_MONBIN) ../exim_monitor/em_version.c \
HDRS = blob.h \
config.h \
dbfunctions.h \
- dbstuff.h \
exim.h \
functions.h \
globals.h \
hash.h \
+ hintsdb.h \
+ hintsdb_structs.h \
local_scan.h \
macros.h \
mytypes.h \
@@ -648,10 +649,11 @@ HDRS = blob.h \
os.h
PHDRS = ../config.h \
../dbfunctions.h \
- ../dbstuff.h \
../exim.h \
../functions.h \
../globals.h \
+ ../hintsdb.h \
+ ../hintsdb_structs.h \
../local_scan.h \
../macros.h \
../mytypes.h \
diff --git a/src/exim_monitor/em_hdr.h b/src/exim_monitor/em_hdr.h
index 87e4fc6df..ee05815df 100644
--- a/src/exim_monitor/em_hdr.h
+++ b/src/exim_monitor/em_hdr.h
@@ -102,7 +102,8 @@ typedef void hctx;
#include "structs.h"
#include "blob.h"
#include "globals.h"
-#include "dbstuff.h"
+#include "hintsdb.h"
+#include "hintsdb_structs.h"
#include "functions.h"
#include "osfunctions.h"
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index 4a714e147..35bb755d5 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -95,8 +95,8 @@ cd ..
# but local_scan.c does not, because its location is taken from the build-time
# configuration. Likewise for the os.c file, which gets build dynamically.
-for f in blob.h dbfunctions.h dbstuff.h exim.h functions.h globals.h \
- hash.h local_scan.h \
+for f in blob.h dbfunctions.h exim.h functions.h globals.h \
+ hash.h hintsdb.h hintsdb_structs.h local_scan.h \
macros.h mytypes.h osfunctions.h store.h structs.h lookupapi.h sha_ver.h \
\
acl.c buildconfig.c base64.c child.c crypt16.c daemon.c dbfn.c debug.c \
diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c
index a1b5485cd..a7f5812b2 100644
--- a/src/src/buildconfig.c
+++ b/src/src/buildconfig.c
@@ -221,8 +221,7 @@ else
/* Now search the makefile for certain settings */
-base = fopen("Makefile", "rb");
-if (base == NULL)
+if (!(base = fopen("Makefile", "rb")))
{
printf("*** Buildconfig: failed to open Makefile\n");
(void)fclose(new);
@@ -387,7 +386,6 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
encountered. */
for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
- {
if (strcmp(name, db_opts[i]) == 0)
{
if (use_which_db == i)
@@ -397,7 +395,6 @@ while (fgets(buffer, sizeof(buffer), base) != NULL)
fprintf(new, "/* %s not set */\n", name);
break;
}
- }
if (i < sizeof(db_opts)/sizeof(char *)) continue;
/* EXIM_USER is a special case. We look in the environment for EXIM_USER or
diff --git a/src/src/dbfn.c b/src/src/dbfn.c
index a9bc892d4..600da18c4 100644
--- a/src/src/dbfn.c
+++ b/src/src/dbfn.c
@@ -39,31 +39,6 @@ arrange to hold the locks for the bare minimum of time. */
/*************************************************
-* Berkeley DB error callback *
-*************************************************/
-
-/* For Berkeley DB >= 2, we can define a function to be called in case of DB
-errors. This should help with debugging strange DB problems, e.g. getting "File
-exists" when you try to open a db file. The API for this function was changed
-at DB release 4.3. */
-
-#if defined(USE_DB) && defined(DB_VERSION_STRING)
-void
-# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
-{
-dbenv = dbenv;
-# else
-dbfn_bdb_error_callback(const char *pfx, char *msg)
-{
-# endif
-pfx = pfx;
-log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
-}
-#endif
-
-
-/*************************************************
* Open and lock a database file *
*************************************************/
@@ -172,12 +147,12 @@ open call. */
snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
priv_drop_temp(exim_uid, exim_gid);
-EXIM_DBOPEN(filename, dirname, flags, EXIMDB_MODE, &(dbblock->dbptr));
+dbblock->dbptr = exim_dbopen(filename, dirname, flags, EXIMDB_MODE);
if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
{
DEBUG(D_hints_lookup)
debug_printf_indent("%s appears not to exist: trying to create\n", filename);
- EXIM_DBOPEN(filename, dirname, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
+ dbblock->dbptr = exim_dbopen(filename, dirname, flags|O_CREAT, EXIMDB_MODE);
}
save_errno = errno;
priv_restore();
@@ -232,7 +207,7 @@ Returns: nothing
void
dbfn_close(open_db *dbblock)
{
-EXIM_DBCLOSE(dbblock->dbptr);
+exim_dbclose(dbblock->dbptr);
(void)close(dbblock->lockfd);
DEBUG(D_hints_lookup)
{ debug_printf_indent("closed hints database and lockfile\n"); acl_level--; }
@@ -274,21 +249,21 @@ memcpy(key_copy, key, klen);
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%s\n", key);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(result_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&result_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
-if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
+if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL;
/* Assume the data store could have been tainted. Properly, we should
store the taint status with the data. */
-yield = store_get(EXIM_DATUM_SIZE(result_datum), GET_TAINTED);
-memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
-if (length) *length = EXIM_DATUM_SIZE(result_datum);
+yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED);
+memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum));
+if (length) *length = exim_datum_size_get(&result_datum);
-EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */
+exim_datum_free(&result_datum); /* Some DBM libs require freeing */
return yield;
}
@@ -350,13 +325,13 @@ gptr->time_stamp = time(NULL);
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_write: key=%s\n", key);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-EXIM_DATUM_DATA(value_datum) = (void *) ptr;
-EXIM_DATUM_SIZE(value_datum) = length;
-return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+exim_datum_data_set(&value_datum, ptr);
+exim_datum_size_set(&value_datum, length);
+return exim_dbput(dbblock->dbptr, &key_datum, &value_datum);
}
@@ -378,15 +353,15 @@ dbfn_delete(open_db *dbblock, const uschar *key)
{
int klen = Ustrlen(key) + 1;
uschar * key_copy = store_get(klen, key);
+EXIM_DATUM key_datum;
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key);
memcpy(key_copy, key, klen);
-EXIM_DATUM key_datum;
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require clearing */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-return EXIM_DBDEL(dbblock->dbptr, key_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require clearing */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+return exim_dbdel(dbblock->dbptr, &key_datum);
}
@@ -417,17 +392,17 @@ DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n");
/* Some dbm require an initialization */
-if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor);
+if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
-yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))?
- US EXIM_DATUM_DATA(key_datum) : NULL;
+yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor)
+ ? US exim_datum_data_get(&key_datum) : NULL;
/* Some dbm require a termination */
-if (!yield) EXIM_DBDELETE_CURSOR(*cursor);
+if (!yield) exim_dbdelete_cursor(*cursor);
return yield;
}
diff --git a/src/src/dbfunctions.h b/src/src/dbfunctions.h
index f3b04ad2f..384613981 100644
--- a/src/src/dbfunctions.h
+++ b/src/src/dbfunctions.h
@@ -5,6 +5,8 @@
/* Copyright (c) University of Cambridge 1995 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
+#ifndef DBFUNCTIONS_H
+#define DBFUNCTIONS_H
/* Functions for reading/writing exim database files */
@@ -24,11 +26,12 @@ int dbfn_write(open_db *, const uschar *, void *, int);
changed at release 4.3. */
#if defined(USE_DB) && defined(DB_VERSION_STRING)
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
+# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
void dbfn_bdb_error_callback(const DB_ENV *, const char *, const char *);
-#else
+# else
void dbfn_bdb_error_callback(const char *, char *);
-#endif
+# endif
#endif
+#endif
/* End of dbfunctions.h */
diff --git a/src/src/dbstuff.h b/src/src/dbstuff.h
deleted file mode 100644
index 8ebf6f6e4..000000000
--- a/src/src/dbstuff.h
+++ /dev/null
@@ -1,724 +0,0 @@
-/*************************************************
-* Exim - an Internet mail transport agent *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* This header file contains macro definitions so that a variety of DBM
-libraries can be used by Exim. Nigel Metheringham provided the original set for
-Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
-2.x and 3.x were added. Later still, support for tdb was added, courtesy of
-James Antill. Most recently, support for native mode gdbm was added, with code
-from Pierre A. Humblet, so Exim could be made to work with Cygwin.
-
-For convenience, the definitions of the structures used in the various hints
-databases are also kept in this file, which is used by the maintenance
-utilities as well as the main Exim binary. */
-
-
-#ifdef USE_TDB
-
-/* ************************* tdb interface ************************ */
-
-# include <tdb.h>
-
-/* Basic DB type */
-# define EXIM_DB TDB_CONTEXT
-
-/* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
-tdb_traverse to be called) */
-# define EXIM_CURSOR TDB_DATA
-
-/* The datum type used for queries */
-# define EXIM_DATUM TDB_DATA
-
-/* Some text for messages */
-# define EXIM_DBTYPE "tdb"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- *(dbpp) = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode)
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
- (data = tdb_fetch(db, key), data.dptr != NULL)
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-# define EXIM_DBPUT(db, key, data) \
- tdb_store(db, key, data, TDB_REPLACE)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-# define EXIM_DBPUTB(db, key, data) \
- tdb_store(db, key, data, TDB_INSERT)
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP (-1)
-
-/* EXIM_DBDEL */
-# define EXIM_DBDEL(db, key) tdb_delete(db, key)
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-# define EXIM_DBCREATE_CURSOR(db, cursor) { \
- *(cursor) = store_malloc(sizeof(TDB_DATA)); (*(cursor))->dptr = NULL; }
-
-/* EXIM_DBSCAN - This is complicated because we have to free the last datum
-free() must not die when passed NULL */
-# define EXIM_DBSCAN(db, key, data, first, cursor) \
- (key = (first ? tdb_firstkey(db) : tdb_nextkey(db, *(cursor))), \
- free((cursor)->dptr), *(cursor) = key, \
- key.dptr != NULL)
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
-# define EXIM_DBDELETE_CURSOR(cursor) store_free(cursor)
-
-/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) tdb_close(db)
-
-/* Datum access types - these are intended to be assignable */
-
-# define EXIM_DATUM_SIZE(datum) (datum).dsize
-# define EXIM_DATUM_DATA(datum) (datum).dptr
-
-/* Free the stuff inside the datum. */
-
-# define EXIM_DATUM_FREE(datum) (free((datum).dptr), (datum).dptr = NULL)
-
-/* No initialization is needed. */
-
-# define EXIM_DATUM_INIT(datum)
-
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-
-
-
-
-
-/********************* Berkeley db native definitions **********************/
-
-#elif defined USE_DB
-
-# include <db.h>
-
-
-/* We can distinguish between versions 1.x and 2.x/3.x by looking for a
-definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
-
-# ifdef DB_VERSION_STRING
-
-# if DB_VERSION_MAJOR >= 6
-# error Version 6 and later BDB API is not supported
-# endif
-
-/* The API changed (again!) between the 2.x and 3.x versions */
-
-# if DB_VERSION_MAJOR >= 3
-
-/***************** Berkeley db 3.x/4.x native definitions ******************/
-
-/* Basic DB type */
-# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
-# define EXIM_DB DB_ENV
-/* Cursor type, for scanning */
-# define EXIM_CURSOR DBC
-
-/* The datum type used for queries */
-# define EXIM_DATUM DBT
-
-/* Some text for messages */
-# define EXIM_DBTYPE "db (v4.1+)"
-
-/* Only more-recent versions. 5+ ? */
-# ifndef DB_FORCESYNC
-# define DB_FORCESYNC 0
-# endif
-
-
-/* Access functions */
-
-/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. The
-API changed for DB 4.1. - and we also starting using the "env" with a
-specified working dir, to avoid the DBCONFIG file trap. */
-
-# define ENV_TO_DB(env) ((DB *)((env)->app_private))
-
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- if ( db_env_create(dbpp, 0) != 0 \
- || ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), 0) \
- || (*dbpp)->open(*dbpp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0\
- ) \
- *dbpp = NULL; \
- else if (db_create((DB **) &((*dbpp)->app_private), *dbpp, 0) != 0) \
- { \
- ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \
- *dbpp = NULL; \
- } \
- else if (ENV_TO_DB(*dbpp)->open(ENV_TO_DB(*dbpp), NULL, CS name, NULL, \
- (flags) == O_RDONLY ? DB_UNKNOWN : DB_HASH, \
- (flags) == O_RDONLY ? DB_RDONLY : DB_CREATE, \
- mode) != 0 \
- ) \
- { \
- ENV_TO_DB(*dbpp)->close(ENV_TO_DB(*dbpp), 0); \
- ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \
- *dbpp = NULL; \
- }
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
- (ENV_TO_DB(db)->get(ENV_TO_DB(db), NULL, &key, &data, 0) == 0)
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-# define EXIM_DBPUT(db, key, data) \
- ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, 0)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-# define EXIM_DBPUTB(db, key, data) \
- ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, DB_NOOVERWRITE)
-
-/* Return values from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP DB_KEYEXIST
-
-/* EXIM_DBDEL */
-# define EXIM_DBDEL(db, key) ENV_TO_DB(db)->del(ENV_TO_DB(db), NULL, &key, 0)
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-
-# define EXIM_DBCREATE_CURSOR(db, cursor) \
- ENV_TO_DB(db)->cursor(ENV_TO_DB(db), NULL, cursor, 0)
-
-/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-# define EXIM_DBSCAN(db, key, data, first, cursor) \
- ((cursor)->c_get(cursor, &key, &data, \
- (first? DB_FIRST : DB_NEXT)) == 0)
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-# define EXIM_DBDELETE_CURSOR(cursor) \
- (cursor)->c_close(cursor)
-
-/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) \
- (ENV_TO_DB(db)->close(ENV_TO_DB(db), 0) , ((DB_ENV *)(db))->close((DB_ENV *)(db), DB_FORCESYNC))
-
-/* Datum access types - these are intended to be assignable. */
-
-# define EXIM_DATUM_SIZE(datum) (datum).size
-# define EXIM_DATUM_DATA(datum) (datum).data
-
-/* The whole datum structure contains other fields that must be cleared
-before use, but we don't have to free anything after reading data. */
-
-# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
-# define EXIM_DATUM_FREE(datum)
-
-# else /* pre- 4.1 */
-
-# define EXIM_DB DB
-
-/* Cursor type, for scanning */
-# define EXIM_CURSOR DBC
-
-/* The datum type used for queries */
-# define EXIM_DATUM DBT
-
-/* Some text for messages */
-# define EXIM_DBTYPE "db (v3/4)"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. */
-
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- if (db_create(dbpp, NULL, 0) != 0 || \
- ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \
- ((*dbpp)->open)(*dbpp, CS name, NULL, \
- ((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \
- ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
- mode)) != 0) *(dbpp) = NULL
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
- ((db)->get(db, NULL, &key, &data, 0) == 0)
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-# define EXIM_DBPUT(db, key, data) \
- (db)->put(db, NULL, &key, &data, 0)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-# define EXIM_DBPUTB(db, key, data) \
- (db)->put(db, NULL, &key, &data, DB_NOOVERWRITE)
-
-/* Return values from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP DB_KEYEXIST
-
-/* EXIM_DBDEL */
-# define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0)
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-
-# define EXIM_DBCREATE_CURSOR(db, cursor) \
- (db)->cursor(db, NULL, cursor, 0)
-
-/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-# define EXIM_DBSCAN(db, key, data, first, cursor) \
- ((cursor)->c_get(cursor, &key, &data, \
- (first? DB_FIRST : DB_NEXT)) == 0)
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-# define EXIM_DBDELETE_CURSOR(cursor) \
- (cursor)->c_close(cursor)
-
-/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) (db)->close(db, 0)
-
-/* Datum access types - these are intended to be assignable. */
-
-# define EXIM_DATUM_SIZE(datum) (datum).size
-# define EXIM_DATUM_DATA(datum) (datum).data
-
-/* The whole datum structure contains other fields that must be cleared
-before use, but we don't have to free anything after reading data. */
-
-# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
-# define EXIM_DATUM_FREE(datum)
-
-# endif
-
-
-# else /* DB_VERSION_MAJOR >= 3 */
-# error Berkeley DB versions earlier than 3 are not supported */
-# endif /* DB_VERSION_MAJOR */
-# else
-# error Berkeley DB version 1 is no longer supported
-# endif /* DB_VERSION_STRING */
-
-
-/* all BDB versions */
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-
-
-
-
-
-/********************* gdbm interface definitions **********************/
-
-#elif defined USE_GDBM
-
-# include <gdbm.h>
-
-/* Basic DB type */
-typedef struct {
- GDBM_FILE gdbm; /* Database */
- datum lkey; /* Last key, for scans */
-} gdbm_db;
-
-#define EXIM_DB gdbm_db
-
-/* Cursor type, not used with gdbm: just set up a dummy */
-# define EXIM_CURSOR int
-
-/* The datum type used for queries */
-# define EXIM_DATUM datum
-
-/* Some text for messages */
-
-# define EXIM_DBTYPE "gdbm"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- { EXIM_DB * dbp = malloc(sizeof(EXIM_DB));\
- if (dbp) { \
- dbp->lkey.dptr = NULL;\
- dbp->gdbm = gdbm_open(CS name, 0, (((flags) & O_CREAT))?GDBM_WRCREAT:(((flags) & (O_RDWR|O_WRONLY))?GDBM_WRITER:GDBM_READER), (mode), 0);\
- if (!dbp->gdbm) {\
- free(dbp);\
- dbp = NULL;\
- }\
- }\
- *(dbpp) = dbp;\
- }
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
- (data = gdbm_fetch(db->gdbm, key), data.dptr != NULL)
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-# define EXIM_DBPUT(db, key, data) \
- gdbm_store(db->gdbm, key, data, GDBM_REPLACE)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-# define EXIM_DBPUTB(db, key, data) \
- gdbm_store(db->gdbm, key, data, GDBM_INSERT)
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP 1
-
-/* EXIM_DBDEL */
-# define EXIM_DBDEL(db, key) gdbm_delete(db->gdbm, key)
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-# define EXIM_DBCREATE_CURSOR(db, cursor) {}
-
-/* EXIM_DBSCAN */
-# define EXIM_DBSCAN(db, key, data, first, cursor) \
- ( key = ((first)? gdbm_firstkey(db->gdbm) : gdbm_nextkey(db->gdbm, db->lkey)), \
- (((db)->lkey.dptr != NULL)? (free((db)->lkey.dptr),1) : 1),\
- db->lkey = key, key.dptr != NULL)
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
-# define EXIM_DBDELETE_CURSOR(cursor) { }
-
-/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) \
-{ gdbm_close((db)->gdbm);\
- if ((db)->lkey.dptr != NULL) free((db)->lkey.dptr);\
- free(db); }
-
-/* Datum access types - these are intended to be assignable */
-
-# define EXIM_DATUM_SIZE(datum) (datum).dsize
-# define EXIM_DATUM_DATA(datum) (datum).dptr
-
-/* There's no clearing required before use, but we have to free the dptr
-after reading data. */
-
-# define EXIM_DATUM_INIT(datum)
-# define EXIM_DATUM_FREE(datum) free(datum.dptr)
-
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-#else /* USE_GDBM */
-
-
-
-
-
-
-/* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
-interface */
-
-
-/********************* ndbm interface definitions **********************/
-
-# include <ndbm.h>
-
-/* Basic DB type */
-# define EXIM_DB DBM
-
-/* Cursor type, not used with ndbm: just set up a dummy */
-# define EXIM_CURSOR int
-
-/* The datum type used for queries */
-# define EXIM_DATUM datum
-
-/* Some text for messages */
-
-# define EXIM_DBTYPE "ndbm"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-/* Check that the name given is not present. This catches
-a directory name; otherwise we would create the name.pag and
-name.dir files in the directory's parent. */
-
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- { \
- struct stat st; \
- *(dbpp) = !(flags & O_CREAT) \
- || lstat(CCS (name), &st) != 0 && errno == ENOENT \
- ? dbm_open(CS (name), (flags), (mode)) \
- : (errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST, \
- NULL); \
- }
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
- (data = dbm_fetch(db, key), data.dptr != NULL)
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-# define EXIM_DBPUT(db, key, data) \
- dbm_store(db, key, data, DBM_REPLACE)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-# define EXIM_DBPUTB(db, key, data) \
- dbm_store(db, key, data, DBM_INSERT)
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP 1
-
-/* EXIM_DBDEL */
-# define EXIM_DBDEL(db, key) dbm_delete(db, key)
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-# define EXIM_DBCREATE_CURSOR(db, cursor) {}
-
-/* EXIM_DBSCAN */
-# define EXIM_DBSCAN(db, key, data, first, cursor) \
- (key = (first? dbm_firstkey(db) : dbm_nextkey(db)), key.dptr != NULL)
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
-# define EXIM_DBDELETE_CURSOR(cursor) { }
-
-/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) dbm_close(db)
-
-/* Datum access types - these are intended to be assignable */
-
-# define EXIM_DATUM_SIZE(datum) (datum).dsize
-# define EXIM_DATUM_DATA(datum) (datum).dptr
-
-/* There's no clearing required before use, and we don't have to free anything
-after reading data. */
-
-# define EXIM_DATUM_INIT(datum)
-# define EXIM_DATUM_FREE(datum)
-
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-#endif /* USE_GDBM */
-
-
-
-
-
-#ifdef COMPILE_UTILITY
-
-# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
- EXIM_DBOPEN__(name, dirname, flags, mode, dbpp)
-# define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db)
-
-#else
-
-# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
- do { \
- DEBUG(D_hints_lookup) \
- debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n", \
- (name), (dirname), \
- (flags) == O_RDONLY ? "O_RDONLY" \
- : (flags) == O_RDWR ? "O_RDWR" \
- : (flags) == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT" \
- : "??"); \
- if (is_tainted(name) || is_tainted(dirname)) \
- { \
- log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); \
- *dbpp = NULL; \
- } \
- else \
- { EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); } \
- DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", *dbpp); \
- } while(0)
-# define EXIM_DBCLOSE(db) \
- do { \
- DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", db); \
- EXIM_DBCLOSE__(db); \
- } while(0)
-
-# endif
-
-#ifndef EXIM_DB
-# define EXIM_DB void /* dummy */
-#endif
-#ifndef EXIM_CURSOR
-# define EXIM_CURSOR void /* dummy */
-#endif
-/********************* End of dbm library definitions **********************/
-
-
-/* Structure for carrying around an open DBM file, and an open locking file
-that relates to it. */
-
-typedef struct {
- EXIM_DB *dbptr;
- int lockfd;
-} open_db;
-
-
-/* Structures for records stored in exim database dbm files. They all
-start with the same fields, described in the generic type. */
-
-
-typedef struct {
- time_t time_stamp; /* Timestamp of writing */
-} dbdata_generic;
-
-
-/* This structure keeps track of retry information for a host or a local
-address. */
-
-typedef struct {
- time_t time_stamp;
- /*************/
- time_t first_failed; /* Time of first failure */
- time_t last_try; /* Time of last try */
- time_t next_try; /* Time of next try */
- BOOL expired; /* Retry time has expired */
- int basic_errno; /* Errno of last failure */
- int more_errno; /* Additional information */
- uschar text[1]; /* Text message for last failure */
-} dbdata_retry;
-
-/* These structures keep track of addresses that have had callout verification
-performed on them. There are two groups of records:
-
-1. keyed by localpart@domain -
- Full address was tested and record holds result
-
-2. keyed by domain -
- Domain response upto MAIL FROM:<>, postmaster, random local part;
-
-If a record exists, the result field is either ccache_accept or ccache_reject,
-or, for a domain record only, ccache_reject_mfnull when MAIL FROM:<> was
-rejected. The other fields, however, (which are only relevant to domain
-records) may also contain ccache_unknown if that particular test has not been
-done.
-
-Originally, there was only one structure, used for both types. However, it got
-expanded for domain records, so it got split. To make it possible for Exim to
-handle the old type of record, we retain the old definition. The different
-kinds of record can be distinguished by their different lengths. */
-
-typedef struct {
- time_t time_stamp;
- /*************/
- int result;
- int postmaster_result; /* Postmaster is accepted */
- int random_result; /* Random local part was accepted */
-} dbdata_callout_cache_obs;
-
-typedef struct {
- time_t time_stamp; /* Timestamp of last address check */
- /*************/
- int result; /* accept or reject */
-} dbdata_callout_cache_address;
-
-/* For this new layout, we put the additional fields (the timestamps)
-last so that if somebody reverts to an older Exim, the new records will
-still make sense because they match the old layout. */
-
-typedef struct {
- time_t time_stamp; /* Time stamp of last connection */
- /*************/
- int result; /* Domain reject or accept */
- int postmaster_result; /* Postmaster result */
- int random_result; /* Random result */
- time_t postmaster_stamp; /* Timestamp of postmaster check */
- time_t random_stamp; /* Timestamp of random check */
-} dbdata_callout_cache;
-
-/* This structure keeps track of messages that are waiting for a particular
-host for a particular transport. */
-
-typedef struct {
- time_t time_stamp;
- /*************/
- int count; /* Count of message ids */
- int sequence; /* Sequence for continued records */
- uschar text[1]; /* One long character string */
-} dbdata_wait;
-
-
-/* The contents of the "misc" database are a mixture of different kinds of
-record, as defined below. The keys used for a specific type all start with a
-given string such as "etrn-" or "host-serialize-". */
-
-
-/* This structure records a connection to a particular host, for the
-purpose of serializing access to certain hosts. For possible future extension,
-a field is defined for holding the count of connections, but it is not
-at present in use. The same structure is used for recording a running ETRN
-process. */
-
-typedef struct {
- time_t time_stamp;
- /*************/
- int count; /* Reserved for possible connection count */
-} dbdata_serialize;
-
-
-/* This structure records the information required for the ratelimit
-ACL condition. */
-
-typedef struct {
- time_t time_stamp;
- /*************/
- int time_usec; /* Fractional part of time, from gettimeofday() */
- double rate; /* Smoothed sending rate at that time */
-} dbdata_ratelimit;
-
-/* Same as above, plus a Bloom filter for uniquifying events. */
-
-typedef struct {
- dbdata_ratelimit dbd;
- time_t bloom_epoch; /* When the Bloom filter was last reset */
- unsigned bloom_size; /* Number of bytes in the Bloom filter */
- uschar bloom[40]; /* Bloom filter which may be larger than this */
-} dbdata_ratelimit_unique;
-
-
-/* For "seen" ACL condition */
-typedef struct {
- time_t time_stamp;
-} dbdata_seen;
-
-#ifndef DISABLE_PIPE_CONNECT
-/* This structure records the EHLO responses, cleartext and crypted,
-for an IP, as bitmasks (cf. OPTION_TLS). For LIMITS, also values
-advertised for MAILMAX, RCPTMAX and RCPTDOMAINMAX; zero meaning no
-value advertised. */
-
-typedef struct {
- unsigned short cleartext_features;
- unsigned short crypted_features;
- unsigned short cleartext_auths;
- unsigned short crypted_auths;
-
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
- unsigned int limit_mail;
- unsigned int limit_rcpt;
- unsigned int limit_rcptdom;
-# endif
-} ehlo_resp_precis;
-
-typedef struct {
- time_t time_stamp;
- /*************/
- ehlo_resp_precis data;
-} dbdata_ehlo_resp;
-#endif
-
-typedef struct {
- time_t time_stamp;
- /*************/
- uschar verify_override:1;
- uschar ocsp:3;
- uschar session[1];
-} dbdata_tls_session;
-
-
-/* End of dbstuff.h */
diff --git a/src/src/exim.h b/src/src/exim.h
index cf8f19eb6..2541baa3d 100644
--- a/src/src/exim.h
+++ b/src/src/exim.h
@@ -531,7 +531,8 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
#include "local_scan.h"
#include "macros.h"
-#include "dbstuff.h"
+#include "hintsdb.h"
+#include "hintsdb_structs.h"
#include "structs.h"
#include "blob.h"
#include "globals.h"
diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c
index 73ca10e90..b33864702 100644
--- a/src/src/exim_dbmbuild.c
+++ b/src/src/exim_dbmbuild.c
@@ -31,7 +31,7 @@ characters. */
#include "exim.h"
-uschar * spool_directory = NULL; /* dummy for dbstuff.h */
+uschar * spool_directory = NULL; /* dummy for hintsdb.h */
/******************************************************************************/
/* dummies needed by Solaris build */
@@ -106,26 +106,6 @@ return sys_errlist[n];
#endif /* STRERROR_FROM_ERRLIST */
-/* For Berkeley DB >= 2, we can define a function to be called in case of DB
-errors. This should help with debugging strange DB problems, e.g. getting "File
-exists" when you try to open a db file. The API changed at release 4.3. */
-
-#if defined(USE_DB) && defined(DB_VERSION_STRING)
-void
-# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
-{
-dbenv = dbenv;
-# else
-dbfn_bdb_error_callback(const char *pfx, char *msg)
-{
-# endif
-pfx = pfx;
-printf("Berkeley DB error: %s\n", msg);
-}
-#endif
-
-
/*************************************************
* Interpret escape sequence *
@@ -266,9 +246,7 @@ else
/* It is apparently necessary to open with O_RDWR for this to work
with gdbm-1.7.3, though no reading is actually going to be done. */
-EXIM_DBOPEN(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
-
-if (d == NULL)
+if (!(d = exim_dbopen(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644)))
{
printf("exim_dbmbuild: unable to create %s: %s\n", temp_dbmname,
strerror(errno));
@@ -347,11 +325,11 @@ while (Ufgets(line, max_insize, f) != NULL)
if (started)
{
- EXIM_DATUM_INIT(content);
- EXIM_DATUM_DATA(content) = (void *) buffer;
- EXIM_DATUM_SIZE(content) = bptr - buffer + add_zero;
+ exim_datum_init(&content);
+ exim_datum_data_set(&content, buffer);
+ exim_datum_size_set(&content, bptr - buffer + add_zero);
- switch(rc = EXIM_DBPUTB(d, key, content))
+ switch(rc = exim_dbputb(d, &key, &content))
{
case EXIM_DBPUTB_OK:
count++;
@@ -361,7 +339,7 @@ while (Ufgets(line, max_insize, f) != NULL)
if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
dupcount++;
if(duperr) yield = 1;
- if (lastdup) EXIM_DBPUT(d, key, content);
+ if (lastdup) exim_dbput(d, &key, &content);
break;
default:
@@ -374,8 +352,8 @@ while (Ufgets(line, max_insize, f) != NULL)
bptr = buffer;
}
- EXIM_DATUM_INIT(key);
- EXIM_DATUM_DATA(key) = (void *) keybuffer;
+ exim_datum_init(&key);
+ exim_datum_data_set(&key, keybuffer);
/* Deal with quoted keys. Escape sequences always make one character
out of several, so we can re-build in place. */
@@ -392,16 +370,16 @@ while (Ufgets(line, max_insize, f) != NULL)
s++;
}
if (*s != 0) s++; /* Past terminating " */
- EXIM_DATUM_SIZE(key) = t - keystart + add_zero;
+ exim_datum_size_set(&key, t - keystart + add_zero);
}
else
{
keystart = s;
while (*s != 0 && *s != ':' && !isspace(*s)) s++;
- EXIM_DATUM_SIZE(key) = s - keystart + add_zero;
+ exim_datum_size_set(&key, s - keystart + add_zero);
}
- if (EXIM_DATUM_SIZE(key) > 256)
+ if (exim_datum_size_get(&key) > 256)
{
printf("Keys longer than 255 characters cannot be handled\n");
started = 0;
@@ -410,10 +388,10 @@ while (Ufgets(line, max_insize, f) != NULL)
}
if (lowercase)
- for (i = 0; i < EXIM_DATUM_SIZE(key) - add_zero; i++)
+ for (i = 0; i < exim_datum_size_get(&key) - add_zero; i++)
keybuffer[i] = tolower(keystart[i]);
else
- for (i = 0; i < EXIM_DATUM_SIZE(key) - add_zero; i++)
+ for (i = 0; i < exim_datum_size_get(&key) - add_zero; i++)
keybuffer[i] = keystart[i];
keybuffer[i] = 0;
@@ -437,11 +415,11 @@ while (Ufgets(line, max_insize, f) != NULL)
if (started)
{
int rc;
- EXIM_DATUM_INIT(content);
- EXIM_DATUM_DATA(content) = (void *) buffer;
- EXIM_DATUM_SIZE(content) = bptr - buffer + add_zero;
+ exim_datum_init(&content);
+ exim_datum_data_set(&content, buffer);
+ exim_datum_size_set(&content, bptr - buffer + add_zero);
- switch(rc = EXIM_DBPUTB(d, key, content))
+ switch(rc = exim_dbputb(d, &key, &content))
{
case EXIM_DBPUTB_OK:
count++;
@@ -451,7 +429,7 @@ if (started)
if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
dupcount++;
if (duperr) yield = 1;
- if (lastdup) EXIM_DBPUT(d, key, content);
+ if (lastdup) exim_dbput(d, &key, &content);
break;
default:
@@ -466,7 +444,7 @@ if (started)
TIDYUP:
-EXIM_DBCLOSE(d);
+exim_dbclose(d);
(void)fclose(f);
/* If successful, output the number of entries and rename the temporary
diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c
index c536a2037..1d87cec17 100644
--- a/src/src/exim_dbutil.c
+++ b/src/src/exim_dbutil.c
@@ -85,31 +85,6 @@ BOOL allow_insecure_tainted_data;
/*************************************************
-* Berkeley DB error callback *
-*************************************************/
-
-/* For Berkeley DB >= 2, we can define a function to be called in case of DB
-errors. This should help with debugging strange DB problems, e.g. getting "File
-exists" when you try to open a db file. The API changed at release 4.3. */
-
-#if defined(USE_DB) && defined(DB_VERSION_STRING)
-void
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
-{
-dbenv = dbenv;
-#else
-dbfn_bdb_error_callback(const char *pfx, char *msg)
-{
-#endif
-pfx = pfx;
-printf("Berkeley DB error: %s\n", msg);
-}
-#endif
-
-
-
-/*************************************************
* SIGALRM handler *
*************************************************/
@@ -364,7 +339,7 @@ if (asprintf(CSS &filename, "%s/%s", dirname, name) < 0) return NULL;
#else
filename = string_sprintf("%s/%s", dirname, name);
#endif
-EXIM_DBOPEN(filename, dirname, flags, 0, &dbblock->dbptr);
+dbblock->dbptr = exim_dbopen(filename, dirname, flags, 0);
if (!dbblock->dbptr)
{
@@ -400,7 +375,7 @@ Returns: nothing
void
dbfn_close(open_db *dbblock)
{
-EXIM_DBCLOSE(dbblock->dbptr);
+exim_dbclose(dbblock->dbptr);
(void)close(dbblock->lockfd);
}
@@ -434,21 +409,21 @@ uschar * key_copy = store_get(klen, key);
memcpy(key_copy, key, klen);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(result_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&result_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
-if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
+if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL;
/* Assume for now that anything stored could have been tainted. Properly
we should store the taint status along with the data. */
-yield = store_get(EXIM_DATUM_SIZE(result_datum), GET_TAINTED);
-memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
-if (length) *length = EXIM_DATUM_SIZE(result_datum);
+yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED);
+memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum));
+if (length) *length = exim_datum_size_get(&result_datum);
-EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */
+exim_datum_free(&result_datum); /* Some DBM libs require freeing */
return yield;
}
@@ -482,13 +457,13 @@ uschar * key_copy = store_get(klen, key);
memcpy(key_copy, key, klen);
gptr->time_stamp = time(NULL);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-EXIM_DATUM_DATA(value_datum) = (void *) ptr;
-EXIM_DATUM_SIZE(value_datum) = length;
-return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+exim_datum_data_set(&value_datum, ptr);
+exim_datum_size_set(&value_datum, length);
+return exim_dbput(dbblock->dbptr, &key_datum, &value_datum);
}
@@ -510,13 +485,13 @@ dbfn_delete(open_db *dbblock, const uschar *key)
{
int klen = Ustrlen(key) + 1;
uschar * key_copy = store_get(klen, key);
+EXIM_DATUM key_datum;
memcpy(key_copy, key, klen);
-EXIM_DATUM key_datum;
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require clearing */
-EXIM_DATUM_DATA(key_datum) = (void *) key_copy;
-EXIM_DATUM_SIZE(key_datum) = klen;
-return EXIM_DBDEL(dbblock->dbptr, key_datum);
+exim_datum_init(&key_datum); /* Some DBM libraries require clearing */
+exim_datum_data_set(&key_datum, key_copy);
+exim_datum_size_set(&key_datum, klen);
+return exim_dbdel(dbblock->dbptr, &key_datum);
}
#endif /* EXIM_TIDYDB || EXIM_FIXDB */
@@ -548,17 +523,17 @@ uschar *yield;
/* Some dbm require an initialization */
-if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor);
+if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr);
-EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */
-EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */
+exim_datum_init(&key_datum); /* Some DBM libraries require the datum */
+exim_datum_init(&value_datum); /* to be cleared before use. */
-yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))?
- US EXIM_DATUM_DATA(key_datum) : NULL;
+yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor)
+ ? US exim_datum_data_get(&key_datum) : NULL;
/* Some dbm require a termination */
-if (!yield) EXIM_DBDELETE_CURSOR(*cursor);
+if (!yield) exim_dbdelete_cursor(*cursor);
return yield;
}
#endif /* EXIM_DUMPDB || EXIM_TIDYDB */
diff --git a/src/src/filter.c b/src/src/filter.c
index 629bbf536..210f7b0e2 100644
--- a/src/src/filter.c
+++ b/src/src/filter.c
@@ -1290,18 +1290,18 @@ switch (command)
if (command == vacation_command)
{
- if (new->args[mailarg_index_file].u == NULL)
+ if (!new->args[mailarg_index_file].u)
{
new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
}
- if (new->args[mailarg_index_log].u == NULL)
+ if (!new->args[mailarg_index_log].u)
new->args[mailarg_index_log].u = string_copy(US".vacation.log");
- if (new->args[mailarg_index_once].u == NULL)
+ if (!new->args[mailarg_index_once].u)
new->args[mailarg_index_once].u = string_copy(US".vacation");
- if (new->args[mailarg_index_once_repeat].u == NULL)
+ if (!new->args[mailarg_index_once_repeat].u)
new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
- if (new->args[mailarg_index_subject].u == NULL)
+ if (!new->args[mailarg_index_subject].u)
new->args[mailarg_index_subject].u = string_copy(US"On vacation");
}
diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h
new file mode 100644
index 000000000..de3e6e4aa
--- /dev/null
+++ b/src/src/hintsdb.h
@@ -0,0 +1,805 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* This header file contains macro definitions so that a variety of DBM
+libraries can be used by Exim. Nigel Metheringham provided the original set for
+Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
+2.x and 3.x were added. Later still, support for tdb was added, courtesy of
+James Antill. Most recently, support for native mode gdbm was added, with code
+from Pierre A. Humblet, so Exim could be made to work with Cygwin.
+
+For convenience, the definitions of the structures used in the various hints
+databases are also kept in this file, which is used by the maintenance
+utilities as well as the main Exim binary. */
+
+#ifndef HINTSDB_H
+#define HINTSDB_H
+
+
+#if defined(USE_TDB)
+
+/* ************************* tdb interface ************************ */
+/*XXX https://manpages.org/tdb/3 mentions concurrent writes.
+Could we lose the file lock? */
+
+# include <tdb.h>
+
+/* Basic DB type */
+# define EXIM_DB TDB_CONTEXT
+
+/* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
+tdb_traverse to be called) */
+# define EXIM_CURSOR TDB_DATA
+
+/* The datum type used for queries */
+# define EXIM_DATUM TDB_DATA
+
+/* Some text for messages */
+# define EXIM_DBTYPE "tdb"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
+static EXIM_DB *
+exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
+}
+
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+static BOOL
+exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
+{
+*res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
+return res->dptr != NULL;
+}
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+static int
+exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return tdb_store(dbp, *key, *data, TDB_REPLACE); }
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+static int
+exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return tdb_store(dbp, *key, *data, TDB_INSERT); }
+
+/* Returns from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP (-1)
+
+/* EXIM_DBDEL */
+static int
+exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
+{ return tdb_delete(dbp, *key); }
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
+static EXIM_CURSOR *
+exim_dbcreate_cursor(EXIM_DB * dbp)
+{
+EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
+c->dptr = NULL;
+return c;
+}
+
+/* EXIM_DBSCAN - This is complicated because we have to free the last datum
+free() must not die when passed NULL */
+
+static BOOL
+exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
+ EXIM_CURSOR * cursor)
+{
+*key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
+free(cursor->dptr);
+*cursor = *key;
+return key->dptr != NULL;
+}
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
+static void
+exim_dbdelete_cursor(EXIM_CURSOR * cursor)
+{ store_free(cursor); }
+
+/* EXIM_DBCLOSE */
+static void
+exim_dbclose__(EXIM_DB * db)
+{ tdb_close(db); }
+
+/* Datum access */
+
+static uschar *
+exim_datum_data_get(EXIM_DATUM * dp)
+{ return US dp->dptr; }
+static void
+exim_datum_data_set(EXIM_DATUM * dp, void * s)
+{ dp->dptr = s; }
+
+static unsigned
+exim_datum_size_get(EXIM_DATUM * dp)
+{ return dp->dsize; }
+static void
+exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
+{ dp->dsize = n; }
+
+/* No initialization is needed. */
+
+static void
+exim_datum_init(EXIM_DATUM * d)
+{ }
+
+/* Free the stuff inside the datum. */
+
+static void
+exim_datum_free(EXIM_DATUM * d)
+{
+free(d->dptr);
+d->dptr = NULL;
+}
+
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
+
+
+
+
+
+
+/********************* Berkeley db native definitions **********************/
+
+#elif defined USE_DB
+
+# include <db.h>
+
+/* 1.x did no locking
+ 2.x had facilities, but exim does it's own
+ 3.x+ unknown
+*/
+
+/* We can distinguish between versions 1.x and 2.x/3.x by looking for a
+definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
+
+# ifdef DB_VERSION_STRING
+
+# if DB_VERSION_MAJOR >= 6
+# error Version 6 and later BDB API is not supported
+# endif
+
+/* The API changed (again!) between the 2.x and 3.x versions */
+
+# if DB_VERSION_MAJOR >= 3
+
+/***************** Berkeley db 3.x/4.x native definitions ******************/
+
+/* Basic DB type */
+# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+# define EXIM_DB DB_ENV
+/* Cursor type, for scanning */
+# define EXIM_CURSOR DBC
+
+/* The datum type used for queries */
+# define EXIM_DATUM DBT
+
+/* Some text for messages */
+# define EXIM_DBTYPE "db (v4.1+)"
+
+/* Only more-recent versions. 5+ ? */
+# ifndef DB_FORCESYNC
+# define DB_FORCESYNC 0
+# endif
+
+/* Error callback */
+/* For Berkeley DB >= 2, we can define a function to be called in case of DB
+errors. This should help with debugging strange DB problems, e.g. getting "File
+exists" when you try to open a db file. The API for this function was changed
+at DB release 4.3. */
+
+static void
+dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
+{ log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); }
+
+
+
+/* Access functions */
+
+/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
+/* The API changed for DB 4.1. - and we also starting using the "env" with a
+specified working dir, to avoid the DBCONFIG file trap. */
+
+# define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
+
+static EXIM_DB *
+exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+EXIM_DB * dbp;
+DB * b;
+if ( db_env_create(&dbp, 0) != 0
+ || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
+ || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
+ )
+ return NULL;
+if (db_create(&b, dbp, 0) == 0)
+ {
+ dbp->app_private = b;
+ if (b->open(b, NULL, CS name, NULL,
+ flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
+ flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
+ mode) == 0
+ )
+ return dbp;
+
+ b->close(b, 0);
+ }
+dbp->close(dbp, 0);
+return NULL;
+}
+
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+static BOOL
+exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
+{
+DB * b = ENV_TO_DB(dbp);
+return b->get(b, NULL, key, res, 0) == 0;
+}
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+static int
+exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{
+DB * b = ENV_TO_DB(dbp);
+return b->put(b, NULL, key, data, 0);
+}
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+static int
+exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{
+DB * b = ENV_TO_DB(dbp);
+return b->put(b, NULL, key, data, DB_NOOVERWRITE);
+}
+
+/* Return values from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
+
+/* EXIM_DBDEL */
+static int
+exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
+{
+DB * b = ENV_TO_DB(dbp);
+return b->del(b, NULL, key, 0);
+}
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
+
+static EXIM_CURSOR *
+exim_dbcreate_cursor(EXIM_DB * dbp)
+{
+DB * b = ENV_TO_DB(dbp);
+EXIM_CURSOR * c;
+b->cursor(b, NULL, &c, 0);
+return c;
+}
+
+/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
+static BOOL
+exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
+ EXIM_CURSOR * cursor)
+{
+return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
+}
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
+static void
+exim_dbdelete_cursor(EXIM_CURSOR * cursor)
+{ cursor->c_close(cursor); }
+
+/* EXIM_DBCLOSE */
+static void
+exim_dbclose__(EXIM_DB * dbp_o)
+{
+DB_ENV * dbp = dbp_o;
+DB * b = ENV_TO_DB(dbp);
+b->close(b, 0);
+dbp->close(dbp, DB_FORCESYNC);
+}
+
+/* Datum access */
+
+static uschar *
+exim_datum_data_get(EXIM_DATUM * dp)
+{ return dp->data; }
+static void
+exim_datum_data_set(EXIM_DATUM * dp, void * s)
+{ dp->data = s; }
+
+static unsigned
+exim_datum_size_get(EXIM_DATUM * dp)
+{ return dp->size; }
+static void
+exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
+{ dp->size = n; }
+
+/* The whole datum structure contains other fields that must be cleared
+before use, but we don't have to free anything after reading data. */
+
+static void
+exim_datum_init(EXIM_DATUM * d)
+{ memset(d, 0, sizeof(*d)); }
+
+static void
+exim_datum_free(EXIM_DATUM * d)
+{ }
+
+# else /* pre- 4.1 */
+
+# define EXIM_DB DB
+
+/* Cursor type, for scanning */
+# define EXIM_CURSOR DBC
+
+/* The datum type used for queries */
+# define EXIM_DATUM DBT
+
+/* Some text for messages */
+# define EXIM_DBTYPE "db (v3/4)"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
+static EXIM_DB *
+exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+EXIM_DB * dbp;
+return db_create(&dbp, NULL, 0) == 0
+ && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
+ dbp->open(dbp, CS name, NULL,
+ flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
+ flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
+ mode)
+ ) == 0
+ ? dbp : NULL;
+}
+
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+static BOOL
+exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
+{ return dbp->get(dbp, NULL, key, res, 0) == 0; }
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+static int
+exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return dbp->put(dbp, NULL, key, data, 0); }
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+static int
+exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
+
+/* Return values from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
+
+/* EXIM_DBDEL */
+static int
+exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
+{ return dbp->del(dbp, NULL, key, 0); }
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
+
+static EXIM_CURSOR *
+exim_dbcreate_cursor(EXIM_DB * dbp)
+{
+EXIM_CURSOR * c;
+dbp->cursor(dbp, NULL, &c, 0);
+return c;
+}
+
+/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
+static BOOL
+exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
+ EXIM_CURSOR * cursor)
+{
+return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
+}
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
+static void
+exim_dbdelete_cursor(EXIM_CURSOR * cursor)
+{ cursor->c_close(cursor); }
+
+/* EXIM_DBCLOSE */
+static void
+exim_dbclose__(EXIM_DB * dbp)
+{ dbp->close(dbp, 0); }
+
+/* Datum access */
+
+static uschar *
+exim_datum_data_get(EXIM_DATUM * dp)
+{ return US dp->dptr; }
+static void
+exim_datum_data_set(EXIM_DATUM * dp, void * s)
+{ dp->dptr = s; }
+
+static uschar *
+exim_datum_size_get(EXIM_DATUM * dp)
+{ return US dp->size; }
+static void
+exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
+{ dp->size = CS s; }
+
+/* The whole datum structure contains other fields that must be cleared
+before use, but we don't have to free anything after reading data. */
+
+static void
+exim_datum_init(EXIM_DATUM * d)
+{ memset(d, 0, sizeof(*d)); }
+
+static void
+exim_datum_free(EXIM_DATUM * d)
+{ }
+
+# endif
+
+
+# else /* DB_VERSION_MAJOR >= 3 */
+# error Berkeley DB versions earlier than 3 are not supported */
+# endif /* DB_VERSION_MAJOR */
+# else
+# error Berkeley DB version 1 is no longer supported
+# endif /* DB_VERSION_STRING */
+
+
+/* all BDB versions */
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
+
+
+
+
+
+
+/********************* gdbm interface definitions **********************/
+
+#elif defined USE_GDBM
+/*XXX TODO: exim's locfile not needed */
+
+# include <gdbm.h>
+
+/* Basic DB type */
+typedef struct {
+ GDBM_FILE gdbm; /* Database */
+ datum lkey; /* Last key, for scans */
+} EXIM_DB;
+
+/* Cursor type, not used with gdbm: just set up a dummy */
+# define EXIM_CURSOR int
+
+/* The datum type used for queries */
+# define EXIM_DATUM datum
+
+/* Some text for messages */
+
+# define EXIM_DBTYPE "gdbm"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
+static EXIM_DB *
+exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
+if (dbp)
+ {
+ dbp->lkey.dptr = NULL;
+ dbp->gdbm = gdbm_open(CS name, 0,
+ flags & O_CREAT ? GDBM_WRCREAT
+ : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
+ : GDBM_READER,
+ mode, 0);
+ if (dbp->gdbm) return dbp;
+ free(dbp);
+ }
+return NULL;
+}
+
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+static BOOL
+exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
+{
+*res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
+return res->dptr != NULL;
+}
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+static int
+exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+static int
+exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
+
+/* Returns from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP 1
+
+/* EXIM_DBDEL */
+static int
+exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
+{ return gdbm_delete(dbp->gdbm, *key); }
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
+static EXIM_CURSOR *
+exim_dbcreate_cursor(EXIM_DB * dbp)
+{ return NULL; }
+
+/* EXIM_DBSCAN */
+static BOOL
+exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
+ EXIM_CURSOR * cursor)
+{
+char * s;
+*key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
+if ((s = dbp->lkey.dptr)) free(s);
+dbp->lkey = *key;
+return key->dptr != NULL;
+}
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
+static void
+exim_dbdelete_cursor(EXIM_CURSOR * cursor)
+{ }
+
+/* EXIM_DBCLOSE */
+static void
+exim_dbclose__(EXIM_DB * dbp)
+{
+char * s;
+gdbm_close(dbp->gdbm);
+if ((s = dbp->lkey.dptr)) free(s);
+free(dbp);
+}
+
+/* Datum access types */
+
+static uschar *
+exim_datum_data_get(EXIM_DATUM * dp)
+{ return US dp->dptr; }
+static void
+exim_datum_data_set(EXIM_DATUM * dp, void * s)
+{ dp->dptr = s; }
+
+static unsigned
+exim_datum_size_get(EXIM_DATUM * dp)
+{ return dp->dsize; }
+static void
+exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
+{ dp->dsize = n; }
+
+/* There's no clearing required before use, but we have to free the dptr
+after reading data. */
+
+static void
+exim_datum_init(EXIM_DATUM * d)
+{ }
+
+static void
+exim_datum_free(EXIM_DATUM * d)
+{ free(d->dptr); }
+
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
+
+#else /* USE_GDBM */
+
+
+
+
+
+
+/* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
+interface */
+
+
+/********************* ndbm interface definitions **********************/
+
+# include <ndbm.h>
+
+/* Basic DB type */
+# define EXIM_DB DBM
+
+/* Cursor type, not used with ndbm: just set up a dummy */
+# define EXIM_CURSOR int
+
+/* The datum type used for queries */
+# define EXIM_DATUM datum
+
+/* Some text for messages */
+
+# define EXIM_DBTYPE "ndbm"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
+/* Check that the name given is not present. This catches
+a directory name; otherwise we would create the name.pag and
+name.dir files in the directory's parent. */
+
+static EXIM_DB *
+exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+struct stat st;
+if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
+ return dbm_open(CS name, flags, mode);
+#ifndef COMPILE_UTILITY
+debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
+#endif
+errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
+return NULL;
+}
+
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+static BOOL
+exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
+{
+*res = dbm_fetch(dbp, *key); /* A struct arg & return! */
+return res->dptr != NULL;
+}
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+static int
+exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return dbm_store(dbp, *key, *data, DBM_REPLACE); }
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+static int
+exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
+{ return dbm_store(dbp, *key, *data, DBM_INSERT); }
+
+/* Returns from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP 1
+
+/* EXIM_DBDEL */
+static int
+exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
+{ return dbm_delete(dbp, *key); }
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
+static EXIM_CURSOR *
+exim_dbcreate_cursor(EXIM_DB * dbp)
+{ return NULL; }
+
+/* EXIM_DBSCAN */
+static BOOL
+exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
+ EXIM_CURSOR * cursor)
+{
+*key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
+return key->dptr != NULL;
+}
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
+static void
+exim_dbdelete_cursor(EXIM_CURSOR * cursor)
+{ }
+
+/* EXIM_DBCLOSE */
+static void
+exim_dbclose__(EXIM_DB * dbp)
+{ dbm_close(dbp); }
+
+/* Datum access types */
+
+static uschar *
+exim_datum_data_get(EXIM_DATUM * dp)
+{ return US dp->dptr; }
+static void
+exim_datum_data_set(EXIM_DATUM * dp, void * s)
+{ dp->dptr = s; }
+
+static unsigned
+exim_datum_size_get(EXIM_DATUM * dp)
+{ return dp->dsize; }
+static void
+exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
+{ dp->dsize = n; }
+
+/* There's no clearing required before use, and we don't have to free anything
+after reading data. */
+
+static void
+exim_datum_init(EXIM_DATUM * d)
+{ }
+
+static void
+exim_datum_free(EXIM_DATUM * d)
+{ }
+
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
+
+#endif /* USE_GDBM */
+
+
+
+
+
+#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
+
+static EXIM_DB *
+exim_dbopen(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+return exim_dbopen__(name, dirname, flags, mode);
+}
+
+static void
+exim_dbclose(EXIM_DB * dbp)
+{ exim_dbclose__(dbp); }
+
+#else
+/* Wrappers for open/close with debug tracing */
+
+extern void debug_printf_indent(const char *, ...);
+static BOOL is_tainted(const void *);
+
+static EXIM_DB *
+exim_dbopen(const uschar * name, const uschar * dirname, int flags,
+ unsigned mode)
+{
+void * dbp;
+DEBUG(D_hints_lookup)
+ debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
+ name, dirname,
+ flags == O_RDONLY ? "O_RDONLY"
+ : flags == O_RDWR ? "O_RDWR"
+ : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
+ : "??");
+if (is_tainted(name) || is_tainted(dirname))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
+ dbp = NULL;
+ }
+else
+ dbp = exim_dbopen__(name, dirname, flags, mode);
+
+DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
+return dbp;
+}
+
+static void
+exim_dbclose(EXIM_DB * dbp)
+{
+DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
+exim_dbclose__(dbp);
+}
+
+# endif
+
+/********************* End of dbm library definitions **********************/
+
+
+#endif /* whole file */
+/* End of hintsdb.h */
diff --git a/src/src/hintsdb_structs.h b/src/src/hintsdb_structs.h
new file mode 100644
index 000000000..e0670a10e
--- /dev/null
+++ b/src/src/hintsdb_structs.h
@@ -0,0 +1,189 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 - 2021 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* This header file contains the definitions of the structures used in the
+various hints databases are also kept in this file, which is used by the
+maintenance utilities as well as the main Exim binary. */
+
+#ifndef HINTSDB_STRUCTS_H
+#define HINTSDB_STRUCTS_H
+
+
+/* Structure for carrying around an open DBM file, and an open locking file
+that relates to it. */
+
+typedef struct {
+ void * dbptr;
+ int lockfd;
+} open_db;
+
+
+/* Structures for records stored in exim database dbm files. They all
+start with the same fields, described in the generic type. */
+
+
+typedef struct {
+ time_t time_stamp; /* Timestamp of writing */
+} dbdata_generic;
+
+
+/* This structure keeps track of retry information for a host or a local
+address. */
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ time_t first_failed; /* Time of first failure */
+ time_t last_try; /* Time of last try */
+ time_t next_try; /* Time of next try */
+ BOOL expired; /* Retry time has expired */
+ int basic_errno; /* Errno of last failure */
+ int more_errno; /* Additional information */
+ uschar text[1]; /* Text message for last failure */
+} dbdata_retry;
+
+/* These structures keep track of addresses that have had callout verification
+performed on them. There are two groups of records:
+
+1. keyed by localpart@domain -
+ Full address was tested and record holds result
+
+2. keyed by domain -
+ Domain response upto MAIL FROM:<>, postmaster, random local part;
+
+If a record exists, the result field is either ccache_accept or ccache_reject,
+or, for a domain record only, ccache_reject_mfnull when MAIL FROM:<> was
+rejected. The other fields, however, (which are only relevant to domain
+records) may also contain ccache_unknown if that particular test has not been
+done.
+
+Originally, there was only one structure, used for both types. However, it got
+expanded for domain records, so it got split. To make it possible for Exim to
+handle the old type of record, we retain the old definition. The different
+kinds of record can be distinguished by their different lengths. */
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ int result;
+ int postmaster_result; /* Postmaster is accepted */
+ int random_result; /* Random local part was accepted */
+} dbdata_callout_cache_obs;
+
+typedef struct {
+ time_t time_stamp; /* Timestamp of last address check */
+ /*************/
+ int result; /* accept or reject */
+} dbdata_callout_cache_address;
+
+/* For this new layout, we put the additional fields (the timestamps)
+last so that if somebody reverts to an older Exim, the new records will
+still make sense because they match the old layout. */
+
+typedef struct {
+ time_t time_stamp; /* Time stamp of last connection */
+ /*************/
+ int result; /* Domain reject or accept */
+ int postmaster_result; /* Postmaster result */
+ int random_result; /* Random result */
+ time_t postmaster_stamp; /* Timestamp of postmaster check */
+ time_t random_stamp; /* Timestamp of random check */
+} dbdata_callout_cache;
+
+/* This structure keeps track of messages that are waiting for a particular
+host for a particular transport. */
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ int count; /* Count of message ids */
+ int sequence; /* Sequence for continued records */
+ uschar text[1]; /* One long character string */
+} dbdata_wait;
+
+
+/* The contents of the "misc" database are a mixture of different kinds of
+record, as defined below. The keys used for a specific type all start with a
+given string such as "etrn-" or "host-serialize-". */
+
+
+/* This structure records a connection to a particular host, for the
+purpose of serializing access to certain hosts. For possible future extension,
+a field is defined for holding the count of connections, but it is not
+at present in use. The same structure is used for recording a running ETRN
+process. */
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ int count; /* Reserved for possible connection count */
+} dbdata_serialize;
+
+
+/* This structure records the information required for the ratelimit
+ACL condition. */
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ int time_usec; /* Fractional part of time, from gettimeofday() */
+ double rate; /* Smoothed sending rate at that time */
+} dbdata_ratelimit;
+
+/* Same as above, plus a Bloom filter for uniquifying events. */
+
+typedef struct {
+ dbdata_ratelimit dbd;
+ time_t bloom_epoch; /* When the Bloom filter was last reset */
+ unsigned bloom_size; /* Number of bytes in the Bloom filter */
+ uschar bloom[40]; /* Bloom filter which may be larger than this */
+} dbdata_ratelimit_unique;
+
+
+/* For "seen" ACL condition */
+typedef struct {
+ time_t time_stamp;
+} dbdata_seen;
+
+#ifndef DISABLE_PIPE_CONNECT
+/* This structure records the EHLO responses, cleartext and crypted,
+for an IP, as bitmasks (cf. OPTION_TLS). For LIMITS, also values
+advertised for MAILMAX, RCPTMAX and RCPTDOMAINMAX; zero meaning no
+value advertised. */
+
+typedef struct {
+ unsigned short cleartext_features;
+ unsigned short crypted_features;
+ unsigned short cleartext_auths;
+ unsigned short crypted_auths;
+
+# ifdef EXPERIMENTAL_ESMTP_LIMITS
+ unsigned int limit_mail;
+ unsigned int limit_rcpt;
+ unsigned int limit_rcptdom;
+# endif
+} ehlo_resp_precis;
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ ehlo_resp_precis data;
+} dbdata_ehlo_resp;
+#endif
+
+typedef struct {
+ time_t time_stamp;
+ /*************/
+ uschar verify_override:1;
+ uschar ocsp:3;
+ uschar session[1];
+} dbdata_tls_session;
+
+
+#endif /* whole file */
+/* End of hintsdb_structs.h */
diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c
index 6db6dedb8..95f31bc16 100644
--- a/src/src/lookups/dbmdb.c
+++ b/src/src/lookups/dbmdb.c
@@ -21,11 +21,10 @@ dbmdb_open(const uschar * filename, uschar ** errmsg)
{
uschar * dirname = string_copy(filename);
uschar * s;
-EXIM_DB *yield = NULL;
+EXIM_DB * yield = NULL;
if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
-EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
-if (!yield)
+if (!(yield = exim_dbopen(filename, dirname, O_RDONLY, 0)))
*errmsg = string_open_failed("%s as a %s file", filename, EXIM_DBTYPE);
return yield;
}
@@ -93,15 +92,15 @@ dbmdb_find(void * handle, const uschar * filename, const uschar * keystring,
EXIM_DB *d = (EXIM_DB *)handle;
EXIM_DATUM key, data;
-EXIM_DATUM_INIT(key); /* Some DBM libraries require datums to */
-EXIM_DATUM_INIT(data); /* be cleared before use. */
-EXIM_DATUM_DATA(key) = (void *) keystring;
-EXIM_DATUM_SIZE(key) = length + 1;
+exim_datum_init(&key); /* Some DBM libraries require datums to */
+exim_datum_init(&data); /* be cleared before use. */
+exim_datum_data_set(&key, string_copyn(keystring, length));
+exim_datum_size_set(&key, length + 1);
-if (EXIM_DBGET(d, key, data))
+if (exim_dbget(d, &key, &data))
{
- *result = string_copyn(US EXIM_DATUM_DATA(data), EXIM_DATUM_SIZE(data));
- EXIM_DATUM_FREE(data); /* Some DBM libraries need a free() call */
+ *result = string_copyn(exim_datum_data_get(&data), exim_datum_size_get(&data));
+ exim_datum_free(&data); /* Some DBM libraries need a free() call */
return OK;
}
return FAIL;
@@ -214,7 +213,7 @@ return dbmdb_find(handle, filename, key_buffer, key_item_len - 1,
void
static dbmdb_close(void *handle)
{
-EXIM_DBCLOSE((EXIM_DB *)handle);
+exim_dbclose((EXIM_DB *)handle);
}
diff --git a/src/src/perl.c b/src/src/perl.c
index 58643f0fa..c6d329102 100644
--- a/src/src/perl.c
+++ b/src/src/perl.c
@@ -15,6 +15,10 @@
/* See the file NOTICE for conditions of use and distribution. */
#include <assert.h>
+
+#define HINTSDB_H
+#define DBFUNCTIONS_H
+
#include "exim.h"
#define EXIM_TRUE TRUE
diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c
index 77e769450..a2441d209 100644
--- a/src/src/transports/autoreply.c
+++ b/src/src/transports/autoreply.c
@@ -264,7 +264,7 @@ int fd, pid, rc;
int cache_fd = -1;
int cache_size = 0;
int add_size = 0;
-EXIM_DB *dbm_file = NULL;
+EXIM_DB * dbm_file = NULL;
BOOL file_expand, return_message;
uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
uschar *logfile, *oncelog;
@@ -476,8 +476,7 @@ if (oncelog && *oncelog && to)
dirname = (s = Ustrrchr(oncelog, '/'))
? string_copyn(oncelog, s - oncelog) : NULL;
- EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
- if (!dbm_file)
+ if (!(dbm_file = exim_dbopen(oncelog, dirname, O_RDWR|O_CREAT, ob->mode)))
{
addr->transport_return = DEFER;
addr->basic_errno = errno;
@@ -487,12 +486,12 @@ if (oncelog && *oncelog && to)
goto END_OFF;
}
- EXIM_DATUM_INIT(key_datum); /* Some DBM libraries need datums */
- EXIM_DATUM_INIT(result_datum); /* to be cleared */
- EXIM_DATUM_DATA(key_datum) = (void *) to;
- EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
+ exim_datum_init(&key_datum); /* Some DBM libraries need datums */
+ exim_datum_init(&result_datum); /* to be cleared */
+ exim_datum_data_set(&key_datum, (void *) to);
+ exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
- if (EXIM_DBGET(dbm_file, key_datum, result_datum))
+ if (exim_dbget(dbm_file, &key_datum, &result_datum))
{
/* If the datum size is that of a binary time, we are in the new world
where messages are sent periodically. Otherwise the file is an old one,
@@ -501,8 +500,8 @@ if (oncelog && *oncelog && to)
introduced at Exim 3.00. In a couple of years' time the test on the size
can be abolished. */
- if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
- memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
+ if (exim_datum_size_get(&result_datum) == sizeof(time_t))
+ memcpy(&then, exim_datum_data_get(&result_datum), sizeof(time_t));
else
then = now;
}
@@ -575,7 +574,7 @@ if ((pid = child_open_exim(&fd, US"autoreply")) < 0)
addr->message = string_sprintf("Failed to create child process to send "
"message from %s transport: %s", tblock->name, strerror(errno));
DEBUG(D_transport) debug_printf("%s\n", addr->message);
- if (dbm_file) EXIM_DBCLOSE(dbm_file);
+ if (dbm_file) exim_dbclose(dbm_file);
return FALSE;
}
@@ -738,18 +737,18 @@ if (cache_fd >= 0)
else if (dbm_file)
{
EXIM_DATUM key_datum, value_datum;
- EXIM_DATUM_INIT(key_datum); /* Some DBM libraries need to have */
- EXIM_DATUM_INIT(value_datum); /* cleared datums. */
- EXIM_DATUM_DATA(key_datum) = (void *) to;
- EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
+ exim_datum_init(&key_datum); /* Some DBM libraries need to have */
+ exim_datum_init(&value_datum); /* cleared datums. */
+ exim_datum_data_set(&key_datum, to);
+ exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
/* Many OS define the datum value, sensibly, as a void *. However, there
are some which still have char *. By casting this address to a char * we
can avoid warning messages from the char * systems. */
- EXIM_DATUM_DATA(value_datum) = (void *) &now;
- EXIM_DATUM_SIZE(value_datum) = (int)sizeof(time_t);
- EXIM_DBPUT(dbm_file, key_datum, value_datum);
+ exim_datum_data_set(&value_datum, &now);
+ exim_datum_size_set(&value_datum, sizeof(time_t));
+ exim_dbput(dbm_file, &key_datum, &value_datum);
}
/* If sending failed, defer to try again - but if once is set the next
@@ -812,7 +811,7 @@ if (logfile)
}
END_OFF:
-if (dbm_file) EXIM_DBCLOSE(dbm_file);
+if (dbm_file) exim_dbclose(dbm_file);
if (cache_fd > 0) (void)close(cache_fd);
DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);