sqlite hintsdb: safer create of table
[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 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_RDONLY ? DB_UNKNOWN : DB_HASH,
546               flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
547               mode) == 0
548           )
549     return dbp;
550
551   b->close(b, 0);
552   }
553 dbp->close(dbp, 0);
554 return NULL;
555 }
556
557 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
558 static inline BOOL
559 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
560 {
561 DB * b = ENV_TO_DB(dbp);
562 return b->get(b, NULL, key, res, 0) == 0;
563 }
564
565 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
566 static inline int
567 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
568 {
569 DB * b = ENV_TO_DB(dbp);
570 return b->put(b, NULL, key, data, 0);
571 }
572
573 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
574 static inline int
575 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
576 {
577 DB * b = ENV_TO_DB(dbp);
578 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
579 }
580
581 /* Return values from EXIM_DBPUTB */
582
583 #   define EXIM_DBPUTB_OK  0
584 #   define EXIM_DBPUTB_DUP DB_KEYEXIST
585
586 /* EXIM_DBDEL */
587 static inline int
588 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
589 {
590 DB * b = ENV_TO_DB(dbp);
591 return b->del(b, NULL, key, 0);
592 }
593
594 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
595
596 static inline EXIM_CURSOR *
597 exim_dbcreate_cursor(EXIM_DB * dbp)
598 {
599 DB * b = ENV_TO_DB(dbp);
600 EXIM_CURSOR * c;
601 b->cursor(b, NULL, &c, 0);
602 return c;
603 }
604
605 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
606 static inline BOOL
607 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
608   EXIM_CURSOR * cursor)
609 {
610 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
611 }
612
613 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
614 static inline void
615 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
616 { cursor->c_close(cursor); }
617
618 /* EXIM_DBCLOSE */
619 static inline void
620 exim_dbclose__(EXIM_DB * dbp_o)
621 {
622 DB_ENV * dbp = dbp_o;
623 DB * b = ENV_TO_DB(dbp);
624 b->close(b, 0);
625 dbp->close(dbp, DB_FORCESYNC);
626 }
627
628 /* Datum access */
629
630 static inline uschar *
631 exim_datum_data_get(EXIM_DATUM * dp)
632 { return dp->data; }
633 static inline void
634 exim_datum_data_set(EXIM_DATUM * dp, void * s)
635 { dp->data = s; }
636
637 static inline unsigned
638 exim_datum_size_get(EXIM_DATUM * dp)
639 { return dp->size; }
640 static inline void
641 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
642 { dp->size = n; }
643
644 /* The whole datum structure contains other fields that must be cleared
645 before use, but we don't have to free anything after reading data. */
646
647 static inline void
648 exim_datum_init(EXIM_DATUM * d)
649 { memset(d, 0, sizeof(*d)); }
650
651 static inline void
652 exim_datum_free(EXIM_DATUM * d)
653 { }
654
655 #  else /* pre- 4.1 */
656
657 #   define EXIM_DB       DB
658
659 /* Cursor type, for scanning */
660 #   define EXIM_CURSOR   DBC
661
662 /* The datum type used for queries */
663 #   define EXIM_DATUM    DBT
664
665 /* Some text for messages */
666 #   define EXIM_DBTYPE   "db (v3/4)"
667
668 /* Access functions */
669
670 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
671 static inline EXIM_DB *
672 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
673   unsigned mode)
674 {
675 EXIM_DB * dbp;
676 return db_create(&dbp, NULL, 0) == 0
677   && (  dbp->set_errcall(dbp, dbfn_bdb_error_callback),
678         dbp->open(dbp, CS name, NULL,
679           flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
680           flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
681           mode)
682      ) == 0
683   ? dbp : NULL;
684 }
685
686 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
687 static inline BOOL
688 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
689 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
690
691 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
692 static inline int
693 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
694 { return dbp->put(dbp, NULL, key, data, 0); }
695
696 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
697 static inline int
698 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
699 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
700
701 /* Return values from EXIM_DBPUTB */
702
703 #   define EXIM_DBPUTB_OK  0
704 #   define EXIM_DBPUTB_DUP DB_KEYEXIST
705
706 /* EXIM_DBDEL */
707 static inline int
708 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
709 { return dbp->del(dbp, NULL, key, 0); }
710
711 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
712
713 static inline EXIM_CURSOR *
714 exim_dbcreate_cursor(EXIM_DB * dbp)
715 {
716 EXIM_CURSOR * c;
717 dbp->cursor(dbp, NULL, &c, 0);
718 return c;
719 }
720
721 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
722 static inline BOOL
723 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
724   EXIM_CURSOR * cursor)
725 {
726 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
727 }
728
729 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
730 static inline void
731 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
732 { cursor->c_close(cursor); }
733
734 /* EXIM_DBCLOSE */
735 static inline void
736 exim_dbclose__(EXIM_DB * dbp)
737 { dbp->close(dbp, 0); }
738
739 /* Datum access */
740
741 static inline uschar *
742 exim_datum_data_get(EXIM_DATUM * dp)
743 { return US dp->dptr; }
744 static inline void
745 exim_datum_data_set(EXIM_DATUM * dp, void * s)
746 { dp->dptr = s; }
747
748 static inline uschar *
749 exim_datum_size_get(EXIM_DATUM * dp)
750 { return US dp->size; }
751 static inline void
752 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
753 { dp->size = CS s; }
754
755 /* The whole datum structure contains other fields that must be cleared
756 before use, but we don't have to free anything after reading data. */
757
758 static inline void
759 exim_datum_init(EXIM_DATUM * d)
760 { memset(d, 0, sizeof(*d)); }
761
762 static inline void
763 exim_datum_free(EXIM_DATUM * d)
764 { }
765
766 #  endif
767
768
769 #  else /* DB_VERSION_MAJOR >= 3 */
770 #   error Berkeley DB versions earlier than 3 are not supported */
771 #  endif /* DB_VERSION_MAJOR */
772 # else
773 #  error Berkeley DB version 1 is no longer supported
774 # endif /* DB_VERSION_STRING */
775
776
777 /* all BDB versions */
778 /* size limit */
779
780 # define EXIM_DB_RLIMIT 150
781
782
783
784
785
786
787 /********************* gdbm interface definitions **********************/
788
789 #elif defined USE_GDBM
790 /*XXX TODO: exim's locfile not needed */
791
792 # if defined(USE_TDB) || defined(USE_DB)
793 #  error USE_GDBM conflict with alternate definition
794 # endif
795
796 # include <gdbm.h>
797
798 /* Basic DB type */
799 typedef struct {
800        GDBM_FILE gdbm;  /* Database */
801        datum lkey;      /* Last key, for scans */
802 } EXIM_DB;
803
804 /* Cursor type, not used with gdbm: just set up a dummy */
805 # define EXIM_CURSOR int
806
807 /* The datum type used for queries */
808 # define EXIM_DATUM datum
809
810 /* Some text for messages */
811
812 # define EXIM_DBTYPE "gdbm"
813
814 /* Access functions */
815
816 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
817 static inline EXIM_DB *
818 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
819   unsigned mode)
820 {
821 EXIM_DB * dbp = malloc(sizeof(EXIM_DB));        /*XXX why not exim mem-mgmt? */
822 if (dbp)
823   {
824   dbp->lkey.dptr = NULL;
825   dbp->gdbm = gdbm_open(CS name, 0,
826     flags & O_CREAT ? GDBM_WRCREAT
827     : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
828     : GDBM_READER,
829     mode, 0);
830   if (dbp->gdbm) return dbp;
831   free(dbp);
832   }
833 return NULL;
834 }
835
836 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
837 static inline BOOL
838 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
839 {
840 *res = gdbm_fetch(dbp->gdbm, *key);     /* A struct arg & return! */
841 return res->dptr != NULL;
842 }
843
844 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
845 static inline int
846 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
847 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
848
849 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
850 static inline int
851 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
852 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
853
854 /* Returns from EXIM_DBPUTB */
855
856 # define EXIM_DBPUTB_OK  0
857 # define EXIM_DBPUTB_DUP 1
858
859 /* EXIM_DBDEL */
860 static inline int
861 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
862 { return gdbm_delete(dbp->gdbm, *key); }
863
864 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
865 static inline EXIM_CURSOR *
866 exim_dbcreate_cursor(EXIM_DB * dbp)
867 { return NULL; }
868
869 /* EXIM_DBSCAN */
870 static inline BOOL
871 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
872   EXIM_CURSOR * cursor)
873 {
874 char * s;
875 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
876 if ((s = dbp->lkey.dptr)) free(s);
877 dbp->lkey = *key;
878 return key->dptr != NULL;
879 }
880
881 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
882 static inline void
883 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
884 { }
885
886 /* EXIM_DBCLOSE */
887 static inline void
888 exim_dbclose__(EXIM_DB * dbp)
889 {
890 char * s;
891 gdbm_close(dbp->gdbm);
892 if ((s = dbp->lkey.dptr)) free(s);
893 free(dbp);
894 }
895
896 /* Datum access types */
897
898 static inline uschar *
899 exim_datum_data_get(EXIM_DATUM * dp)
900 { return US dp->dptr; }
901 static inline void
902 exim_datum_data_set(EXIM_DATUM * dp, void * s)
903 { dp->dptr = s; }
904
905 static inline unsigned
906 exim_datum_size_get(EXIM_DATUM * dp)
907 { return dp->dsize; }
908 static inline void
909 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
910 { dp->dsize = n; }
911
912 /* There's no clearing required before use, but we have to free the dptr
913 after reading data. */
914
915 static inline void
916 exim_datum_init(EXIM_DATUM * d)
917 { }
918
919 static inline void
920 exim_datum_free(EXIM_DATUM * d)
921 { free(d->dptr); }
922
923 /* size limit. GDBM is int-max limited, but we want to be less silly */
924
925 # define EXIM_DB_RLIMIT 150
926
927 #else  /* USE_GDBM */
928
929
930
931
932
933
934 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
935 interface (which seems to be a wrapper for GDBM) */
936
937
938 /********************* ndbm interface definitions **********************/
939
940 # include <ndbm.h>
941
942 /* Basic DB type */
943 # define EXIM_DB DBM
944
945 /* Cursor type, not used with ndbm: just set up a dummy */
946 # define EXIM_CURSOR int
947
948 /* The datum type used for queries */
949 # define EXIM_DATUM datum
950
951 /* Some text for messages */
952
953 # define EXIM_DBTYPE "ndbm"
954
955 /* Access functions */
956
957 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
958 /* Check that the name given is not present. This catches
959 a directory name; otherwise we would create the name.pag and
960 name.dir files in the directory's parent. */
961
962 static inline EXIM_DB *
963 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
964   unsigned mode)
965 {
966 struct stat st;
967 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
968   return dbm_open(CS name, flags, mode);
969 #ifndef COMPILE_UTILITY
970 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
971 #endif
972 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
973 return NULL;
974 }
975
976 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
977 static inline BOOL
978 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
979 {
980 *res = dbm_fetch(dbp, *key);    /* A struct arg & return! */
981 return res->dptr != NULL;
982 }
983
984 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
985 static inline int
986 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
987 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
988
989 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
990 static inline int
991 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
992 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
993
994 /* Returns from EXIM_DBPUTB */
995
996 # define EXIM_DBPUTB_OK  0
997 # define EXIM_DBPUTB_DUP 1
998
999 /* EXIM_DBDEL */
1000 static inline int
1001 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1002 { return dbm_delete(dbp, *key); }
1003
1004 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1005 static inline EXIM_CURSOR *
1006 exim_dbcreate_cursor(EXIM_DB * dbp)
1007 { return NULL; }
1008
1009 /* EXIM_DBSCAN */
1010 static inline BOOL
1011 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1012   EXIM_CURSOR * cursor)
1013 {
1014 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1015 return key->dptr != NULL;
1016 }
1017
1018 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1019 static inline void
1020 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1021 { }
1022
1023 /* EXIM_DBCLOSE */
1024 static inline void
1025 exim_dbclose__(EXIM_DB * dbp)
1026 { dbm_close(dbp); }
1027
1028 /* Datum access types */
1029
1030 static inline uschar *
1031 exim_datum_data_get(EXIM_DATUM * dp)
1032 { return US dp->dptr; }
1033 static inline void
1034 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1035 { dp->dptr = s; }
1036
1037 static inline unsigned
1038 exim_datum_size_get(EXIM_DATUM * dp)
1039 { return dp->dsize; }
1040 static inline void
1041 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1042 { dp->dsize = n; }
1043
1044 /* There's no clearing required before use, and we don't have to free anything
1045 after reading data. */
1046
1047 static inline void
1048 exim_datum_init(EXIM_DATUM * d)
1049 { }
1050
1051 static inline void
1052 exim_datum_free(EXIM_DATUM * d)
1053 { }
1054
1055 /* size limit */
1056
1057 # define EXIM_DB_RLIMIT 150
1058
1059 #endif /* !USE_GDBM */
1060
1061
1062
1063
1064
1065 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1066
1067 static inline EXIM_DB *
1068 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1069   unsigned mode)
1070 {
1071 return exim_dbopen__(name, dirname, flags, mode);
1072 }
1073
1074 static inline void
1075 exim_dbclose(EXIM_DB * dbp)
1076 { exim_dbclose__(dbp); }
1077
1078 #else   /*  exim mainline code */
1079
1080 /* Wrappers for open/close with debug tracing */
1081
1082 extern void debug_printf_indent(const char *, ...);
1083 static inline BOOL is_tainted(const void *);
1084
1085 static inline EXIM_DB *
1086 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1087   unsigned mode)
1088 {
1089 void * dbp;
1090 DEBUG(D_hints_lookup)
1091   debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1092     name, dirname,
1093     flags == O_RDONLY ? "O_RDONLY"
1094     : flags == O_RDWR ? "O_RDWR"
1095     : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1096     : "??");
1097 if (is_tainted(name) || is_tainted(dirname))
1098   {
1099   log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1100   dbp = NULL;
1101   }
1102 else
1103   dbp = exim_dbopen__(name, dirname, flags, mode);
1104
1105 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1106 return dbp;
1107 }
1108
1109 static inline void
1110 exim_dbclose(EXIM_DB * dbp)
1111 {
1112 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1113 exim_dbclose__(dbp);
1114 }
1115
1116 # endif         /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1117
1118 /********************* End of dbm library definitions **********************/
1119
1120
1121 #endif  /* whole file */
1122 /* End of hintsdb.h */
1123 /* vi: aw ai sw=2
1124 */