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)
206 { log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); }
210 /* Access functions */
212 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
213 /* The API changed for DB 4.1. - and we also starting using the "env" with a
214 specified working dir, to avoid the DBCONFIG file trap. */
216 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
218 static inline EXIM_DB *
219 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
224 if ( db_env_create(&dbp, 0) != 0
225 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
226 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
229 if (db_create(&b, dbp, 0) == 0)
231 dbp->app_private = b;
232 if (b->open(b, NULL, CS name, NULL,
233 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
234 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
245 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
247 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
249 DB * b = ENV_TO_DB(dbp);
250 return b->get(b, NULL, key, res, 0) == 0;
253 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
255 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
257 DB * b = ENV_TO_DB(dbp);
258 return b->put(b, NULL, key, data, 0);
261 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
263 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
265 DB * b = ENV_TO_DB(dbp);
266 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
269 /* Return values from EXIM_DBPUTB */
271 # define EXIM_DBPUTB_OK 0
272 # define EXIM_DBPUTB_DUP DB_KEYEXIST
276 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
278 DB * b = ENV_TO_DB(dbp);
279 return b->del(b, NULL, key, 0);
282 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
284 static inline EXIM_CURSOR *
285 exim_dbcreate_cursor(EXIM_DB * dbp)
287 DB * b = ENV_TO_DB(dbp);
289 b->cursor(b, NULL, &c, 0);
293 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
295 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
296 EXIM_CURSOR * cursor)
298 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
301 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
303 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
304 { cursor->c_close(cursor); }
308 exim_dbclose__(EXIM_DB * dbp_o)
310 DB_ENV * dbp = dbp_o;
311 DB * b = ENV_TO_DB(dbp);
313 dbp->close(dbp, DB_FORCESYNC);
318 static inline uschar *
319 exim_datum_data_get(EXIM_DATUM * dp)
322 exim_datum_data_set(EXIM_DATUM * dp, void * s)
325 static inline unsigned
326 exim_datum_size_get(EXIM_DATUM * dp)
329 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
332 /* The whole datum structure contains other fields that must be cleared
333 before use, but we don't have to free anything after reading data. */
336 exim_datum_init(EXIM_DATUM * d)
337 { memset(d, 0, sizeof(*d)); }
340 exim_datum_free(EXIM_DATUM * d)
343 # else /* pre- 4.1 */
347 /* Cursor type, for scanning */
348 # define EXIM_CURSOR DBC
350 /* The datum type used for queries */
351 # define EXIM_DATUM DBT
353 /* Some text for messages */
354 # define EXIM_DBTYPE "db (v3/4)"
356 /* Access functions */
358 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
359 static inline EXIM_DB *
360 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
364 return db_create(&dbp, NULL, 0) == 0
365 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
366 dbp->open(dbp, CS name, NULL,
367 flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
368 flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
374 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
376 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
377 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
379 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
381 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
382 { return dbp->put(dbp, NULL, key, data, 0); }
384 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
386 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
387 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
389 /* Return values from EXIM_DBPUTB */
391 # define EXIM_DBPUTB_OK 0
392 # define EXIM_DBPUTB_DUP DB_KEYEXIST
396 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
397 { return dbp->del(dbp, NULL, key, 0); }
399 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
401 static inline EXIM_CURSOR *
402 exim_dbcreate_cursor(EXIM_DB * dbp)
405 dbp->cursor(dbp, NULL, &c, 0);
409 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
411 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
412 EXIM_CURSOR * cursor)
414 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
417 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
419 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
420 { cursor->c_close(cursor); }
424 exim_dbclose__(EXIM_DB * dbp)
425 { dbp->close(dbp, 0); }
429 static inline uschar *
430 exim_datum_data_get(EXIM_DATUM * dp)
431 { return US dp->dptr; }
433 exim_datum_data_set(EXIM_DATUM * dp, void * s)
436 static inline uschar *
437 exim_datum_size_get(EXIM_DATUM * dp)
438 { return US dp->size; }
440 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
443 /* The whole datum structure contains other fields that must be cleared
444 before use, but we don't have to free anything after reading data. */
447 exim_datum_init(EXIM_DATUM * d)
448 { memset(d, 0, sizeof(*d)); }
451 exim_datum_free(EXIM_DATUM * d)
457 # else /* DB_VERSION_MAJOR >= 3 */
458 # error Berkeley DB versions earlier than 3 are not supported */
459 # endif /* DB_VERSION_MAJOR */
461 # error Berkeley DB version 1 is no longer supported
462 # endif /* DB_VERSION_STRING */
465 /* all BDB versions */
468 # define EXIM_DB_RLIMIT 150
475 /********************* gdbm interface definitions **********************/
477 #elif defined USE_GDBM
478 /*XXX TODO: exim's locfile not needed */
484 GDBM_FILE gdbm; /* Database */
485 datum lkey; /* Last key, for scans */
488 /* Cursor type, not used with gdbm: just set up a dummy */
489 # define EXIM_CURSOR int
491 /* The datum type used for queries */
492 # define EXIM_DATUM datum
494 /* Some text for messages */
496 # define EXIM_DBTYPE "gdbm"
498 /* Access functions */
500 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
501 static inline EXIM_DB *
502 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
505 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
508 dbp->lkey.dptr = NULL;
509 dbp->gdbm = gdbm_open(CS name, 0,
510 flags & O_CREAT ? GDBM_WRCREAT
511 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
514 if (dbp->gdbm) return dbp;
520 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
522 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
524 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
525 return res->dptr != NULL;
528 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
530 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
531 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
533 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
535 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
536 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
538 /* Returns from EXIM_DBPUTB */
540 # define EXIM_DBPUTB_OK 0
541 # define EXIM_DBPUTB_DUP 1
545 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
546 { return gdbm_delete(dbp->gdbm, *key); }
548 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
549 static inline EXIM_CURSOR *
550 exim_dbcreate_cursor(EXIM_DB * dbp)
555 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
556 EXIM_CURSOR * cursor)
559 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
560 if ((s = dbp->lkey.dptr)) free(s);
562 return key->dptr != NULL;
565 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
567 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
572 exim_dbclose__(EXIM_DB * dbp)
575 gdbm_close(dbp->gdbm);
576 if ((s = dbp->lkey.dptr)) free(s);
580 /* Datum access types */
582 static inline uschar *
583 exim_datum_data_get(EXIM_DATUM * dp)
584 { return US dp->dptr; }
586 exim_datum_data_set(EXIM_DATUM * dp, void * s)
589 static inline unsigned
590 exim_datum_size_get(EXIM_DATUM * dp)
591 { return dp->dsize; }
593 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
596 /* There's no clearing required before use, but we have to free the dptr
597 after reading data. */
600 exim_datum_init(EXIM_DATUM * d)
604 exim_datum_free(EXIM_DATUM * d)
609 # define EXIM_DB_RLIMIT 150
618 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
622 /********************* ndbm interface definitions **********************/
629 /* Cursor type, not used with ndbm: just set up a dummy */
630 # define EXIM_CURSOR int
632 /* The datum type used for queries */
633 # define EXIM_DATUM datum
635 /* Some text for messages */
637 # define EXIM_DBTYPE "ndbm"
639 /* Access functions */
641 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
642 /* Check that the name given is not present. This catches
643 a directory name; otherwise we would create the name.pag and
644 name.dir files in the directory's parent. */
646 static inline EXIM_DB *
647 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
651 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
652 return dbm_open(CS name, flags, mode);
653 #ifndef COMPILE_UTILITY
654 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
656 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
660 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
662 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
664 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
665 return res->dptr != NULL;
668 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
670 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
671 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
673 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
675 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
676 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
678 /* Returns from EXIM_DBPUTB */
680 # define EXIM_DBPUTB_OK 0
681 # define EXIM_DBPUTB_DUP 1
685 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
686 { return dbm_delete(dbp, *key); }
688 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
689 static inline EXIM_CURSOR *
690 exim_dbcreate_cursor(EXIM_DB * dbp)
695 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
696 EXIM_CURSOR * cursor)
698 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
699 return key->dptr != NULL;
702 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
704 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
709 exim_dbclose__(EXIM_DB * dbp)
712 /* Datum access types */
714 static inline uschar *
715 exim_datum_data_get(EXIM_DATUM * dp)
716 { return US dp->dptr; }
718 exim_datum_data_set(EXIM_DATUM * dp, void * s)
721 static inline unsigned
722 exim_datum_size_get(EXIM_DATUM * dp)
723 { return dp->dsize; }
725 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
728 /* There's no clearing required before use, and we don't have to free anything
729 after reading data. */
732 exim_datum_init(EXIM_DATUM * d)
736 exim_datum_free(EXIM_DATUM * d)
741 # define EXIM_DB_RLIMIT 150
743 #endif /* USE_GDBM */
749 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
751 static inline EXIM_DB *
752 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
755 return exim_dbopen__(name, dirname, flags, mode);
759 exim_dbclose(EXIM_DB * dbp)
760 { exim_dbclose__(dbp); }
762 #else /* exim mainline code */
764 /* Wrappers for open/close with debug tracing */
766 extern void debug_printf_indent(const char *, ...);
767 static inline BOOL is_tainted(const void *);
769 static inline EXIM_DB *
770 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
774 DEBUG(D_hints_lookup)
775 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
777 flags == O_RDONLY ? "O_RDONLY"
778 : flags == O_RDWR ? "O_RDWR"
779 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
781 if (is_tainted(name) || is_tainted(dirname))
783 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
787 dbp = exim_dbopen__(name, dirname, flags, mode);
789 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
794 exim_dbclose(EXIM_DB * dbp)
796 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
800 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
802 /********************* End of dbm library definitions **********************/
805 #endif /* whole file */
806 /* End of hintsdb.h */