Dsearch: require absolute dirname
[exim.git] / src / src / lookups / dbmdb.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
0756eb3c
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8#include "../exim.h"
9#include "lf_functions.h"
0756eb3c
PH
10
11
12/*************************************************
13* Open entry point *
14*************************************************/
15
16/* See local README for interface description */
17
e6d225ae 18static void *
d447dbd1 19dbmdb_open(const uschar * filename, uschar ** errmsg)
0756eb3c 20{
cfb9cf20
JH
21uschar * dirname = string_copy(filename);
22uschar * s;
4a6a987a 23EXIM_DB *yield = NULL;
cfb9cf20
JH
24
25if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
26EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
d447dbd1 27if (!yield)
0756eb3c
PH
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
e6d225ae 49static BOOL
d447dbd1 50dbmdb_check(void *handle, const uschar *filename, int modemask, uid_t *owners,
0756eb3c
PH
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];
f1e894f3 62 (void)sprintf(CS filebuffer, "%.250s.db", filename);
0756eb3c
PH
63 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
64 "dbm", errmsg);
65 if (rc < 0) /* stat() failed */
66 {
f1e894f3 67 (void)sprintf(CS filebuffer, "%.250s.dir", filename);
0756eb3c
PH
68 rc = lf_check_file(-1, filebuffer, S_IFREG, modemask, owners, owngroups,
69 "dbm", errmsg);
70 if (rc == 0) /* x.dir was OK */
71 {
f1e894f3 72 (void)sprintf(CS filebuffer, "%.250s.pag", filename);
0756eb3c
PH
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
e6d225ae 92static int
d447dbd1
JH
93dbmdb_find(void * handle, const uschar * filename, const uschar * keystring,
94 int length, uschar ** result, uschar ** errmsg, uint * do_cache)
0756eb3c
PH
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
d447dbd1
JH
125static int
126dbmnz_find(void * handle, const uschar * filename, const uschar * keystring,
127 int length, uschar ** result, uschar ** errmsg, uint * do_cache)
0756eb3c
PH
128{
129return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
130 do_cache);
131}
132
133
134
4a6a987a
PP
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
d447dbd1
JH
146dbmjz_find(void * handle, const uschar * filename, const uschar * keystring,
147 int length, uschar ** result, uschar ** errmsg, uint * do_cache)
4a6a987a
PP
148{
149uschar *key_item, *key_buffer, *key_p;
55414b25 150const uschar *key_elems = keystring;
4a6a987a
PP
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;
f3ebb786 157key_buffer = store_get(buflen, is_tainted(keystring));
4a6a987a
PP
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
42c7f0b4 202DEBUG(D_lookup) debug_printf_indent("NUL-joined key length: %d\n", key_item_len);
4a6a987a
PP
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 */
d447dbd1
JH
206
207return dbmdb_find(handle, filename, key_buffer, key_item_len - 1,
4a6a987a
PP
208 result, errmsg, do_cache);
209}
210
211
212
0756eb3c
PH
213/*************************************************
214* Close entry point *
215*************************************************/
216
217/* See local README for interface description */
218
219void
e6d225ae 220static dbmdb_close(void *handle)
0756eb3c
PH
221{
222EXIM_DBCLOSE((EXIM_DB *)handle);
223}
224
6545de78
PP
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
e6d225ae
DW
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 */
6545de78
PP
252 NULL, /* no quoting function */
253 dbm_version_report /* version reporting */
e6d225ae
DW
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 */
6545de78
PP
264 NULL, /* no quoting function */
265 NULL /* no version reporting (redundant) */
e6d225ae
DW
266};
267
4a6a987a
PP
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
e6d225ae
DW
280#ifdef DYNLOOKUP
281#define dbmdb_lookup_module_info _lookup_module_info
282#endif
283
4a6a987a
PP
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 };
e6d225ae 286
0756eb3c 287/* End of lookups/dbmdb.c */