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 /* ************************* tdb interface ************************ */
28 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
29 Could we lose the file lock? */
34 # define EXIM_DB TDB_CONTEXT
36 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
37 tdb_traverse to be called) */
38 # define EXIM_CURSOR TDB_DATA
40 /* The datum type used for queries */
41 # define EXIM_DATUM TDB_DATA
43 /* Some text for messages */
44 # define EXIM_DBTYPE "tdb"
46 /* Access functions */
48 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
49 static inline EXIM_DB *
50 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
53 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
56 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
58 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
60 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
61 return res->dptr != NULL;
64 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
66 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
67 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
69 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
71 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
72 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
74 /* Returns from EXIM_DBPUTB */
76 # define EXIM_DBPUTB_OK 0
77 # define EXIM_DBPUTB_DUP (-1)
81 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
82 { return tdb_delete(dbp, *key); }
84 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
85 static inline EXIM_CURSOR *
86 exim_dbcreate_cursor(EXIM_DB * dbp)
88 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
93 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
94 free() must not die when passed NULL */
97 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
100 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
103 return key->dptr != NULL;
106 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
108 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
109 { store_free(cursor); }
113 exim_dbclose__(EXIM_DB * db)
118 static inline uschar *
119 exim_datum_data_get(EXIM_DATUM * dp)
120 { return US dp->dptr; }
122 exim_datum_data_set(EXIM_DATUM * dp, void * s)
125 static inline unsigned
126 exim_datum_size_get(EXIM_DATUM * dp)
127 { return dp->dsize; }
129 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
132 /* No initialization is needed. */
135 exim_datum_init(EXIM_DATUM * d)
138 /* Free the stuff inside the datum. */
141 exim_datum_free(EXIM_DATUM * d)
149 # define EXIM_DB_RLIMIT 150
156 /********************* Berkeley db native definitions **********************/
162 /* 1.x did no locking
163 2.x had facilities, but exim does it's own
167 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
168 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
170 # ifdef DB_VERSION_STRING
172 # if DB_VERSION_MAJOR >= 6
173 # error Version 6 and later BDB API is not supported
176 /* The API changed (again!) between the 2.x and 3.x versions */
178 # if DB_VERSION_MAJOR >= 3
180 /***************** Berkeley db 3.x/4.x native definitions ******************/
183 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
184 # define EXIM_DB DB_ENV
185 /* Cursor type, for scanning */
186 # define EXIM_CURSOR DBC
188 /* The datum type used for queries */
189 # define EXIM_DATUM DBT
191 /* Some text for messages */
192 # define EXIM_DBTYPE "db (v4.1+)"
194 /* Only more-recent versions. 5+ ? */
195 # ifndef DB_FORCESYNC
196 # define DB_FORCESYNC 0
200 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
201 errors. This should help with debugging strange DB problems, e.g. getting "File
202 exists" when you try to open a db file. The API for this function was changed
203 at DB release 4.3. */
206 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
209 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
215 /* Access functions */
217 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
218 /* The API changed for DB 4.1. - and we also starting using the "env" with a
219 specified working dir, to avoid the DBCONFIG file trap. */
221 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
223 static inline EXIM_DB *
224 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
229 if ( db_env_create(&dbp, 0) != 0
230 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
231 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
234 if (db_create(&b, dbp, 0) == 0)
236 dbp->app_private = b;
237 if (b->open(b, NULL, CS name, NULL,
238 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
239 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
250 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
252 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
254 DB * b = ENV_TO_DB(dbp);
255 return b->get(b, NULL, key, res, 0) == 0;
258 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
260 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
262 DB * b = ENV_TO_DB(dbp);
263 return b->put(b, NULL, key, data, 0);
266 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
268 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
270 DB * b = ENV_TO_DB(dbp);
271 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
274 /* Return values from EXIM_DBPUTB */
276 # define EXIM_DBPUTB_OK 0
277 # define EXIM_DBPUTB_DUP DB_KEYEXIST
281 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
283 DB * b = ENV_TO_DB(dbp);
284 return b->del(b, NULL, key, 0);
287 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
289 static inline EXIM_CURSOR *
290 exim_dbcreate_cursor(EXIM_DB * dbp)
292 DB * b = ENV_TO_DB(dbp);
294 b->cursor(b, NULL, &c, 0);
298 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
300 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
301 EXIM_CURSOR * cursor)
303 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
306 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
308 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
309 { cursor->c_close(cursor); }
313 exim_dbclose__(EXIM_DB * dbp_o)
315 DB_ENV * dbp = dbp_o;
316 DB * b = ENV_TO_DB(dbp);
318 dbp->close(dbp, DB_FORCESYNC);
323 static inline uschar *
324 exim_datum_data_get(EXIM_DATUM * dp)
327 exim_datum_data_set(EXIM_DATUM * dp, void * s)
330 static inline unsigned
331 exim_datum_size_get(EXIM_DATUM * dp)
334 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
337 /* The whole datum structure contains other fields that must be cleared
338 before use, but we don't have to free anything after reading data. */
341 exim_datum_init(EXIM_DATUM * d)
342 { memset(d, 0, sizeof(*d)); }
345 exim_datum_free(EXIM_DATUM * d)
348 # else /* pre- 4.1 */
352 /* Cursor type, for scanning */
353 # define EXIM_CURSOR DBC
355 /* The datum type used for queries */
356 # define EXIM_DATUM DBT
358 /* Some text for messages */
359 # define EXIM_DBTYPE "db (v3/4)"
361 /* Access functions */
363 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
364 static inline EXIM_DB *
365 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
369 return db_create(&dbp, NULL, 0) == 0
370 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
371 dbp->open(dbp, CS name, NULL,
372 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
373 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
379 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
381 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
382 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
384 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
386 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
387 { return dbp->put(dbp, NULL, key, data, 0); }
389 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
391 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
392 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
394 /* Return values from EXIM_DBPUTB */
396 # define EXIM_DBPUTB_OK 0
397 # define EXIM_DBPUTB_DUP DB_KEYEXIST
401 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
402 { return dbp->del(dbp, NULL, key, 0); }
404 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
406 static inline EXIM_CURSOR *
407 exim_dbcreate_cursor(EXIM_DB * dbp)
410 dbp->cursor(dbp, NULL, &c, 0);
414 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
416 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
417 EXIM_CURSOR * cursor)
419 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
422 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
424 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
425 { cursor->c_close(cursor); }
429 exim_dbclose__(EXIM_DB * dbp)
430 { dbp->close(dbp, 0); }
434 static inline uschar *
435 exim_datum_data_get(EXIM_DATUM * dp)
436 { return US dp->dptr; }
438 exim_datum_data_set(EXIM_DATUM * dp, void * s)
441 static inline uschar *
442 exim_datum_size_get(EXIM_DATUM * dp)
443 { return US dp->size; }
445 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
448 /* The whole datum structure contains other fields that must be cleared
449 before use, but we don't have to free anything after reading data. */
452 exim_datum_init(EXIM_DATUM * d)
453 { memset(d, 0, sizeof(*d)); }
456 exim_datum_free(EXIM_DATUM * d)
462 # else /* DB_VERSION_MAJOR >= 3 */
463 # error Berkeley DB versions earlier than 3 are not supported */
464 # endif /* DB_VERSION_MAJOR */
466 # error Berkeley DB version 1 is no longer supported
467 # endif /* DB_VERSION_STRING */
470 /* all BDB versions */
473 # define EXIM_DB_RLIMIT 150
480 /********************* gdbm interface definitions **********************/
482 #elif defined USE_GDBM
483 /*XXX TODO: exim's locfile not needed */
489 GDBM_FILE gdbm; /* Database */
490 datum lkey; /* Last key, for scans */
493 /* Cursor type, not used with gdbm: just set up a dummy */
494 # define EXIM_CURSOR int
496 /* The datum type used for queries */
497 # define EXIM_DATUM datum
499 /* Some text for messages */
501 # define EXIM_DBTYPE "gdbm"
503 /* Access functions */
505 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
506 static inline EXIM_DB *
507 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
510 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
513 dbp->lkey.dptr = NULL;
514 dbp->gdbm = gdbm_open(CS name, 0,
515 flags & O_CREAT ? GDBM_WRCREAT
516 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
519 if (dbp->gdbm) return dbp;
525 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
527 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
529 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
530 return res->dptr != NULL;
533 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
535 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
536 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
538 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
540 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
541 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
543 /* Returns from EXIM_DBPUTB */
545 # define EXIM_DBPUTB_OK 0
546 # define EXIM_DBPUTB_DUP 1
550 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
551 { return gdbm_delete(dbp->gdbm, *key); }
553 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
554 static inline EXIM_CURSOR *
555 exim_dbcreate_cursor(EXIM_DB * dbp)
560 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
561 EXIM_CURSOR * cursor)
564 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
565 if ((s = dbp->lkey.dptr)) free(s);
567 return key->dptr != NULL;
570 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
572 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
577 exim_dbclose__(EXIM_DB * dbp)
580 gdbm_close(dbp->gdbm);
581 if ((s = dbp->lkey.dptr)) free(s);
585 /* Datum access types */
587 static inline uschar *
588 exim_datum_data_get(EXIM_DATUM * dp)
589 { return US dp->dptr; }
591 exim_datum_data_set(EXIM_DATUM * dp, void * s)
594 static inline unsigned
595 exim_datum_size_get(EXIM_DATUM * dp)
596 { return dp->dsize; }
598 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
601 /* There's no clearing required before use, but we have to free the dptr
602 after reading data. */
605 exim_datum_init(EXIM_DATUM * d)
609 exim_datum_free(EXIM_DATUM * d)
614 # define EXIM_DB_RLIMIT 150
623 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
627 /********************* ndbm interface definitions **********************/
634 /* Cursor type, not used with ndbm: just set up a dummy */
635 # define EXIM_CURSOR int
637 /* The datum type used for queries */
638 # define EXIM_DATUM datum
640 /* Some text for messages */
642 # define EXIM_DBTYPE "ndbm"
644 /* Access functions */
646 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
647 /* Check that the name given is not present. This catches
648 a directory name; otherwise we would create the name.pag and
649 name.dir files in the directory's parent. */
651 static inline EXIM_DB *
652 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
656 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
657 return dbm_open(CS name, flags, mode);
658 #ifndef COMPILE_UTILITY
659 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
661 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
665 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
667 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
669 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
670 return res->dptr != NULL;
673 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
675 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
676 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
678 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
680 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
681 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
683 /* Returns from EXIM_DBPUTB */
685 # define EXIM_DBPUTB_OK 0
686 # define EXIM_DBPUTB_DUP 1
690 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
691 { return dbm_delete(dbp, *key); }
693 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
694 static inline EXIM_CURSOR *
695 exim_dbcreate_cursor(EXIM_DB * dbp)
700 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
701 EXIM_CURSOR * cursor)
703 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
704 return key->dptr != NULL;
707 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
709 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
714 exim_dbclose__(EXIM_DB * dbp)
717 /* Datum access types */
719 static inline uschar *
720 exim_datum_data_get(EXIM_DATUM * dp)
721 { return US dp->dptr; }
723 exim_datum_data_set(EXIM_DATUM * dp, void * s)
726 static inline unsigned
727 exim_datum_size_get(EXIM_DATUM * dp)
728 { return dp->dsize; }
730 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
733 /* There's no clearing required before use, and we don't have to free anything
734 after reading data. */
737 exim_datum_init(EXIM_DATUM * d)
741 exim_datum_free(EXIM_DATUM * d)
746 # define EXIM_DB_RLIMIT 150
748 #endif /* USE_GDBM */
754 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
756 static inline EXIM_DB *
757 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
760 return exim_dbopen__(name, dirname, flags, mode);
764 exim_dbclose(EXIM_DB * dbp)
765 { exim_dbclose__(dbp); }
767 #else /* exim mainline code */
769 /* Wrappers for open/close with debug tracing */
771 extern void debug_printf_indent(const char *, ...);
772 static inline BOOL is_tainted(const void *);
774 static inline EXIM_DB *
775 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
779 DEBUG(D_hints_lookup)
780 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
782 flags == O_RDONLY ? "O_RDONLY"
783 : flags == O_RDWR ? "O_RDWR"
784 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
786 if (is_tainted(name) || is_tainted(dirname))
788 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
792 dbp = exim_dbopen__(name, dirname, flags, mode);
794 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
799 exim_dbclose(EXIM_DB * dbp)
801 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
805 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
807 /********************* End of dbm library definitions **********************/
810 #endif /* whole file */
811 /* End of hintsdb.h */