1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
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. */
27 # if defined(USE_DB) || defined(USE_GDBM)
28 # error USE_TDB conflict with alternate definition
31 /* ************************* tdb interface ************************ */
32 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
33 Could we lose the file lock? */
38 # define EXIM_DB TDB_CONTEXT
40 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
41 tdb_traverse to be called) */
42 # define EXIM_CURSOR TDB_DATA
44 /* The datum type used for queries */
45 # define EXIM_DATUM TDB_DATA
47 /* Some text for messages */
48 # define EXIM_DBTYPE "tdb"
50 /* Access functions */
52 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
53 static inline EXIM_DB *
54 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
57 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
60 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
62 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
64 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
65 return res->dptr != NULL;
68 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
70 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
71 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
73 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
75 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
76 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
78 /* Returns from EXIM_DBPUTB */
80 # define EXIM_DBPUTB_OK 0
81 # define EXIM_DBPUTB_DUP (-1)
85 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
86 { return tdb_delete(dbp, *key); }
88 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
89 static inline EXIM_CURSOR *
90 exim_dbcreate_cursor(EXIM_DB * dbp)
92 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
97 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
98 free() must not die when passed NULL */
101 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
102 EXIM_CURSOR * cursor)
104 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
107 return key->dptr != NULL;
110 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
112 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
113 { store_free(cursor); }
117 exim_dbclose__(EXIM_DB * db)
122 static inline uschar *
123 exim_datum_data_get(EXIM_DATUM * dp)
124 { return US dp->dptr; }
126 exim_datum_data_set(EXIM_DATUM * dp, void * s)
129 static inline unsigned
130 exim_datum_size_get(EXIM_DATUM * dp)
131 { return dp->dsize; }
133 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
136 /* No initialization is needed. */
139 exim_datum_init(EXIM_DATUM * d)
142 /* Free the stuff inside the datum. */
145 exim_datum_free(EXIM_DATUM * d)
153 # define EXIM_DB_RLIMIT 150
160 /********************* Berkeley db native definitions **********************/
164 # if defined(USE_TDB) || defined(USE_GDBM)
165 # error USE_DB conflict with alternate definition
170 /* 1.x did no locking
171 2.x had facilities, but exim does it's own
175 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
176 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
178 # ifdef DB_VERSION_STRING
180 # if DB_VERSION_MAJOR >= 6
181 # error Version 6 and later BDB API is not supported
184 /* The API changed (again!) between the 2.x and 3.x versions */
186 # if DB_VERSION_MAJOR >= 3
188 /***************** Berkeley db 3.x/4.x native definitions ******************/
191 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
192 # define EXIM_DB DB_ENV
193 /* Cursor type, for scanning */
194 # define EXIM_CURSOR DBC
196 /* The datum type used for queries */
197 # define EXIM_DATUM DBT
199 /* Some text for messages */
200 # define EXIM_DBTYPE "db (v4.1+)"
202 /* Only more-recent versions. 5+ ? */
203 # ifndef DB_FORCESYNC
204 # define DB_FORCESYNC 0
208 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
209 errors. This should help with debugging strange DB problems, e.g. getting "File
210 exists" when you try to open a db file. The API for this function was changed
211 at DB release 4.3. */
214 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
217 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
223 /* Access functions */
225 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
226 /* The API changed for DB 4.1. - and we also starting using the "env" with a
227 specified working dir, to avoid the DBCONFIG file trap. */
229 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
231 static inline EXIM_DB *
232 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
237 if ( db_env_create(&dbp, 0) != 0
238 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
239 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
242 if (db_create(&b, dbp, 0) == 0)
244 dbp->app_private = b;
245 if (b->open(b, NULL, CS name, NULL,
246 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
247 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
258 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
260 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
262 DB * b = ENV_TO_DB(dbp);
263 return b->get(b, NULL, key, res, 0) == 0;
266 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
268 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
270 DB * b = ENV_TO_DB(dbp);
271 return b->put(b, NULL, key, data, 0);
274 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
276 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
278 DB * b = ENV_TO_DB(dbp);
279 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
282 /* Return values from EXIM_DBPUTB */
284 # define EXIM_DBPUTB_OK 0
285 # define EXIM_DBPUTB_DUP DB_KEYEXIST
289 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
291 DB * b = ENV_TO_DB(dbp);
292 return b->del(b, NULL, key, 0);
295 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
297 static inline EXIM_CURSOR *
298 exim_dbcreate_cursor(EXIM_DB * dbp)
300 DB * b = ENV_TO_DB(dbp);
302 b->cursor(b, NULL, &c, 0);
306 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
308 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
309 EXIM_CURSOR * cursor)
311 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
314 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
316 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
317 { cursor->c_close(cursor); }
321 exim_dbclose__(EXIM_DB * dbp_o)
323 DB_ENV * dbp = dbp_o;
324 DB * b = ENV_TO_DB(dbp);
326 dbp->close(dbp, DB_FORCESYNC);
331 static inline uschar *
332 exim_datum_data_get(EXIM_DATUM * dp)
335 exim_datum_data_set(EXIM_DATUM * dp, void * s)
338 static inline unsigned
339 exim_datum_size_get(EXIM_DATUM * dp)
342 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
345 /* The whole datum structure contains other fields that must be cleared
346 before use, but we don't have to free anything after reading data. */
349 exim_datum_init(EXIM_DATUM * d)
350 { memset(d, 0, sizeof(*d)); }
353 exim_datum_free(EXIM_DATUM * d)
356 # else /* pre- 4.1 */
360 /* Cursor type, for scanning */
361 # define EXIM_CURSOR DBC
363 /* The datum type used for queries */
364 # define EXIM_DATUM DBT
366 /* Some text for messages */
367 # define EXIM_DBTYPE "db (v3/4)"
369 /* Access functions */
371 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
372 static inline EXIM_DB *
373 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
377 return db_create(&dbp, NULL, 0) == 0
378 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
379 dbp->open(dbp, CS name, NULL,
380 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
381 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
387 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
389 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
390 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
392 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
394 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
395 { return dbp->put(dbp, NULL, key, data, 0); }
397 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
399 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
400 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
402 /* Return values from EXIM_DBPUTB */
404 # define EXIM_DBPUTB_OK 0
405 # define EXIM_DBPUTB_DUP DB_KEYEXIST
409 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
410 { return dbp->del(dbp, NULL, key, 0); }
412 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
414 static inline EXIM_CURSOR *
415 exim_dbcreate_cursor(EXIM_DB * dbp)
418 dbp->cursor(dbp, NULL, &c, 0);
422 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
424 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
425 EXIM_CURSOR * cursor)
427 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
430 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
432 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
433 { cursor->c_close(cursor); }
437 exim_dbclose__(EXIM_DB * dbp)
438 { dbp->close(dbp, 0); }
442 static inline uschar *
443 exim_datum_data_get(EXIM_DATUM * dp)
444 { return US dp->dptr; }
446 exim_datum_data_set(EXIM_DATUM * dp, void * s)
449 static inline uschar *
450 exim_datum_size_get(EXIM_DATUM * dp)
451 { return US dp->size; }
453 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
456 /* The whole datum structure contains other fields that must be cleared
457 before use, but we don't have to free anything after reading data. */
460 exim_datum_init(EXIM_DATUM * d)
461 { memset(d, 0, sizeof(*d)); }
464 exim_datum_free(EXIM_DATUM * d)
470 # else /* DB_VERSION_MAJOR >= 3 */
471 # error Berkeley DB versions earlier than 3 are not supported */
472 # endif /* DB_VERSION_MAJOR */
474 # error Berkeley DB version 1 is no longer supported
475 # endif /* DB_VERSION_STRING */
478 /* all BDB versions */
481 # define EXIM_DB_RLIMIT 150
488 /********************* gdbm interface definitions **********************/
490 #elif defined USE_GDBM
491 /*XXX TODO: exim's locfile not needed */
493 # if defined(USE_TDB) || defined(USE_DB)
494 # error USE_GDBM conflict with alternate definition
501 GDBM_FILE gdbm; /* Database */
502 datum lkey; /* Last key, for scans */
505 /* Cursor type, not used with gdbm: just set up a dummy */
506 # define EXIM_CURSOR int
508 /* The datum type used for queries */
509 # define EXIM_DATUM datum
511 /* Some text for messages */
513 # define EXIM_DBTYPE "gdbm"
515 /* Access functions */
517 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
518 static inline EXIM_DB *
519 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
522 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
525 dbp->lkey.dptr = NULL;
526 dbp->gdbm = gdbm_open(CS name, 0,
527 flags & O_CREAT ? GDBM_WRCREAT
528 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
531 if (dbp->gdbm) return dbp;
537 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
539 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
541 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
542 return res->dptr != NULL;
545 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
547 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
548 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
550 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
552 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
553 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
555 /* Returns from EXIM_DBPUTB */
557 # define EXIM_DBPUTB_OK 0
558 # define EXIM_DBPUTB_DUP 1
562 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
563 { return gdbm_delete(dbp->gdbm, *key); }
565 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
566 static inline EXIM_CURSOR *
567 exim_dbcreate_cursor(EXIM_DB * dbp)
572 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
573 EXIM_CURSOR * cursor)
576 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
577 if ((s = dbp->lkey.dptr)) free(s);
579 return key->dptr != NULL;
582 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
584 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
589 exim_dbclose__(EXIM_DB * dbp)
592 gdbm_close(dbp->gdbm);
593 if ((s = dbp->lkey.dptr)) free(s);
597 /* Datum access types */
599 static inline uschar *
600 exim_datum_data_get(EXIM_DATUM * dp)
601 { return US dp->dptr; }
603 exim_datum_data_set(EXIM_DATUM * dp, void * s)
606 static inline unsigned
607 exim_datum_size_get(EXIM_DATUM * dp)
608 { return dp->dsize; }
610 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
613 /* There's no clearing required before use, but we have to free the dptr
614 after reading data. */
617 exim_datum_init(EXIM_DATUM * d)
621 exim_datum_free(EXIM_DATUM * d)
624 /* size limit. GDBM is int-max limited, but we want to be less silly */
626 # define EXIM_DB_RLIMIT 150
635 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
636 interface (which seems to be a wrapper for GDBM) */
639 /********************* ndbm interface definitions **********************/
646 /* Cursor type, not used with ndbm: just set up a dummy */
647 # define EXIM_CURSOR int
649 /* The datum type used for queries */
650 # define EXIM_DATUM datum
652 /* Some text for messages */
654 # define EXIM_DBTYPE "ndbm"
656 /* Access functions */
658 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
659 /* Check that the name given is not present. This catches
660 a directory name; otherwise we would create the name.pag and
661 name.dir files in the directory's parent. */
663 static inline EXIM_DB *
664 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
668 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
669 return dbm_open(CS name, flags, mode);
670 #ifndef COMPILE_UTILITY
671 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
673 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
677 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
679 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
681 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
682 return res->dptr != NULL;
685 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
687 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
688 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
690 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
692 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
693 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
695 /* Returns from EXIM_DBPUTB */
697 # define EXIM_DBPUTB_OK 0
698 # define EXIM_DBPUTB_DUP 1
702 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
703 { return dbm_delete(dbp, *key); }
705 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
706 static inline EXIM_CURSOR *
707 exim_dbcreate_cursor(EXIM_DB * dbp)
712 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
713 EXIM_CURSOR * cursor)
715 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
716 return key->dptr != NULL;
719 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
721 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
726 exim_dbclose__(EXIM_DB * dbp)
729 /* Datum access types */
731 static inline uschar *
732 exim_datum_data_get(EXIM_DATUM * dp)
733 { return US dp->dptr; }
735 exim_datum_data_set(EXIM_DATUM * dp, void * s)
738 static inline unsigned
739 exim_datum_size_get(EXIM_DATUM * dp)
740 { return dp->dsize; }
742 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
745 /* There's no clearing required before use, and we don't have to free anything
746 after reading data. */
749 exim_datum_init(EXIM_DATUM * d)
753 exim_datum_free(EXIM_DATUM * d)
758 # define EXIM_DB_RLIMIT 150
760 #endif /* !USE_GDBM */
766 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
768 static inline EXIM_DB *
769 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
772 return exim_dbopen__(name, dirname, flags, mode);
776 exim_dbclose(EXIM_DB * dbp)
777 { exim_dbclose__(dbp); }
779 #else /* exim mainline code */
781 /* Wrappers for open/close with debug tracing */
783 extern void debug_printf_indent(const char *, ...);
784 static inline BOOL is_tainted(const void *);
786 static inline EXIM_DB *
787 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
791 DEBUG(D_hints_lookup)
792 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
794 flags == O_RDONLY ? "O_RDONLY"
795 : flags == O_RDWR ? "O_RDWR"
796 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
798 if (is_tainted(name) || is_tainted(dirname))
800 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
804 dbp = exim_dbopen__(name, dirname, flags, mode);
806 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
811 exim_dbclose(EXIM_DB * dbp)
813 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
817 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
819 /********************* End of dbm library definitions **********************/
822 #endif /* whole file */
823 /* End of hintsdb.h */