c5a856abc97bdb8783fae93e7fa02145a927e139
[exim.git] / src / src / hintsdb.h
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
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 */
9
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.
16
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.
20
21 A key/value store is supported (only).  Keys are strings; values arbitrary
22 binary blobs.
23
24 The API is:
25   Functions:
26     exim_lockfile_needed        API semantics predicate
27     exim_dbopen
28     exim_dbclose
29     exim_dbget
30     exim_dbput
31     exim_dbputb                 non-overwriting put
32     exim_dbdel
33     exim_dbcreate_cursor
34     exim_dbscan                 get, and bump cursor
35     exim_dbdelete_cursor
36     exim_datum_init
37     exim_datum_size_get/set
38     exim_datum_data_get/set
39     exim_datum_free
40   Defines:
41     EXIM_DB             access handle
42     EXIM_CURSOR         datatype for cursor
43     EXIM_DATUM          datatype for "value"
44     EXIM_DBTYPE         text for logging & debuug
45
46 Selection of the shim layer implementation, and backend, is by #defines.
47
48 The users of this API are:
49   hintsdb interface     dbfn.c
50   hintsdb utilities     exim_dbutil.c and exim_dbmvuild.c
51   dbmdb lookup          lookups/dbmdb,c
52   autoreply transport   transports/autoreply.c
53
54 Note that the dbmdb lookup use, bypassing the dbfn.c layer,
55 means that no file-locking is done.
56 XXX This feels like a layering violation; I don't see it commented on
57 anywhere.
58
59 Future: consider re-architecting to support caching of the open-handle
60 for hintsdb uses (the dbmdb use gets that already).  This would need APIs
61 for transaction locks.  Perhaps merge the implementation with the lookups
62 layer, in some way, for the open-handle caching (since that manages closes
63 required by Exim's process transisitions)?
64 */
65
66 #ifndef HINTSDB_H
67 #define HINTSDB_H
68
69
70 #ifdef USE_SQLITE
71 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB)
72 #  error USE_SQLITE conflict with alternate definition
73 # endif
74
75 /* ********************* sqlite3 interface ************************ */
76
77 # include <sqlite3.h>
78
79 /* Basic DB type */
80 # define EXIM_DB sqlite3
81
82 # define EXIM_CURSOR int
83
84 # /* The datum type used for queries */
85 # define EXIM_DATUM blob
86
87 /* Some text for messages */
88 # define EXIM_DBTYPE "sqlite3"
89
90 # /* Access functions */
91
92 static inline BOOL
93 exim_lockfile_needed(void)
94 {
95 return FALSE;   /* We do transaction; no extra locking needed */
96 }
97
98 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
99 static inline EXIM_DB *
100 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
101   unsigned mode)
102 {
103 EXIM_DB * dbp;
104 int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
105 if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE;
106 if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK)
107   {
108   sqlite3_busy_timeout(dbp, 5000);
109   ret = sqlite3_exec(dbp, "BEGIN TRANSACTION;", NULL, NULL, NULL);
110   if (ret == SQLITE_OK && flags & O_CREAT)
111     ret = sqlite3_exec(dbp,
112             "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);",
113             NULL, NULL, NULL);
114   if (ret != SQLITE_OK)
115     sqlite3_close(dbp);
116   }
117 //else
118 //  fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp));
119 return ret == SQLITE_OK ? dbp : NULL;
120 }
121
122 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
123 /* note we alloc'n'copy - the caller need not do so */
124 /* result has a NUL appended, but the length is as per the DB */
125
126 static inline BOOL
127 exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res)
128 {
129 sqlite3_stmt * statement;
130 int ret;
131
132 res->len = (size_t) -1;
133 /* fprintf(stderr, "exim_dbget__(%s)\n", s); */
134 if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK)
135   {
136 /* fprintf(stderr, "prepare fail: %s\n", sqlite3_errmsg(dbp)); */
137   return FALSE;
138   }
139 if (sqlite3_step(statement) != SQLITE_ROW)
140   {
141 /* fprintf(stderr, "step fail: %s\n", sqlite3_errmsg(dbp)); */
142   sqlite3_finalize(statement);
143   return FALSE;
144   }
145
146 res->len = sqlite3_column_bytes(statement, 0);
147 # ifdef COMPILE_UTILITY
148 res->data = malloc(res->len);
149 # else
150 res->data = store_get(res->len, GET_TAINTED);
151 # endif
152 memcpy(res->data, sqlite3_column_blob(statement, 0), res->len);
153 res->data[res->len] = '\0';
154 /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */
155 sqlite3_finalize(statement);
156 return TRUE;
157 }
158
159 static inline BOOL
160 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
161 {
162 # define FMT "SELECT dat FROM tbl WHERE ky = '%.*s';"
163 uschar * qry;
164 int i;
165 BOOL ret;
166
167 # ifdef COMPILE_UTILITY
168 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
169 qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data));
170 snprintf(CS qry, i, FMT, (int) key->len, key->data);
171 ret = exim_dbget__(dbp, qry, res);
172 free(qry);
173 # else
174 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
175 qry = string_sprintf(FMT, (int) key->len, key->data);
176 ret = exim_dbget__(dbp, qry, res);
177 # endif
178
179 return ret;
180 # undef FMT
181 }
182
183 /**/
184 # define EXIM_DBPUTB_OK  0
185 # define EXIM_DBPUTB_DUP (-1)
186
187 static inline int
188 exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt)
189 {
190 int hlen = data->len * 2, off = 0, res;
191 # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
192 # ifdef COMPILE_UTILITY
193 uschar * hex = malloc(hlen+1);
194 # else
195 uschar * hex = store_get(hlen+1, data->data);
196 # endif
197 uschar * qry;
198
199 for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2)
200   sprintf(CS hex + off, "%02X", *s);
201
202 # ifdef COMPILE_UTILITY
203 res = snprintf(CS hex, 0, FMT, alt, (int) key->len, key->data, hlen, hex);
204 qry = malloc(res);
205 snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, hlen, hex);
206 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
207 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
208 free(qry);
209 free(hex);
210 # else
211 qry = string_sprintf(FMT, alt, (int) key->len, key->data, hlen, hex);
212 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
213 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
214 /* fprintf(stderr, "exim_s_dbp res %d\n", res); */
215 # endif
216
217 if (res != SQLITE_OK)
218   fprintf(stderr, "sqlite3_exec: %s\n", sqlite3_errmsg(dbp));
219
220 return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP;
221 # undef FMT
222 }
223
224 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
225
226 static inline int
227 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
228 {
229 /* fprintf(stderr, "exim_dbput()\n"); */
230 (void) exim_s_dbp(dbp, key, data, US"REPLACE");
231 return 0;
232 }
233
234 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
235
236 /* Returns from EXIM_DBPUTB */
237
238 static inline int
239 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
240 {
241 return exim_s_dbp(dbp, key, data, US"ABORT");
242 }
243
244 /* EXIM_DBDEL */
245 static inline int
246 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
247 {
248 # define FMT "DELETE FROM tbl WHERE ky = '%.*s';"
249 uschar * qry;
250 int res;
251
252 # ifdef COMPILE_UTILITY
253 res = snprintf(NULL, 0, FMT, (int) key->len, key->data); /* res excludes nul */
254 qry = malloc(res);
255 snprintf(CS qry, res, FMT, (int) key->len, key->data);
256 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
257 free(qry);
258 # else
259 qry = string_sprintf(FMT, (int) key->len, key->data);
260 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
261 # endif
262
263 return res;
264 # undef FMT
265 }
266
267
268 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
269 /* Cursors are inefficiently emulated by repeating searches */
270
271 static inline EXIM_CURSOR *
272 exim_dbcreate_cursor(EXIM_DB * dbp)
273 {
274 # ifdef COMPILE_UTILITY
275 EXIM_CURSOR * c = malloc(sizeof(int));
276 # else
277 EXIM_CURSOR * c = store_malloc(sizeof(int));
278 # endif
279 *c = 0;
280 return c;
281 }
282
283 /* EXIM_DBSCAN */
284 /* Note that we return the (next) key, not the record value */
285 static inline BOOL
286 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
287   EXIM_CURSOR * cursor)
288 {
289 # define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;"
290 uschar * qry;
291 int i;
292 BOOL ret;
293
294 # ifdef COMPILE_UTILITY
295 qry = malloc((i = snprintf(NULL, 0, FMT, *cursor)));
296 snprintf(CS qry, i-1, FMT, *cursor);
297 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
298 ret = exim_dbget__(dbp, qry, key);
299 free(qry);
300 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
301 # else
302 qry = string_sprintf(FMT, *cursor);
303 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
304 ret = exim_dbget__(dbp, qry, key);
305 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
306 # endif
307 if (ret) *cursor = *cursor + 1;
308 return ret;
309 # undef FMT
310 }
311
312 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
313 static inline void
314 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
315 {
316 # ifdef COMPILE_UTILITY
317 free(cursor);
318 # else
319 store_free(cursor);
320 # endif
321 }
322
323
324 /* EXIM_DBCLOSE */
325 static void
326 exim_dbclose__(EXIM_DB * dbp)
327 {
328 (void) sqlite3_exec(dbp, "COMMIT TRANSACTION;", NULL, NULL, NULL);
329 sqlite3_close(dbp);
330 }
331
332
333 /* Datum access */
334
335 static uschar *
336 exim_datum_data_get(EXIM_DATUM * dp)
337 { return US dp->data; }
338 static void
339 exim_datum_data_set(EXIM_DATUM * dp, void * s)
340 { dp->data = s; }
341  
342 static unsigned
343 exim_datum_size_get(EXIM_DATUM * dp)
344 { return dp->len; }
345 static void
346 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
347 { dp->len = n; }
348
349
350
351 static inline void
352 exim_datum_init(EXIM_DATUM * dp)
353 { dp->data = NULL; }                    /* compiler quietening */
354
355 /* No free needed for a datum */
356
357 static inline void
358 exim_datum_free(EXIM_DATUM * dp)
359 { }
360
361 /* size limit */
362
363 # define EXIM_DB_RLIMIT 150
364
365
366
367
368
369
370 #elif defined(USE_TDB)
371
372 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE)
373 #  error USE_TDB conflict with alternate definition
374 # endif
375
376 /* ************************* tdb interface ************************ */
377 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
378 Could we lose the file lock? */
379
380 # include <tdb.h>
381
382 /* Basic DB type */
383 # define EXIM_DB TDB_CONTEXT
384
385 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
386 tdb_traverse to be called) */
387 # define EXIM_CURSOR TDB_DATA
388
389 /* The datum type used for queries */
390 # define EXIM_DATUM TDB_DATA
391
392 /* Some text for messages */
393 # define EXIM_DBTYPE "tdb"
394
395 /* Access functions */
396
397 static inline BOOL
398 exim_lockfile_needed(void)
399 {
400 return TRUE;
401 }
402
403 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
404 static inline EXIM_DB *
405 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
406   unsigned mode)
407 {
408 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
409 }
410
411 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
412 static inline BOOL
413 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
414 {
415 *res = tdb_fetch(dbp, *key);    /* A struct arg and return!! */
416 return res->dptr != NULL;
417 }
418
419 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
420 static inline int
421 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
422 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
423
424 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
425 static inline int
426 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
427 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
428
429 /* Returns from EXIM_DBPUTB */
430
431 # define EXIM_DBPUTB_OK  0
432 # define EXIM_DBPUTB_DUP (-1)
433
434 /* EXIM_DBDEL */
435 static inline int
436 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
437 { return tdb_delete(dbp, *key); }
438
439 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
440 static inline EXIM_CURSOR *
441 exim_dbcreate_cursor(EXIM_DB * dbp)
442 {
443 # ifdef COMPILE_UTILITY
444 EXIM_CURSOR * c = malloc(sizeof(TDB_DATA));
445 # else
446 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
447 # endif
448 c->dptr = NULL;
449 return c;
450 }
451
452 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
453 free() must not die when passed NULL */
454
455 static inline BOOL
456 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
457   EXIM_CURSOR * cursor)
458 {
459 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
460 free(cursor->dptr);
461 *cursor = *key;
462 return key->dptr != NULL;
463 }
464
465 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
466 static inline void
467 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
468 { store_free(cursor); }
469
470 /* EXIM_DBCLOSE */
471 static inline void
472 exim_dbclose__(EXIM_DB * db)
473 { tdb_close(db); }
474
475 /* Datum access */
476
477 static inline uschar *
478 exim_datum_data_get(EXIM_DATUM * dp)
479 { return US dp->dptr; }
480 static inline void
481 exim_datum_data_set(EXIM_DATUM * dp, void * s)
482 { dp->dptr = s; }
483
484 static inline unsigned
485 exim_datum_size_get(EXIM_DATUM * dp)
486 { return dp->dsize; }
487 static inline void
488 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
489 { dp->dsize = n; }
490
491 /* No initialization is needed. */
492
493 static inline void
494 exim_datum_init(EXIM_DATUM * d)
495 { }
496
497 /* Free the stuff inside the datum. */
498
499 static inline void
500 exim_datum_free(EXIM_DATUM * d)
501 {
502 free(d->dptr);
503 d->dptr = NULL;
504 }
505
506 /* size limit */
507
508 # define EXIM_DB_RLIMIT 150
509
510
511
512
513
514
515 /********************* Berkeley db native definitions **********************/
516
517 #elif defined USE_DB
518
519 # if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE)
520 #  error USE_DB conflict with alternate definition
521 # endif
522
523 # include <db.h>
524
525 /* 1.x did no locking
526    2.x had facilities, but exim does it's own
527    3.x+ unknown
528 */
529
530 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
531 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
532
533 # ifdef DB_VERSION_STRING
534
535 #  if DB_VERSION_MAJOR >= 6
536 #   error Version 6 and later BDB API is not supported
537 #  endif
538
539 /* The API changed (again!) between the 2.x and 3.x versions */
540
541 # if DB_VERSION_MAJOR >= 3
542
543 /***************** Berkeley db 3.x/4.x native definitions ******************/
544
545 /* Basic DB type */
546 #  if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
547 #   define EXIM_DB       DB_ENV
548 /* Cursor type, for scanning */
549 #   define EXIM_CURSOR   DBC
550
551 /* The datum type used for queries */
552 #   define EXIM_DATUM    DBT
553
554 /* Some text for messages */
555 #   define EXIM_DBTYPE   "db (v4.1+)"
556
557 /* Only more-recent versions.  5+ ? */
558 #   ifndef DB_FORCESYNC
559 #    define DB_FORCESYNC 0
560 #   endif
561
562 /* Error callback */
563 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
564 errors. This should help with debugging strange DB problems, e.g. getting "File
565 exists" when you try to open a db file. The API for this function was changed
566 at DB release 4.3. */
567
568 static inline void
569 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
570 {
571 #ifndef MACRO_PREDEF 
572 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
573 #endif
574 }
575
576
577
578 /* Access functions (BDB 4.1+) */
579
580 static inline BOOL
581 exim_lockfile_needed(void)
582 {
583 return TRUE;
584 }
585
586 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
587 /* The API changed for DB 4.1. - and we also starting using the "env" with a
588 specified working dir, to avoid the DBCONFIG file trap. */
589
590 #   define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
591
592 static inline EXIM_DB *
593 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
594   unsigned mode)
595 {
596 EXIM_DB * dbp;
597 DB * b;
598 if (  db_env_create(&dbp, 0) != 0
599    || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
600    || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
601    )
602   return NULL;
603 if (db_create(&b, dbp, 0) == 0)
604   {
605   dbp->app_private = b;
606   if (b->open(b, NULL, CS name, NULL,
607               flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
608               flags & O_CREAT ? DB_CREATE
609               : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
610               mode) == 0
611           )
612     return dbp;
613
614   b->close(b, 0);
615   }
616 dbp->close(dbp, 0);
617 return NULL;
618 }
619
620 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
621 static inline BOOL
622 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
623 {
624 DB * b = ENV_TO_DB(dbp);
625 return b->get(b, NULL, key, res, 0) == 0;
626 }
627
628 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
629 static inline int
630 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
631 {
632 DB * b = ENV_TO_DB(dbp);
633 return b->put(b, NULL, key, data, 0);
634 }
635
636 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
637 static inline int
638 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
639 {
640 DB * b = ENV_TO_DB(dbp);
641 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
642 }
643
644 /* Return values from EXIM_DBPUTB */
645
646 #   define EXIM_DBPUTB_OK  0
647 #   define EXIM_DBPUTB_DUP DB_KEYEXIST
648
649 /* EXIM_DBDEL */
650 static inline int
651 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
652 {
653 DB * b = ENV_TO_DB(dbp);
654 return b->del(b, NULL, key, 0);
655 }
656
657 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
658
659 static inline EXIM_CURSOR *
660 exim_dbcreate_cursor(EXIM_DB * dbp)
661 {
662 DB * b = ENV_TO_DB(dbp);
663 EXIM_CURSOR * c;
664 b->cursor(b, NULL, &c, 0);
665 return c;
666 }
667
668 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
669 static inline BOOL
670 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
671   EXIM_CURSOR * cursor)
672 {
673 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
674 }
675
676 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
677 static inline void
678 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
679 { cursor->c_close(cursor); }
680
681 /* EXIM_DBCLOSE */
682 static inline void
683 exim_dbclose__(EXIM_DB * dbp_o)
684 {
685 DB_ENV * dbp = dbp_o;
686 DB * b = ENV_TO_DB(dbp);
687 b->close(b, 0);
688 dbp->close(dbp, DB_FORCESYNC);
689 }
690
691 /* Datum access */
692
693 static inline uschar *
694 exim_datum_data_get(EXIM_DATUM * dp)
695 { return dp->data; }
696 static inline void
697 exim_datum_data_set(EXIM_DATUM * dp, void * s)
698 { dp->data = s; }
699
700 static inline unsigned
701 exim_datum_size_get(EXIM_DATUM * dp)
702 { return dp->size; }
703 static inline void
704 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
705 { dp->size = n; }
706
707 /* The whole datum structure contains other fields that must be cleared
708 before use, but we don't have to free anything after reading data. */
709
710 static inline void
711 exim_datum_init(EXIM_DATUM * d)
712 { memset(d, 0, sizeof(*d)); }
713
714 static inline void
715 exim_datum_free(EXIM_DATUM * d)
716 { }
717
718 #  else /* pre- 4.1 */
719
720 #   define EXIM_DB       DB
721
722 /* Cursor type, for scanning */
723 #   define EXIM_CURSOR   DBC
724
725 /* The datum type used for queries */
726 #   define EXIM_DATUM    DBT
727
728 /* Some text for messages */
729 #   define EXIM_DBTYPE   "db (v3/4)"
730
731 /* Access functions (BDB 3/4) */
732
733 static inline BOOL
734 exim_lockfile_needed(void)
735 {
736 return TRUE;
737 }
738
739 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
740 static inline EXIM_DB *
741 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
742   unsigned mode)
743 {
744 EXIM_DB * dbp;
745 return db_create(&dbp, NULL, 0) == 0
746   && (  dbp->set_errcall(dbp, dbfn_bdb_error_callback),
747         dbp->open(dbp, CS name, NULL,
748           flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
749           flags & O_CREAT ? DB_CREATE
750           : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
751           mode)
752      ) == 0
753   ? dbp : NULL;
754 }
755
756 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
757 static inline BOOL
758 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
759 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
760
761 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
762 static inline int
763 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
764 { return dbp->put(dbp, NULL, key, data, 0); }
765
766 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
767 static inline int
768 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
769 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
770
771 /* Return values from EXIM_DBPUTB */
772
773 #   define EXIM_DBPUTB_OK  0
774 #   define EXIM_DBPUTB_DUP DB_KEYEXIST
775
776 /* EXIM_DBDEL */
777 static inline int
778 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
779 { return dbp->del(dbp, NULL, key, 0); }
780
781 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
782
783 static inline EXIM_CURSOR *
784 exim_dbcreate_cursor(EXIM_DB * dbp)
785 {
786 EXIM_CURSOR * c;
787 dbp->cursor(dbp, NULL, &c, 0);
788 return c;
789 }
790
791 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
792 static inline BOOL
793 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
794   EXIM_CURSOR * cursor)
795 {
796 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
797 }
798
799 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
800 static inline void
801 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
802 { cursor->c_close(cursor); }
803
804 /* EXIM_DBCLOSE */
805 static inline void
806 exim_dbclose__(EXIM_DB * dbp)
807 { dbp->close(dbp, 0); }
808
809 /* Datum access */
810
811 static inline uschar *
812 exim_datum_data_get(EXIM_DATUM * dp)
813 { return US dp->dptr; }
814 static inline void
815 exim_datum_data_set(EXIM_DATUM * dp, void * s)
816 { dp->dptr = s; }
817
818 static inline uschar *
819 exim_datum_size_get(EXIM_DATUM * dp)
820 { return US dp->size; }
821 static inline void
822 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
823 { dp->size = CS s; }
824
825 /* The whole datum structure contains other fields that must be cleared
826 before use, but we don't have to free anything after reading data. */
827
828 static inline void
829 exim_datum_init(EXIM_DATUM * d)
830 { memset(d, 0, sizeof(*d)); }
831
832 static inline void
833 exim_datum_free(EXIM_DATUM * d)
834 { }
835
836 #  endif
837
838
839 #  else /* DB_VERSION_MAJOR >= 3 */
840 #   error Berkeley DB versions earlier than 3 are not supported */
841 #  endif /* DB_VERSION_MAJOR */
842 # else
843 #  error Berkeley DB version 1 is no longer supported
844 # endif /* DB_VERSION_STRING */
845
846
847 /* all BDB versions */
848 /* size limit */
849
850 # define EXIM_DB_RLIMIT 150
851
852
853
854
855
856
857 /********************* gdbm interface definitions **********************/
858
859 #elif defined USE_GDBM
860 /*XXX TODO: exim's lockfile not needed? */
861
862 # if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE)
863 #  error USE_GDBM conflict with alternate definition
864 # endif
865
866 # include <gdbm.h>
867
868 /* Basic DB type */
869 typedef struct {
870        GDBM_FILE gdbm;  /* Database */
871        datum lkey;      /* Last key, for scans */
872 } EXIM_DB;
873
874 /* Cursor type, not used with gdbm: just set up a dummy */
875 # define EXIM_CURSOR int
876
877 /* The datum type used for queries */
878 # define EXIM_DATUM datum
879
880 /* Some text for messages */
881
882 # define EXIM_DBTYPE "gdbm"
883
884 /* Access functions (gdbm) */
885
886 static inline BOOL
887 exim_lockfile_needed(void)
888 {
889 return TRUE;
890 }
891
892 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
893 static inline EXIM_DB *
894 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
895   unsigned mode)
896 {
897 EXIM_DB * dbp = malloc(sizeof(EXIM_DB));        /*XXX why not exim mem-mgmt? */
898 if (dbp)
899   {
900   dbp->lkey.dptr = NULL;
901   dbp->gdbm = gdbm_open(CS name, 0,
902     flags & O_CREAT ? GDBM_WRCREAT
903     : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER : GDBM_READER,
904     mode, 0);
905   if (dbp->gdbm) return dbp;
906   free(dbp);
907   }
908 return NULL;
909 }
910
911 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
912 static inline BOOL
913 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
914 {
915 *res = gdbm_fetch(dbp->gdbm, *key);     /* A struct arg & return! */
916 return res->dptr != NULL;
917 }
918
919 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
920 static inline int
921 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
922 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
923
924 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
925 static inline int
926 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
927 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
928
929 /* Returns from EXIM_DBPUTB */
930
931 # define EXIM_DBPUTB_OK  0
932 # define EXIM_DBPUTB_DUP 1
933
934 /* EXIM_DBDEL */
935 static inline int
936 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
937 { return gdbm_delete(dbp->gdbm, *key); }
938
939 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
940 static inline EXIM_CURSOR *
941 exim_dbcreate_cursor(EXIM_DB * dbp)
942 { return NULL; }
943
944 /* EXIM_DBSCAN */
945 static inline BOOL
946 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
947   EXIM_CURSOR * cursor)
948 {
949 char * s;
950 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
951 if ((s = dbp->lkey.dptr)) free(s);
952 dbp->lkey = *key;
953 return key->dptr != NULL;
954 }
955
956 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
957 static inline void
958 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
959 { }
960
961 /* EXIM_DBCLOSE */
962 static inline void
963 exim_dbclose__(EXIM_DB * dbp)
964 {
965 char * s;
966 gdbm_close(dbp->gdbm);
967 if ((s = dbp->lkey.dptr)) free(s);
968 free(dbp);
969 }
970
971 /* Datum access types */
972
973 static inline uschar *
974 exim_datum_data_get(EXIM_DATUM * dp)
975 { return US dp->dptr; }
976 static inline void
977 exim_datum_data_set(EXIM_DATUM * dp, void * s)
978 { dp->dptr = s; }
979
980 static inline unsigned
981 exim_datum_size_get(EXIM_DATUM * dp)
982 { return dp->dsize; }
983 static inline void
984 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
985 { dp->dsize = n; }
986
987 /* There's no clearing required before use, but we have to free the dptr
988 after reading data. */
989
990 static inline void
991 exim_datum_init(EXIM_DATUM * d)
992 { }
993
994 static inline void
995 exim_datum_free(EXIM_DATUM * d)
996 { free(d->dptr); }
997
998 /* size limit. GDBM is int-max limited, but we want to be less silly */
999
1000 # define EXIM_DB_RLIMIT 150
1001
1002 #else  /* USE_GDBM */
1003
1004
1005
1006
1007
1008
1009 /* If none of USE_DB, USG_GDBM, USE_SQLITE or USE_TDB are set,
1010 the default is the NDBM interface (which seems to be a wrapper for GDBM) */
1011
1012
1013 /********************* ndbm interface definitions **********************/
1014
1015 # include <ndbm.h>
1016
1017 /* Basic DB type */
1018 # define EXIM_DB DBM
1019
1020 /* Cursor type, not used with ndbm: just set up a dummy */
1021 # define EXIM_CURSOR int
1022
1023 /* The datum type used for queries */
1024 # define EXIM_DATUM datum
1025
1026 /* Some text for messages */
1027
1028 # define EXIM_DBTYPE "ndbm"
1029
1030 /* Access functions (ndbm) */
1031
1032 static inline BOOL
1033 exim_lockfile_needed(void)
1034 {
1035 return TRUE;
1036 }
1037
1038 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
1039 /* Check that the name given is not present. This catches
1040 a directory name; otherwise we would create the name.pag and
1041 name.dir files in the directory's parent. */
1042
1043 static inline EXIM_DB *
1044 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
1045   unsigned mode)
1046 {
1047 struct stat st;
1048 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
1049   return dbm_open(CS name, flags, mode);
1050 #ifndef COMPILE_UTILITY
1051 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
1052 #endif
1053 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
1054 return NULL;
1055 }
1056
1057 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
1058 static inline BOOL
1059 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
1060 {
1061 *res = dbm_fetch(dbp, *key);    /* A struct arg & return! */
1062 return res->dptr != NULL;
1063 }
1064
1065 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
1066 static inline int
1067 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1068 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
1069
1070 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
1071 static inline int
1072 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1073 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
1074
1075 /* Returns from EXIM_DBPUTB */
1076
1077 # define EXIM_DBPUTB_OK  0
1078 # define EXIM_DBPUTB_DUP 1
1079
1080 /* EXIM_DBDEL */
1081 static inline int
1082 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1083 { return dbm_delete(dbp, *key); }
1084
1085 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1086 static inline EXIM_CURSOR *
1087 exim_dbcreate_cursor(EXIM_DB * dbp)
1088 { return NULL; }
1089
1090 /* EXIM_DBSCAN */
1091 static inline BOOL
1092 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1093   EXIM_CURSOR * cursor)
1094 {
1095 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1096 return key->dptr != NULL;
1097 }
1098
1099 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1100 static inline void
1101 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1102 { }
1103
1104 /* EXIM_DBCLOSE */
1105 static inline void
1106 exim_dbclose__(EXIM_DB * dbp)
1107 { dbm_close(dbp); }
1108
1109 /* Datum access types */
1110
1111 static inline uschar *
1112 exim_datum_data_get(EXIM_DATUM * dp)
1113 { return US dp->dptr; }
1114 static inline void
1115 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1116 { dp->dptr = s; }
1117
1118 static inline unsigned
1119 exim_datum_size_get(EXIM_DATUM * dp)
1120 { return dp->dsize; }
1121 static inline void
1122 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1123 { dp->dsize = n; }
1124
1125 /* There's no clearing required before use, and we don't have to free anything
1126 after reading data. */
1127
1128 static inline void
1129 exim_datum_init(EXIM_DATUM * d)
1130 { }
1131
1132 static inline void
1133 exim_datum_free(EXIM_DATUM * d)
1134 { }
1135
1136 /* size limit */
1137
1138 # define EXIM_DB_RLIMIT 150
1139
1140 #endif /* !USE_GDBM */
1141
1142
1143
1144
1145
1146 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1147
1148 static inline EXIM_DB *
1149 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1150   unsigned mode)
1151 {
1152 return exim_dbopen__(name, dirname, flags, mode);
1153 }
1154
1155 static inline void
1156 exim_dbclose(EXIM_DB * dbp)
1157 { exim_dbclose__(dbp); }
1158
1159 #else   /*  exim mainline code */
1160
1161 /* Wrappers for open/close with debug tracing */
1162
1163 extern void debug_printf_indent(const char *, ...);
1164 static inline BOOL is_tainted(const void *);
1165
1166 static inline EXIM_DB *
1167 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1168   unsigned mode)
1169 {
1170 void * dbp;
1171 DEBUG(D_hints_lookup)
1172   debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1173     name, dirname,
1174     flags == O_RDONLY ? "O_RDONLY"
1175     : flags == O_RDWR ? "O_RDWR"
1176     : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1177     : "??");
1178 if (is_tainted(name) || is_tainted(dirname))
1179   {
1180   log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1181   dbp = NULL;
1182   }
1183 else
1184   dbp = exim_dbopen__(name, dirname, flags, mode);
1185
1186 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1187 return dbp;
1188 }
1189
1190 static inline void
1191 exim_dbclose(EXIM_DB * dbp)
1192 {
1193 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1194 exim_dbclose__(dbp);
1195 }
1196
1197 # endif         /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1198
1199 /********************* End of dbm library definitions **********************/
1200
1201
1202 #endif  /* whole file */
1203 /* End of hintsdb.h */
1204 /* vi: aw ai sw=2
1205 */