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