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