X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c3d6f1ff09458b3e7619f9bc4799aec0ab5fc2f2..0cc804c87799fb5902e66d5bd537a762f786dc2a:/src/src/hintsdb.h diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h new file mode 100644 index 000000000..de3e6e4aa --- /dev/null +++ b/src/src/hintsdb.h @@ -0,0 +1,805 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* See the file NOTICE for conditions of use and distribution. */ + +/* This header file contains macro definitions so that a variety of DBM +libraries can be used by Exim. Nigel Metheringham provided the original set for +Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB +2.x and 3.x were added. Later still, support for tdb was added, courtesy of +James Antill. Most recently, support for native mode gdbm was added, with code +from Pierre A. Humblet, so Exim could be made to work with Cygwin. + +For convenience, the definitions of the structures used in the various hints +databases are also kept in this file, which is used by the maintenance +utilities as well as the main Exim binary. */ + +#ifndef HINTSDB_H +#define HINTSDB_H + + +#if defined(USE_TDB) + +/* ************************* tdb interface ************************ */ +/*XXX https://manpages.org/tdb/3 mentions concurrent writes. +Could we lose the file lock? */ + +# include + +/* 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 + +/* 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 + +/* 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 + +/* 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 */