1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "time-util.h"
6 #include "istream.h"
7
8 #include "sieve-ldap-storage.h"
9
10 #if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
11
12 #include "str.h"
13 #include "strfuncs.h"
14
15 #include "sieve-error.h"
16 #include "sieve-dump.h"
17 #include "sieve-binary.h"
18
19 /*
20 * Script file implementation
21 */
22
sieve_ldap_script_alloc(void)23 static struct sieve_ldap_script *sieve_ldap_script_alloc(void)
24 {
25 struct sieve_ldap_script *lscript;
26 pool_t pool;
27
28 pool = pool_alloconly_create("sieve_ldap_script", 1024);
29 lscript = p_new(pool, struct sieve_ldap_script, 1);
30 lscript->script = sieve_ldap_script;
31 lscript->script.pool = pool;
32
33 return lscript;
34 }
35
sieve_ldap_script_init(struct sieve_ldap_storage * lstorage,const char * name)36 struct sieve_ldap_script *sieve_ldap_script_init
37 (struct sieve_ldap_storage *lstorage, const char *name)
38 {
39 struct sieve_storage *storage = &lstorage->storage;
40 struct sieve_ldap_script *lscript = NULL;
41 const char *location;
42
43 if ( name == NULL ) {
44 name = SIEVE_LDAP_SCRIPT_DEFAULT;
45 location = storage->location;
46 } else {
47 location = t_strconcat
48 (storage->location, ";name=", name, NULL);
49 }
50
51 lscript = sieve_ldap_script_alloc();
52 sieve_script_init(&lscript->script,
53 storage, &sieve_ldap_script, location, name);
54 return lscript;
55 }
56
sieve_ldap_script_open(struct sieve_script * script,enum sieve_error * error_r)57 static int sieve_ldap_script_open
58 (struct sieve_script *script, enum sieve_error *error_r)
59 {
60 struct sieve_ldap_script *lscript =
61 (struct sieve_ldap_script *)script;
62 struct sieve_storage *storage = script->storage;
63 struct sieve_ldap_storage *lstorage =
64 (struct sieve_ldap_storage *)storage;
65 int ret;
66
67 if ( sieve_ldap_db_connect(lstorage->conn) < 0 ) {
68 sieve_storage_set_critical(storage,
69 "Failed to connect to LDAP database");
70 *error_r = storage->error_code;
71 return -1;
72 }
73
74 if ( (ret=sieve_ldap_db_lookup_script(lstorage->conn,
75 script->name, &lscript->dn, &lscript->modattr)) <= 0 ) {
76 if ( ret == 0 ) {
77 e_debug(script->event, "Script entry not found");
78 sieve_script_set_error(script,
79 SIEVE_ERROR_NOT_FOUND,
80 "Sieve script not found");
81 } else {
82 sieve_script_set_internal_error(script);
83 }
84 *error_r = script->storage->error_code;
85 return -1;
86 }
87
88 return 0;
89 }
90
sieve_ldap_script_get_stream(struct sieve_script * script,struct istream ** stream_r,enum sieve_error * error_r)91 static int sieve_ldap_script_get_stream
92 (struct sieve_script *script, struct istream **stream_r,
93 enum sieve_error *error_r)
94 {
95 struct sieve_ldap_script *lscript =
96 (struct sieve_ldap_script *)script;
97 struct sieve_storage *storage = script->storage;
98 struct sieve_ldap_storage *lstorage =
99 (struct sieve_ldap_storage *)storage;
100 int ret;
101
102 i_assert(lscript->dn != NULL);
103
104 if ( (ret=sieve_ldap_db_read_script(
105 lstorage->conn, lscript->dn, stream_r)) <= 0 ) {
106 if ( ret == 0 ) {
107 e_debug(script->event, "Script attribute not found");
108 sieve_script_set_error(script,
109 SIEVE_ERROR_NOT_FOUND,
110 "Sieve script not found");
111 } else {
112 sieve_script_set_internal_error(script);
113 }
114 *error_r = script->storage->error_code;
115 return -1;
116 }
117 return 0;
118 }
119
sieve_ldap_script_binary_read_metadata(struct sieve_script * script,struct sieve_binary_block * sblock,sieve_size_t * offset)120 static int sieve_ldap_script_binary_read_metadata
121 (struct sieve_script *script, struct sieve_binary_block *sblock,
122 sieve_size_t *offset)
123 {
124 struct sieve_ldap_script *lscript =
125 (struct sieve_ldap_script *)script;
126 struct sieve_instance *svinst = script->storage->svinst;
127 struct sieve_ldap_storage *lstorage =
128 (struct sieve_ldap_storage *)script->storage;
129 struct sieve_binary *sbin =
130 sieve_binary_block_get_binary(sblock);
131 time_t bmtime = sieve_binary_mtime(sbin);
132 string_t *dn, *modattr;
133
134 /* config file changed? */
135 if ( bmtime <= lstorage->set_mtime ) {
136 if ( svinst->debug ) {
137 e_debug(script->event,
138 "Sieve binary `%s' is not newer "
139 "than the LDAP configuration `%s' (%s <= %s)",
140 sieve_binary_path(sbin), lstorage->config_file,
141 t_strflocaltime("%Y-%m-%d %H:%M:%S", bmtime),
142 t_strflocaltime("%Y-%m-%d %H:%M:%S", lstorage->set_mtime));
143 }
144 return 0;
145 }
146
147 /* open script if not open already */
148 if ( lscript->dn == NULL &&
149 sieve_script_open(script, NULL) < 0 )
150 return 0;
151
152 /* if modattr not found, recompile always */
153 if ( lscript->modattr == NULL || *lscript->modattr == '\0' ) {
154 e_error(script->event,
155 "LDAP entry for script `%s' "
156 "has no modified attribute `%s'",
157 sieve_script_location(script),
158 lstorage->set.sieve_ldap_mod_attr);
159 return 0;
160 }
161
162 /* compare DN in binary and from search result */
163 if ( !sieve_binary_read_string(sblock, offset, &dn) ) {
164 e_error(script->event,
165 "Binary `%s' has invalid metadata for script `%s': "
166 "Invalid DN",
167 sieve_binary_path(sbin), sieve_script_location(script));
168 return -1;
169 }
170 i_assert( lscript->dn != NULL );
171 if ( strcmp(str_c(dn), lscript->dn) != 0 ) {
172 e_debug(script->event,
173 "Binary `%s' reports different LDAP DN for script `%s' "
174 "(`%s' rather than `%s')",
175 sieve_binary_path(sbin), sieve_script_location(script),
176 str_c(dn), lscript->dn);
177 return 0;
178 }
179
180 /* compare modattr in binary and from search result */
181 if ( !sieve_binary_read_string(sblock, offset, &modattr) ) {
182 e_error(script->event,
183 "Binary `%s' has invalid metadata for script `%s': "
184 "Invalid modified attribute",
185 sieve_binary_path(sbin), sieve_script_location(script));
186 return -1;
187 }
188 if ( strcmp(str_c(modattr), lscript->modattr) != 0 ) {
189 e_debug(script->event,
190 "Binary `%s' reports different modified attribute content "
191 "for script `%s' (`%s' rather than `%s')",
192 sieve_binary_path(sbin), sieve_script_location(script),
193 str_c(modattr), lscript->modattr);
194 return 0;
195 }
196 return 1;
197 }
198
sieve_ldap_script_binary_write_metadata(struct sieve_script * script,struct sieve_binary_block * sblock)199 static void sieve_ldap_script_binary_write_metadata
200 (struct sieve_script *script, struct sieve_binary_block *sblock)
201 {
202 struct sieve_ldap_script *lscript =
203 (struct sieve_ldap_script *)script;
204
205 sieve_binary_emit_cstring(sblock, lscript->dn);
206 if (lscript->modattr == NULL)
207 sieve_binary_emit_cstring(sblock, "");
208 else
209 sieve_binary_emit_cstring(sblock, lscript->modattr);
210 }
211
sieve_ldap_script_binary_dump_metadata(struct sieve_script * script ATTR_UNUSED,struct sieve_dumptime_env * denv,struct sieve_binary_block * sblock,sieve_size_t * offset)212 static bool sieve_ldap_script_binary_dump_metadata
213 (struct sieve_script *script ATTR_UNUSED, struct sieve_dumptime_env *denv,
214 struct sieve_binary_block *sblock, sieve_size_t *offset)
215 {
216 string_t *dn, *modattr;
217
218 if ( !sieve_binary_read_string(sblock, offset, &dn) )
219 return FALSE;
220 sieve_binary_dumpf(denv, "ldap.dn = %s\n", str_c(dn));
221
222 if ( !sieve_binary_read_string(sblock, offset, &modattr) )
223 return FALSE;
224 sieve_binary_dumpf(denv, "ldap.mod_attr = %s\n", str_c(modattr));
225
226 return TRUE;
227 }
228
sieve_ldap_script_get_binpath(struct sieve_ldap_script * lscript)229 static const char *sieve_ldap_script_get_binpath
230 (struct sieve_ldap_script *lscript)
231 {
232 struct sieve_script *script = &lscript->script;
233 struct sieve_storage *storage = script->storage;
234
235 if ( lscript->binpath == NULL ) {
236 if ( storage->bin_dir == NULL )
237 return NULL;
238 lscript->binpath = p_strconcat(script->pool,
239 storage->bin_dir, "/",
240 sieve_binfile_from_name(script->name), NULL);
241 }
242
243 return lscript->binpath;
244 }
245
sieve_ldap_script_binary_load(struct sieve_script * script,enum sieve_error * error_r)246 static struct sieve_binary *sieve_ldap_script_binary_load
247 (struct sieve_script *script, enum sieve_error *error_r)
248 {
249 struct sieve_storage *storage = script->storage;
250 struct sieve_ldap_script *lscript =
251 (struct sieve_ldap_script *)script;
252
253 if ( sieve_ldap_script_get_binpath(lscript) == NULL )
254 return NULL;
255
256 return sieve_binary_open(storage->svinst,
257 lscript->binpath, script, error_r);
258 }
259
sieve_ldap_script_binary_save(struct sieve_script * script,struct sieve_binary * sbin,bool update,enum sieve_error * error_r)260 static int sieve_ldap_script_binary_save
261 (struct sieve_script *script, struct sieve_binary *sbin, bool update,
262 enum sieve_error *error_r)
263 {
264 struct sieve_ldap_script *lscript =
265 (struct sieve_ldap_script *)script;
266
267 if ( sieve_ldap_script_get_binpath(lscript) == NULL )
268 return 0;
269
270 if ( sieve_storage_setup_bindir(script->storage, 0700) < 0 )
271 return -1;
272
273 return sieve_binary_save
274 (sbin, lscript->binpath, update, 0600, error_r);
275 }
276
sieve_ldap_script_equals(const struct sieve_script * script,const struct sieve_script * other)277 static bool sieve_ldap_script_equals
278 (const struct sieve_script *script, const struct sieve_script *other)
279 {
280 struct sieve_storage *storage = script->storage;
281 struct sieve_storage *sother = other->storage;
282
283 if ( strcmp(storage->location, sother->location) != 0 )
284 return FALSE;
285
286 i_assert( script->name != NULL && other->name != NULL );
287
288 return ( strcmp(script->name, other->name) == 0 );
289 }
290
291 const struct sieve_script sieve_ldap_script = {
292 .driver_name = SIEVE_LDAP_STORAGE_DRIVER_NAME,
293 .v = {
294 .open = sieve_ldap_script_open,
295
296 .get_stream = sieve_ldap_script_get_stream,
297
298 .binary_read_metadata = sieve_ldap_script_binary_read_metadata,
299 .binary_write_metadata = sieve_ldap_script_binary_write_metadata,
300 .binary_dump_metadata = sieve_ldap_script_binary_dump_metadata,
301 .binary_load = sieve_ldap_script_binary_load,
302 .binary_save = sieve_ldap_script_binary_save,
303
304 .equals = sieve_ldap_script_equals
305 }
306 };
307
308 /*
309 * Script sequence
310 */
311
312 struct sieve_ldap_script_sequence {
313 struct sieve_script_sequence seq;
314
315 bool done:1;
316 };
317
sieve_ldap_storage_get_script_sequence(struct sieve_storage * storage,enum sieve_error * error_r)318 struct sieve_script_sequence *sieve_ldap_storage_get_script_sequence
319 (struct sieve_storage *storage, enum sieve_error *error_r)
320 {
321 struct sieve_ldap_script_sequence *lsec = NULL;
322
323 if ( error_r != NULL )
324 *error_r = SIEVE_ERROR_NONE;
325
326 /* Create sequence object */
327 lsec = i_new(struct sieve_ldap_script_sequence, 1);
328 sieve_script_sequence_init(&lsec->seq, storage);
329
330 return &lsec->seq;
331 }
332
sieve_ldap_script_sequence_next(struct sieve_script_sequence * seq,enum sieve_error * error_r)333 struct sieve_script *sieve_ldap_script_sequence_next
334 (struct sieve_script_sequence *seq, enum sieve_error *error_r)
335 {
336 struct sieve_ldap_script_sequence *lsec =
337 (struct sieve_ldap_script_sequence *)seq;
338 struct sieve_ldap_storage *lstorage =
339 (struct sieve_ldap_storage *)seq->storage;
340 struct sieve_ldap_script *lscript;
341
342 if ( error_r != NULL )
343 *error_r = SIEVE_ERROR_NONE;
344
345 if ( lsec->done )
346 return NULL;
347 lsec->done = TRUE;
348
349 lscript = sieve_ldap_script_init
350 (lstorage, seq->storage->script_name);
351 if ( sieve_script_open(&lscript->script, error_r) < 0 ) {
352 struct sieve_script *script = &lscript->script;
353 sieve_script_unref(&script);
354 return NULL;
355 }
356
357 return &lscript->script;
358 }
359
sieve_ldap_script_sequence_destroy(struct sieve_script_sequence * seq)360 void sieve_ldap_script_sequence_destroy
361 (struct sieve_script_sequence *seq)
362 {
363 struct sieve_ldap_script_sequence *lsec =
364 (struct sieve_ldap_script_sequence *)seq;
365 i_free(lsec);
366 }
367
368
369 #endif
370