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