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