Hints DB interface: convert from macros to inlinable functions.
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 20 Mar 2022 14:20:13 +0000 (14:20 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 28 Mar 2022 11:32:47 +0000 (12:32 +0100)
Testing status: tdb, dbm, gdbm & ndbm build and pass testsuite.

17 files changed:
src/Makefile
src/OS/Makefile-Base
src/exim_monitor/em_hdr.h
src/scripts/MakeLinks
src/src/buildconfig.c
src/src/dbfn.c
src/src/dbfunctions.h
src/src/dbstuff.h [deleted file]
src/src/exim.h
src/src/exim_dbmbuild.c
src/src/exim_dbutil.c
src/src/filter.c
src/src/hintsdb.h [new file with mode: 0644]
src/src/hintsdb_structs.h [new file with mode: 0644]
src/src/lookups/dbmdb.c
src/src/perl.c
src/src/transports/autoreply.c

index 3aa3cc374122b01106db6a370a58e3f60ee6dc27..a48938023597dbceee8889f421260cf93f0ba895 100644 (file)
@@ -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 \
index 612db7a9cf573fe611dae011c9bd58348f9d6a71..cab56cc3868af3f72def87d884c836a84494b6fd 100644 (file)
@@ -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 \
index 87e4fc6dfc53f42aaa4a4a4f6e1c2969402c90ae..ee05815dfcefb1921ecb16502784b11389a2b798 100644 (file)
@@ -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"
 
index 4a714e147eee7da0d5033a8779fe75011f9617b5..35bb755d51c703b1ad55d6404e1865d5abe155ee 100755 (executable)
@@ -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 \
index a1b5485cd08aa168af1b5620ca93a8afca9acce6..a7f5812b2ae8898dca679fdb5a541965538b82a0 100644 (file)
@@ -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
index a9bc892d4e9fd2c1edaab83610157932d0050331..600da18c4c921f5b1aaa15d7bdf6f4ee108399b2 100644 (file)
@@ -38,31 +38,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;
 }
 
index f3b04ad2f29d3243b41818062b095d1a52304494..3846139819fb6d97d3a3aade8d25afa9f1efc10b 100644 (file)
@@ -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 (file)
index 8ebf6f6..0000000
+++ /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 */
index cf8f19eb6f1114b803b3672bbf4d0370d35a0243..2541baa3d66d05eab396c68100ed753c3b406b6a 100644 (file)
@@ -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"
index 73ca10e90157134f0edf7550b62af69dcb9a8301..b3386470242df94f0c9a18966986d46493b66e1e 100644 (file)
@@ -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
index c536a20375df7af50e83490f664af7f5a9b8ecf9..1d87cec1768cee626458f914155b426e83773297 100644 (file)
@@ -84,31 +84,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 */
index 629bbf5363fea923be392ac9770694edbe59ebb3..210f7b0e2441c0119ac47d815197f6e2c84392fc 100644 (file)
@@ -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 (file)
index 0000000..de3e6e4
--- /dev/null
@@ -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 (file)
index 0000000..e0670a1
--- /dev/null
@@ -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 */
index 6db6dedb89e4efad3a2f48e832f889123faa40e7..95f31bc160a4a2a02097b6530b90b211901a1c38 100644 (file)
@@ -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);
 }
 
 
index 58643f0fa24707009068a5e361b4d4f94ddb33be..c6d329102d87ff9c51c9f4cd55eaf9e675339e17 100644 (file)
 /* 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
index 77e769450bfc224a81ef4a86e9f1f467920bc388..a2441d20960805ff0f7ca80f187ffd84cf1ff8c3 100644 (file)
@@ -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);