Import Upstream version 4.92
[hcoop/debian/exim4.git] / src / lookups / dbmdb.c
CommitLineData
420a0d19
CE
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
2ea97746 5/* Copyright (c) University of Cambridge 1995 - 2018 */
420a0d19
CE
6/* See the file NOTICE for conditions of use and distribution. */
7
8#include "../exim.h"
9#include "lf_functions.h"
10
11
12/*************************************************
13* Open entry point *
14*************************************************/
15
16/* See local README for interface description */
17
18static void *
19dbmdb_open(uschar *filename, uschar **errmsg)
20{
2ea97746
CE
21uschar * dirname = string_copy(filename);
22uschar * s;
420a0d19 23EXIM_DB *yield = NULL;
2ea97746
CE
24
25if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
26EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
420a0d19
CE
27if (yield == NULL)
28 {
29 int save_errno = errno;
30 *errmsg = string_open_failed(errno, "%s as a %s file", filename, EXIM_DBTYPE);
31 errno = save_errno;
32 }
33return yield;
34}
35
36
37
38/*************************************************
39* Check entry point *
40*************************************************/
41
42/* This needs to know more about the underlying files than is good for it!
43We need to know what the real file names are in order to check the owners and
44modes. If USE_DB is set, we know it is Berkeley DB, which uses an unmodified
45file name. If USE_TDB or USE_GDBM is set, we know it is tdb or gdbm, which do
46the same. Otherwise, for safety, we have to check for x.db or x.dir and x.pag.
47*/
48
49static BOOL
50dbmdb_check(void *handle, uschar *filename, int modemask, uid_t *owners,
51 gid_t *owngroups, uschar **errmsg)
52{
53int rc;
54handle = handle; /* Keep picky compilers happy */
55
56#if defined(USE_DB) || defined(USE_TDB) || defined(USE_GDBM)
57rc = lf_check_file(-1, filename, S_IFREG, modemask, owners, owngroups,
58 "dbm", errmsg);
59#else
60 {
61 uschar filebuffer[256];
62 (void)sprintf(CS filebuffer, "%.250s.db", filename);
63 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
64 "dbm", errmsg);
65 if (rc < 0) /* stat() failed */
66 {
67 (void)sprintf(CS filebuffer, "%.250s.dir", filename);
68 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
69 "dbm", errmsg);
70 if (rc == 0) /* x.dir was OK */
71 {
72 (void)sprintf(CS filebuffer, "%.250s.pag", filename);
73 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
74 "dbm", errmsg);
75 }
76 }
77 }
78#endif
79
80return rc == 0;
81}
82
83
84
85/*************************************************
86* Find entry point *
87*************************************************/
88
89/* See local README for interface description. This function adds 1 to
90the keylength in order to include the terminating zero. */
91
92static int
2ea97746
CE
93dbmdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
94 uschar **result, uschar **errmsg, uint *do_cache)
420a0d19
CE
95{
96EXIM_DB *d = (EXIM_DB *)handle;
97EXIM_DATUM key, data;
98
99filename = filename; /* Keep picky compilers happy */
100errmsg = errmsg;
101do_cache = do_cache;
102
103EXIM_DATUM_INIT(key); /* Some DBM libraries require datums to */
104EXIM_DATUM_INIT(data); /* be cleared before use. */
105EXIM_DATUM_DATA(key) = CS keystring;
106EXIM_DATUM_SIZE(key) = length + 1;
107
108if (EXIM_DBGET(d, key, data))
109 {
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 */
112 return OK;
113 }
114return FAIL;
115}
116
117
118
119/*************************************************
120* Find entry point - no zero on key *
121*************************************************/
122
123/* See local README for interface description */
124
125int
2ea97746
CE
126static dbmnz_find(void *handle, uschar *filename, const uschar *keystring, int length,
127 uschar **result, uschar **errmsg, uint *do_cache)
420a0d19
CE
128{
129return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
130 do_cache);
131}
132
133
134
135/*************************************************
136* Find entry point - zero-joined list key *
137*************************************************/
138
139/*
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.
143 */
144
145static int
2ea97746
CE
146dbmjz_find(void *handle, uschar *filename, const uschar *keystring, int length,
147 uschar **result, uschar **errmsg, uint *do_cache)
420a0d19
CE
148{
149uschar *key_item, *key_buffer, *key_p;
2ea97746 150const uschar *key_elems = keystring;
420a0d19
CE
151int buflen, bufleft, key_item_len, sep = 0;
152
153/* To a first approximation, the size of the lookup key needs to be about,
154or less than, the length of the delimited list passed in + 1. */
155
156buflen = length + 3;
157key_buffer = store_get(buflen);
158
159key_buffer[0] = '\0';
160
161key_p = key_buffer;
162bufleft = buflen;
163
164/* In all cases of an empty list item, we can set 1 and advance by 1 and then
165pick up the trailing NUL from the previous list item, EXCEPT when at the
166beginning of the output string, in which case we need to supply that NUL
167ourselves. */
168while ((key_item = string_nextinlist(&key_elems, &sep, key_p, bufleft)) != NULL)
169 {
170 key_item_len = Ustrlen(key_item) + 1;
171 if (key_item_len == 1)
172 {
173 key_p[0] = '\0';
174 if (key_p == key_buffer)
175 {
176 key_p[1] = '\0';
177 key_item_len += 1;
178 }
179 }
180
181 bufleft -= key_item_len;
182 if (bufleft <= 0)
183 {
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");
187 return DEFER;
188 }
189 key_p += key_item_len;
190 }
191
192if (key_p == key_buffer)
193 {
194 *errmsg = string_copy(US"empty list key");
195 return FAIL;
196 }
197
198/* We do not pass in the final NULL; if needed, the list should include an
199empty element to put one in. Boundary: key length 1, is a NULL */
200key_item_len = key_p - key_buffer - 1;
201
202DEBUG(D_lookup) debug_printf("NUL-joined key length: %d\n", key_item_len);
203
204/* beware that dbmdb_find() adds 1 to length to get back terminating NUL, so
205because we've calculated the real length, we need to subtract one more here */
206return dbmdb_find(handle, filename,
207 key_buffer, key_item_len - 1,
208 result, errmsg, do_cache);
209}
210
211
212
213/*************************************************
214* Close entry point *
215*************************************************/
216
217/* See local README for interface description */
218
219void
220static dbmdb_close(void *handle)
221{
222EXIM_DBCLOSE((EXIM_DB *)handle);
223}
224
225
226
227/*************************************************
228* Version reporting entry point *
229*************************************************/
230
231/* See local README for interface description. */
232
233#include "../version.h"
234
235void
236dbm_version_report(FILE *f)
237{
238#ifdef DYNLOOKUP
239fprintf(f, "Library version: DBM: Exim version %s\n", EXIM_VERSION_STR);
240#endif
241}
242
243
244lookup_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 */
254};
255
256lookup_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) */
266};
267
268lookup_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) */
278};
279
280#ifdef DYNLOOKUP
281#define dbmdb_lookup_module_info _lookup_module_info
282#endif
283
284static lookup_info *_lookup_list[] = { &dbm_lookup_info, &dbmz_lookup_info, &dbmjz_lookup_info };
285lookup_module_info dbmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 };
286
287/* End of lookups/dbmdb.c */