1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 #include "hash.h"
6 #include "str.h"
7 #include "array.h"
8 
9 #include "sieve-common.h"
10 #include "sieve-settings.h"
11 
12 #include "sieve-ast.h"
13 #include "sieve-binary.h"
14 #include "sieve-code.h"
15 #include "sieve-objects.h"
16 #include "sieve-match-types.h"
17 
18 #include "sieve-commands.h"
19 #include "sieve-validator.h"
20 #include "sieve-generator.h"
21 #include "sieve-dump.h"
22 #include "sieve-interpreter.h"
23 
24 #include "ext-variables-common.h"
25 #include "ext-variables-limits.h"
26 #include "ext-variables-name.h"
27 #include "ext-variables-modifiers.h"
28 
29 /*
30  * Limits
31  */
32 
33 unsigned int
sieve_variables_get_max_scope_size(const struct sieve_extension * var_ext)34 sieve_variables_get_max_scope_size(const struct sieve_extension *var_ext)
35 {
36 	const struct ext_variables_config *config =
37 		ext_variables_get_config(var_ext);
38 
39 	return config->max_scope_size;
40 }
41 
42 size_t
sieve_variables_get_max_variable_size(const struct sieve_extension * var_ext)43 sieve_variables_get_max_variable_size(const struct sieve_extension *var_ext)
44 {
45 	const struct ext_variables_config *config =
46 		ext_variables_get_config(var_ext);
47 
48 	return config->max_variable_size;
49 }
50 
51 /*
52  * Extension configuration
53  */
54 
55 bool
ext_variables_load(const struct sieve_extension * ext,void ** context)56 ext_variables_load(const struct sieve_extension *ext, void **context)
57 {
58 	struct sieve_instance *svinst = ext->svinst;
59 	struct ext_variables_config *config;
60 	unsigned long long int uint_setting;
61 	size_t size_setting;
62 
63 	if (*context != NULL)
64 		ext_variables_unload(ext);
65 
66 	config = i_new(struct ext_variables_config, 1);
67 
68 	/* Get limits */
69 	config->max_scope_size = EXT_VARIABLES_DEFAULT_MAX_SCOPE_SIZE;
70 	config->max_variable_size = EXT_VARIABLES_DEFAULT_MAX_VARIABLE_SIZE;
71 
72 	if (sieve_setting_get_uint_value(
73 		svinst, "sieve_variables_max_scope_size", &uint_setting)) {
74 		if (uint_setting < EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE) {
75 			e_warning(svinst->event, "variables: "
76 				  "setting sieve_variables_max_scope_size "
77 				  "is lower than required by standards "
78 				  "(>= %llu items)",
79 				  (unsigned long long)EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE);
80 		} else {
81 			config->max_scope_size = (unsigned int)uint_setting;
82 		}
83 	}
84 
85 	if (sieve_setting_get_size_value(
86 		svinst, "sieve_variables_max_variable_size", &size_setting)) {
87 		if (size_setting < EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE) {
88 			e_warning(svinst->event, "variables: "
89 				  "setting sieve_variables_max_variable_size "
90 				  "is lower than required by standards "
91 				  "(>= %zu bytes)",
92 				  (size_t)EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE);
93 		} else {
94 			config->max_variable_size = size_setting;
95 		}
96 	}
97 
98 	*context = (void *)config;
99 	return TRUE;
100 }
101 
ext_variables_unload(const struct sieve_extension * ext)102 void ext_variables_unload(const struct sieve_extension *ext)
103 {
104 	struct ext_variables_config *config =
105 		(struct ext_variables_config *)ext->context;
106 
107 	i_free(config);
108 }
109 
110 const struct ext_variables_config *
ext_variables_get_config(const struct sieve_extension * var_ext)111 ext_variables_get_config(const struct sieve_extension *var_ext)
112 {
113 	const struct ext_variables_config *config =
114 		(const struct ext_variables_config *)var_ext->context;
115 
116 	i_assert(var_ext->def == &variables_extension);
117 	return config;
118 }
119 
120 /*
121  * Variable scope
122  */
123 
124 struct sieve_variable_scope {
125 	pool_t pool;
126 	int refcount;
127 
128 	struct sieve_instance *svinst;
129 	const struct sieve_extension *var_ext;
130 	const struct sieve_extension *ext;
131 
132 	struct sieve_variable *error_var;
133 
134 	HASH_TABLE(const char *, struct sieve_variable *) variables;
135 	ARRAY(struct sieve_variable *) variable_index;
136 };
137 
138 struct sieve_variable_scope_binary {
139 	struct sieve_variable_scope *scope;
140 
141 	unsigned int size;
142 	struct sieve_binary_block *sblock;
143 	sieve_size_t address;
144 };
145 
146 struct sieve_variable_scope_iter {
147 	struct sieve_variable_scope *scope;
148 	struct hash_iterate_context *hctx;
149 };
150 
151 struct sieve_variable_scope *
sieve_variable_scope_create(struct sieve_instance * svinst,const struct sieve_extension * var_ext,const struct sieve_extension * ext)152 sieve_variable_scope_create(struct sieve_instance *svinst,
153 			    const struct sieve_extension *var_ext,
154 			    const struct sieve_extension *ext)
155 {
156 	struct sieve_variable_scope *scope;
157 	pool_t pool;
158 
159 	i_assert(var_ext->def == &variables_extension);
160 
161 	pool = pool_alloconly_create("sieve_variable_scope", 4096);
162 	scope = p_new(pool, struct sieve_variable_scope, 1);
163 	scope->pool = pool;
164 	scope->refcount = 1;
165 
166 	scope->svinst = svinst;
167 	scope->var_ext = var_ext;
168 	scope->ext = ext;
169 
170 	hash_table_create(&scope->variables, pool, 0, strcase_hash, strcasecmp);
171 	p_array_init(&scope->variable_index, pool, 128);
172 
173 	return scope;
174 }
175 
sieve_variable_scope_ref(struct sieve_variable_scope * scope)176 void sieve_variable_scope_ref(struct sieve_variable_scope *scope)
177 {
178 	scope->refcount++;
179 }
180 
sieve_variable_scope_unref(struct sieve_variable_scope ** _scope)181 void sieve_variable_scope_unref(struct sieve_variable_scope **_scope)
182 {
183 	struct sieve_variable_scope *scope = *_scope;
184 
185 	i_assert(scope->refcount > 0);
186 
187 	if (--scope->refcount != 0)
188 		return;
189 
190 	hash_table_destroy(&scope->variables);
191 
192 	*_scope = NULL;
193 	pool_unref(&scope->pool);
194 }
195 
sieve_variable_scope_pool(struct sieve_variable_scope * scope)196 pool_t sieve_variable_scope_pool(struct sieve_variable_scope *scope)
197 {
198 	return scope->pool;
199 }
200 
201 struct sieve_variable *
sieve_variable_scope_declare(struct sieve_variable_scope * scope,const char * identifier)202 sieve_variable_scope_declare(struct sieve_variable_scope *scope,
203 			     const char *identifier)
204 {
205 	unsigned int max_scope_size;
206 	struct sieve_variable *var;
207 
208 	var = hash_table_lookup(scope->variables, identifier);
209 	if (var != NULL)
210 		return var;
211 
212 	max_scope_size = sieve_variables_get_max_scope_size(scope->var_ext);
213 	if (array_count(&scope->variable_index) >= max_scope_size) {
214 		if (scope->error_var == NULL) {
215 			var = p_new(scope->pool, struct sieve_variable, 1);
216 			var->identifier = "@ERROR@";
217 			var->index = 0;
218 
219 			scope->error_var = var;
220 			return NULL;
221 		}
222 
223 		return scope->error_var;
224 	}
225 
226 	var = p_new(scope->pool, struct sieve_variable, 1);
227 	var->ext = scope->ext;
228 	var->identifier = p_strdup(scope->pool, identifier);
229 	var->index = array_count(&scope->variable_index);
230 
231 	hash_table_insert(scope->variables, var->identifier, var);
232 	array_append(&scope->variable_index, &var, 1);
233 	return var;
234 }
235 
236 struct sieve_variable *
sieve_variable_scope_get_variable(struct sieve_variable_scope * scope,const char * identifier)237 sieve_variable_scope_get_variable(struct sieve_variable_scope *scope,
238 				  const char *identifier)
239 {
240 	return hash_table_lookup(scope->variables, identifier);
241 }
242 
243 struct sieve_variable *
sieve_variable_scope_import(struct sieve_variable_scope * scope,struct sieve_variable * var)244 sieve_variable_scope_import(struct sieve_variable_scope *scope,
245 			    struct sieve_variable *var)
246 {
247 	struct sieve_variable *old_var, *new_var;
248 
249 	old_var = sieve_variable_scope_get_variable(scope, var->identifier);
250 	if (old_var != NULL) {
251 		i_assert(memcmp(old_var, var, sizeof(*var)) == 0);
252 		return old_var;
253 	}
254 
255 	new_var = p_new(scope->pool, struct sieve_variable, 1);
256 	memcpy(new_var, var, sizeof(*new_var));
257 
258 	hash_table_insert(scope->variables, new_var->identifier, new_var);
259 
260 	/* Not entered into the index because it is an external variable
261 	   (This can be done unlimited; only limited by the size of the external
262 	   scope)
263 	 */
264 	return new_var;
265 }
266 
267 struct sieve_variable_scope_iter *
sieve_variable_scope_iterate_init(struct sieve_variable_scope * scope)268 sieve_variable_scope_iterate_init(struct sieve_variable_scope *scope)
269 {
270 	struct sieve_variable_scope_iter *iter;
271 
272 	iter = t_new(struct sieve_variable_scope_iter, 1);
273 	iter->scope = scope;
274 	iter->hctx = hash_table_iterate_init(scope->variables);
275 
276 	return iter;
277 }
278 
sieve_variable_scope_iterate(struct sieve_variable_scope_iter * iter,struct sieve_variable ** var_r)279 bool sieve_variable_scope_iterate(struct sieve_variable_scope_iter *iter,
280 				  struct sieve_variable **var_r)
281 {
282 	const char *key;
283 
284 	return hash_table_iterate(iter->hctx, iter->scope->variables,
285 				  &key, var_r);
286 }
287 
sieve_variable_scope_iterate_deinit(struct sieve_variable_scope_iter ** iter)288 void sieve_variable_scope_iterate_deinit(
289 	struct sieve_variable_scope_iter **iter)
290 {
291 	hash_table_iterate_deinit(&(*iter)->hctx);
292 	*iter = NULL;
293 }
294 
295 unsigned int
sieve_variable_scope_declarations(struct sieve_variable_scope * scope)296 sieve_variable_scope_declarations(struct sieve_variable_scope *scope)
297 {
298 	return hash_table_count(scope->variables);
299 }
300 
sieve_variable_scope_size(struct sieve_variable_scope * scope)301 unsigned int sieve_variable_scope_size(struct sieve_variable_scope *scope)
302 {
303 	return array_count(&scope->variable_index);
304 }
305 
306 struct sieve_variable * const *
sieve_variable_scope_get_variables(struct sieve_variable_scope * scope,unsigned int * size_r)307 sieve_variable_scope_get_variables(struct sieve_variable_scope *scope,
308 				   unsigned int *size_r)
309 {
310 	return array_get(&scope->variable_index, size_r);
311 }
312 
313 struct sieve_variable *
sieve_variable_scope_get_indexed(struct sieve_variable_scope * scope,unsigned int index)314 sieve_variable_scope_get_indexed(struct sieve_variable_scope *scope,
315 				 unsigned int index)
316 {
317 	struct sieve_variable * const *var;
318 
319 	if (index >= array_count(&scope->variable_index))
320 		return NULL;
321 
322 	var = array_idx(&scope->variable_index, index);
323 	return *var;
324 }
325 
326 /* Scope binary */
327 
328 struct sieve_variable_scope *
sieve_variable_scope_binary_dump(struct sieve_instance * svinst,const struct sieve_extension * var_ext,const struct sieve_extension * ext,const struct sieve_dumptime_env * denv,sieve_size_t * address)329 sieve_variable_scope_binary_dump(struct sieve_instance *svinst,
330 				 const struct sieve_extension *var_ext,
331 				 const struct sieve_extension *ext,
332 				 const struct sieve_dumptime_env *denv,
333 				 sieve_size_t *address)
334 {
335 	struct sieve_variable_scope *local_scope;
336 	unsigned int i, scope_size;
337 	sieve_size_t pc;
338 	sieve_offset_t end_offset;
339 
340 	/* Read scope size */
341 	sieve_code_mark(denv);
342 	if (!sieve_binary_read_unsigned(denv->sblock, address, &scope_size))
343 		return NULL;
344 
345 	/* Read offset */
346 	pc = *address;
347 	if (!sieve_binary_read_offset(denv->sblock, address, &end_offset))
348 		return NULL;
349 
350 	/* Create scope */
351 	local_scope = sieve_variable_scope_create(svinst, var_ext, ext);
352 
353 	/* Read and dump scope itself */
354 
355 	sieve_code_dumpf(denv, "VARIABLES SCOPE [%u] (end: %08x)",
356 			 scope_size, (unsigned int)(pc + end_offset));
357 
358 	for (i = 0; i < scope_size; i++) {
359 		string_t *identifier;
360 
361 		sieve_code_mark(denv);
362 		if (!sieve_binary_read_string(denv->sblock, address,
363 					      &identifier))
364 			return NULL;
365 
366 		sieve_code_dumpf(denv, "%3d: '%s'", i, str_c(identifier));
367 
368 		(void)sieve_variable_scope_declare(local_scope,
369 						   str_c(identifier));
370 	}
371 
372 	return local_scope;
373 }
374 
375 struct sieve_variable_scope_binary *
sieve_variable_scope_binary_create(struct sieve_variable_scope * scope)376 sieve_variable_scope_binary_create(struct sieve_variable_scope *scope)
377 {
378 	struct sieve_variable_scope_binary *scpbin;
379 
380 	scpbin = p_new(scope->pool, struct sieve_variable_scope_binary, 1);
381 	scpbin->scope = scope;
382 
383 	return scpbin;
384 }
385 
sieve_variable_scope_binary_ref(struct sieve_variable_scope_binary * scpbin)386 void sieve_variable_scope_binary_ref(struct sieve_variable_scope_binary *scpbin)
387 {
388 	sieve_variable_scope_ref(scpbin->scope);
389 }
390 
sieve_variable_scope_binary_unref(struct sieve_variable_scope_binary ** scpbin)391 void sieve_variable_scope_binary_unref(
392 	struct sieve_variable_scope_binary **scpbin)
393 {
394 	sieve_variable_scope_unref(&(*scpbin)->scope);
395 	*scpbin = NULL;
396 }
397 
398 struct sieve_variable_scope_binary *
sieve_variable_scope_binary_read(struct sieve_instance * svinst,const struct sieve_extension * var_ext,const struct sieve_extension * ext,struct sieve_binary_block * sblock,sieve_size_t * address)399 sieve_variable_scope_binary_read(struct sieve_instance *svinst,
400 				 const struct sieve_extension *var_ext,
401 				 const struct sieve_extension *ext,
402 				 struct sieve_binary_block *sblock,
403 				 sieve_size_t *address)
404 {
405 	struct sieve_variable_scope *scope;
406 	struct sieve_variable_scope_binary *scpbin;
407 	unsigned int scope_size, max_scope_size;
408 	const char *ext_name = (ext == NULL ? "variables" :
409 				sieve_extension_name(ext));
410 	sieve_size_t pc;
411 	sieve_offset_t end_offset;
412 
413 	/* Read scope size */
414 	if (!sieve_binary_read_unsigned(sblock, address, &scope_size)) {
415 		e_error(svinst->event, "%s: "
416 			"variable scope: failed to read size", ext_name);
417 		return NULL;
418 	}
419 
420 	/* Check size limit */
421 	max_scope_size = sieve_variables_get_max_scope_size(var_ext);
422 	if (scope_size > max_scope_size) {
423 		e_error(svinst->event, "%s: "
424 			"variable scope: size exceeds the limit (%u > %u)",
425 			ext_name, scope_size, max_scope_size);
426 		return NULL;
427 	}
428 
429 	/* Read offset */
430 	pc = *address;
431 	if (!sieve_binary_read_offset(sblock, address, &end_offset)) {
432 		e_error(svinst->event, "%s: "
433 			"variable scope: failed to read end offset", ext_name);
434 		return NULL;
435 	}
436 
437 	/* Create scope */
438 	scope = sieve_variable_scope_create(svinst, var_ext, ext);
439 
440 	scpbin = sieve_variable_scope_binary_create(scope);
441 	scpbin->size = scope_size;
442 	scpbin->sblock = sblock;
443 	scpbin->address = *address;
444 
445 	*address = pc + end_offset;
446 
447 	return scpbin;
448 }
449 
450 struct sieve_variable_scope *
sieve_variable_scope_binary_get(struct sieve_variable_scope_binary * scpbin)451 sieve_variable_scope_binary_get(struct sieve_variable_scope_binary *scpbin)
452 {
453 	const struct sieve_extension *ext = scpbin->scope->ext;
454 	struct sieve_instance *svinst = scpbin->scope->svinst;
455 	const char *ext_name = (ext == NULL ? "variables" :
456 				sieve_extension_name(ext));
457 	unsigned int i;
458 
459 	if (scpbin->sblock != NULL) {
460 		sieve_size_t *address = &scpbin->address;
461 
462 		/* Read scope itself */
463 		for (i = 0; i < scpbin->size; i++) {
464 			struct sieve_variable *var;
465 			string_t *identifier;
466 
467 			if (!sieve_binary_read_string(scpbin->sblock, address,
468 						      &identifier)) {
469 				e_error(svinst->event, "%s: variable scope: "
470 					"failed to read variable name",
471 					ext_name);
472 				return NULL;
473 			}
474 
475 			var = sieve_variable_scope_declare(scpbin->scope,
476 							   str_c(identifier));
477 
478 			i_assert(var != NULL);
479 			i_assert(var->index == i);
480 		}
481 
482 		scpbin->sblock = NULL;
483 	}
484 
485 	return scpbin->scope;
486 }
487 
488 unsigned int
sieve_variable_scope_binary_get_size(struct sieve_variable_scope_binary * scpbin)489 sieve_variable_scope_binary_get_size(
490 	struct sieve_variable_scope_binary *scpbin)
491 {
492 	if (scpbin->sblock != NULL)
493 		return scpbin->size;
494 
495 	return array_count(&scpbin->scope->variable_index);
496 }
497 
498 /*
499  * Variable storage
500  */
501 
502 struct sieve_variable_storage {
503 	pool_t pool;
504 	const struct sieve_extension *var_ext;
505 	struct sieve_variable_scope *scope;
506 	struct sieve_variable_scope_binary *scope_bin;
507 	unsigned int max_size;
508 	ARRAY(string_t *) var_values;
509 };
510 
511 struct sieve_variable_storage *
sieve_variable_storage_create(const struct sieve_extension * var_ext,pool_t pool,struct sieve_variable_scope_binary * scpbin)512 sieve_variable_storage_create(const struct sieve_extension *var_ext,
513 			      pool_t pool,
514 			      struct sieve_variable_scope_binary *scpbin)
515 {
516 	struct sieve_variable_storage *storage;
517 
518 	storage = p_new(pool, struct sieve_variable_storage, 1);
519 	storage->pool = pool;
520 	storage->var_ext = var_ext;
521 	storage->scope_bin = scpbin;
522 	storage->scope = NULL;
523 
524 	storage->max_size = sieve_variable_scope_binary_get_size(scpbin);
525 
526 	p_array_init(&storage->var_values, pool, 4);
527 
528 	return storage;
529 }
530 
531 static inline bool
sieve_variable_valid(struct sieve_variable_storage * storage,unsigned int index)532 sieve_variable_valid(struct sieve_variable_storage *storage,
533 		     unsigned int index)
534 {
535 	if (storage->scope_bin == NULL)
536 		return TRUE;
537 
538 	return (index < storage->max_size);
539 }
540 
sieve_variable_get_identifier(struct sieve_variable_storage * storage,unsigned int index,const char ** identifier)541 bool sieve_variable_get_identifier(struct sieve_variable_storage *storage,
542 				   unsigned int index, const char **identifier)
543 {
544 	struct sieve_variable * const *var;
545 
546 	*identifier = NULL;
547 
548 	if (storage->scope_bin == NULL)
549 		return TRUE;
550 
551 	if (storage->scope == NULL) {
552 		storage->scope =
553 			sieve_variable_scope_binary_get(storage->scope_bin);
554 		if (storage->scope == NULL)
555 			return FALSE;
556 	}
557 
558 	/* FIXME: direct invasion of the scope object is a bit ugly */
559 	if (index >= array_count(&storage->scope->variable_index))
560 		return FALSE;
561 
562 	var = array_idx(&storage->scope->variable_index, index);
563 	if (*var != NULL)
564 		*identifier = (*var)->identifier;
565 	return TRUE;
566 }
567 
568 const char *
sieve_variable_get_varid(struct sieve_variable_storage * storage,unsigned int index)569 sieve_variable_get_varid(struct sieve_variable_storage *storage,
570 			 unsigned int index)
571 {
572 	if (storage->scope_bin == NULL)
573 		return t_strdup_printf("%ld", (long)index);
574 
575 	if (storage->scope == NULL) {
576 		storage->scope =
577 			sieve_variable_scope_binary_get(storage->scope_bin);
578 		if (storage->scope == NULL)
579 			return NULL;
580 	}
581 
582 	return sieve_ext_variables_get_varid(storage->scope->ext, index);
583 }
584 
sieve_variable_get(struct sieve_variable_storage * storage,unsigned int index,string_t ** value)585 bool sieve_variable_get(struct sieve_variable_storage *storage,
586 			unsigned int index, string_t **value)
587 {
588 	*value = NULL;
589 
590 	if (index < array_count(&storage->var_values)) {
591 		string_t * const *varent;
592 
593 		varent = array_idx(&storage->var_values, index);
594 
595 		*value = *varent;
596 	} else if (!sieve_variable_valid(storage, index)) {
597 		return FALSE;
598 	}
599 
600 	return TRUE;
601 }
602 
sieve_variable_get_modifiable(struct sieve_variable_storage * storage,unsigned int index,string_t ** value)603 bool sieve_variable_get_modifiable(struct sieve_variable_storage *storage,
604 				   unsigned int index, string_t **value)
605 {
606 	string_t *dummy;
607 
608 	if (value == NULL)
609 		value = &dummy;
610 
611 	if (!sieve_variable_get(storage, index, value))
612 		return FALSE;
613 
614 	if (*value == NULL) {
615 		*value = str_new(storage->pool, 256);
616 		array_idx_set(&storage->var_values, index, value);
617 	}
618 	return TRUE;
619 }
620 
sieve_variable_assign(struct sieve_variable_storage * storage,unsigned int index,const string_t * value)621 bool sieve_variable_assign(struct sieve_variable_storage *storage,
622 			   unsigned int index, const string_t *value)
623 {
624 	const struct ext_variables_config *config =
625 		ext_variables_get_config(storage->var_ext);
626 	string_t *varval;
627 
628 	if (!sieve_variable_get_modifiable(storage, index, &varval))
629 		return FALSE;
630 
631 	str_truncate(varval, 0);
632 	str_append_str(varval, value);
633 
634 	/* Just a precaution, caller should prevent this in the first place */
635 	if (str_len(varval) > config->max_variable_size)
636 		str_truncate_utf8(varval, config->max_variable_size);
637 
638 	return TRUE;
639 }
640 
sieve_variable_assign_cstr(struct sieve_variable_storage * storage,unsigned int index,const char * value)641 bool sieve_variable_assign_cstr(struct sieve_variable_storage *storage,
642 				unsigned int index, const char *value)
643 {
644 	const struct ext_variables_config *config =
645 		ext_variables_get_config(storage->var_ext);
646 	string_t *varval;
647 
648 	if (!sieve_variable_get_modifiable(storage, index, &varval))
649 		return FALSE;
650 
651 	str_truncate(varval, 0);
652 	str_append(varval, value);
653 
654 	/* Just a precaution, caller should prevent this in the first place */
655 	if (str_len(varval) > config->max_variable_size)
656 		str_truncate_utf8(varval, config->max_variable_size);
657 
658 	return TRUE;
659 }
660 
661 /*
662  * AST Context
663  */
664 
665 static void
ext_variables_ast_free(const struct sieve_extension * ext ATTR_UNUSED,struct sieve_ast * ast ATTR_UNUSED,void * context)666 ext_variables_ast_free(const struct sieve_extension *ext ATTR_UNUSED,
667 		       struct sieve_ast *ast ATTR_UNUSED, void *context)
668 {
669 	struct sieve_variable_scope *local_scope =
670 		(struct sieve_variable_scope *)context;
671 
672 	/* Unreference main variable scope */
673 	sieve_variable_scope_unref(&local_scope);
674 }
675 
676 static const struct sieve_ast_extension variables_ast_extension = {
677     &variables_extension,
678     ext_variables_ast_free
679 };
680 
681 static struct sieve_variable_scope *
ext_variables_create_local_scope(const struct sieve_extension * this_ext,struct sieve_ast * ast)682 ext_variables_create_local_scope(const struct sieve_extension *this_ext,
683 				 struct sieve_ast *ast)
684 {
685 	struct sieve_variable_scope *scope;
686 
687 	scope = sieve_variable_scope_create(this_ext->svinst, this_ext, NULL);
688 
689 	sieve_ast_extension_register(ast, this_ext, &variables_ast_extension,
690 				     (void *)scope);
691 	return scope;
692 }
693 
694 static struct sieve_variable_scope *
ext_variables_ast_get_local_scope(const struct sieve_extension * this_ext,struct sieve_ast * ast)695 ext_variables_ast_get_local_scope(const struct sieve_extension *this_ext,
696 				  struct sieve_ast *ast)
697 {
698 	struct sieve_variable_scope *local_scope =
699 		(struct sieve_variable_scope *)
700 			sieve_ast_extension_get_context(ast, this_ext);
701 
702 	return local_scope;
703 }
704 
705 /*
706  * Validator context
707  */
708 
709 static struct ext_variables_validator_context *
ext_variables_validator_context_create(const struct sieve_extension * this_ext,struct sieve_validator * valdtr)710 ext_variables_validator_context_create(const struct sieve_extension *this_ext,
711 				       struct sieve_validator *valdtr)
712 {
713 	pool_t pool = sieve_validator_pool(valdtr);
714 	struct ext_variables_validator_context *ctx;
715 	struct sieve_ast *ast = sieve_validator_ast(valdtr);
716 
717 	ctx = p_new(pool, struct ext_variables_validator_context, 1);
718 	ctx->modifiers = sieve_validator_object_registry_create(valdtr);
719 	ctx->namespaces = sieve_validator_object_registry_create(valdtr);
720 	ctx->local_scope = ext_variables_create_local_scope(this_ext, ast);
721 
722 	sieve_validator_extension_set_context(valdtr, this_ext, (void *)ctx);
723 	return ctx;
724 }
725 
726 struct ext_variables_validator_context *
ext_variables_validator_context_get(const struct sieve_extension * this_ext,struct sieve_validator * valdtr)727 ext_variables_validator_context_get(const struct sieve_extension *this_ext,
728 				    struct sieve_validator *valdtr)
729 {
730 	struct ext_variables_validator_context *ctx;
731 
732 	i_assert(sieve_extension_is(this_ext, variables_extension));
733 	ctx = (struct ext_variables_validator_context *)
734 		sieve_validator_extension_get_context(valdtr, this_ext);
735 
736 	if (ctx == NULL)
737 		ctx = ext_variables_validator_context_create(this_ext, valdtr);
738 	return ctx;
739 }
740 
ext_variables_validator_initialize(const struct sieve_extension * this_ext,struct sieve_validator * valdtr)741 void ext_variables_validator_initialize(const struct sieve_extension *this_ext,
742 					struct sieve_validator *valdtr)
743 {
744 	struct ext_variables_validator_context *ctx;
745 
746 	/* Create our context */
747 	ctx = ext_variables_validator_context_get(this_ext, valdtr);
748 
749 	ext_variables_register_core_modifiers(this_ext, ctx);
750 
751 	ctx->active = TRUE;
752 }
753 
ext_variables_validator_get_variable(const struct sieve_extension * this_ext,struct sieve_validator * validator,const char * variable)754 struct sieve_variable *ext_variables_validator_get_variable(
755 	const struct sieve_extension *this_ext,
756 	struct sieve_validator *validator, const char *variable)
757 {
758 	struct ext_variables_validator_context *ctx =
759 		ext_variables_validator_context_get(this_ext, validator);
760 
761 	return sieve_variable_scope_get_variable(ctx->local_scope, variable);
762 }
763 
764 struct sieve_variable *
ext_variables_validator_declare_variable(const struct sieve_extension * this_ext,struct sieve_validator * validator,const char * variable)765 ext_variables_validator_declare_variable(const struct sieve_extension *this_ext,
766 					 struct sieve_validator *validator,
767 					 const char *variable)
768 {
769 	struct ext_variables_validator_context *ctx =
770 		ext_variables_validator_context_get(this_ext, validator);
771 
772 	return sieve_variable_scope_declare(ctx->local_scope, variable);
773 }
774 
775 struct sieve_variable_scope *
sieve_ext_variables_get_local_scope(const struct sieve_extension * var_ext,struct sieve_validator * validator)776 sieve_ext_variables_get_local_scope(const struct sieve_extension *var_ext,
777 				    struct sieve_validator *validator)
778 {
779 	struct ext_variables_validator_context *ctx =
780 		ext_variables_validator_context_get(var_ext, validator);
781 
782 	return ctx->local_scope;
783 }
784 
sieve_ext_variables_is_active(const struct sieve_extension * var_ext,struct sieve_validator * valdtr)785 bool sieve_ext_variables_is_active(const struct sieve_extension *var_ext,
786 				   struct sieve_validator *valdtr)
787 {
788 	struct ext_variables_validator_context *ctx =
789 		ext_variables_validator_context_get(var_ext, valdtr);
790 
791 	return (ctx != NULL && ctx->active);
792 }
793 
794 /*
795  * Code generation
796  */
797 
ext_variables_generator_load(const struct sieve_extension * ext,const struct sieve_codegen_env * cgenv)798 bool ext_variables_generator_load(const struct sieve_extension *ext,
799 				  const struct sieve_codegen_env *cgenv)
800 {
801 	struct sieve_variable_scope *local_scope =
802 		ext_variables_ast_get_local_scope(ext, cgenv->ast);
803 	unsigned int count = sieve_variable_scope_size(local_scope);
804 	sieve_size_t jump;
805 
806 	sieve_binary_emit_unsigned(cgenv->sblock, count);
807 
808 	jump = sieve_binary_emit_offset(cgenv->sblock, 0);
809 
810 	if (count > 0) {
811 		unsigned int size, i;
812 		struct sieve_variable *const *vars =
813 			sieve_variable_scope_get_variables(local_scope, &size);
814 
815 		for (i = 0; i < size; i++) {
816 			sieve_binary_emit_cstring(cgenv->sblock,
817 						  vars[i]->identifier);
818 		}
819 	}
820 
821 	sieve_binary_resolve_offset(cgenv->sblock, jump);
822 	return TRUE;
823 }
824 
825 /*
826  * Interpreter context
827  */
828 
829 struct ext_variables_interpreter_context {
830 	pool_t pool;
831 
832 	struct sieve_variable_scope *local_scope;
833 	struct sieve_variable_scope_binary *local_scope_bin;
834 
835 	struct sieve_variable_storage *local_storage;
836 	ARRAY(struct sieve_variable_storage *) ext_storages;
837 };
838 
839 static void
ext_variables_interpreter_free(const struct sieve_extension * ext ATTR_UNUSED,struct sieve_interpreter * interp ATTR_UNUSED,void * context)840 ext_variables_interpreter_free(const struct sieve_extension *ext ATTR_UNUSED,
841 			       struct sieve_interpreter *interp ATTR_UNUSED,
842 			       void *context)
843 {
844 	struct ext_variables_interpreter_context *ctx =
845 		(struct ext_variables_interpreter_context *)context;
846 
847 	sieve_variable_scope_binary_unref(&ctx->local_scope_bin);
848 }
849 
850 static struct sieve_interpreter_extension
851 variables_interpreter_extension = {
852 	.ext_def = &variables_extension,
853 	.free = ext_variables_interpreter_free
854 };
855 
856 static struct ext_variables_interpreter_context *
ext_variables_interpreter_context_create(const struct sieve_extension * this_ext,struct sieve_interpreter * interp,struct sieve_variable_scope_binary * scpbin)857 ext_variables_interpreter_context_create(
858 	const struct sieve_extension *this_ext,
859 	struct sieve_interpreter *interp,
860 					struct sieve_variable_scope_binary *scpbin)
861 {
862 	pool_t pool = sieve_interpreter_pool(interp);
863 	struct ext_variables_interpreter_context *ctx;
864 
865 	ctx = p_new(pool, struct ext_variables_interpreter_context, 1);
866 	ctx->pool = pool;
867 	ctx->local_scope = NULL;
868 	ctx->local_scope_bin = scpbin;
869 	ctx->local_storage =
870 		sieve_variable_storage_create(this_ext, pool, scpbin);
871 	p_array_init(&ctx->ext_storages, pool,
872 		     sieve_extensions_get_count(this_ext->svinst));
873 
874 	sieve_interpreter_extension_register(interp, this_ext,
875 					     &variables_interpreter_extension,
876 					     (void *)ctx);
877 	return ctx;
878 }
879 
ext_variables_interpreter_load(const struct sieve_extension * ext,const struct sieve_runtime_env * renv,sieve_size_t * address)880 bool ext_variables_interpreter_load(const struct sieve_extension *ext,
881 				    const struct sieve_runtime_env *renv,
882 				    sieve_size_t *address)
883 {
884 	const struct sieve_execute_env *eenv = renv->exec_env;
885 	struct sieve_variable_scope_binary *scpbin;
886 
887 	scpbin = sieve_variable_scope_binary_read(eenv->svinst, ext, NULL,
888 						  renv->sblock, address);
889 	if (scpbin == NULL)
890 		return FALSE;
891 
892 	/* Create our context */
893 	(void)ext_variables_interpreter_context_create(ext, renv->interp,
894 						       scpbin);
895 
896 	/* Enable support for match values */
897 	(void)sieve_match_values_set_enabled(renv, TRUE);
898 
899 	return TRUE;
900 }
901 
902 static inline struct ext_variables_interpreter_context *
ext_variables_interpreter_context_get(const struct sieve_extension * this_ext,struct sieve_interpreter * interp)903 ext_variables_interpreter_context_get(const struct sieve_extension *this_ext,
904 				      struct sieve_interpreter *interp)
905 {
906 	struct ext_variables_interpreter_context *ctx;
907 
908 	i_assert(sieve_extension_is(this_ext, variables_extension));
909 	ctx = (struct ext_variables_interpreter_context *)
910 		sieve_interpreter_extension_get_context(interp, this_ext);
911 	return ctx;
912 }
913 
914 struct sieve_variable_storage *
sieve_ext_variables_runtime_get_storage(const struct sieve_extension * var_ext,const struct sieve_runtime_env * renv,const struct sieve_extension * ext)915 sieve_ext_variables_runtime_get_storage(const struct sieve_extension *var_ext,
916 					const struct sieve_runtime_env *renv,
917 					const struct sieve_extension *ext)
918 {
919 	struct ext_variables_interpreter_context *ctx =
920 		ext_variables_interpreter_context_get(var_ext, renv->interp);
921 	struct sieve_variable_storage * const *storage;
922 
923 	if (ext == NULL)
924 		return ctx->local_storage;
925 
926 	if (ext->id >= (int)array_count(&ctx->ext_storages))
927 		storage = NULL;
928 	else
929 		storage = array_idx(&ctx->ext_storages, ext->id);
930 
931 	if (storage == NULL)
932 		return NULL;
933 	return *storage;
934 }
935 
sieve_ext_variables_runtime_set_storage(const struct sieve_extension * var_ext,const struct sieve_runtime_env * renv,const struct sieve_extension * ext,struct sieve_variable_storage * storage)936 void sieve_ext_variables_runtime_set_storage(
937 	const struct sieve_extension *var_ext,
938 	const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
939 	struct sieve_variable_storage *storage)
940 {
941 	struct ext_variables_interpreter_context *ctx =
942 		ext_variables_interpreter_context_get(var_ext, renv->interp);
943 
944 	if (ctx == NULL || ext == NULL || storage == NULL)
945 		return;
946 	if (ext->id < 0)
947 		return;
948 
949 	array_idx_set(&ctx->ext_storages, (unsigned int) ext->id, &storage);
950 }
951