1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2017 */
6 /* See the file NOTICE for conditions of use and distribution. */
9 #include "lf_functions.h"
12 /*************************************************
14 *************************************************/
16 /* See local README for interface description */
19 dbmdb_open(uschar *filename, uschar **errmsg)
21 uschar * dirname = string_copy(filename);
23 EXIM_DB *yield = NULL;
25 if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
26 EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
29 int save_errno = errno;
30 *errmsg = string_open_failed(errno, "%s as a %s file", filename, EXIM_DBTYPE);
38 /*************************************************
40 *************************************************/
42 /* This needs to know more about the underlying files than is good for it!
43 We need to know what the real file names are in order to check the owners and
44 modes. If USE_DB is set, we know it is Berkeley DB, which uses an unmodified
45 file name. If USE_TDB or USE_GDBM is set, we know it is tdb or gdbm, which do
46 the same. Otherwise, for safety, we have to check for x.db or x.dir and x.pag.
50 dbmdb_check(void *handle, uschar *filename, int modemask, uid_t *owners,
51 gid_t *owngroups, uschar **errmsg)
54 handle = handle; /* Keep picky compilers happy */
56 #if defined(USE_DB) || defined(USE_TDB) || defined(USE_GDBM)
57 rc = lf_check_file(-1, filename, S_IFREG, modemask, owners, owngroups,
61 uschar filebuffer[256];
62 (void)sprintf(CS filebuffer, "%.250s.db", filename);
63 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
65 if (rc < 0) /* stat() failed */
67 (void)sprintf(CS filebuffer, "%.250s.dir", filename);
68 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
70 if (rc == 0) /* x.dir was OK */
72 (void)sprintf(CS filebuffer, "%.250s.pag", filename);
73 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
85 /*************************************************
87 *************************************************/
89 /* See local README for interface description. This function adds 1 to
90 the keylength in order to include the terminating zero. */
93 dbmdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
94 uschar **result, uschar **errmsg, uint *do_cache)
96 EXIM_DB *d = (EXIM_DB *)handle;
99 filename = filename; /* Keep picky compilers happy */
103 EXIM_DATUM_INIT(key); /* Some DBM libraries require datums to */
104 EXIM_DATUM_INIT(data); /* be cleared before use. */
105 EXIM_DATUM_DATA(key) = CS keystring;
106 EXIM_DATUM_SIZE(key) = length + 1;
108 if (EXIM_DBGET(d, key, data))
110 *result = string_copyn(US EXIM_DATUM_DATA(data), EXIM_DATUM_SIZE(data));
111 EXIM_DATUM_FREE(data); /* Some DBM libraries need a free() call */
119 /*************************************************
120 * Find entry point - no zero on key *
121 *************************************************/
123 /* See local README for interface description */
126 static dbmnz_find(void *handle, uschar *filename, const uschar *keystring, int length,
127 uschar **result, uschar **errmsg, uint *do_cache)
129 return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
135 /*************************************************
136 * Find entry point - zero-joined list key *
137 *************************************************/
140 * The parameter passed as a key is a list in normal Exim list syntax.
141 * The elements of that list are joined together on NUL, with no trailing
142 * NUL, to form the key.
146 dbmjz_find(void *handle, uschar *filename, const uschar *keystring, int length,
147 uschar **result, uschar **errmsg, uint *do_cache)
149 uschar *key_item, *key_buffer, *key_p;
150 const uschar *key_elems = keystring;
151 int buflen, bufleft, key_item_len, sep = 0;
153 /* To a first approximation, the size of the lookup key needs to be about,
154 or less than, the length of the delimited list passed in + 1. */
157 key_buffer = store_get(buflen);
159 key_buffer[0] = '\0';
164 /* In all cases of an empty list item, we can set 1 and advance by 1 and then
165 pick up the trailing NUL from the previous list item, EXCEPT when at the
166 beginning of the output string, in which case we need to supply that NUL
168 while ((key_item = string_nextinlist(&key_elems, &sep, key_p, bufleft)) != NULL)
170 key_item_len = Ustrlen(key_item) + 1;
171 if (key_item_len == 1)
174 if (key_p == key_buffer)
181 bufleft -= key_item_len;
184 /* The string_nextinlist() will stop at buffer size, but we should always
185 have at least 1 character extra, so some assumption has failed. */
186 *errmsg = string_copy(US"Ran out of buffer space for joining elements");
189 key_p += key_item_len;
192 if (key_p == key_buffer)
194 *errmsg = string_copy(US"empty list key");
198 /* We do not pass in the final NULL; if needed, the list should include an
199 empty element to put one in. Boundary: key length 1, is a NULL */
200 key_item_len = key_p - key_buffer - 1;
202 DEBUG(D_lookup) debug_printf("NUL-joined key length: %d\n", key_item_len);
204 /* beware that dbmdb_find() adds 1 to length to get back terminating NUL, so
205 because we've calculated the real length, we need to subtract one more here */
206 return dbmdb_find(handle, filename,
207 key_buffer, key_item_len - 1,
208 result, errmsg, do_cache);
213 /*************************************************
214 * Close entry point *
215 *************************************************/
217 /* See local README for interface description */
220 static dbmdb_close(void *handle)
222 EXIM_DBCLOSE((EXIM_DB *)handle);
227 /*************************************************
228 * Version reporting entry point *
229 *************************************************/
231 /* See local README for interface description. */
233 #include "../version.h"
236 dbm_version_report(FILE *f)
239 fprintf(f, "Library version: DBM: Exim version %s\n", EXIM_VERSION_STR);
244 lookup_info dbm_lookup_info = {
245 US"dbm", /* lookup name */
246 lookup_absfile, /* uses absolute file name */
247 dbmdb_open, /* open function */
248 dbmdb_check, /* check function */
249 dbmdb_find, /* find function */
250 dbmdb_close, /* close function */
251 NULL, /* no tidy function */
252 NULL, /* no quoting function */
253 dbm_version_report /* version reporting */
256 lookup_info dbmz_lookup_info = {
257 US"dbmnz", /* lookup name */
258 lookup_absfile, /* uses absolute file name */
259 dbmdb_open, /* sic */ /* open function */
260 dbmdb_check, /* sic */ /* check function */
261 dbmnz_find, /* find function */
262 dbmdb_close, /* sic */ /* close function */
263 NULL, /* no tidy function */
264 NULL, /* no quoting function */
265 NULL /* no version reporting (redundant) */
268 lookup_info dbmjz_lookup_info = {
269 US"dbmjz", /* lookup name */
270 lookup_absfile, /* uses absolute file name */
271 dbmdb_open, /* sic */ /* open function */
272 dbmdb_check, /* sic */ /* check function */
273 dbmjz_find, /* find function */
274 dbmdb_close, /* sic */ /* close function */
275 NULL, /* no tidy function */
276 NULL, /* no quoting function */
277 NULL /* no version reporting (redundant) */
281 #define dbmdb_lookup_module_info _lookup_module_info
284 static lookup_info *_lookup_list[] = { &dbm_lookup_info, &dbmz_lookup_info, &dbmjz_lookup_info };
285 lookup_module_info dbmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 };
287 /* End of lookups/dbmdb.c */