1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
10 /* This header file contains macro definitions so that a variety of DBM
11 libraries can be used by Exim. Nigel Metheringham provided the original set for
12 Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
13 2.x and 3.x were added. Later still, support for tdb was added, courtesy of
14 James Antill. Most recently, support for native mode gdbm was added, with code
15 from Pierre A. Humblet, so Exim could be made to work with Cygwin.
17 For convenience, the definitions of the structures used in the various hints
18 databases are also kept in this file, which is used by the maintenance
19 utilities as well as the main Exim binary.
21 A key/value store is supported (only). Keys are strings; values arbitrary
26 exim_lockfile_needed API semantics predicate
31 exim_dbputb non-overwriting put
34 exim_dbscan get, and bump cursor
37 exim_datum_size_get/set
38 exim_datum_data_get/set
42 EXIM_CURSOR datatype for cursor
43 EXIM_DATUM datatype for "value"
44 EXIM_DBTYPE text for logging & debuug
46 Selection of the shim layer implementation, and backend, is by #defines.
48 The users of this API are:
49 hintsdb interface dbfn.c
50 hintsdb utilities exim_dbutil.c and exim_dbmvuild.c
51 dbmdb lookup lookups/dbmdb,c
52 autoreply transport transports/autoreply.c
54 Note that the dbmdb lookup use, bypassing the dbfn.c layer,
55 means that no file-locking is done.
56 XXX This feels like a layering violation; I don't see it commented on
59 Future: consider re-architecting to support caching of the open-handle
60 for hintsdb uses (the dbmdb use gets that already). This would need APIs
61 for transaction locks. Perhaps merge the implementation with the lookups
62 layer, in some way, for the open-handle caching (since that manages closes
63 required by Exim's process transisitions)?
71 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB)
72 # error USE_SQLITE conflict with alternate definition
75 /* ********************* sqlite3 interface ************************ */
80 # define EXIM_DB sqlite3
82 # define EXIM_CURSOR int
84 # /* The datum type used for queries */
85 # define EXIM_DATUM blob
87 /* Some text for messages */
88 # define EXIM_DBTYPE "sqlite3"
90 # /* Access functions */
93 exim_lockfile_needed(void)
95 return FALSE; /* We do transaction; no extra locking needed */
98 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
99 static inline EXIM_DB *
100 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
104 int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
105 if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE;
106 if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK)
108 sqlite3_busy_timeout(dbp, 5000);
110 ret = sqlite3_exec(dbp,
111 "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);",
113 if (ret != SQLITE_OK)
117 // fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp));
118 return ret == SQLITE_OK ? dbp : NULL;
122 exim_dbtransaction_start(EXIM_DB * dbp)
124 return sqlite3_exec(dbp, "BEGIN TRANSACTION;", NULL, NULL, NULL) == SQLITE_OK;
127 static inline EXIM_DB *
128 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
131 EXIM_DB * dbp = exim_dbopen_multi(name, dirname, flags, mode);
132 if (!dbp || exim_dbtransaction_start(dbp))
138 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
139 /* note we alloc'n'copy - the caller need not do so */
140 /* result has a NUL appended, but the length is as per the DB */
143 exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res)
145 sqlite3_stmt * statement;
148 res->len = (size_t) -1;
149 /* fprintf(stderr, "exim_dbget__(%s)\n", s); */
150 if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK)
152 /* fprintf(stderr, "prepare fail: %s\n", sqlite3_errmsg(dbp)); */
155 if (sqlite3_step(statement) != SQLITE_ROW)
157 /* fprintf(stderr, "step fail: %s\n", sqlite3_errmsg(dbp)); */
158 sqlite3_finalize(statement);
162 res->len = sqlite3_column_bytes(statement, 0);
163 # ifdef COMPILE_UTILITY
164 res->data = malloc(res->len);
166 res->data = store_get(res->len, GET_TAINTED);
168 memcpy(res->data, sqlite3_column_blob(statement, 0), res->len);
169 res->data[res->len] = '\0';
170 /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */
171 sqlite3_finalize(statement);
176 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
178 # define FMT "SELECT dat FROM tbl WHERE ky = '%.*s';"
183 # ifdef COMPILE_UTILITY
184 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
185 qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data));
186 snprintf(CS qry, i, FMT, (int) key->len, key->data);
187 ret = exim_dbget__(dbp, qry, res);
190 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
191 qry = string_sprintf(FMT, (int) key->len, key->data);
192 ret = exim_dbget__(dbp, qry, res);
200 # define EXIM_DBPUTB_OK 0
201 # define EXIM_DBPUTB_DUP (-1)
204 exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt)
206 int hlen = data->len * 2, off = 0, res;
207 # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
208 # ifdef COMPILE_UTILITY
209 uschar * hex = malloc(hlen+1);
211 uschar * hex = store_get(hlen+1, data->data);
215 for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2)
216 sprintf(CS hex + off, "%02X", *s);
218 # ifdef COMPILE_UTILITY
219 res = snprintf(CS hex, 0, FMT, alt, (int) key->len, key->data, hlen, hex);
221 snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, hlen, hex);
222 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
223 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
227 qry = string_sprintf(FMT, alt, (int) key->len, key->data, hlen, hex);
228 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
229 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
230 /* fprintf(stderr, "exim_s_dbp res %d\n", res); */
233 if (res != SQLITE_OK)
234 fprintf(stderr, "sqlite3_exec: %s\n", sqlite3_errmsg(dbp));
236 return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP;
240 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
243 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
245 /* fprintf(stderr, "exim_dbput()\n"); */
246 (void) exim_s_dbp(dbp, key, data, US"REPLACE");
250 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
252 /* Returns from EXIM_DBPUTB */
255 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
257 return exim_s_dbp(dbp, key, data, US"ABORT");
262 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
264 # define FMT "DELETE FROM tbl WHERE ky = '%.*s';"
268 # ifdef COMPILE_UTILITY
269 res = snprintf(NULL, 0, FMT, (int) key->len, key->data); /* res excludes nul */
271 snprintf(CS qry, res, FMT, (int) key->len, key->data);
272 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
275 qry = string_sprintf(FMT, (int) key->len, key->data);
276 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
284 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
285 /* Cursors are inefficiently emulated by repeating searches */
287 static inline EXIM_CURSOR *
288 exim_dbcreate_cursor(EXIM_DB * dbp)
290 # ifdef COMPILE_UTILITY
291 EXIM_CURSOR * c = malloc(sizeof(int));
293 EXIM_CURSOR * c = store_malloc(sizeof(int));
300 /* Note that we return the (next) key, not the record value */
302 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
303 EXIM_CURSOR * cursor)
305 # define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;"
310 # ifdef COMPILE_UTILITY
311 qry = malloc((i = snprintf(NULL, 0, FMT, *cursor)));
312 snprintf(CS qry, i-1, FMT, *cursor);
313 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
314 ret = exim_dbget__(dbp, qry, key);
316 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
318 qry = string_sprintf(FMT, *cursor);
319 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
320 ret = exim_dbget__(dbp, qry, key);
321 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
323 if (ret) *cursor = *cursor + 1;
328 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
330 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
332 # ifdef COMPILE_UTILITY
342 exim_dbclose_multi(EXIM_DB * dbp)
347 exim_dbtransaction_commit(EXIM_DB * dbp)
349 (void) sqlite3_exec(dbp, "COMMIT TRANSACTION;", NULL, NULL, NULL);
352 exim_dbclose__(EXIM_DB * dbp)
354 exim_dbtransaction_commit(dbp);
355 exim_dbclose_multi(dbp);
362 exim_datum_data_get(EXIM_DATUM * dp)
363 { return US dp->data; }
365 exim_datum_data_set(EXIM_DATUM * dp, void * s)
369 exim_datum_size_get(EXIM_DATUM * dp)
372 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
378 exim_datum_init(EXIM_DATUM * dp)
379 { dp->data = NULL; } /* compiler quietening */
381 /* No free needed for a datum */
384 exim_datum_free(EXIM_DATUM * dp)
389 # define EXIM_DB_RLIMIT 150
396 #elif defined(USE_TDB)
398 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE)
399 # error USE_TDB conflict with alternate definition
402 /* ************************* tdb interface ************************ */
403 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
404 Could we lose the file lock? */
409 # define EXIM_DB TDB_CONTEXT
411 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
412 tdb_traverse to be called) */
413 # define EXIM_CURSOR TDB_DATA
415 /* The datum type used for queries */
416 # define EXIM_DATUM TDB_DATA
418 /* Some text for messages */
419 # define EXIM_DBTYPE "tdb"
421 /* Access functions */
424 exim_lockfile_needed(void)
429 static inline EXIM_DB *
430 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
431 unsigned mode) { return NULL; }
432 static inline void exim_dbclose_multi(EXIM_DB * dbp) {}
433 static inline BOOL exim_dbtransaction_start(EXIM_DB * dbp) { return FALSE; }
434 static inline void exim_dbtransaction_commit(EXIM_DB * dbp) {}
436 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
437 static inline EXIM_DB *
438 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
441 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
444 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
446 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
448 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
449 return res->dptr != NULL;
452 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
454 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
455 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
457 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
459 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
460 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
462 /* Returns from EXIM_DBPUTB */
464 # define EXIM_DBPUTB_OK 0
465 # define EXIM_DBPUTB_DUP (-1)
469 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
470 { return tdb_delete(dbp, *key); }
472 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
473 static inline EXIM_CURSOR *
474 exim_dbcreate_cursor(EXIM_DB * dbp)
476 # ifdef COMPILE_UTILITY
477 EXIM_CURSOR * c = malloc(sizeof(TDB_DATA));
479 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
485 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
486 free() must not die when passed NULL */
489 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
490 EXIM_CURSOR * cursor)
492 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
495 return key->dptr != NULL;
498 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
500 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
501 { store_free(cursor); }
505 exim_dbclose__(EXIM_DB * db)
510 static inline uschar *
511 exim_datum_data_get(EXIM_DATUM * dp)
512 { return US dp->dptr; }
514 exim_datum_data_set(EXIM_DATUM * dp, void * s)
517 static inline unsigned
518 exim_datum_size_get(EXIM_DATUM * dp)
519 { return dp->dsize; }
521 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
524 /* No initialization is needed. */
527 exim_datum_init(EXIM_DATUM * d)
530 /* Free the stuff inside the datum. */
533 exim_datum_free(EXIM_DATUM * d)
541 # define EXIM_DB_RLIMIT 150
548 /********************* Berkeley db native definitions **********************/
552 # if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE)
553 # error USE_DB conflict with alternate definition
558 /* 1.x did no locking
559 2.x had facilities, but exim does it's own
563 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
564 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
566 # ifdef DB_VERSION_STRING
568 # if DB_VERSION_MAJOR >= 6
569 # error Version 6 and later BDB API is not supported
572 /* The API changed (again!) between the 2.x and 3.x versions */
574 # if DB_VERSION_MAJOR >= 3
576 /***************** Berkeley db 3.x/4.x native definitions ******************/
579 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
580 # define EXIM_DB DB_ENV
581 /* Cursor type, for scanning */
582 # define EXIM_CURSOR DBC
584 /* The datum type used for queries */
585 # define EXIM_DATUM DBT
587 /* Some text for messages */
588 # define EXIM_DBTYPE "db (v4.1+)"
590 /* Only more-recent versions. 5+ ? */
591 # ifndef DB_FORCESYNC
592 # define DB_FORCESYNC 0
596 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
597 errors. This should help with debugging strange DB problems, e.g. getting "File
598 exists" when you try to open a db file. The API for this function was changed
599 at DB release 4.3. */
602 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
605 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
611 /* Access functions (BDB 4.1+) */
614 exim_lockfile_needed(void)
619 static inline EXIM_DB *
620 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
621 unsigned mode) { return NULL; }
622 static inline void exim_dbclose_multi(EXIM_DB * dbp) {}
623 static inline BOOL exim_dbtransaction_start(EXIM_DB * dbp) { return FALSE; }
624 static inline void exim_dbtransaction_commit(EXIM_DB * dbp) {}
626 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
627 /* The API changed for DB 4.1. - and we also starting using the "env" with a
628 specified working dir, to avoid the DBCONFIG file trap. */
630 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
632 static inline EXIM_DB *
633 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
638 if ( db_env_create(&dbp, 0) != 0
639 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
640 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
643 if (db_create(&b, dbp, 0) == 0)
645 dbp->app_private = b;
646 if (b->open(b, NULL, CS name, NULL,
647 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
648 flags & O_CREAT ? DB_CREATE
649 : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
660 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
662 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
664 DB * b = ENV_TO_DB(dbp);
665 return b->get(b, NULL, key, res, 0) == 0;
668 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
670 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
672 DB * b = ENV_TO_DB(dbp);
673 return b->put(b, NULL, key, data, 0);
676 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
678 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
680 DB * b = ENV_TO_DB(dbp);
681 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
684 /* Return values from EXIM_DBPUTB */
686 # define EXIM_DBPUTB_OK 0
687 # define EXIM_DBPUTB_DUP DB_KEYEXIST
691 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
693 DB * b = ENV_TO_DB(dbp);
694 return b->del(b, NULL, key, 0);
697 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
699 static inline EXIM_CURSOR *
700 exim_dbcreate_cursor(EXIM_DB * dbp)
702 DB * b = ENV_TO_DB(dbp);
704 b->cursor(b, NULL, &c, 0);
708 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
710 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
711 EXIM_CURSOR * cursor)
713 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
716 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
718 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
719 { cursor->c_close(cursor); }
723 exim_dbclose__(EXIM_DB * dbp_o)
725 DB_ENV * dbp = dbp_o;
726 DB * b = ENV_TO_DB(dbp);
728 dbp->close(dbp, DB_FORCESYNC);
733 static inline uschar *
734 exim_datum_data_get(EXIM_DATUM * dp)
737 exim_datum_data_set(EXIM_DATUM * dp, void * s)
740 static inline unsigned
741 exim_datum_size_get(EXIM_DATUM * dp)
744 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
747 /* The whole datum structure contains other fields that must be cleared
748 before use, but we don't have to free anything after reading data. */
751 exim_datum_init(EXIM_DATUM * d)
752 { memset(d, 0, sizeof(*d)); }
755 exim_datum_free(EXIM_DATUM * d)
758 # else /* pre- 4.1 */
762 /* Cursor type, for scanning */
763 # define EXIM_CURSOR DBC
765 /* The datum type used for queries */
766 # define EXIM_DATUM DBT
768 /* Some text for messages */
769 # define EXIM_DBTYPE "db (v3/4)"
771 /* Access functions (BDB 3/4) */
774 exim_lockfile_needed(void)
779 static inline EXIM_DB *
780 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
781 unsigned mode) { return NULL; }
782 static inline void exim_dbclose_multi(EXIM_DB * dbp) {}
783 static inline BOOL exim_dbtransaction_start(EXIM_DB * dbp) { return FALSE; }
784 static inline void exim_dbtransaction_commit(EXIM_DB * dbp) {}
786 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
787 static inline EXIM_DB *
788 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
792 return db_create(&dbp, NULL, 0) == 0
793 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
794 dbp->open(dbp, CS name, NULL,
795 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
796 flags & O_CREAT ? DB_CREATE
797 : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
803 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
805 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
806 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
808 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
810 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
811 { return dbp->put(dbp, NULL, key, data, 0); }
813 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
815 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
816 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
818 /* Return values from EXIM_DBPUTB */
820 # define EXIM_DBPUTB_OK 0
821 # define EXIM_DBPUTB_DUP DB_KEYEXIST
825 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
826 { return dbp->del(dbp, NULL, key, 0); }
828 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
830 static inline EXIM_CURSOR *
831 exim_dbcreate_cursor(EXIM_DB * dbp)
834 dbp->cursor(dbp, NULL, &c, 0);
838 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
840 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
841 EXIM_CURSOR * cursor)
843 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
846 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
848 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
849 { cursor->c_close(cursor); }
853 exim_dbclose__(EXIM_DB * dbp)
854 { dbp->close(dbp, 0); }
858 static inline uschar *
859 exim_datum_data_get(EXIM_DATUM * dp)
860 { return US dp->dptr; }
862 exim_datum_data_set(EXIM_DATUM * dp, void * s)
865 static inline uschar *
866 exim_datum_size_get(EXIM_DATUM * dp)
867 { return US dp->size; }
869 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
872 /* The whole datum structure contains other fields that must be cleared
873 before use, but we don't have to free anything after reading data. */
876 exim_datum_init(EXIM_DATUM * d)
877 { memset(d, 0, sizeof(*d)); }
880 exim_datum_free(EXIM_DATUM * d)
886 # else /* DB_VERSION_MAJOR >= 3 */
887 # error Berkeley DB versions earlier than 3 are not supported */
888 # endif /* DB_VERSION_MAJOR */
890 # error Berkeley DB version 1 is no longer supported
891 # endif /* DB_VERSION_STRING */
894 /* all BDB versions */
897 # define EXIM_DB_RLIMIT 150
904 /********************* gdbm interface definitions **********************/
906 #elif defined USE_GDBM
907 /*XXX TODO: exim's lockfile not needed? */
909 # if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE)
910 # error USE_GDBM conflict with alternate definition
917 GDBM_FILE gdbm; /* Database */
918 datum lkey; /* Last key, for scans */
921 /* Cursor type, not used with gdbm: just set up a dummy */
922 # define EXIM_CURSOR int
924 /* The datum type used for queries */
925 # define EXIM_DATUM datum
927 /* Some text for messages */
929 # define EXIM_DBTYPE "gdbm"
931 /* Access functions (gdbm) */
934 exim_lockfile_needed(void)
939 static inline EXIM_DB *
940 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
941 unsigned mode) { return NULL; }
942 static inline void exim_dbclose_multi(EXIM_DB * dbp) {}
943 static inline BOOL exim_dbtransaction_start(EXIM_DB * dbp) { return FALSE; }
944 static inline void exim_dbtransaction_commit(EXIM_DB * dbp) {}
946 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
947 static inline EXIM_DB *
948 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
951 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
954 dbp->lkey.dptr = NULL;
955 dbp->gdbm = gdbm_open(CS name, 0,
956 flags & O_CREAT ? GDBM_WRCREAT
957 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER : GDBM_READER,
959 if (dbp->gdbm) return dbp;
965 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
967 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
969 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
970 return res->dptr != NULL;
973 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
975 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
976 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
978 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
980 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
981 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
983 /* Returns from EXIM_DBPUTB */
985 # define EXIM_DBPUTB_OK 0
986 # define EXIM_DBPUTB_DUP 1
990 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
991 { return gdbm_delete(dbp->gdbm, *key); }
993 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
994 static inline EXIM_CURSOR *
995 exim_dbcreate_cursor(EXIM_DB * dbp)
1000 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1001 EXIM_CURSOR * cursor)
1004 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
1005 if ((s = dbp->lkey.dptr)) free(s);
1007 return key->dptr != NULL;
1010 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1012 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1017 exim_dbclose__(EXIM_DB * dbp)
1020 gdbm_close(dbp->gdbm);
1021 if ((s = dbp->lkey.dptr)) free(s);
1025 /* Datum access types */
1027 static inline uschar *
1028 exim_datum_data_get(EXIM_DATUM * dp)
1029 { return US dp->dptr; }
1031 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1034 static inline unsigned
1035 exim_datum_size_get(EXIM_DATUM * dp)
1036 { return dp->dsize; }
1038 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1041 /* There's no clearing required before use, but we have to free the dptr
1042 after reading data. */
1045 exim_datum_init(EXIM_DATUM * d)
1049 exim_datum_free(EXIM_DATUM * d)
1052 /* size limit. GDBM is int-max limited, but we want to be less silly */
1054 # define EXIM_DB_RLIMIT 150
1056 #else /* USE_GDBM */
1063 /* If none of USE_DB, USG_GDBM, USE_SQLITE or USE_TDB are set,
1064 the default is the NDBM interface (which seems to be a wrapper for GDBM) */
1067 /********************* ndbm interface definitions **********************/
1072 # define EXIM_DB DBM
1074 /* Cursor type, not used with ndbm: just set up a dummy */
1075 # define EXIM_CURSOR int
1077 /* The datum type used for queries */
1078 # define EXIM_DATUM datum
1080 /* Some text for messages */
1082 # define EXIM_DBTYPE "ndbm"
1084 /* Access functions (ndbm) */
1087 exim_lockfile_needed(void)
1092 static inline EXIM_DB *
1093 exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags,
1094 unsigned mode) { return NULL; }
1095 static inline void exim_dbclose_multi(EXIM_DB * dbp) {}
1096 static inline BOOL exim_dbtransaction_start(EXIM_DB * dbp) { return FALSE; }
1097 static inline void exim_dbtransaction_commit(EXIM_DB * dbp) {}
1099 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
1100 /* Check that the name given is not present. This catches
1101 a directory name; otherwise we would create the name.pag and
1102 name.dir files in the directory's parent. */
1104 static inline EXIM_DB *
1105 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
1109 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
1110 return dbm_open(CS name, flags, mode);
1111 #ifndef COMPILE_UTILITY
1112 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
1114 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
1118 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
1120 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
1122 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
1123 return res->dptr != NULL;
1126 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
1128 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1129 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
1131 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
1133 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1134 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
1136 /* Returns from EXIM_DBPUTB */
1138 # define EXIM_DBPUTB_OK 0
1139 # define EXIM_DBPUTB_DUP 1
1143 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1144 { return dbm_delete(dbp, *key); }
1146 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1147 static inline EXIM_CURSOR *
1148 exim_dbcreate_cursor(EXIM_DB * dbp)
1153 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1154 EXIM_CURSOR * cursor)
1156 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1157 return key->dptr != NULL;
1160 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1162 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1167 exim_dbclose__(EXIM_DB * dbp)
1170 /* Datum access types */
1172 static inline uschar *
1173 exim_datum_data_get(EXIM_DATUM * dp)
1174 { return US dp->dptr; }
1176 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1179 static inline unsigned
1180 exim_datum_size_get(EXIM_DATUM * dp)
1181 { return dp->dsize; }
1183 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1186 /* There's no clearing required before use, and we don't have to free anything
1187 after reading data. */
1190 exim_datum_init(EXIM_DATUM * d)
1194 exim_datum_free(EXIM_DATUM * d)
1199 # define EXIM_DB_RLIMIT 150
1201 #endif /* !USE_GDBM */
1207 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1209 static inline EXIM_DB *
1210 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1213 return exim_dbopen__(name, dirname, flags, mode);
1217 exim_dbclose(EXIM_DB * dbp)
1218 { exim_dbclose__(dbp); }
1220 #else /* exim mainline code */
1222 /* Wrappers for open/close with debug tracing */
1224 extern void debug_printf_indent(const char *, ...);
1225 static inline BOOL is_tainted(const void *);
1227 static inline EXIM_DB *
1228 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1232 DEBUG(D_hints_lookup)
1233 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1235 flags == O_RDONLY ? "O_RDONLY"
1236 : flags == O_RDWR ? "O_RDWR"
1237 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1239 if (is_tainted(name) || is_tainted(dirname))
1241 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1245 dbp = exim_dbopen__(name, dirname, flags, mode);
1247 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1252 exim_dbclose(EXIM_DB * dbp)
1254 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1255 exim_dbclose__(dbp);
1258 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1260 /********************* End of dbm library definitions **********************/
1263 #endif /* whole file */
1264 /* End of hintsdb.h */