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. */
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 */
48 static inline EXIM_DB *
49 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
52 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
55 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
57 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
59 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
60 return res->dptr != NULL;
63 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
65 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
66 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
68 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
70 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
71 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
73 /* Returns from EXIM_DBPUTB */
75 # define EXIM_DBPUTB_OK 0
76 # define EXIM_DBPUTB_DUP (-1)
80 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
81 { return tdb_delete(dbp, *key); }
83 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
84 static inline EXIM_CURSOR *
85 exim_dbcreate_cursor(EXIM_DB * dbp)
87 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
92 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
93 free() must not die when passed NULL */
96 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
99 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
102 return key->dptr != NULL;
105 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
107 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
108 { store_free(cursor); }
112 exim_dbclose__(EXIM_DB * db)
117 static inline uschar *
118 exim_datum_data_get(EXIM_DATUM * dp)
119 { return US dp->dptr; }
121 exim_datum_data_set(EXIM_DATUM * dp, void * s)
124 static inline unsigned
125 exim_datum_size_get(EXIM_DATUM * dp)
126 { return dp->dsize; }
128 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
131 /* No initialization is needed. */
134 exim_datum_init(EXIM_DATUM * d)
137 /* Free the stuff inside the datum. */
140 exim_datum_free(EXIM_DATUM * d)
148 # define EXIM_DB_RLIMIT 150
155 /********************* Berkeley db native definitions **********************/
161 /* 1.x did no locking
162 2.x had facilities, but exim does it's own
166 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
167 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
169 # ifdef DB_VERSION_STRING
171 # if DB_VERSION_MAJOR >= 6
172 # error Version 6 and later BDB API is not supported
175 /* The API changed (again!) between the 2.x and 3.x versions */
177 # if DB_VERSION_MAJOR >= 3
179 /***************** Berkeley db 3.x/4.x native definitions ******************/
182 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
183 # define EXIM_DB DB_ENV
184 /* Cursor type, for scanning */
185 # define EXIM_CURSOR DBC
187 /* The datum type used for queries */
188 # define EXIM_DATUM DBT
190 /* Some text for messages */
191 # define EXIM_DBTYPE "db (v4.1+)"
193 /* Only more-recent versions. 5+ ? */
194 # ifndef DB_FORCESYNC
195 # define DB_FORCESYNC 0
199 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
200 errors. This should help with debugging strange DB problems, e.g. getting "File
201 exists" when you try to open a db file. The API for this function was changed
202 at DB release 4.3. */
205 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
208 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
214 /* Access functions */
216 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
217 /* The API changed for DB 4.1. - and we also starting using the "env" with a
218 specified working dir, to avoid the DBCONFIG file trap. */
220 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
222 static inline EXIM_DB *
223 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
228 if ( db_env_create(&dbp, 0) != 0
229 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
230 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
233 if (db_create(&b, dbp, 0) == 0)
235 dbp->app_private = b;
236 if (b->open(b, NULL, CS name, NULL,
237 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
238 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
249 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
251 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
253 DB * b = ENV_TO_DB(dbp);
254 return b->get(b, NULL, key, res, 0) == 0;
257 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
259 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
261 DB * b = ENV_TO_DB(dbp);
262 return b->put(b, NULL, key, data, 0);
265 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
267 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
269 DB * b = ENV_TO_DB(dbp);
270 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
273 /* Return values from EXIM_DBPUTB */
275 # define EXIM_DBPUTB_OK 0
276 # define EXIM_DBPUTB_DUP DB_KEYEXIST
280 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
282 DB * b = ENV_TO_DB(dbp);
283 return b->del(b, NULL, key, 0);
286 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
288 static inline EXIM_CURSOR *
289 exim_dbcreate_cursor(EXIM_DB * dbp)
291 DB * b = ENV_TO_DB(dbp);
293 b->cursor(b, NULL, &c, 0);
297 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
299 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
300 EXIM_CURSOR * cursor)
302 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
305 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
307 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
308 { cursor->c_close(cursor); }
312 exim_dbclose__(EXIM_DB * dbp_o)
314 DB_ENV * dbp = dbp_o;
315 DB * b = ENV_TO_DB(dbp);
317 dbp->close(dbp, DB_FORCESYNC);
322 static inline uschar *
323 exim_datum_data_get(EXIM_DATUM * dp)
326 exim_datum_data_set(EXIM_DATUM * dp, void * s)
329 static inline unsigned
330 exim_datum_size_get(EXIM_DATUM * dp)
333 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
336 /* The whole datum structure contains other fields that must be cleared
337 before use, but we don't have to free anything after reading data. */
340 exim_datum_init(EXIM_DATUM * d)
341 { memset(d, 0, sizeof(*d)); }
344 exim_datum_free(EXIM_DATUM * d)
347 # else /* pre- 4.1 */
351 /* Cursor type, for scanning */
352 # define EXIM_CURSOR DBC
354 /* The datum type used for queries */
355 # define EXIM_DATUM DBT
357 /* Some text for messages */
358 # define EXIM_DBTYPE "db (v3/4)"
360 /* Access functions */
362 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
363 static inline EXIM_DB *
364 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
368 return db_create(&dbp, NULL, 0) == 0
369 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
370 dbp->open(dbp, CS name, NULL,
371 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
372 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
378 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
380 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
381 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
383 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
385 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
386 { return dbp->put(dbp, NULL, key, data, 0); }
388 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
390 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
391 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
393 /* Return values from EXIM_DBPUTB */
395 # define EXIM_DBPUTB_OK 0
396 # define EXIM_DBPUTB_DUP DB_KEYEXIST
400 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
401 { return dbp->del(dbp, NULL, key, 0); }
403 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
405 static inline EXIM_CURSOR *
406 exim_dbcreate_cursor(EXIM_DB * dbp)
409 dbp->cursor(dbp, NULL, &c, 0);
413 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
415 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
416 EXIM_CURSOR * cursor)
418 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
421 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
423 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
424 { cursor->c_close(cursor); }
428 exim_dbclose__(EXIM_DB * dbp)
429 { dbp->close(dbp, 0); }
433 static inline uschar *
434 exim_datum_data_get(EXIM_DATUM * dp)
435 { return US dp->dptr; }
437 exim_datum_data_set(EXIM_DATUM * dp, void * s)
440 static inline uschar *
441 exim_datum_size_get(EXIM_DATUM * dp)
442 { return US dp->size; }
444 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
447 /* The whole datum structure contains other fields that must be cleared
448 before use, but we don't have to free anything after reading data. */
451 exim_datum_init(EXIM_DATUM * d)
452 { memset(d, 0, sizeof(*d)); }
455 exim_datum_free(EXIM_DATUM * d)
461 # else /* DB_VERSION_MAJOR >= 3 */
462 # error Berkeley DB versions earlier than 3 are not supported */
463 # endif /* DB_VERSION_MAJOR */
465 # error Berkeley DB version 1 is no longer supported
466 # endif /* DB_VERSION_STRING */
469 /* all BDB versions */
472 # define EXIM_DB_RLIMIT 150
479 /********************* gdbm interface definitions **********************/
481 #elif defined USE_GDBM
482 /*XXX TODO: exim's locfile not needed */
488 GDBM_FILE gdbm; /* Database */
489 datum lkey; /* Last key, for scans */
492 /* Cursor type, not used with gdbm: just set up a dummy */
493 # define EXIM_CURSOR int
495 /* The datum type used for queries */
496 # define EXIM_DATUM datum
498 /* Some text for messages */
500 # define EXIM_DBTYPE "gdbm"
502 /* Access functions */
504 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
505 static inline EXIM_DB *
506 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
509 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
512 dbp->lkey.dptr = NULL;
513 dbp->gdbm = gdbm_open(CS name, 0,
514 flags & O_CREAT ? GDBM_WRCREAT
515 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
518 if (dbp->gdbm) return dbp;
524 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
526 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
528 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
529 return res->dptr != NULL;
532 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
534 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
535 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
537 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
539 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
540 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
542 /* Returns from EXIM_DBPUTB */
544 # define EXIM_DBPUTB_OK 0
545 # define EXIM_DBPUTB_DUP 1
549 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
550 { return gdbm_delete(dbp->gdbm, *key); }
552 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
553 static inline EXIM_CURSOR *
554 exim_dbcreate_cursor(EXIM_DB * dbp)
559 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
560 EXIM_CURSOR * cursor)
563 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
564 if ((s = dbp->lkey.dptr)) free(s);
566 return key->dptr != NULL;
569 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
571 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
576 exim_dbclose__(EXIM_DB * dbp)
579 gdbm_close(dbp->gdbm);
580 if ((s = dbp->lkey.dptr)) free(s);
584 /* Datum access types */
586 static inline uschar *
587 exim_datum_data_get(EXIM_DATUM * dp)
588 { return US dp->dptr; }
590 exim_datum_data_set(EXIM_DATUM * dp, void * s)
593 static inline unsigned
594 exim_datum_size_get(EXIM_DATUM * dp)
595 { return dp->dsize; }
597 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
600 /* There's no clearing required before use, but we have to free the dptr
601 after reading data. */
604 exim_datum_init(EXIM_DATUM * d)
608 exim_datum_free(EXIM_DATUM * d)
613 # define EXIM_DB_RLIMIT 150
622 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
626 /********************* ndbm interface definitions **********************/
633 /* Cursor type, not used with ndbm: just set up a dummy */
634 # define EXIM_CURSOR int
636 /* The datum type used for queries */
637 # define EXIM_DATUM datum
639 /* Some text for messages */
641 # define EXIM_DBTYPE "ndbm"
643 /* Access functions */
645 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
646 /* Check that the name given is not present. This catches
647 a directory name; otherwise we would create the name.pag and
648 name.dir files in the directory's parent. */
650 static inline EXIM_DB *
651 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
655 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
656 return dbm_open(CS name, flags, mode);
657 #ifndef COMPILE_UTILITY
658 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
660 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
664 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
666 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
668 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
669 return res->dptr != NULL;
672 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
674 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
675 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
677 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
679 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
680 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
682 /* Returns from EXIM_DBPUTB */
684 # define EXIM_DBPUTB_OK 0
685 # define EXIM_DBPUTB_DUP 1
689 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
690 { return dbm_delete(dbp, *key); }
692 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
693 static inline EXIM_CURSOR *
694 exim_dbcreate_cursor(EXIM_DB * dbp)
699 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
700 EXIM_CURSOR * cursor)
702 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
703 return key->dptr != NULL;
706 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
708 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
713 exim_dbclose__(EXIM_DB * dbp)
716 /* Datum access types */
718 static inline uschar *
719 exim_datum_data_get(EXIM_DATUM * dp)
720 { return US dp->dptr; }
722 exim_datum_data_set(EXIM_DATUM * dp, void * s)
725 static inline unsigned
726 exim_datum_size_get(EXIM_DATUM * dp)
727 { return dp->dsize; }
729 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
732 /* There's no clearing required before use, and we don't have to free anything
733 after reading data. */
736 exim_datum_init(EXIM_DATUM * d)
740 exim_datum_free(EXIM_DATUM * d)
745 # define EXIM_DB_RLIMIT 150
747 #endif /* USE_GDBM */
753 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
755 static inline EXIM_DB *
756 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
759 return exim_dbopen__(name, dirname, flags, mode);
763 exim_dbclose(EXIM_DB * dbp)
764 { exim_dbclose__(dbp); }
766 #else /* exim mainline code */
768 /* Wrappers for open/close with debug tracing */
770 extern void debug_printf_indent(const char *, ...);
771 static inline BOOL is_tainted(const void *);
773 static inline EXIM_DB *
774 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
778 DEBUG(D_hints_lookup)
779 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
781 flags == O_RDONLY ? "O_RDONLY"
782 : flags == O_RDWR ? "O_RDWR"
783 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
785 if (is_tainted(name) || is_tainted(dirname))
787 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
791 dbp = exim_dbopen__(name, dirname, flags, mode);
793 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
798 exim_dbclose(EXIM_DB * dbp)
800 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
804 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
806 /********************* End of dbm library definitions **********************/
809 #endif /* whole file */
810 /* End of hintsdb.h */