1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 #include "unichar.h"
6 #include "str-sanitize.h"
7 
8 #include "sieve-common.h"
9 #include "sieve-commands.h"
10 #include "sieve-code.h"
11 #include "sieve-binary.h"
12 #include "sieve-validator.h"
13 #include "sieve-generator.h"
14 #include "sieve-runtime.h"
15 
16 #include "ext-variables-common.h"
17 #include "ext-variables-limits.h"
18 #include "ext-variables-modifiers.h"
19 
20 #include <ctype.h>
21 
22 /*
23  * Core modifiers
24  */
25 
26 extern const struct sieve_variables_modifier_def lower_modifier;
27 extern const struct sieve_variables_modifier_def upper_modifier;
28 extern const struct sieve_variables_modifier_def lowerfirst_modifier;
29 extern const struct sieve_variables_modifier_def upperfirst_modifier;
30 extern const struct sieve_variables_modifier_def quotewildcard_modifier;
31 extern const struct sieve_variables_modifier_def length_modifier;
32 
33 enum ext_variables_modifier_code {
34     EXT_VARIABLES_MODIFIER_LOWER,
35     EXT_VARIABLES_MODIFIER_UPPER,
36     EXT_VARIABLES_MODIFIER_LOWERFIRST,
37     EXT_VARIABLES_MODIFIER_UPPERFIRST,
38     EXT_VARIABLES_MODIFIER_QUOTEWILDCARD,
39     EXT_VARIABLES_MODIFIER_LENGTH
40 };
41 
42 const struct sieve_variables_modifier_def *ext_variables_core_modifiers[] = {
43 	&lower_modifier,
44 	&upper_modifier,
45 	&lowerfirst_modifier,
46 	&upperfirst_modifier,
47 	&quotewildcard_modifier,
48 	&length_modifier
49 };
50 
51 const unsigned int ext_variables_core_modifiers_count =
52     N_ELEMENTS(ext_variables_core_modifiers);
53 
54 #define ext_variables_modifier_name(modf) \
55 	(modf)->object->def->name
56 #define ext_variables_modifiers_equal(modf1, modf2) \
57 	( (modf1)->def == (modf2)->def )
58 #define ext_variables_modifiers_equal_precedence(modf1, modf2) \
59 	( (modf1)->def->precedence == (modf2)->def->precendence )
60 
61 /*
62  * Modifier registry
63  */
64 
sieve_variables_modifier_register(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,const struct sieve_extension * ext,const struct sieve_variables_modifier_def * smodf_def)65 void sieve_variables_modifier_register
66 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
67 	const struct sieve_extension *ext,
68 	const struct sieve_variables_modifier_def *smodf_def)
69 {
70 	struct ext_variables_validator_context *ctx =
71 		ext_variables_validator_context_get(var_ext, valdtr);
72 
73 	sieve_validator_object_registry_add(ctx->modifiers, ext, &smodf_def->obj_def);
74 }
75 
ext_variables_modifier_exists(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,const char * identifier)76 bool ext_variables_modifier_exists
77 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
78 	const char *identifier)
79 {
80 	struct ext_variables_validator_context *ctx =
81 		ext_variables_validator_context_get(var_ext, valdtr);
82 
83 	return sieve_validator_object_registry_find(ctx->modifiers, identifier, NULL);
84 }
85 
ext_variables_modifier_create_instance(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,struct sieve_command * cmd,const char * identifier)86 const struct sieve_variables_modifier *ext_variables_modifier_create_instance
87 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
88 	struct sieve_command *cmd, const char *identifier)
89 {
90 	struct ext_variables_validator_context *ctx =
91 		ext_variables_validator_context_get(var_ext, valdtr);
92 	struct sieve_object object;
93 	struct sieve_variables_modifier *modf;
94 	pool_t pool;
95 
96 	if ( !sieve_validator_object_registry_find
97 		(ctx->modifiers, identifier, &object) )
98 		return NULL;
99 
100 	pool = sieve_command_pool(cmd);
101 	modf = p_new(pool, struct sieve_variables_modifier, 1);
102 	modf->object = object;
103 	modf->var_ext = var_ext;
104 	modf->def = (const struct sieve_variables_modifier_def *) object.def;
105 
106   return modf;
107 }
108 
ext_variables_register_core_modifiers(const struct sieve_extension * ext,struct ext_variables_validator_context * ctx)109 void ext_variables_register_core_modifiers
110 (const struct sieve_extension *ext, struct ext_variables_validator_context *ctx)
111 {
112 	unsigned int i;
113 
114 	/* Register core modifiers*/
115 	for ( i = 0; i < ext_variables_core_modifiers_count; i++ ) {
116 		sieve_validator_object_registry_add
117 			(ctx->modifiers, ext, &(ext_variables_core_modifiers[i]->obj_def));
118 	}
119 }
120 
121 /*
122  * Core modifiers
123  */
124 
125 /* Forward declarations */
126 
127 static bool
128 mod_lower_modify(const struct sieve_variables_modifier *modf,
129 		 string_t *in, string_t **result);
130 static bool
131 mod_upper_modify(const struct sieve_variables_modifier *modf,
132 		 string_t *in, string_t **result);
133 static bool
134 mod_lowerfirst_modify(const struct sieve_variables_modifier *modf,
135 		      string_t *in, string_t **result);
136 static bool
137 mod_upperfirst_modify(const struct sieve_variables_modifier *modf,
138 		      string_t *in, string_t **result);
139 static bool
140 mod_length_modify(const struct sieve_variables_modifier *modf,
141 		  string_t *in, string_t **result);
142 static bool
143 mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
144 			 string_t *in, string_t **result);
145 
146 /* Modifier objects */
147 
148 const struct sieve_variables_modifier_def lower_modifier = {
149 	SIEVE_OBJECT("lower", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWER),
150 	40,
151 	mod_lower_modify
152 };
153 
154 const struct sieve_variables_modifier_def upper_modifier = {
155 	SIEVE_OBJECT("upper", &modifier_operand, EXT_VARIABLES_MODIFIER_UPPER),
156 	40,
157 	mod_upper_modify
158 };
159 
160 const struct sieve_variables_modifier_def lowerfirst_modifier = {
161 	SIEVE_OBJECT
162 		("lowerfirst", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWERFIRST),
163 	30,
164 	mod_lowerfirst_modify
165 };
166 
167 const struct sieve_variables_modifier_def upperfirst_modifier = {
168 	SIEVE_OBJECT
169 		("upperfirst", &modifier_operand,	EXT_VARIABLES_MODIFIER_UPPERFIRST),
170 	30,
171 	mod_upperfirst_modify
172 };
173 
174 const struct sieve_variables_modifier_def quotewildcard_modifier = {
175 	SIEVE_OBJECT
176 		("quotewildcard", &modifier_operand, EXT_VARIABLES_MODIFIER_QUOTEWILDCARD),
177 	20,
178 	mod_quotewildcard_modify
179 };
180 
181 const struct sieve_variables_modifier_def length_modifier = {
182 	SIEVE_OBJECT("length", &modifier_operand, EXT_VARIABLES_MODIFIER_LENGTH),
183 	10,
184 	mod_length_modify
185 };
186 
187 /* Modifier implementations */
188 
189 static bool
mod_upperfirst_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)190 mod_upperfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
191 		      string_t *in, string_t **result)
192 {
193 	char *content;
194 
195 	if ( str_len(in) == 0 ) {
196 		*result = in;
197 		return TRUE;
198 	}
199 
200 	*result = t_str_new(str_len(in));
201 	str_append_str(*result, in);
202 
203 	content = str_c_modifiable(*result);
204 	content[0] = i_toupper(content[0]);
205 
206 	return TRUE;
207 }
208 
209 static bool
mod_lowerfirst_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)210 mod_lowerfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
211 		      string_t *in, string_t **result)
212 {
213 	char *content;
214 
215 	if ( str_len(in) == 0 ) {
216 		*result = in;
217 		return TRUE;
218 	}
219 
220 	*result = t_str_new(str_len(in));
221 	str_append_str(*result, in);
222 
223 	content = str_c_modifiable(*result);
224 	content[0] = i_tolower(content[0]);
225 
226 	return TRUE;
227 }
228 
229 static bool
mod_upper_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)230 mod_upper_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
231 		 string_t *in, string_t **result)
232 {
233 	char *content;
234 
235 	if ( str_len(in) == 0 ) {
236 		*result = in;
237 		return TRUE;
238 	}
239 
240 	*result = t_str_new(str_len(in));
241 	str_append_str(*result, in);
242 
243 	content = str_c_modifiable(*result);
244 	(void)str_ucase(content);
245 
246 	return TRUE;
247 }
248 
249 static bool
mod_lower_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)250 mod_lower_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
251 		 string_t *in, string_t **result)
252 {
253 	char *content;
254 
255 	if ( str_len(in) == 0 ) {
256 		*result = in;
257 		return TRUE;
258 	}
259 
260 	*result = t_str_new(str_len(in));
261 	str_append_str(*result, in);
262 
263 	content = str_c_modifiable(*result);
264 	(void)str_lcase(content);
265 
266 	return TRUE;
267 }
268 
269 static bool
mod_length_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)270 mod_length_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
271 		  string_t *in, string_t **result)
272 {
273 	*result = t_str_new(64);
274 	str_printfa(*result, "%llu", (unsigned long long)
275 		uni_utf8_strlen_n(str_data(in), str_len(in)));
276 	return TRUE;
277 }
278 
279 static bool
mod_quotewildcard_modify(const struct sieve_variables_modifier * modf,string_t * in,string_t ** result)280 mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
281 			 string_t *in, string_t **result)
282 {
283 	size_t max_var_size =
284 		sieve_variables_get_max_variable_size(modf->var_ext);
285 	const unsigned char *p, *poff, *pend;
286 	size_t new_size;
287 
288 	if ( str_len(in) == 0 ) {
289 		/* empty string */
290 		*result = in;
291 		return TRUE;
292 	}
293 
294 	/* allocate new string */
295 	new_size = str_len(in) + 16;
296 	if (new_size > max_var_size)
297 		new_size = max_var_size;
298 	*result = t_str_new(new_size + 1);
299 
300 	/* escape string */
301 	p = str_data(in);
302 	pend = p + str_len(in);
303 	poff = p;
304 	while (p < pend) {
305 		unsigned int n = uni_utf8_char_bytes((char)*p);
306 
307 		if (n == 1 && (*p == '*' || *p == '?' || *p == '\\')) {
308 			str_append_data(*result, poff, p - poff);
309 			poff = p;
310 
311 			if (str_len(*result) + 2 > max_var_size)
312 				break;
313 
314 			str_append_c(*result, '\\');
315 		} else if ((str_len(*result) + (p - poff) + n) > max_var_size) {
316 			break;
317 		}
318 		if (p + n > pend) {
319 			p = pend;
320 			break;
321 		}
322 		p += n;
323 	}
324 
325 	str_append_data(*result, poff, p - poff);
326 
327 	return TRUE;
328 }
329 
330 /*
331  * Modifier argument
332  */
333 
334 /* [MODIFIER]:
335  *   ":lower" / ":upper" / ":lowerfirst" / ":upperfirst" /
336  *             ":quotewildcard" / ":length"
337  */
338 
339 /* Forward declarations */
340 
341 static bool tag_modifier_is_instance_of
342 	(struct sieve_validator *valdtr, struct sieve_command *cmd,
343 		const struct sieve_extension *ext, const char *identifier, void **context);
344 
345 /* Modifier tag object */
346 
347 static const struct sieve_argument_def modifier_tag = {
348 	.identifier = "MODIFIER",
349 	.flags = SIEVE_ARGUMENT_FLAG_MULTIPLE,
350 	.is_instance_of = tag_modifier_is_instance_of
351 };
352 
353 /* Modifier tag implementation */
354 
tag_modifier_is_instance_of(struct sieve_validator * valdtr,struct sieve_command * cmd,const struct sieve_extension * ext,const char * identifier,void ** data)355 static bool tag_modifier_is_instance_of
356 (struct sieve_validator *valdtr, struct sieve_command *cmd,
357 	const struct sieve_extension *ext, const char *identifier, void **data)
358 {
359 	const struct sieve_variables_modifier *modf;
360 
361 	if ( data == NULL ) {
362 		return ext_variables_modifier_exists(ext, valdtr, identifier);
363 	}
364 
365 	if ( (modf=ext_variables_modifier_create_instance
366 		(ext, valdtr, cmd, identifier)) == NULL )
367 		return FALSE;
368 
369 	*data = (void *) modf;
370 
371 	return TRUE;
372 }
373 
374 /* Registration */
375 
sieve_variables_modifiers_link_tag(struct sieve_validator * valdtr,const struct sieve_extension * var_ext,struct sieve_command_registration * cmd_reg)376 void sieve_variables_modifiers_link_tag
377 (struct sieve_validator *valdtr, const struct sieve_extension *var_ext,
378 	struct sieve_command_registration *cmd_reg)
379 {
380 	sieve_validator_register_tag(valdtr, cmd_reg, var_ext, &modifier_tag, 0);
381 }
382 
383 /* Validation */
384 
sieve_variables_modifiers_validate(struct sieve_validator * valdtr,struct sieve_command * cmd,ARRAY_TYPE (sieve_variables_modifier)* modifiers)385 bool sieve_variables_modifiers_validate
386 (struct sieve_validator *valdtr, struct sieve_command *cmd,
387 	ARRAY_TYPE(sieve_variables_modifier) *modifiers)
388 {
389 	struct sieve_ast_argument *arg;
390 
391 	arg = sieve_command_first_argument(cmd);
392 	while ( arg != NULL && arg != cmd->first_positional ) {
393 		const struct sieve_variables_modifier *modfs;
394 		const struct sieve_variables_modifier *modf;
395 		unsigned int i, modf_count;
396 		bool inserted;
397 
398 		if ( !sieve_argument_is(arg, modifier_tag) ) {
399 			arg = sieve_ast_argument_next(arg);
400 			continue;
401 		}
402 		modf = (const struct sieve_variables_modifier *)
403 			arg->argument->data;
404 
405 		inserted = FALSE;
406 		modfs = array_get(modifiers, &modf_count);
407 		for ( i = 0; i < modf_count && !inserted; i++ ) {
408 
409 			if ( modfs[i].def->precedence == modf->def->precedence ) {
410 				sieve_argument_validate_error(valdtr, arg,
411 					"modifiers :%s and :%s specified for the set command conflict "
412 					"having equal precedence",
413 					modfs[i].def->obj_def.identifier, modf->def->obj_def.identifier);
414 				return FALSE;
415 			}
416 
417 			if ( modfs[i].def->precedence < modf->def->precedence ) {
418 				array_insert(modifiers, i, modf, 1);
419 				inserted = TRUE;
420 			}
421 		}
422 
423 		if ( !inserted )
424 			array_append(modifiers, modf, 1);
425 
426 		/* Added to modifier list;
427 		   self-destruct to prevent implicit code generation */
428 		arg = sieve_ast_arguments_detach(arg, 1);
429 	}
430 	return TRUE;
431 }
432 
sieve_variables_modifiers_generate(const struct sieve_codegen_env * cgenv,ARRAY_TYPE (sieve_variables_modifier)* modifiers)433 bool sieve_variables_modifiers_generate
434 (const struct sieve_codegen_env *cgenv,
435 	ARRAY_TYPE(sieve_variables_modifier) *modifiers)
436 {
437 	struct sieve_binary_block *sblock = cgenv->sblock;
438 	const struct sieve_variables_modifier *modfs;
439 	unsigned int i, modf_count;
440 
441 	sieve_binary_emit_byte(sblock, array_count(modifiers));
442 
443 	modfs = array_get(modifiers, &modf_count);
444 	for ( i = 0; i < modf_count; i++ ) {
445 		ext_variables_opr_modifier_emit(sblock,
446 			modfs[i].object.ext, modfs[i].def);
447 	}
448 	return TRUE;
449 }
450 
451 /*
452  * Modifier coding
453  */
454 
455 const struct sieve_operand_class sieve_variables_modifier_operand_class =
456 	{ "modifier" };
457 
458 static const struct sieve_extension_objects core_modifiers =
459 	SIEVE_VARIABLES_DEFINE_MODIFIERS(ext_variables_core_modifiers);
460 
461 const struct sieve_operand_def modifier_operand = {
462 	.name = "modifier",
463 	.ext_def = &variables_extension,
464 	.code = EXT_VARIABLES_OPERAND_MODIFIER,
465 	.class = &sieve_variables_modifier_operand_class,
466 	.interface = &core_modifiers
467 };
468 
sieve_variables_modifiers_code_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address)469 bool sieve_variables_modifiers_code_dump
470 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
471 {
472 	unsigned int mdfs, i;
473 
474 	/* Read the number of applied modifiers we need to read */
475 	if ( !sieve_binary_read_byte(denv->sblock, address, &mdfs) )
476 		return FALSE;
477 
478 	/* Print all modifiers (sorted during code generation already) */
479 	for ( i = 0; i < mdfs; i++ ) {
480 		if ( !ext_variables_opr_modifier_dump(denv, address) )
481 			return FALSE;
482 	}
483 	return TRUE;
484 }
485 
sieve_variables_modifiers_code_read(const struct sieve_runtime_env * renv,const struct sieve_extension * var_ext,sieve_size_t * address,ARRAY_TYPE (sieve_variables_modifier)* modifiers)486 int sieve_variables_modifiers_code_read(
487 	const struct sieve_runtime_env *renv,
488 	const struct sieve_extension *var_ext, sieve_size_t *address,
489 	ARRAY_TYPE(sieve_variables_modifier) *modifiers)
490 {
491 	unsigned int lprec, mdfs, i;
492 
493 	if ( !sieve_binary_read_byte(renv->sblock, address, &mdfs) ) {
494 		sieve_runtime_trace_error(renv, "invalid modifier count");
495 		return SIEVE_EXEC_BIN_CORRUPT;
496 	}
497 
498 	t_array_init(modifiers, mdfs);
499 
500 	lprec = (unsigned int)-1;
501 	for ( i = 0; i < mdfs; i++ ) {
502 		struct sieve_variables_modifier modf;
503 
504 		if ( !ext_variables_opr_modifier_read(renv, var_ext,
505 						      address, &modf) )
506 			return SIEVE_EXEC_BIN_CORRUPT;
507 		if ( modf.def != NULL ) {
508 			if ( modf.def->precedence >= lprec ) {
509 				sieve_runtime_trace_error(renv,
510 					"unsorted modifier precedence");
511 				return SIEVE_EXEC_BIN_CORRUPT;
512 			}
513 			lprec = modf.def->precedence;
514 		}
515 
516 		array_append(modifiers, &modf, 1);
517 	}
518 
519 	return SIEVE_EXEC_OK;
520 }
521 
522 /*
523  * Modifier application
524  */
525 
sieve_variables_modifiers_apply(const struct sieve_runtime_env * renv,const struct sieve_extension * var_ext,ARRAY_TYPE (sieve_variables_modifier)* modifiers,string_t ** value)526 int sieve_variables_modifiers_apply
527 (const struct sieve_runtime_env *renv,
528 	const struct sieve_extension *var_ext,
529 	ARRAY_TYPE(sieve_variables_modifier) *modifiers,
530 	string_t **value)
531 {
532 	const struct ext_variables_config *config =
533 		ext_variables_get_config(var_ext);
534 	const struct sieve_variables_modifier *modfs;
535 	unsigned int i, modf_count;
536 
537 	/* Hold value within limits */
538 	if ( str_len(*value) > config->max_variable_size ) {
539 		/* assume variable originates from code, so copy it first */
540 		string_t *new_value = t_str_new(config->max_variable_size+3);
541 		str_append_str(new_value, *value);
542 		*value = new_value;
543 		str_truncate_utf8(*value, config->max_variable_size);
544 	}
545 
546 	if ( !array_is_created(modifiers) )
547 		return SIEVE_EXEC_OK;
548 
549 	modfs = array_get(modifiers, &modf_count);
550 	if ( modf_count == 0 )
551 		return SIEVE_EXEC_OK;
552 
553 	for ( i = 0; i < modf_count; i++ ) {
554 		string_t *new_value;
555 		const struct sieve_variables_modifier *modf = &modfs[i];
556 
557 		if ( modf->def != NULL && modf->def->modify != NULL ) {
558 			if ( !modf->def->modify(modf, *value, &new_value) )
559 				return SIEVE_EXEC_FAILURE;
560 
561 			*value = new_value;
562 			if ( *value == NULL )
563 				return SIEVE_EXEC_FAILURE;
564 
565 			sieve_runtime_trace_here
566 				(renv, SIEVE_TRLVL_COMMANDS,
567 					"modify :%s \"%s\" => \"%s\"",
568 					sieve_variables_modifier_name(modf),
569 					str_sanitize(str_c(*value), 256),
570 					str_sanitize(str_c(new_value), 256));
571 
572 			/* Hold value within limits */
573 			if ( str_len(*value) > config->max_variable_size )
574 				str_truncate_utf8(*value, config->max_variable_size);
575 		}
576 	}
577 	return SIEVE_EXEC_OK;
578 }
579