1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
7 /* See the file NOTICE for conditions of use and distribution. */
9 /* This header file contains macro definitions so that a variety of DBM
10 libraries can be used by Exim. Nigel Metheringham provided the original set for
11 Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
12 2.x and 3.x were added. Later still, support for tdb was added, courtesy of
13 James Antill. Most recently, support for native mode gdbm was added, with code
14 from Pierre A. Humblet, so Exim could be made to work with Cygwin.
16 For convenience, the definitions of the structures used in the various hints
17 databases are also kept in this file, which is used by the maintenance
18 utilities as well as the main Exim binary. */
26 /* ************************* tdb interface ************************ */
27 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
28 Could we lose the file lock? */
33 # define EXIM_DB TDB_CONTEXT
35 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
36 tdb_traverse to be called) */
37 # define EXIM_CURSOR TDB_DATA
39 /* The datum type used for queries */
40 # define EXIM_DATUM TDB_DATA
42 /* Some text for messages */
43 # define EXIM_DBTYPE "tdb"
45 /* Access functions */
47 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
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 */
59 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
61 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
62 return res->dptr != NULL;
65 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
68 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
69 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
71 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
74 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
75 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
77 /* Returns from EXIM_DBPUTB */
79 # define EXIM_DBPUTB_OK 0
80 # 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 */
91 exim_dbcreate_cursor(EXIM_DB * dbp)
93 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
98 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
99 free() must not die when passed NULL */
103 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
104 EXIM_CURSOR * cursor)
106 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
109 return key->dptr != NULL;
112 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
115 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
116 { store_free(cursor); }
121 exim_dbclose__(EXIM_DB * db)
128 exim_datum_data_get(EXIM_DATUM * dp)
129 { return US dp->dptr; }
132 exim_datum_data_set(EXIM_DATUM * dp, void * s)
137 exim_datum_size_get(EXIM_DATUM * dp)
138 { return dp->dsize; }
141 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
144 /* No initialization is needed. */
148 exim_datum_init(EXIM_DATUM * d)
151 /* Free the stuff inside the datum. */
155 exim_datum_free(EXIM_DATUM * d)
163 # define EXIM_DB_RLIMIT 150
170 /********************* Berkeley db native definitions **********************/
176 /* 1.x did no locking
177 2.x had facilities, but exim does it's own
181 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
182 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
184 # ifdef DB_VERSION_STRING
186 # if DB_VERSION_MAJOR >= 6
187 # error Version 6 and later BDB API is not supported
190 /* The API changed (again!) between the 2.x and 3.x versions */
192 # if DB_VERSION_MAJOR >= 3
194 /***************** Berkeley db 3.x/4.x native definitions ******************/
197 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
198 # define EXIM_DB DB_ENV
199 /* Cursor type, for scanning */
200 # define EXIM_CURSOR DBC
202 /* The datum type used for queries */
203 # define EXIM_DATUM DBT
205 /* Some text for messages */
206 # define EXIM_DBTYPE "db (v4.1+)"
208 /* Only more-recent versions. 5+ ? */
209 # ifndef DB_FORCESYNC
210 # define DB_FORCESYNC 0
214 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
215 errors. This should help with debugging strange DB problems, e.g. getting "File
216 exists" when you try to open a db file. The API for this function was changed
217 at DB release 4.3. */
220 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
221 { log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); }
225 /* Access functions */
227 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
228 /* The API changed for DB 4.1. - and we also starting using the "env" with a
229 specified working dir, to avoid the DBCONFIG file trap. */
231 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
235 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
240 if ( db_env_create(&dbp, 0) != 0
241 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
242 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
245 if (db_create(&b, dbp, 0) == 0)
247 dbp->app_private = b;
248 if (b->open(b, NULL, CS name, NULL,
249 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
250 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
261 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
264 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
266 DB * b = ENV_TO_DB(dbp);
267 return b->get(b, NULL, key, res, 0) == 0;
270 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
273 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
275 DB * b = ENV_TO_DB(dbp);
276 return b->put(b, NULL, key, data, 0);
279 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
282 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
284 DB * b = ENV_TO_DB(dbp);
285 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
288 /* Return values from EXIM_DBPUTB */
290 # define EXIM_DBPUTB_OK 0
291 # define EXIM_DBPUTB_DUP DB_KEYEXIST
296 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
298 DB * b = ENV_TO_DB(dbp);
299 return b->del(b, NULL, key, 0);
302 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
306 exim_dbcreate_cursor(EXIM_DB * dbp)
308 DB * b = ENV_TO_DB(dbp);
310 b->cursor(b, NULL, &c, 0);
314 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
317 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
318 EXIM_CURSOR * cursor)
320 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
323 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
326 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
327 { cursor->c_close(cursor); }
332 exim_dbclose__(EXIM_DB * dbp_o)
334 DB_ENV * dbp = dbp_o;
335 DB * b = ENV_TO_DB(dbp);
337 dbp->close(dbp, DB_FORCESYNC);
344 exim_datum_data_get(EXIM_DATUM * dp)
348 exim_datum_data_set(EXIM_DATUM * dp, void * s)
353 exim_datum_size_get(EXIM_DATUM * dp)
357 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
360 /* The whole datum structure contains other fields that must be cleared
361 before use, but we don't have to free anything after reading data. */
365 exim_datum_init(EXIM_DATUM * d)
366 { memset(d, 0, sizeof(*d)); }
370 exim_datum_free(EXIM_DATUM * d)
373 # else /* pre- 4.1 */
377 /* Cursor type, for scanning */
378 # define EXIM_CURSOR DBC
380 /* The datum type used for queries */
381 # define EXIM_DATUM DBT
383 /* Some text for messages */
384 # define EXIM_DBTYPE "db (v3/4)"
386 /* Access functions */
388 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
391 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
395 return db_create(&dbp, NULL, 0) == 0
396 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
397 dbp->open(dbp, CS name, NULL,
398 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
399 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
405 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
408 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
409 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
411 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
414 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
415 { return dbp->put(dbp, NULL, key, data, 0); }
417 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
420 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
421 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
423 /* Return values from EXIM_DBPUTB */
425 # define EXIM_DBPUTB_OK 0
426 # define EXIM_DBPUTB_DUP DB_KEYEXIST
431 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
432 { return dbp->del(dbp, NULL, key, 0); }
434 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
438 exim_dbcreate_cursor(EXIM_DB * dbp)
441 dbp->cursor(dbp, NULL, &c, 0);
445 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
448 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
449 EXIM_CURSOR * cursor)
451 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
454 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
457 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
458 { cursor->c_close(cursor); }
463 exim_dbclose__(EXIM_DB * dbp)
464 { dbp->close(dbp, 0); }
470 exim_datum_data_get(EXIM_DATUM * dp)
471 { return US dp->dptr; }
474 exim_datum_data_set(EXIM_DATUM * dp, void * s)
479 exim_datum_size_get(EXIM_DATUM * dp)
480 { return US dp->size; }
483 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
486 /* The whole datum structure contains other fields that must be cleared
487 before use, but we don't have to free anything after reading data. */
491 exim_datum_init(EXIM_DATUM * d)
492 { memset(d, 0, sizeof(*d)); }
496 exim_datum_free(EXIM_DATUM * d)
502 # else /* DB_VERSION_MAJOR >= 3 */
503 # error Berkeley DB versions earlier than 3 are not supported */
504 # endif /* DB_VERSION_MAJOR */
506 # error Berkeley DB version 1 is no longer supported
507 # endif /* DB_VERSION_STRING */
510 /* all BDB versions */
513 # define EXIM_DB_RLIMIT 150
520 /********************* gdbm interface definitions **********************/
522 #elif defined USE_GDBM
523 /*XXX TODO: exim's locfile not needed */
529 GDBM_FILE gdbm; /* Database */
530 datum lkey; /* Last key, for scans */
533 /* Cursor type, not used with gdbm: just set up a dummy */
534 # define EXIM_CURSOR int
536 /* The datum type used for queries */
537 # define EXIM_DATUM datum
539 /* Some text for messages */
541 # define EXIM_DBTYPE "gdbm"
543 /* Access functions */
545 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
548 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
551 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
554 dbp->lkey.dptr = NULL;
555 dbp->gdbm = gdbm_open(CS name, 0,
556 flags & O_CREAT ? GDBM_WRCREAT
557 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
560 if (dbp->gdbm) return dbp;
566 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
569 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
571 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
572 return res->dptr != NULL;
575 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
578 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
579 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
581 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
584 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
585 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
587 /* Returns from EXIM_DBPUTB */
589 # define EXIM_DBPUTB_OK 0
590 # define EXIM_DBPUTB_DUP 1
595 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
596 { return gdbm_delete(dbp->gdbm, *key); }
598 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
601 exim_dbcreate_cursor(EXIM_DB * dbp)
607 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
608 EXIM_CURSOR * cursor)
611 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
612 if ((s = dbp->lkey.dptr)) free(s);
614 return key->dptr != NULL;
617 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
620 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
626 exim_dbclose__(EXIM_DB * dbp)
629 gdbm_close(dbp->gdbm);
630 if ((s = dbp->lkey.dptr)) free(s);
634 /* Datum access types */
638 exim_datum_data_get(EXIM_DATUM * dp)
639 { return US dp->dptr; }
642 exim_datum_data_set(EXIM_DATUM * dp, void * s)
647 exim_datum_size_get(EXIM_DATUM * dp)
648 { return dp->dsize; }
651 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
654 /* There's no clearing required before use, but we have to free the dptr
655 after reading data. */
659 exim_datum_init(EXIM_DATUM * d)
664 exim_datum_free(EXIM_DATUM * d)
669 # define EXIM_DB_RLIMIT 150
678 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
682 /********************* ndbm interface definitions **********************/
689 /* Cursor type, not used with ndbm: just set up a dummy */
690 # define EXIM_CURSOR int
692 /* The datum type used for queries */
693 # define EXIM_DATUM datum
695 /* Some text for messages */
697 # define EXIM_DBTYPE "ndbm"
699 /* Access functions */
701 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
702 /* Check that the name given is not present. This catches
703 a directory name; otherwise we would create the name.pag and
704 name.dir files in the directory's parent. */
708 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
712 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
713 return dbm_open(CS name, flags, mode);
714 #ifndef COMPILE_UTILITY
715 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
717 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
721 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
724 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
726 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
727 return res->dptr != NULL;
730 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
733 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
734 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
736 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
739 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
740 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
742 /* Returns from EXIM_DBPUTB */
744 # define EXIM_DBPUTB_OK 0
745 # define EXIM_DBPUTB_DUP 1
750 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
751 { return dbm_delete(dbp, *key); }
753 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
756 exim_dbcreate_cursor(EXIM_DB * dbp)
762 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
763 EXIM_CURSOR * cursor)
765 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
766 return key->dptr != NULL;
769 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
772 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
778 exim_dbclose__(EXIM_DB * dbp)
781 /* Datum access types */
785 exim_datum_data_get(EXIM_DATUM * dp)
786 { return US dp->dptr; }
789 exim_datum_data_set(EXIM_DATUM * dp, void * s)
794 exim_datum_size_get(EXIM_DATUM * dp)
795 { return dp->dsize; }
798 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
801 /* There's no clearing required before use, and we don't have to free anything
802 after reading data. */
806 exim_datum_init(EXIM_DATUM * d)
811 exim_datum_free(EXIM_DATUM * d)
816 # define EXIM_DB_RLIMIT 150
818 #endif /* USE_GDBM */
824 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
828 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
831 return exim_dbopen__(name, dirname, flags, mode);
836 exim_dbclose(EXIM_DB * dbp)
837 { exim_dbclose__(dbp); }
840 /* Wrappers for open/close with debug tracing */
842 extern void debug_printf_indent(const char *, ...);
843 static BOOL is_tainted(const void *);
847 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
851 DEBUG(D_hints_lookup)
852 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
854 flags == O_RDONLY ? "O_RDONLY"
855 : flags == O_RDWR ? "O_RDWR"
856 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
858 if (is_tainted(name) || is_tainted(dirname))
860 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
864 dbp = exim_dbopen__(name, dirname, flags, mode);
866 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
872 exim_dbclose(EXIM_DB * dbp)
874 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
880 /********************* End of dbm library definitions **********************/
883 #endif /* whole file */
884 /* End of hintsdb.h */