Commit | Line | Data |
---|---|---|
059ec3d9 PH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
f9ba5e22 | 5 | /* Copyright (c) University of Cambridge 1995 - 2018 */ |
059ec3d9 PH |
6 | /* See the file NOTICE for conditions of use and distribution. */ |
7 | ||
8 | /* This header file contains macro definitions so that a variety of DBM | |
9 | libraries can be used by Exim. Nigel Metheringham provided the original set for | |
10 | Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB | |
11 | 2.x and 3.x were added. Later still, support for tdb was added, courtesy of | |
12 | James Antill. Most recently, support for native mode gdbm was added, with code | |
13 | from Pierre A. Humblet, so Exim could be made to work with Cygwin. | |
14 | ||
15 | For convenience, the definitions of the structures used in the various hints | |
16 | databases are also kept in this file, which is used by the maintenance | |
17 | utilities as well as the main Exim binary. */ | |
18 | ||
19 | ||
20 | # ifdef USE_TDB | |
21 | ||
22 | /* ************************* tdb interface ************************ */ | |
23 | ||
24 | #include <tdb.h> | |
25 | ||
26 | /* Basic DB type */ | |
27 | #define EXIM_DB TDB_CONTEXT | |
28 | ||
29 | /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants | |
30 | tdb_traverse to be called) */ | |
31 | #define EXIM_CURSOR TDB_DATA | |
32 | ||
33 | /* The datum type used for queries */ | |
34 | #define EXIM_DATUM TDB_DATA | |
35 | ||
36 | /* Some text for messages */ | |
37 | #define EXIM_DBTYPE "tdb" | |
38 | ||
39 | /* Access functions */ | |
40 | ||
41 | /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */ | |
0a6c178c | 42 | #define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
43 | *(dbpp) = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode) |
44 | ||
45 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
46 | #define EXIM_DBGET(db, key, data) \ | |
47 | (data = tdb_fetch(db, key), data.dptr != NULL) | |
48 | ||
49 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
50 | #define EXIM_DBPUT(db, key, data) \ | |
51 | tdb_store(db, key, data, TDB_REPLACE) | |
52 | ||
53 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
54 | #define EXIM_DBPUTB(db, key, data) \ | |
55 | tdb_store(db, key, data, TDB_INSERT) | |
56 | ||
57 | /* Returns from EXIM_DBPUTB */ | |
58 | ||
59 | #define EXIM_DBPUTB_OK 0 | |
60 | #define EXIM_DBPUTB_DUP (-1) | |
61 | ||
62 | /* EXIM_DBDEL */ | |
63 | #define EXIM_DBDEL(db, key) tdb_delete(db, key) | |
64 | ||
65 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */ | |
66 | #define EXIM_DBCREATE_CURSOR(db, cursor) { \ | |
40c90bca | 67 | *(cursor) = store_malloc(sizeof(TDB_DATA)); (*(cursor))->dptr = NULL; } |
059ec3d9 PH |
68 | |
69 | /* EXIM_DBSCAN - This is complicated because we have to free the last datum | |
70 | free() must not die when passed NULL */ | |
71 | #define EXIM_DBSCAN(db, key, data, first, cursor) \ | |
72 | (key = (first ? tdb_firstkey(db) : tdb_nextkey(db, *(cursor))), \ | |
73 | free((cursor)->dptr), *(cursor) = key, \ | |
74 | key.dptr != NULL) | |
75 | ||
76 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */ | |
77 | #define EXIM_DBDELETE_CURSOR(cursor) free(cursor) | |
78 | ||
79 | /* EXIM_DBCLOSE */ | |
0a6c178c | 80 | #define EXIM_DBCLOSE__(db) tdb_close(db) |
059ec3d9 PH |
81 | |
82 | /* Datum access types - these are intended to be assignable */ | |
83 | ||
84 | #define EXIM_DATUM_SIZE(datum) (datum).dsize | |
85 | #define EXIM_DATUM_DATA(datum) (datum).dptr | |
86 | ||
87 | /* Free the stuff inside the datum. */ | |
88 | ||
89 | #define EXIM_DATUM_FREE(datum) (free((datum).dptr), (datum).dptr = NULL) | |
90 | ||
91 | /* No initialization is needed. */ | |
92 | ||
93 | #define EXIM_DATUM_INIT(datum) | |
94 | ||
95 | ||
96 | ||
97 | /********************* Berkeley db native definitions **********************/ | |
98 | ||
99 | #elif defined USE_DB | |
100 | ||
101 | #include <db.h> | |
102 | ||
103 | ||
104 | /* We can distinguish between versions 1.x and 2.x/3.x by looking for a | |
105 | definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */ | |
106 | ||
107 | #ifdef DB_VERSION_STRING | |
108 | ||
fd622879 JH |
109 | # if DB_VERSION_MAJOR >= 6 |
110 | # error Version 6 and later BDB API is not supported | |
111 | # endif | |
112 | ||
059ec3d9 PH |
113 | /* The API changed (again!) between the 2.x and 3.x versions */ |
114 | ||
115 | #if DB_VERSION_MAJOR >= 3 | |
116 | ||
117 | /***************** Berkeley db 3.x/4.x native definitions ******************/ | |
118 | ||
119 | /* Basic DB type */ | |
fd622879 JH |
120 | # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) |
121 | # define EXIM_DB DB_ENV | |
059ec3d9 | 122 | /* Cursor type, for scanning */ |
fd622879 | 123 | # define EXIM_CURSOR DBC |
059ec3d9 PH |
124 | |
125 | /* The datum type used for queries */ | |
fd622879 | 126 | # define EXIM_DATUM DBT |
059ec3d9 PH |
127 | |
128 | /* Some text for messages */ | |
fd622879 | 129 | # define EXIM_DBTYPE "db (v4.1+)" |
0d64dcb0 JH |
130 | |
131 | /* Only more-recent versions. 5+ ? */ | |
fd622879 JH |
132 | # ifndef DB_FORCESYNC |
133 | # define DB_FORCESYNC 0 | |
134 | # endif | |
0d64dcb0 | 135 | |
059ec3d9 PH |
136 | |
137 | /* Access functions */ | |
138 | ||
139 | /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. The | |
0a6c178c JH |
140 | API changed for DB 4.1. - and we also starting using the "env" with a |
141 | specified working dir, to avoid the DBCONFIG file trap. */ | |
142 | ||
fd622879 | 143 | # define ENV_TO_DB(env) ((DB *)((env)->app_private)) |
0a6c178c | 144 | |
fd622879 | 145 | # define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
0a6c178c JH |
146 | if ( db_env_create(dbpp, 0) != 0 \ |
147 | || ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), 0) \ | |
148 | || (*dbpp)->open(*dbpp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0\ | |
149 | ) \ | |
150 | *dbpp = NULL; \ | |
151 | else if (db_create((DB **) &((*dbpp)->app_private), *dbpp, 0) != 0) \ | |
152 | { \ | |
153 | ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \ | |
154 | *dbpp = NULL; \ | |
155 | } \ | |
156 | else if (ENV_TO_DB(*dbpp)->open(ENV_TO_DB(*dbpp), NULL, CS name, NULL, \ | |
157 | (flags) == O_RDONLY ? DB_UNKNOWN : DB_HASH, \ | |
158 | (flags) == O_RDONLY ? DB_RDONLY : DB_CREATE, \ | |
159 | mode) != 0 \ | |
160 | ) \ | |
161 | { \ | |
162 | ENV_TO_DB(*dbpp)->close(ENV_TO_DB(*dbpp), 0); \ | |
163 | ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0); \ | |
164 | *dbpp = NULL; \ | |
165 | } | |
059ec3d9 | 166 | |
0a6c178c | 167 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ |
fd622879 | 168 | # define EXIM_DBGET(db, key, data) \ |
0a6c178c JH |
169 | (ENV_TO_DB(db)->get(ENV_TO_DB(db), NULL, &key, &data, 0) == 0) |
170 | ||
171 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
fd622879 | 172 | # define EXIM_DBPUT(db, key, data) \ |
0a6c178c JH |
173 | ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, 0) |
174 | ||
175 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
fd622879 | 176 | # define EXIM_DBPUTB(db, key, data) \ |
0a6c178c JH |
177 | ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, DB_NOOVERWRITE) |
178 | ||
179 | /* Return values from EXIM_DBPUTB */ | |
180 | ||
fd622879 JH |
181 | # define EXIM_DBPUTB_OK 0 |
182 | # define EXIM_DBPUTB_DUP DB_KEYEXIST | |
0a6c178c JH |
183 | |
184 | /* EXIM_DBDEL */ | |
fd622879 | 185 | # define EXIM_DBDEL(db, key) ENV_TO_DB(db)->del(ENV_TO_DB(db), NULL, &key, 0) |
0a6c178c JH |
186 | |
187 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */ | |
188 | ||
fd622879 | 189 | # define EXIM_DBCREATE_CURSOR(db, cursor) \ |
0a6c178c JH |
190 | ENV_TO_DB(db)->cursor(ENV_TO_DB(db), NULL, cursor, 0) |
191 | ||
192 | /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */ | |
fd622879 | 193 | # define EXIM_DBSCAN(db, key, data, first, cursor) \ |
0a6c178c JH |
194 | ((cursor)->c_get(cursor, &key, &data, \ |
195 | (first? DB_FIRST : DB_NEXT)) == 0) | |
196 | ||
197 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation */ | |
fd622879 | 198 | # define EXIM_DBDELETE_CURSOR(cursor) \ |
0a6c178c JH |
199 | (cursor)->c_close(cursor) |
200 | ||
201 | /* EXIM_DBCLOSE */ | |
fd622879 | 202 | # define EXIM_DBCLOSE__(db) \ |
0a6c178c JH |
203 | (ENV_TO_DB(db)->close(ENV_TO_DB(db), 0) , ((DB_ENV *)(db))->close((DB_ENV *)(db), DB_FORCESYNC)) |
204 | ||
205 | /* Datum access types - these are intended to be assignable. */ | |
206 | ||
fd622879 JH |
207 | # define EXIM_DATUM_SIZE(datum) (datum).size |
208 | # define EXIM_DATUM_DATA(datum) (datum).data | |
0a6c178c JH |
209 | |
210 | /* The whole datum structure contains other fields that must be cleared | |
211 | before use, but we don't have to free anything after reading data. */ | |
212 | ||
fd622879 JH |
213 | # define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum)) |
214 | # define EXIM_DATUM_FREE(datum) | |
0a6c178c | 215 | |
fd622879 | 216 | # else /* pre- 4.1 */ |
0a6c178c | 217 | |
fd622879 | 218 | # define EXIM_DB DB |
0a6c178c JH |
219 | |
220 | /* Cursor type, for scanning */ | |
fd622879 | 221 | # define EXIM_CURSOR DBC |
0a6c178c JH |
222 | |
223 | /* The datum type used for queries */ | |
fd622879 | 224 | # define EXIM_DATUM DBT |
0a6c178c JH |
225 | |
226 | /* Some text for messages */ | |
fd622879 | 227 | # define EXIM_DBTYPE "db (v3/4)" |
0a6c178c JH |
228 | |
229 | /* Access functions */ | |
230 | ||
231 | /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. */ | |
232 | ||
fd622879 | 233 | # define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
234 | if (db_create(dbpp, NULL, 0) != 0 || \ |
235 | ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \ | |
19897d52 | 236 | ((*dbpp)->open)(*dbpp, CS name, NULL, \ |
059ec3d9 PH |
237 | ((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \ |
238 | ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \ | |
239 | mode)) != 0) *(dbpp) = NULL | |
059ec3d9 PH |
240 | |
241 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
fd622879 | 242 | # define EXIM_DBGET(db, key, data) \ |
059ec3d9 PH |
243 | ((db)->get(db, NULL, &key, &data, 0) == 0) |
244 | ||
245 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
fd622879 | 246 | # define EXIM_DBPUT(db, key, data) \ |
059ec3d9 PH |
247 | (db)->put(db, NULL, &key, &data, 0) |
248 | ||
249 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
fd622879 | 250 | # define EXIM_DBPUTB(db, key, data) \ |
059ec3d9 PH |
251 | (db)->put(db, NULL, &key, &data, DB_NOOVERWRITE) |
252 | ||
253 | /* Return values from EXIM_DBPUTB */ | |
254 | ||
fd622879 JH |
255 | # define EXIM_DBPUTB_OK 0 |
256 | # define EXIM_DBPUTB_DUP DB_KEYEXIST | |
059ec3d9 PH |
257 | |
258 | /* EXIM_DBDEL */ | |
fd622879 | 259 | # define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0) |
059ec3d9 PH |
260 | |
261 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */ | |
262 | ||
fd622879 | 263 | # define EXIM_DBCREATE_CURSOR(db, cursor) \ |
059ec3d9 PH |
264 | (db)->cursor(db, NULL, cursor, 0) |
265 | ||
266 | /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */ | |
fd622879 | 267 | # define EXIM_DBSCAN(db, key, data, first, cursor) \ |
059ec3d9 PH |
268 | ((cursor)->c_get(cursor, &key, &data, \ |
269 | (first? DB_FIRST : DB_NEXT)) == 0) | |
270 | ||
271 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation */ | |
fd622879 | 272 | # define EXIM_DBDELETE_CURSOR(cursor) \ |
059ec3d9 PH |
273 | (cursor)->c_close(cursor) |
274 | ||
275 | /* EXIM_DBCLOSE */ | |
fd622879 | 276 | # define EXIM_DBCLOSE__(db) (db)->close(db, 0) |
059ec3d9 PH |
277 | |
278 | /* Datum access types - these are intended to be assignable. */ | |
279 | ||
fd622879 JH |
280 | # define EXIM_DATUM_SIZE(datum) (datum).size |
281 | # define EXIM_DATUM_DATA(datum) (datum).data | |
059ec3d9 PH |
282 | |
283 | /* The whole datum structure contains other fields that must be cleared | |
284 | before use, but we don't have to free anything after reading data. */ | |
285 | ||
fd622879 JH |
286 | # define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum)) |
287 | # define EXIM_DATUM_FREE(datum) | |
0a6c178c | 288 | |
fd622879 | 289 | # endif |
059ec3d9 PH |
290 | |
291 | ||
292 | #else /* DB_VERSION_MAJOR >= 3 */ | |
293 | ||
294 | /******************* Berkeley db 2.x native definitions ********************/ | |
295 | ||
296 | /* Basic DB type */ | |
297 | #define EXIM_DB DB | |
298 | ||
299 | /* Cursor type, for scanning */ | |
300 | #define EXIM_CURSOR DBC | |
301 | ||
302 | /* The datum type used for queries */ | |
303 | #define EXIM_DATUM DBT | |
304 | ||
305 | /* Some text for messages */ | |
306 | #define EXIM_DBTYPE "db (v2)" | |
307 | ||
308 | /* Access functions */ | |
309 | ||
310 | /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */ | |
0a6c178c | 311 | #define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
312 | if ((errno = db_open(CS name, DB_HASH, \ |
313 | ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \ | |
314 | mode, NULL, NULL, dbpp)) != 0) *(dbpp) = NULL | |
315 | ||
316 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
317 | #define EXIM_DBGET(db, key, data) \ | |
318 | ((db)->get(db, NULL, &key, &data, 0) == 0) | |
319 | ||
320 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
321 | #define EXIM_DBPUT(db, key, data) \ | |
322 | (db)->put(db, NULL, &key, &data, 0) | |
323 | ||
324 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
325 | #define EXIM_DBPUTB(db, key, data) \ | |
326 | (db)->put(db, NULL, &key, &data, DB_NOOVERWRITE) | |
327 | ||
328 | /* Return values from EXIM_DBPUTB */ | |
329 | ||
330 | #define EXIM_DBPUTB_OK 0 | |
331 | #define EXIM_DBPUTB_DUP DB_KEYEXIST | |
332 | ||
333 | /* EXIM_DBDEL */ | |
334 | #define EXIM_DBDEL(db, key) (db)->del(db, NULL, &key, 0) | |
335 | ||
336 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */ | |
337 | ||
338 | /* The API of this function was changed between releases 2.4.14 and 2.7.3. I do | |
339 | not know exactly where the change happened, but the Change Log for 2.5.9 lists | |
340 | the new option that is available, so I guess that it happened at 2.5.x. */ | |
341 | ||
342 | #if DB_VERSION_MINOR >= 5 | |
343 | #define EXIM_DBCREATE_CURSOR(db, cursor) \ | |
344 | (db)->cursor(db, NULL, cursor, 0) | |
345 | #else | |
346 | #define EXIM_DBCREATE_CURSOR(db, cursor) \ | |
347 | (db)->cursor(db, NULL, cursor) | |
348 | #endif | |
349 | ||
350 | /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */ | |
351 | #define EXIM_DBSCAN(db, key, data, first, cursor) \ | |
352 | ((cursor)->c_get(cursor, &key, &data, \ | |
353 | (first? DB_FIRST : DB_NEXT)) == 0) | |
354 | ||
355 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation */ | |
356 | #define EXIM_DBDELETE_CURSOR(cursor) \ | |
357 | (cursor)->c_close(cursor) | |
358 | ||
359 | /* EXIM_DBCLOSE */ | |
0a6c178c | 360 | #define EXIM_DBCLOSE__(db) (db)->close(db, 0) |
059ec3d9 PH |
361 | |
362 | /* Datum access types - these are intended to be assignable. */ | |
363 | ||
364 | #define EXIM_DATUM_SIZE(datum) (datum).size | |
365 | #define EXIM_DATUM_DATA(datum) (datum).data | |
366 | ||
367 | /* The whole datum structure contains other fields that must be cleared | |
368 | before use, but we don't have to free anything after reading data. */ | |
369 | ||
370 | #define EXIM_DATUM_INIT(datum) memset(&datum, 0, sizeof(datum)) | |
371 | #define EXIM_DATUM_FREE(datum) | |
372 | ||
373 | #endif /* DB_VERSION_MAJOR >= 3 */ | |
374 | ||
375 | ||
376 | /* If DB_VERSION_TYPE is not defined, we have version 1.x */ | |
377 | ||
378 | #else /* DB_VERSION_TYPE */ | |
379 | ||
380 | /******************* Berkeley db 1.x native definitions ********************/ | |
381 | ||
382 | /* Basic DB type */ | |
383 | #define EXIM_DB DB | |
384 | ||
385 | /* Cursor type, not used with DB 1.x: just set up a dummy */ | |
386 | #define EXIM_CURSOR int | |
387 | ||
388 | /* The datum type used for queries */ | |
389 | #define EXIM_DATUM DBT | |
390 | ||
391 | /* Some text for messages */ | |
392 | #define EXIM_DBTYPE "db (v1)" | |
393 | ||
9ad41a42 TK |
394 | /* When scanning, for the non-first case we historically just passed 0 |
395 | as the flags field and it worked. On FreeBSD 8 it no longer works and | |
396 | instead leads to memory exhaustion. The man-page on FreeBSD says to use | |
397 | R_NEXT, but this 1.x is a historical fallback and I've no idea how portable | |
398 | the use of that flag is; so the solution is to define R_NEXT here if it's not | |
399 | already defined, with a default value of 0 because that's what we've always | |
400 | before been able to pass successfully. */ | |
401 | #ifndef R_NEXT | |
402 | #define R_NEXT 0 | |
403 | #endif | |
404 | ||
059ec3d9 PH |
405 | /* Access functions */ |
406 | ||
407 | /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */ | |
0a6c178c | 408 | #define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
409 | *(dbpp) = dbopen(CS name, flags, mode, DB_HASH, NULL) |
410 | ||
411 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
412 | #define EXIM_DBGET(db, key, data) \ | |
413 | ((db)->get(db, &key, &data, 0) == 0) | |
414 | ||
415 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
416 | #define EXIM_DBPUT(db, key, data) \ | |
417 | (db)->put(db, &key, &data, 0) | |
418 | ||
419 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
420 | #define EXIM_DBPUTB(db, key, data) \ | |
421 | (db)->put(db, &key, &data, R_NOOVERWRITE) | |
422 | ||
423 | /* Returns from EXIM_DBPUTB */ | |
424 | ||
425 | #define EXIM_DBPUTB_OK 0 | |
426 | #define EXIM_DBPUTB_DUP 1 | |
427 | ||
428 | /* EXIM_DBDEL */ | |
429 | #define EXIM_DBDEL(db, key) (db)->del(db, &key, 0) | |
430 | ||
431 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */ | |
432 | #define EXIM_DBCREATE_CURSOR(db, cursor) {} | |
433 | ||
434 | /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */ | |
435 | #define EXIM_DBSCAN(db, key, data, first, cursor) \ | |
9ad41a42 | 436 | ((db)->seq(db, &key, &data, (first? R_FIRST : R_NEXT)) == 0) |
059ec3d9 PH |
437 | |
438 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). Make it | |
439 | refer to cursor, to keep picky compilers happy. */ | |
440 | #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; } | |
441 | ||
442 | /* EXIM_DBCLOSE */ | |
0a6c178c | 443 | #define EXIM_DBCLOSE__(db) (db)->close(db) |
059ec3d9 PH |
444 | |
445 | /* Datum access types - these are intended to be assignable */ | |
446 | ||
447 | #define EXIM_DATUM_SIZE(datum) (datum).size | |
448 | #define EXIM_DATUM_DATA(datum) (datum).data | |
449 | ||
450 | /* There's no clearing required before use, and we don't have to free anything | |
451 | after reading data. */ | |
452 | ||
453 | #define EXIM_DATUM_INIT(datum) | |
454 | #define EXIM_DATUM_FREE(datum) | |
455 | ||
456 | #endif /* DB_VERSION_STRING */ | |
457 | ||
458 | ||
459 | ||
460 | /********************* gdbm interface definitions **********************/ | |
461 | ||
462 | #elif defined USE_GDBM | |
463 | ||
464 | #include <gdbm.h> | |
465 | ||
466 | /* Basic DB type */ | |
467 | typedef struct { | |
870f6ba8 TF |
468 | GDBM_FILE gdbm; /* Database */ |
469 | datum lkey; /* Last key, for scans */ | |
059ec3d9 PH |
470 | } EXIM_DB; |
471 | ||
472 | /* Cursor type, not used with gdbm: just set up a dummy */ | |
473 | #define EXIM_CURSOR int | |
474 | ||
475 | /* The datum type used for queries */ | |
476 | #define EXIM_DATUM datum | |
477 | ||
478 | /* Some text for messages */ | |
479 | ||
480 | #define EXIM_DBTYPE "gdbm" | |
481 | ||
482 | /* Access functions */ | |
483 | ||
484 | /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */ | |
0a6c178c | 485 | #define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
486 | { (*(dbpp)) = (EXIM_DB *) malloc(sizeof(EXIM_DB));\ |
487 | if (*(dbpp) != NULL) { \ | |
488 | (*(dbpp))->lkey.dptr = NULL;\ | |
489 | (*(dbpp))->gdbm = gdbm_open(CS name, 0, (((flags) & O_CREAT))?GDBM_WRCREAT:(((flags) & (O_RDWR|O_WRONLY))?GDBM_WRITER:GDBM_READER), mode, 0);\ | |
490 | if ((*(dbpp))->gdbm == NULL) {\ | |
491 | free(*(dbpp));\ | |
492 | *(dbpp) = NULL;\ | |
493 | }\ | |
494 | }\ | |
495 | } | |
496 | ||
497 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
498 | #define EXIM_DBGET(db, key, data) \ | |
499 | (data = gdbm_fetch(db->gdbm, key), data.dptr != NULL) | |
500 | ||
501 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
502 | #define EXIM_DBPUT(db, key, data) \ | |
503 | gdbm_store(db->gdbm, key, data, GDBM_REPLACE) | |
504 | ||
505 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
506 | #define EXIM_DBPUTB(db, key, data) \ | |
507 | gdbm_store(db->gdbm, key, data, GDBM_INSERT) | |
508 | ||
509 | /* Returns from EXIM_DBPUTB */ | |
510 | ||
511 | #define EXIM_DBPUTB_OK 0 | |
512 | #define EXIM_DBPUTB_DUP 1 | |
513 | ||
514 | /* EXIM_DBDEL */ | |
515 | #define EXIM_DBDEL(db, key) gdbm_delete(db->gdbm, key) | |
516 | ||
517 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */ | |
518 | #define EXIM_DBCREATE_CURSOR(db, cursor) {} | |
519 | ||
520 | /* EXIM_DBSCAN */ | |
521 | #define EXIM_DBSCAN(db, key, data, first, cursor) \ | |
522 | ( key = ((first)? gdbm_firstkey(db->gdbm) : gdbm_nextkey(db->gdbm, db->lkey)), \ | |
523 | (((db)->lkey.dptr != NULL)? (free((db)->lkey.dptr),1) : 1),\ | |
524 | db->lkey = key, key.dptr != NULL) | |
525 | ||
526 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). Make it | |
527 | refer to cursor, to keep picky compilers happy. */ | |
528 | #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; } | |
529 | ||
530 | /* EXIM_DBCLOSE */ | |
0a6c178c | 531 | #define EXIM_DBCLOSE__(db) \ |
059ec3d9 PH |
532 | { gdbm_close((db)->gdbm);\ |
533 | if ((db)->lkey.dptr != NULL) free((db)->lkey.dptr);\ | |
534 | free(db); } | |
535 | ||
536 | /* Datum access types - these are intended to be assignable */ | |
537 | ||
538 | #define EXIM_DATUM_SIZE(datum) (datum).dsize | |
539 | #define EXIM_DATUM_DATA(datum) (datum).dptr | |
540 | ||
541 | /* There's no clearing required before use, but we have to free the dptr | |
542 | after reading data. */ | |
543 | ||
544 | #define EXIM_DATUM_INIT(datum) | |
545 | #define EXIM_DATUM_FREE(datum) free(datum.dptr) | |
546 | ||
547 | #else /* USE_GDBM */ | |
548 | ||
549 | ||
550 | /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM | |
551 | interface */ | |
552 | ||
553 | ||
554 | /********************* ndbm interface definitions **********************/ | |
555 | ||
556 | #include <ndbm.h> | |
557 | ||
558 | /* Basic DB type */ | |
559 | #define EXIM_DB DBM | |
560 | ||
561 | /* Cursor type, not used with ndbm: just set up a dummy */ | |
562 | #define EXIM_CURSOR int | |
563 | ||
564 | /* The datum type used for queries */ | |
565 | #define EXIM_DATUM datum | |
566 | ||
567 | /* Some text for messages */ | |
568 | ||
569 | #define EXIM_DBTYPE "ndbm" | |
570 | ||
571 | /* Access functions */ | |
572 | ||
573 | /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */ | |
0a6c178c | 574 | #define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \ |
059ec3d9 PH |
575 | *(dbpp) = dbm_open(CS name, flags, mode) |
576 | ||
577 | /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ | |
578 | #define EXIM_DBGET(db, key, data) \ | |
579 | (data = dbm_fetch(db, key), data.dptr != NULL) | |
580 | ||
581 | /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ | |
582 | #define EXIM_DBPUT(db, key, data) \ | |
583 | dbm_store(db, key, data, DBM_REPLACE) | |
584 | ||
585 | /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */ | |
586 | #define EXIM_DBPUTB(db, key, data) \ | |
587 | dbm_store(db, key, data, DBM_INSERT) | |
588 | ||
589 | /* Returns from EXIM_DBPUTB */ | |
590 | ||
591 | #define EXIM_DBPUTB_OK 0 | |
592 | #define EXIM_DBPUTB_DUP 1 | |
593 | ||
594 | /* EXIM_DBDEL */ | |
595 | #define EXIM_DBDEL(db, key) dbm_delete(db, key) | |
596 | ||
597 | /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */ | |
598 | #define EXIM_DBCREATE_CURSOR(db, cursor) {} | |
599 | ||
600 | /* EXIM_DBSCAN */ | |
601 | #define EXIM_DBSCAN(db, key, data, first, cursor) \ | |
602 | (key = (first? dbm_firstkey(db) : dbm_nextkey(db)), key.dptr != NULL) | |
603 | ||
604 | /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). Make it | |
605 | refer to cursor, to keep picky compilers happy. */ | |
606 | #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; } | |
607 | ||
608 | /* EXIM_DBCLOSE */ | |
0a6c178c | 609 | #define EXIM_DBCLOSE__(db) dbm_close(db) |
059ec3d9 PH |
610 | |
611 | /* Datum access types - these are intended to be assignable */ | |
612 | ||
613 | #define EXIM_DATUM_SIZE(datum) (datum).dsize | |
614 | #define EXIM_DATUM_DATA(datum) (datum).dptr | |
615 | ||
616 | /* There's no clearing required before use, and we don't have to free anything | |
617 | after reading data. */ | |
618 | ||
619 | #define EXIM_DATUM_INIT(datum) | |
620 | #define EXIM_DATUM_FREE(datum) | |
621 | ||
622 | #endif /* USE_GDBM */ | |
623 | ||
0a6c178c JH |
624 | |
625 | ||
626 | ||
627 | ||
628 | # ifdef COMPILE_UTILITY | |
629 | ||
630 | # define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \ | |
631 | EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) | |
632 | # define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db) | |
633 | ||
634 | # else | |
635 | ||
636 | # define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \ | |
637 | do { \ | |
638 | DEBUG(D_hints_lookup) \ | |
966e829c | 639 | debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n", \ |
552f4602 JH |
640 | (name), (dirname), \ |
641 | (flags) == O_RDONLY ? "O_RDONLY" \ | |
642 | : (flags) == O_RDWR ? "O_RDWR" \ | |
643 | : (flags) == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT" \ | |
644 | : "??"); \ | |
0a6c178c | 645 | EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); \ |
966e829c | 646 | DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", *dbpp); \ |
0a6c178c JH |
647 | } while(0) |
648 | # define EXIM_DBCLOSE(db) \ | |
649 | do { \ | |
966e829c | 650 | DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", db); \ |
0a6c178c JH |
651 | EXIM_DBCLOSE__(db); \ |
652 | } while(0) | |
653 | ||
654 | # endif | |
655 | ||
059ec3d9 PH |
656 | /********************* End of dbm library definitions **********************/ |
657 | ||
658 | ||
659 | /* Structure for carrying around an open DBM file, and an open locking file | |
660 | that relates to it. */ | |
661 | ||
662 | typedef struct { | |
663 | EXIM_DB *dbptr; | |
664 | int lockfd; | |
665 | } open_db; | |
666 | ||
667 | ||
668 | /* Structures for records stored in exim database dbm files. They all | |
669 | start with the same fields, described in the generic type. */ | |
670 | ||
671 | ||
672 | typedef struct { | |
673 | time_t time_stamp; /* Timestamp of writing */ | |
674 | } dbdata_generic; | |
675 | ||
676 | ||
677 | /* This structure keeps track of retry information for a host or a local | |
678 | address. */ | |
679 | ||
680 | typedef struct { | |
681 | time_t time_stamp; | |
682 | /*************/ | |
683 | time_t first_failed; /* Time of first failure */ | |
684 | time_t last_try; /* Time of last try */ | |
685 | time_t next_try; /* Time of next try */ | |
686 | BOOL expired; /* Retry time has expired */ | |
687 | int basic_errno; /* Errno of last failure */ | |
688 | int more_errno; /* Additional information */ | |
689 | uschar text[1]; /* Text message for last failure */ | |
690 | } dbdata_retry; | |
691 | ||
692 | /* These structures keep track of addresses that have had callout verification | |
693 | performed on them. There are two groups of records: | |
694 | ||
695 | 1. keyed by localpart@domain - | |
696 | Full address was tested and record holds result | |
697 | ||
698 | 2. keyed by domain - | |
699 | Domain response upto MAIL FROM:<>, postmaster, random local part; | |
700 | ||
2b1c6e3a PH |
701 | If a record exists, the result field is either ccache_accept or ccache_reject, |
702 | or, for a domain record only, ccache_reject_mfnull when MAIL FROM:<> was | |
703 | rejected. The other fields, however, (which are only relevant to domain | |
704 | records) may also contain ccache_unknown if that particular test has not been | |
705 | done. | |
059ec3d9 PH |
706 | |
707 | Originally, there was only one structure, used for both types. However, it got | |
708 | expanded for domain records, so it got split. To make it possible for Exim to | |
709 | handle the old type of record, we retain the old definition. The different | |
4c04137d | 710 | kinds of record can be distinguished by their different lengths. */ |
059ec3d9 PH |
711 | |
712 | typedef struct { | |
713 | time_t time_stamp; | |
714 | /*************/ | |
715 | int result; | |
716 | int postmaster_result; /* Postmaster is accepted */ | |
717 | int random_result; /* Random local part was accepted */ | |
718 | } dbdata_callout_cache_obs; | |
719 | ||
720 | typedef struct { | |
721 | time_t time_stamp; /* Timestamp of last address check */ | |
722 | /*************/ | |
723 | int result; /* accept or reject */ | |
724 | } dbdata_callout_cache_address; | |
725 | ||
726 | /* For this new layout, we put the additional fields (the timestamps) | |
727 | last so that if somebody reverts to an older Exim, the new records will | |
728 | still make sense because they match the old layout. */ | |
729 | ||
730 | typedef struct { | |
731 | time_t time_stamp; /* Time stamp of last connection */ | |
732 | /*************/ | |
733 | int result; /* Domain reject or accept */ | |
734 | int postmaster_result; /* Postmaster result */ | |
735 | int random_result; /* Random result */ | |
736 | time_t postmaster_stamp; /* Timestamp of postmaster check */ | |
737 | time_t random_stamp; /* Timestamp of random check */ | |
738 | } dbdata_callout_cache; | |
739 | ||
740 | /* This structure keeps track of messages that are waiting for a particular | |
741 | host for a particular transport. */ | |
742 | ||
743 | typedef struct { | |
744 | time_t time_stamp; | |
745 | /*************/ | |
746 | int count; /* Count of message ids */ | |
747 | int sequence; /* Sequence for continued records */ | |
748 | uschar text[1]; /* One long character string */ | |
749 | } dbdata_wait; | |
750 | ||
751 | ||
752 | /* The contents of the "misc" database are a mixture of different kinds of | |
753 | record, as defined below. The keys used for a specific type all start with a | |
754 | given string such as "etrn-" or "host-serialize-". */ | |
755 | ||
756 | ||
757 | /* This structure records a connection to a particular host, for the | |
758 | purpose of serializing access to certain hosts. For possible future extension, | |
759 | a field is defined for holding the count of connections, but it is not | |
760 | at present in use. The same structure is used for recording a running ETRN | |
761 | process. */ | |
762 | ||
763 | typedef struct { | |
764 | time_t time_stamp; | |
765 | /*************/ | |
766 | int count; /* Reserved for possible connection count */ | |
767 | } dbdata_serialize; | |
768 | ||
769 | ||
870f6ba8 TF |
770 | /* This structure records the information required for the ratelimit |
771 | ACL condition. */ | |
772 | ||
773 | typedef struct { | |
774 | time_t time_stamp; | |
775 | /*************/ | |
776 | int time_usec; /* Fractional part of time, from gettimeofday() */ | |
777 | double rate; /* Smoothed sending rate at that time */ | |
778 | } dbdata_ratelimit; | |
779 | ||
c99ce5c9 TF |
780 | /* Same as above, plus a Bloom filter for uniquifying events. */ |
781 | ||
782 | typedef struct { | |
783 | dbdata_ratelimit dbd; | |
784 | time_t bloom_epoch; /* When the Bloom filter was last reset */ | |
785 | unsigned bloom_size; /* Number of bytes in the Bloom filter */ | |
786 | uschar bloom[40]; /* Bloom filter which may be larger than this */ | |
787 | } dbdata_ratelimit_unique; | |
788 | ||
ee8b8090 JH |
789 | #ifdef EXPERIMENTAL_PIPE_CONNECT |
790 | /* This structure records the EHLO responses, cleartext and crypted, | |
791 | for an IP, as bitmasks (cf. OPTION_TLS) */ | |
792 | ||
793 | typedef struct { | |
794 | unsigned short cleartext_features; | |
795 | unsigned short crypted_features; | |
796 | unsigned short cleartext_auths; | |
797 | unsigned short crypted_auths; | |
798 | } ehlo_resp_precis; | |
799 | ||
800 | typedef struct { | |
801 | time_t time_stamp; | |
802 | /*************/ | |
803 | ehlo_resp_precis data; | |
804 | } dbdata_ehlo_resp; | |
805 | #endif | |
806 | ||
870f6ba8 | 807 | |
059ec3d9 | 808 | /* End of dbstuff.h */ |