*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* 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
utilities as well as the main Exim binary. */
-# ifdef USE_TDB
+#ifdef USE_TDB
/* ************************* tdb interface ************************ */
-#include <tdb.h>
+# include <tdb.h>
/* Basic DB type */
-#define EXIM_DB TDB_CONTEXT
+# 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
+# define EXIM_CURSOR TDB_DATA
/* The datum type used for queries */
-#define EXIM_DATUM TDB_DATA
+# define EXIM_DATUM TDB_DATA
/* Some text for messages */
-#define EXIM_DBTYPE "tdb"
+# 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) \
+# 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) \
+# 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) \
+# 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) \
+# 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)
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP (-1)
/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) tdb_delete(db, key)
+# define EXIM_DBDEL(db, key) tdb_delete(db, key)
/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-#define EXIM_DBCREATE_CURSOR(db, cursor) { \
+# 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) \
+# 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)
+# define EXIM_DBDELETE_CURSOR(cursor) store_free(cursor)
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE__(db) tdb_close(db)
+# 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
+# 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)
+# define EXIM_DATUM_FREE(datum) (free((datum).dptr), (datum).dptr = NULL)
/* No initialization is needed. */
-#define EXIM_DATUM_INIT(datum)
+# define EXIM_DATUM_INIT(datum)
+
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
+
+
+
#elif defined USE_DB
-#include <db.h>
+# 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
+# ifdef DB_VERSION_STRING
-# if DB_VERSION_MAJOR >= 6
-# error Version 6 and later BDB API is not supported
-# endif
+# 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
+# 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
+# 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
+# define EXIM_CURSOR DBC
/* The datum type used for queries */
-# define EXIM_DATUM DBT
+# define EXIM_DATUM DBT
/* Some text for messages */
-# define EXIM_DBTYPE "db (v4.1+)"
+# define EXIM_DBTYPE "db (v4.1+)"
/* Only more-recent versions. 5+ ? */
-# ifndef DB_FORCESYNC
-# define DB_FORCESYNC 0
-# endif
+# ifndef DB_FORCESYNC
+# define DB_FORCESYNC 0
+# endif
/* Access functions */
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 ENV_TO_DB(env) ((DB *)((env)->app_private))
-# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
+# 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\
}
/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-# define EXIM_DBGET(db, key, data) \
+# 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) \
+# 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) \
+# 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
+# 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)
+# 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) \
+# 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) \
+# 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) \
+# define EXIM_DBDELETE_CURSOR(cursor) \
(cursor)->c_close(cursor)
/* EXIM_DBCLOSE */
-# define EXIM_DBCLOSE__(db) \
+# 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
+# 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)
+# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
-# else /* pre- 4.1 */
+# else /* pre- 4.1 */
-# define EXIM_DB DB
+# define EXIM_DB DB
/* Cursor type, for scanning */
-# define EXIM_CURSOR DBC
+# define EXIM_CURSOR DBC
/* The datum type used for queries */
-# define EXIM_DATUM DBT
+# define EXIM_DATUM DBT
/* Some text for messages */
-# define EXIM_DBTYPE "db (v3/4)"
+# 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) \
+# 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, \
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 */
-
-/******************* Berkeley db 2.x native definitions ********************/
-
-/* Basic DB type */
-#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 (v2)"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- if ((errno = db_open(CS name, DB_HASH, \
- ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
- mode, NULL, NULL, dbpp)) != 0) *(dbpp) = NULL
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-#define EXIM_DBGET(db, key, data) \
+# 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) \
+# 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) \
+# 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
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0)
+# define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0)
/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-/* The API of this function was changed between releases 2.4.14 and 2.7.3. I do
-not know exactly where the change happened, but the Change Log for 2.5.9 lists
-the new option that is available, so I guess that it happened at 2.5.x. */
-
-#if DB_VERSION_MINOR >= 5
-#define EXIM_DBCREATE_CURSOR(db, cursor) \
+# define EXIM_DBCREATE_CURSOR(db, cursor) \
(db)->cursor(db, NULL, cursor, 0)
-#else
-#define EXIM_DBCREATE_CURSOR(db, cursor) \
- (db)->cursor(db, NULL, cursor)
-#endif
/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-#define EXIM_DBSCAN(db, key, data, first, cursor) \
+# 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) \
+# define EXIM_DBDELETE_CURSOR(cursor) \
(cursor)->c_close(cursor)
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE__(db) (db)->close(db, 0)
+# 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
+# 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 /* DB_VERSION_MAJOR >= 3 */
-
-
-/* If DB_VERSION_TYPE is not defined, we have version 1.x */
-
-#else /* DB_VERSION_TYPE */
-
-/******************* Berkeley db 1.x native definitions ********************/
-
-/* Basic DB type */
-#define EXIM_DB DB
-
-/* Cursor type, not used with DB 1.x: just set up a dummy */
-#define EXIM_CURSOR int
-
-/* The datum type used for queries */
-#define EXIM_DATUM DBT
-
-/* Some text for messages */
-#define EXIM_DBTYPE "db (v1)"
-
-/* When scanning, for the non-first case we historically just passed 0
-as the flags field and it worked. On FreeBSD 8 it no longer works and
-instead leads to memory exhaustion. The man-page on FreeBSD says to use
-R_NEXT, but this 1.x is a historical fallback and I've no idea how portable
-the use of that flag is; so the solution is to define R_NEXT here if it's not
-already defined, with a default value of 0 because that's what we've always
-before been able to pass successfully. */
-#ifndef R_NEXT
-#define R_NEXT 0
-#endif
-
-/* Access functions */
+# define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
-/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- *(dbpp) = dbopen(CS name, flags, mode, DB_HASH, NULL)
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-#define EXIM_DBGET(db, key, data) \
- ((db)->get(db, &key, &data, 0) == 0)
+# endif
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-#define EXIM_DBPUT(db, key, data) \
- (db)->put(db, &key, &data, 0)
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-#define EXIM_DBPUTB(db, key, data) \
- (db)->put(db, &key, &data, R_NOOVERWRITE)
-
-/* Returns from EXIM_DBPUTB */
-
-#define EXIM_DBPUTB_OK 0
-#define EXIM_DBPUTB_DUP 1
-
-/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) (db)->del(db, &key, 0)
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-#define EXIM_DBCREATE_CURSOR(db, cursor) {}
+# 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 */
-/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-#define EXIM_DBSCAN(db, key, data, first, cursor) \
- ((db)->seq(db, &key, &data, (first? R_FIRST : R_NEXT)) == 0)
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
-#define EXIM_DBDELETE_CURSOR(cursor) { }
+/* all BDB versions */
+/* size limit */
-/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE__(db) (db)->close(db)
+# define EXIM_DB_RLIMIT 150
-/* Datum access types - these are intended to be assignable */
-#define EXIM_DATUM_SIZE(datum) (datum).size
-#define EXIM_DATUM_DATA(datum) (datum).data
-/* 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)
-
-#endif /* DB_VERSION_STRING */
#elif defined USE_GDBM
-#include <gdbm.h>
+# include <gdbm.h>
/* Basic DB type */
typedef struct {
GDBM_FILE gdbm; /* Database */
datum lkey; /* Last key, for scans */
-} EXIM_DB;
+} gdbm_db;
+
+#define EXIM_DB gdbm_db
/* Cursor type, not used with gdbm: just set up a dummy */
-#define EXIM_CURSOR int
+# define EXIM_CURSOR int
/* The datum type used for queries */
-#define EXIM_DATUM datum
+# define EXIM_DATUM datum
/* Some text for messages */
-#define EXIM_DBTYPE "gdbm"
+# define EXIM_DBTYPE "gdbm"
/* Access functions */
/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- { (*(dbpp)) = (EXIM_DB *) malloc(sizeof(EXIM_DB));\
- if (*(dbpp) != NULL) { \
- (*(dbpp))->lkey.dptr = NULL;\
- (*(dbpp))->gdbm = gdbm_open(CS name, 0, (((flags) & O_CREAT))?GDBM_WRCREAT:(((flags) & (O_RDWR|O_WRONLY))?GDBM_WRITER:GDBM_READER), mode, 0);\
- if ((*(dbpp))->gdbm == NULL) {\
- free(*(dbpp));\
- *(dbpp) = NULL;\
+# 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) \
+# 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) \
+# 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) \
+# 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
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP 1
/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) gdbm_delete(db->gdbm, key)
+# define EXIM_DBDEL(db, key) gdbm_delete(db->gdbm, key)
/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-#define EXIM_DBCREATE_CURSOR(db, cursor) {}
+# define EXIM_DBCREATE_CURSOR(db, cursor) {}
/* EXIM_DBSCAN */
-#define EXIM_DBSCAN(db, key, data, first, cursor) \
+# 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) { }
+# define EXIM_DBDELETE_CURSOR(cursor) { }
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE__(db) \
+# 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
+# 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)
+# 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>
+# include <ndbm.h>
/* Basic DB type */
-#define EXIM_DB DBM
+# define EXIM_DB DBM
/* Cursor type, not used with ndbm: just set up a dummy */
-#define EXIM_CURSOR int
+# define EXIM_CURSOR int
/* The datum type used for queries */
-#define EXIM_DATUM datum
+# define EXIM_DATUM datum
/* Some text for messages */
-#define EXIM_DBTYPE "ndbm"
+# define EXIM_DBTYPE "ndbm"
/* Access functions */
/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
- *(dbpp) = dbm_open(CS name, flags, mode)
+/* 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) \
+# 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) \
+# 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) \
+# 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
+# define EXIM_DBPUTB_OK 0
+# define EXIM_DBPUTB_DUP 1
/* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key) dbm_delete(db, key)
+# define EXIM_DBDEL(db, key) dbm_delete(db, key)
/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-#define EXIM_DBCREATE_CURSOR(db, cursor) {}
+# define EXIM_DBCREATE_CURSOR(db, cursor) {}
/* EXIM_DBSCAN */
-#define EXIM_DBSCAN(db, key, data, first, cursor) \
+# 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) { }
+# define EXIM_DBDELETE_CURSOR(cursor) { }
/* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE__(db) dbm_close(db)
+# 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
+# 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)
+# define EXIM_DATUM_INIT(datum)
+# define EXIM_DATUM_FREE(datum)
+
+/* size limit */
+
+# define EXIM_DB_RLIMIT 150
#endif /* USE_GDBM */
-# ifdef COMPILE_UTILITY
+#ifdef COMPILE_UTILITY
-# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
EXIM_DBOPEN__(name, dirname, flags, mode, dbpp)
-# define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db)
+# define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db)
-# else
+#else
-# define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+# 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", \
: (flags) == O_RDWR ? "O_RDWR" \
: (flags) == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT" \
: "??"); \
- if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB file not permitted", name) \
- || is_tainted2(dirname, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB directory not permitted", dirname)) \
+ 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) \
+# define EXIM_DBCLOSE(db) \
do { \
DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", db); \
EXIM_DBCLOSE__(db); \
} while(0)
-# endif
+# endif
+#ifndef EXIM_DB
+# define EXIM_DB void /* dummy */
+#endif
+#ifndef EXIM_CURSOR
+# define EXIM_CURSOR void /* dummy */
+#endif
/********************* End of dbm library definitions **********************/
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