1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 #include "str.h"
6 #include "str-sanitize.h"
7 
8 #include "sieve-common.h"
9 #include "sieve-limits.h"
10 #include "sieve-extensions.h"
11 #include "sieve-stringlist.h"
12 #include "sieve-actions.h"
13 #include "sieve-binary.h"
14 #include "sieve-generator.h"
15 #include "sieve-interpreter.h"
16 #include "sieve-dump.h"
17 
18 #include "sieve-code.h"
19 
20 #include <stdio.h>
21 
22 /*
23  * Code stringlist
24  */
25 
26 /* Forward declarations */
27 
28 static int sieve_code_stringlist_next_item
29 	(struct sieve_stringlist *_strlist, string_t **str_r);
30 static void sieve_code_stringlist_reset
31 	(struct sieve_stringlist *_strlist);
32 static int sieve_code_stringlist_get_length
33 	(struct sieve_stringlist *_strlist);
34 
35 /* Coded stringlist object */
36 
37 struct sieve_code_stringlist {
38 	struct sieve_stringlist strlist;
39 
40 	sieve_size_t start_address;
41 	sieve_size_t end_address;
42 	sieve_size_t current_offset;
43 	int length;
44 	int index;
45 };
46 
sieve_code_stringlist_create(const struct sieve_runtime_env * renv,sieve_size_t start_address,unsigned int length,sieve_size_t end)47 static struct sieve_stringlist *sieve_code_stringlist_create
48 (const struct sieve_runtime_env *renv,
49 	 sieve_size_t start_address, unsigned int length, sieve_size_t end)
50 {
51 	struct sieve_code_stringlist *strlist;
52 
53 	if ( end > sieve_binary_block_get_size(renv->sblock) )
54   		return NULL;
55 
56 	strlist = t_new(struct sieve_code_stringlist, 1);
57 	strlist->strlist.runenv = renv;
58 	strlist->strlist.exec_status = SIEVE_EXEC_OK;
59 	strlist->strlist.next_item = sieve_code_stringlist_next_item;
60 	strlist->strlist.reset = sieve_code_stringlist_reset;
61 	strlist->strlist.get_length = sieve_code_stringlist_get_length;
62 	strlist->start_address = start_address;
63 	strlist->current_offset = start_address;
64 	strlist->end_address = end;
65 	strlist->length = length;
66 	strlist->index = 0;
67 
68 	return &strlist->strlist;
69 }
70 
71 /* Stringlist implementation */
72 
sieve_code_stringlist_next_item(struct sieve_stringlist * _strlist,string_t ** str_r)73 static int sieve_code_stringlist_next_item
74 (struct sieve_stringlist *_strlist, string_t **str_r)
75 {
76 	struct sieve_code_stringlist *strlist =
77 		(struct sieve_code_stringlist *) _strlist;
78 	sieve_size_t address;
79 	*str_r = NULL;
80 	int ret;
81 
82 	/* Check for end of list */
83 	if ( strlist->index >= strlist->length )
84 		return 0;
85 
86 	/* Read next item */
87 	address = strlist->current_offset;
88 	if ( (ret=sieve_opr_string_read(_strlist->runenv, &address, NULL, str_r))
89 		== SIEVE_EXEC_OK ) {
90 		strlist->index++;
91 		strlist->current_offset = address;
92 		return 1;
93 	}
94 
95 	_strlist->exec_status = ret;
96 	return -1;
97 }
98 
sieve_code_stringlist_reset(struct sieve_stringlist * _strlist)99 static void sieve_code_stringlist_reset
100 (struct sieve_stringlist *_strlist)
101 {
102 	struct sieve_code_stringlist *strlist =
103 		(struct sieve_code_stringlist *) _strlist;
104 
105 	strlist->current_offset = strlist->start_address;
106 	strlist->index = 0;
107 }
108 
sieve_code_stringlist_get_length(struct sieve_stringlist * _strlist)109 static int sieve_code_stringlist_get_length
110 (struct sieve_stringlist *_strlist)
111 {
112 	struct sieve_code_stringlist *strlist =
113 		(struct sieve_code_stringlist *) _strlist;
114 
115 	return strlist->length;
116 }
117 
sieve_code_stringlist_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address,unsigned int length,sieve_size_t end,const char * field_name)118 static bool sieve_code_stringlist_dump
119 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
120 	unsigned int length, sieve_size_t end, const char *field_name)
121 {
122 	unsigned int i;
123 
124 	if ( end > sieve_binary_block_get_size(denv->sblock) )
125   		return FALSE;
126 
127 	if ( field_name != NULL )
128 		sieve_code_dumpf(denv, "%s: STRLIST [%u] (end: %08llx)",
129 			field_name, length, (unsigned long long) end);
130 	else
131 		sieve_code_dumpf(denv, "STRLIST [%u] (end: %08llx)",
132 			length, (unsigned long long) end);
133 
134 	sieve_code_descend(denv);
135 
136 	for ( i = 0; i < length; i++ ) {
137 		bool success = TRUE;
138 
139 		T_BEGIN {
140 			success = sieve_opr_string_dump(denv, address, NULL);
141 		} T_END;
142 
143 		if ( !success || *address > end )
144 			return FALSE;
145 	}
146 
147 	if ( *address != end ) return FALSE;
148 
149 	sieve_code_ascend(denv);
150 
151 	return TRUE;
152 }
153 
154 /*
155  * Core operands
156  */
157 
158 extern const struct sieve_operand_def comparator_operand;
159 extern const struct sieve_operand_def match_type_operand;
160 extern const struct sieve_operand_def address_part_operand;
161 
162 const struct sieve_operand_def *sieve_operands[] = {
163 	&omitted_operand, /* SIEVE_OPERAND_OPTIONAL */
164 	&number_operand,
165 	&string_operand,
166 	&stringlist_operand,
167 	&comparator_operand,
168 	&match_type_operand,
169 	&address_part_operand,
170 	&catenated_string_operand
171 };
172 
173 const unsigned int sieve_operand_count =
174 	N_ELEMENTS(sieve_operands);
175 
176 /*
177  * Operand functions
178  */
179 
sieve_operand_emit(struct sieve_binary_block * sblock,const struct sieve_extension * ext,const struct sieve_operand_def * opr_def)180 sieve_size_t sieve_operand_emit
181 (struct sieve_binary_block *sblock, const struct sieve_extension *ext,
182 	const struct sieve_operand_def *opr_def)
183 {
184 	sieve_size_t address;
185 
186 	if ( ext != NULL ) {
187 		address = sieve_binary_emit_extension
188 			(sblock, ext, sieve_operand_count);
189 
190 		sieve_binary_emit_extension_object
191 			(sblock, &opr_def->ext_def->operands, opr_def->code);
192 
193 		return address;
194 	}
195 
196 	return sieve_binary_emit_byte(sblock, opr_def->code);
197 }
198 
sieve_operand_read(struct sieve_binary_block * sblock,sieve_size_t * address,const char * field_name,struct sieve_operand * operand)199 bool sieve_operand_read
200 (struct sieve_binary_block *sblock, sieve_size_t *address,
201 	const char *field_name, struct sieve_operand *operand)
202 {
203 	unsigned int code = sieve_operand_count;
204 
205 	operand->address = *address;
206 	operand->field_name = field_name;
207 	operand->ext = NULL;
208 	operand->def = NULL;
209 
210 	if ( !sieve_binary_read_extension(sblock, address, &code, &operand->ext) )
211 		return FALSE;
212 
213 	if ( operand->ext == NULL ) {
214 		if ( code < sieve_operand_count )
215 			operand->def = sieve_operands[code];
216 
217 		return ( operand->def != NULL );
218 	}
219 
220 	if ( operand->ext->def == NULL )
221 		return FALSE;
222 
223 	operand->def = (const struct sieve_operand_def *)
224 		sieve_binary_read_extension_object(sblock, address,
225 			&operand->ext->def->operands);
226 
227 	return ( operand->def != NULL );
228 }
229 
230 /*
231  * Optional operand
232  */
233 
sieve_opr_optional_next(struct sieve_binary_block * sblock,sieve_size_t * address,signed int * opt_code)234 int sieve_opr_optional_next
235 (struct sieve_binary_block *sblock, sieve_size_t *address, signed int *opt_code)
236 {
237 	/* Start of optional operand block */
238 	if ( *opt_code == 0 ) {
239 		sieve_size_t tmp_addr = *address;
240 		unsigned int op;
241 
242 		if ( !sieve_binary_read_byte(sblock, &tmp_addr, &op) ||
243 			op != SIEVE_OPERAND_OPTIONAL )
244 			return 0;
245 
246 		*address = tmp_addr;
247 	}
248 
249 	/* Read optional operand code */
250 	if ( !sieve_binary_read_code(sblock, address, opt_code) )
251 		return -1;
252 
253 	/* Return 0 at end of list */
254 	return ( *opt_code != 0 ? 1 : 0 );
255 }
256 
257 /*
258  * Operand definitions
259  */
260 
261 /* Omitted */
262 
263 const struct sieve_operand_class omitted_class =
264 	{ "OMITTED" };
265 
266 const struct sieve_operand_def omitted_operand = {
267 	.name = "@OMITTED",
268 	.code = SIEVE_OPERAND_OPTIONAL,
269 	.class = &omitted_class
270 };
271 
272 /* Number */
273 
274 static bool opr_number_dump
275 	(const struct sieve_dumptime_env *denv,	const struct sieve_operand *oprnd,
276 		sieve_size_t *address);
277 static int opr_number_read
278 	(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
279 		sieve_size_t *address, sieve_number_t *number_r);
280 
281 const struct sieve_opr_number_interface number_interface = {
282 	opr_number_dump,
283 	opr_number_read
284 };
285 
286 const struct sieve_operand_class number_class =
287 	{ "number" };
288 
289 const struct sieve_operand_def number_operand = {
290 	.name = "@number",
291 	.code = SIEVE_OPERAND_NUMBER,
292 	.class = &number_class,
293 	.interface = &number_interface
294 };
295 
296 /* String */
297 
298 static bool opr_string_dump
299 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
300 		sieve_size_t *address);
301 static int opr_string_read
302 	(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
303 		sieve_size_t *address, string_t **str_r);
304 
305 const struct sieve_opr_string_interface string_interface ={
306 	opr_string_dump,
307 	opr_string_read
308 };
309 
310 const struct sieve_operand_class string_class =
311 	{ "string" };
312 
313 const struct sieve_operand_def string_operand = {
314 	.name = "@string",
315 	.code = SIEVE_OPERAND_STRING,
316 	.class = &string_class,
317 	.interface = &string_interface
318 };
319 
320 /* String List */
321 
322 static bool opr_stringlist_dump
323 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
324 		sieve_size_t *address);
325 static int opr_stringlist_read
326 	(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
327 		sieve_size_t *address, struct sieve_stringlist **strlist_r);
328 
329 const struct sieve_opr_stringlist_interface stringlist_interface = {
330 	opr_stringlist_dump,
331 	opr_stringlist_read
332 };
333 
334 const struct sieve_operand_class stringlist_class =
335 	{ "string-list" };
336 
337 const struct sieve_operand_def stringlist_operand =	{
338 	.name = "@string-list",
339 	.code = SIEVE_OPERAND_STRING_LIST,
340 	.class = &stringlist_class,
341 	.interface = &stringlist_interface
342 };
343 
344 /* Catenated String */
345 
346 static bool opr_catenated_string_dump
347 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *operand,
348 		sieve_size_t *address);
349 static int opr_catenated_string_read
350 	(const struct sieve_runtime_env *renv, const struct sieve_operand *operand,
351 		sieve_size_t *address, string_t **str);
352 
353 const struct sieve_opr_string_interface catenated_string_interface = {
354 	opr_catenated_string_dump,
355 	opr_catenated_string_read
356 };
357 
358 const struct sieve_operand_def catenated_string_operand = {
359 	.name = "@catenated-string",
360 	.code = SIEVE_OPERAND_CATENATED_STRING,
361 	.class = &string_class,
362 	.interface = &catenated_string_interface
363 };
364 
365 /*
366  * Operand implementations
367  */
368 
369 /* Omitted */
370 
sieve_opr_omitted_emit(struct sieve_binary_block * sblock)371 void sieve_opr_omitted_emit(struct sieve_binary_block *sblock)
372 {
373 	(void) sieve_operand_emit(sblock, NULL, &omitted_operand);
374 }
375 
376 /* Number */
377 
sieve_opr_number_emit(struct sieve_binary_block * sblock,sieve_number_t number)378 void sieve_opr_number_emit
379 (struct sieve_binary_block *sblock, sieve_number_t number)
380 {
381 	(void) sieve_operand_emit(sblock, NULL, &number_operand);
382 	(void) sieve_binary_emit_integer(sblock, number);
383 }
384 
sieve_opr_number_dump_data(const struct sieve_dumptime_env * denv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name)385 bool sieve_opr_number_dump_data
386 (const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
387 	sieve_size_t *address, const char *field_name)
388 {
389 	const struct sieve_opr_number_interface *intf;
390 
391 	oprnd->field_name = field_name;
392 
393 	if ( !sieve_operand_is_number(oprnd) )
394 		return FALSE;
395 
396 	intf = (const struct sieve_opr_number_interface *) oprnd->def->interface;
397 
398 	if ( intf->dump == NULL )
399 		return FALSE;
400 
401 	return intf->dump(denv, oprnd, address);
402 }
403 
sieve_opr_number_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address,const char * field_name)404 bool sieve_opr_number_dump
405 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
406 	const char *field_name)
407 {
408 	struct sieve_operand operand;
409 
410 	sieve_code_mark(denv);
411 
412 	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) )
413 		return FALSE;
414 
415 	return sieve_opr_number_dump_data(denv, &operand, address, field_name);
416 }
417 
sieve_opr_number_read_data(const struct sieve_runtime_env * renv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name,sieve_number_t * number_r)418 int sieve_opr_number_read_data
419 (const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
420 	sieve_size_t *address, const char *field_name, sieve_number_t *number_r)
421 {
422 	const struct sieve_opr_number_interface *intf;
423 
424 	oprnd->field_name = field_name;
425 
426 	if ( !sieve_operand_is_number(oprnd) ) {
427 		sieve_runtime_trace_operand_error(renv, oprnd,
428 			"expected number operand but found %s", sieve_operand_name(oprnd));
429 		return SIEVE_EXEC_BIN_CORRUPT;
430 	}
431 
432 	intf = (const struct sieve_opr_number_interface *) oprnd->def->interface;
433 
434 	if ( intf->read == NULL ) {
435 		sieve_runtime_trace_operand_error(renv, oprnd,
436 			"number operand not implemented");
437 		return SIEVE_EXEC_FAILURE;
438 	}
439 
440 	return intf->read(renv, oprnd, address, number_r);
441 }
442 
sieve_opr_number_read(const struct sieve_runtime_env * renv,sieve_size_t * address,const char * field_name,sieve_number_t * number_r)443 int sieve_opr_number_read
444 (const struct sieve_runtime_env *renv, sieve_size_t *address,
445 	const char *field_name, sieve_number_t *number_r)
446 {
447 	struct sieve_operand operand;
448 	int ret;
449 
450 	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
451 		<= 0)
452 		return ret;
453 
454 	return sieve_opr_number_read_data
455 		(renv, &operand, address, field_name, number_r);
456 }
457 
opr_number_dump(const struct sieve_dumptime_env * denv,const struct sieve_operand * oprnd,sieve_size_t * address)458 static bool opr_number_dump
459 (const struct sieve_dumptime_env *denv,	const struct sieve_operand *oprnd,
460 	sieve_size_t *address)
461 {
462 	sieve_number_t number = 0;
463 
464 	if (sieve_binary_read_integer(denv->sblock, address, &number) ) {
465 		if ( oprnd->field_name != NULL )
466 			sieve_code_dumpf(denv, "%s: NUM %llu", oprnd->field_name,
467 				(unsigned long long) number);
468 		else
469 			sieve_code_dumpf(denv, "NUM %llu", (unsigned long long) number);
470 
471 		return TRUE;
472 	}
473 
474 	return FALSE;
475 }
476 
opr_number_read(const struct sieve_runtime_env * renv,const struct sieve_operand * oprnd,sieve_size_t * address,sieve_number_t * number_r)477 static int opr_number_read
478 (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
479 	sieve_size_t *address, sieve_number_t *number_r)
480 {
481 	if ( !sieve_binary_read_integer(renv->sblock, address, number_r) ) {
482 		sieve_runtime_trace_operand_error(renv, oprnd, "invalid number operand");
483 		return SIEVE_EXEC_BIN_CORRUPT;
484 	}
485 
486 	return SIEVE_EXEC_OK;
487 }
488 
489 /* String */
490 
sieve_opr_string_emit(struct sieve_binary_block * sblock,string_t * str)491 void sieve_opr_string_emit(struct sieve_binary_block *sblock, string_t *str)
492 {
493 	(void) sieve_operand_emit(sblock, NULL, &string_operand);
494 	(void) sieve_binary_emit_string(sblock, str);
495 }
496 
sieve_opr_string_dump_data(const struct sieve_dumptime_env * denv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name)497 bool sieve_opr_string_dump_data
498 (const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
499 	sieve_size_t *address, const char *field_name)
500 {
501 	const struct sieve_opr_string_interface *intf;
502 
503 	oprnd->field_name = field_name;
504 
505 	if ( !sieve_operand_is_string(oprnd) ) {
506 		sieve_code_dumpf(denv, "ERROR: INVALID STRING OPERAND %s",
507 			sieve_operand_name(oprnd));
508 		return FALSE;
509 	}
510 
511 	intf = (const struct sieve_opr_string_interface *) oprnd->def->interface;
512 
513 	if ( intf->dump == NULL ) {
514 		sieve_code_dumpf(denv, "ERROR: DUMP STRING OPERAND");
515 		return FALSE;
516 	}
517 
518 	return intf->dump(denv, oprnd, address);
519 }
520 
sieve_opr_string_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address,const char * field_name)521 bool sieve_opr_string_dump
522 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
523 	const char *field_name)
524 {
525 	struct sieve_operand operand;
526 
527 	sieve_code_mark(denv);
528 
529 	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
530 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
531 		return FALSE;
532 	}
533 
534 	return sieve_opr_string_dump_data(denv, &operand, address, field_name);
535 }
536 
sieve_opr_string_dump_ex(const struct sieve_dumptime_env * denv,sieve_size_t * address,const char * field_name,const char * omitted_value)537 bool sieve_opr_string_dump_ex
538 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
539 	const char *field_name, const char *omitted_value)
540 {
541 	struct sieve_operand operand;
542 
543 	sieve_code_mark(denv);
544 	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
545 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
546 		return FALSE;
547 	}
548 
549 	if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
550 		if ( *omitted_value != '\0' )
551 			sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
552 		return TRUE;
553 	}
554 
555 	return sieve_opr_string_dump_data(denv, &operand, address, field_name);
556 }
557 
sieve_opr_string_read_data(const struct sieve_runtime_env * renv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name,string_t ** str_r)558 int sieve_opr_string_read_data
559 (const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
560 	sieve_size_t *address, const char *field_name, string_t **str_r)
561 {
562 	const struct sieve_opr_string_interface *intf;
563 
564 	oprnd->field_name = field_name;
565 
566 	if ( !sieve_operand_is_string(oprnd) ) {
567 		sieve_runtime_trace_operand_error(renv, oprnd,
568 			"expected string operand but found %s", sieve_operand_name(oprnd));
569 		return SIEVE_EXEC_BIN_CORRUPT;
570 	}
571 
572 	intf = (const struct sieve_opr_string_interface *) oprnd->def->interface;
573 
574 	if ( intf->read == NULL ) {
575 		sieve_runtime_trace_operand_error(renv, oprnd,
576 			"string operand not implemented");
577 		return SIEVE_EXEC_FAILURE;
578 	}
579 
580 	return intf->read(renv, oprnd, address, str_r);
581 }
582 
sieve_opr_string_read(const struct sieve_runtime_env * renv,sieve_size_t * address,const char * field_name,string_t ** str_r)583 int sieve_opr_string_read
584 (const struct sieve_runtime_env *renv, sieve_size_t *address,
585 	const char *field_name, string_t **str_r)
586 {
587 	struct sieve_operand operand;
588 	int ret;
589 
590 	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
591 		<= 0 )
592 		return ret;
593 
594 	return sieve_opr_string_read_data(renv, &operand, address, field_name, str_r);
595 }
596 
sieve_opr_string_read_ex(const struct sieve_runtime_env * renv,sieve_size_t * address,const char * field_name,bool optional,string_t ** str_r,bool * literal_r)597 int sieve_opr_string_read_ex
598 (const struct sieve_runtime_env *renv, sieve_size_t *address,
599 	const char *field_name, bool optional, string_t **str_r, bool *literal_r)
600 {
601 	struct sieve_operand operand;
602 	int ret;
603 
604 	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
605 		<= 0 )
606 		return ret;
607 
608 	if ( optional && sieve_operand_is_omitted(&operand) ) {
609 		*str_r = NULL;
610 		return 1;
611 	}
612 
613 	if ( literal_r != NULL )
614 		*literal_r = sieve_operand_is_string_literal(&operand);
615 
616 	return sieve_opr_string_read_data(renv, &operand, address, field_name, str_r);
617 }
618 
_dump_string(const struct sieve_dumptime_env * denv,string_t * str,const char * field_name)619 static void _dump_string
620 (const struct sieve_dumptime_env *denv, string_t *str,
621 	const char *field_name)
622 {
623 	if ( str_len(str) > 80 ) {
624 		if ( field_name != NULL )
625 			sieve_code_dumpf(denv, "%s: STR[%ld] \"%s",
626 				field_name, (long) str_len(str), str_sanitize(str_c(str), 80));
627 		else
628 			sieve_code_dumpf(denv, "STR[%ld] \"%s",
629 				(long) str_len(str), str_sanitize(str_c(str), 80));
630 	} else {
631 		if ( field_name != NULL )
632 			sieve_code_dumpf(denv, "%s: STR[%ld] \"%s\"",
633 				field_name, (long) str_len(str), str_sanitize(str_c(str), 80));
634 		else
635 			sieve_code_dumpf(denv, "STR[%ld] \"%s\"",
636 				(long) str_len(str), str_sanitize(str_c(str), 80));
637 	}
638 }
639 
opr_string_dump(const struct sieve_dumptime_env * denv,const struct sieve_operand * oprnd,sieve_size_t * address)640 bool opr_string_dump
641 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
642 	sieve_size_t *address)
643 {
644 	string_t *str;
645 
646 	if ( sieve_binary_read_string(denv->sblock, address, &str) ) {
647 		_dump_string(denv, str, oprnd->field_name);
648 
649 		return TRUE;
650 	}
651 
652 	return FALSE;
653 }
654 
opr_string_read(const struct sieve_runtime_env * renv,const struct sieve_operand * oprnd,sieve_size_t * address,string_t ** str_r)655 static int opr_string_read
656 (const struct sieve_runtime_env *renv, 	const struct sieve_operand *oprnd,
657 	sieve_size_t *address, string_t **str_r)
658 {
659 	if ( !sieve_binary_read_string(renv->sblock, address, str_r) ) {
660 		sieve_runtime_trace_operand_error(renv, oprnd,
661 			"invalid string operand");
662 		return SIEVE_EXEC_BIN_CORRUPT;
663 	}
664 
665 	return SIEVE_EXEC_OK;
666 }
667 
668 /* String list */
669 
sieve_opr_stringlist_emit_start(struct sieve_binary_block * sblock,unsigned int listlen,void ** context)670 void sieve_opr_stringlist_emit_start
671 (struct sieve_binary_block *sblock, unsigned int listlen, void **context)
672 {
673 	sieve_size_t *end_offset = t_new(sieve_size_t, 1);
674 
675 	/* Emit byte identifying the type of operand */
676 	(void) sieve_operand_emit(sblock, NULL, &stringlist_operand);
677 
678 	/* Give the interpreter an easy way to skip over this string list */
679 	*end_offset = sieve_binary_emit_offset(sblock, 0);
680 	*context = (void *) end_offset;
681 
682 	/* Emit the length of the list */
683 	(void) sieve_binary_emit_unsigned(sblock, listlen);
684 }
685 
sieve_opr_stringlist_emit_item(struct sieve_binary_block * sblock,void * context ATTR_UNUSED,string_t * item)686 void sieve_opr_stringlist_emit_item
687 (struct sieve_binary_block *sblock, void *context ATTR_UNUSED, string_t *item)
688 {
689 	(void) sieve_opr_string_emit(sblock, item);
690 }
691 
sieve_opr_stringlist_emit_end(struct sieve_binary_block * sblock,void * context)692 void sieve_opr_stringlist_emit_end
693 (struct sieve_binary_block *sblock, void *context)
694 {
695 	sieve_size_t *end_offset = (sieve_size_t *) context;
696 
697 	(void) sieve_binary_resolve_offset(sblock, *end_offset);
698 }
699 
sieve_opr_stringlist_dump_data(const struct sieve_dumptime_env * denv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name)700 bool sieve_opr_stringlist_dump_data
701 (const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
702 	sieve_size_t *address, const char *field_name)
703 {
704 	if ( oprnd == NULL || oprnd->def == NULL )
705 		return FALSE;
706 
707 	oprnd->field_name = field_name;
708 
709 	if ( oprnd->def->class == &stringlist_class ) {
710 		const struct sieve_opr_stringlist_interface *intf =
711 			(const struct sieve_opr_stringlist_interface *) oprnd->def->interface;
712 
713 		if ( intf->dump == NULL )
714 			return FALSE;
715 
716 		return intf->dump(denv, oprnd, address);
717 	} else if ( oprnd->def->class == &string_class ) {
718 		const struct sieve_opr_string_interface *intf =
719 			(const struct sieve_opr_string_interface *) oprnd->def->interface;
720 
721 		if ( intf->dump == NULL )
722 			return FALSE;
723 
724 		return intf->dump(denv, oprnd, address);
725 	}
726 
727 	return FALSE;
728 }
729 
sieve_opr_stringlist_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address,const char * field_name)730 bool sieve_opr_stringlist_dump
731 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
732 	const char *field_name)
733 {
734 	struct sieve_operand operand;
735 
736 	sieve_code_mark(denv);
737 
738 	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
739 		return FALSE;
740 	}
741 
742 	return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
743 }
744 
sieve_opr_stringlist_dump_ex(const struct sieve_dumptime_env * denv,sieve_size_t * address,const char * field_name,const char * omitted_value)745 bool sieve_opr_stringlist_dump_ex
746 (const struct sieve_dumptime_env *denv, sieve_size_t *address,
747 	const char *field_name, const char *omitted_value)
748 {
749 	struct sieve_operand operand;
750 
751 	sieve_code_mark(denv);
752 
753 	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
754 		return FALSE;
755 	}
756 
757 	if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
758 		if ( *omitted_value != '\0' )
759 			sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
760 		return TRUE;
761 	}
762 
763 	return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
764 }
765 
sieve_opr_stringlist_read_data(const struct sieve_runtime_env * renv,struct sieve_operand * oprnd,sieve_size_t * address,const char * field_name,struct sieve_stringlist ** strlist_r)766 int sieve_opr_stringlist_read_data
767 (const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
768 	sieve_size_t *address, const char *field_name,
769 	struct sieve_stringlist **strlist_r)
770 {
771 	if ( oprnd == NULL || oprnd->def == NULL )
772 		return SIEVE_EXEC_FAILURE;
773 
774 	oprnd->field_name = field_name;
775 
776 	if ( oprnd->def->class == &stringlist_class ) {
777 		const struct sieve_opr_stringlist_interface *intf =
778 			(const struct sieve_opr_stringlist_interface *) oprnd->def->interface;
779 		int ret;
780 
781 		if ( intf->read == NULL ) {
782 			sieve_runtime_trace_operand_error(renv, oprnd,
783 				"stringlist operand not implemented");
784 			return SIEVE_EXEC_FAILURE;
785 		}
786 
787 		if ( (ret=intf->read(renv, oprnd, address, strlist_r)) <= 0 )
788 			return ret;
789 
790 		return SIEVE_EXEC_OK;
791 	} else if ( oprnd->def->class == &string_class ) {
792 		/* Special case, accept single string as string list as well. */
793 		const struct sieve_opr_string_interface *intf =
794 			(const struct sieve_opr_string_interface *) oprnd->def->interface;
795 		int ret;
796 
797 		if ( intf->read == NULL ) {
798 			sieve_runtime_trace_operand_error(renv, oprnd,
799 				"stringlist string operand not implemented");
800 			return SIEVE_EXEC_FAILURE;
801 		}
802 
803 		if ( strlist_r == NULL ) {
804 			if ( (ret=intf->read(renv, oprnd, address, NULL)) <= 0 )
805 				return ret;
806 		} else {
807 			string_t *stritem;
808 			if ( (ret=intf->read(renv, oprnd, address, &stritem)) <= 0 )
809 				return ret;
810 
811 			*strlist_r = sieve_single_stringlist_create
812 				(renv, stritem, FALSE);
813 		}
814 		return SIEVE_EXEC_OK;
815 	}
816 
817 	sieve_runtime_trace_operand_error(renv, oprnd,
818 		"expected stringlist or string operand but found %s",
819 		sieve_operand_name(oprnd));
820 	return SIEVE_EXEC_BIN_CORRUPT;
821 }
822 
sieve_opr_stringlist_read(const struct sieve_runtime_env * renv,sieve_size_t * address,const char * field_name,struct sieve_stringlist ** strlist_r)823 int sieve_opr_stringlist_read
824 (const struct sieve_runtime_env *renv, sieve_size_t *address,
825 	const char *field_name, struct sieve_stringlist **strlist_r)
826 {
827 	struct sieve_operand operand;
828 	int ret;
829 
830 	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
831 		<= 0 )
832 		return ret;
833 
834 	return sieve_opr_stringlist_read_data
835 		(renv, &operand, address, field_name, strlist_r);
836 }
837 
sieve_opr_stringlist_read_ex(const struct sieve_runtime_env * renv,sieve_size_t * address,const char * field_name,bool optional,struct sieve_stringlist ** strlist_r)838 int sieve_opr_stringlist_read_ex
839 (const struct sieve_runtime_env *renv, sieve_size_t *address,
840 	const char *field_name, bool optional, struct sieve_stringlist **strlist_r)
841 {
842 	struct sieve_operand operand;
843 	int ret;
844 
845 	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
846 		<= 0 )
847 		return ret;
848 
849 	if ( optional && sieve_operand_is_omitted(&operand) ) {
850 		*strlist_r = NULL;
851 		return 1;
852 	}
853 
854 	return sieve_opr_stringlist_read_data
855 		(renv, &operand, address, field_name, strlist_r);
856 }
857 
opr_stringlist_dump(const struct sieve_dumptime_env * denv,const struct sieve_operand * oprnd,sieve_size_t * address)858 static bool opr_stringlist_dump
859 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
860 	sieve_size_t *address)
861 {
862 	sieve_size_t pc = *address;
863 	sieve_size_t end;
864 	unsigned int length = 0;
865  	sieve_offset_t end_offset;
866 
867 	if ( !sieve_binary_read_offset(denv->sblock, address, &end_offset) )
868 		return FALSE;
869 
870 	end = pc + end_offset;
871 
872 	if ( !sieve_binary_read_unsigned(denv->sblock, address, &length) )
873 		return FALSE;
874 
875 	return sieve_code_stringlist_dump
876 		(denv, address, length, end, oprnd->field_name);
877 }
878 
opr_stringlist_read(const struct sieve_runtime_env * renv,const struct sieve_operand * oprnd,sieve_size_t * address,struct sieve_stringlist ** strlist_r)879 static int opr_stringlist_read
880 (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
881 	sieve_size_t *address, struct sieve_stringlist **strlist_r)
882 {
883 	sieve_size_t pc = *address;
884 	sieve_size_t end;
885 	unsigned int length = 0;
886 	sieve_offset_t end_offset;
887 
888 	if ( !sieve_binary_read_offset(renv->sblock, address, &end_offset) ) {
889 		sieve_runtime_trace_operand_error(renv, oprnd,
890 			"stringlist corrupt: invalid end offset");
891 		return SIEVE_EXEC_BIN_CORRUPT;
892 	}
893 
894 	end = pc + end_offset;
895 
896 	if ( !sieve_binary_read_unsigned(renv->sblock, address, &length) ) {
897 		sieve_runtime_trace_operand_error(renv, oprnd,
898 			"stringlist corrupt: invalid length data");
899 		return SIEVE_EXEC_BIN_CORRUPT;
900 	}
901 
902 	if ( strlist_r != NULL )
903 		*strlist_r = sieve_code_stringlist_create
904 			(renv, *address, (unsigned int) length, end);
905 
906 	/* Skip over the string list for now */
907 	*address = end;
908 
909 	return SIEVE_EXEC_OK;
910 }
911 
912 /* Catenated String */
913 
sieve_opr_catenated_string_emit(struct sieve_binary_block * sblock,unsigned int elements)914 void sieve_opr_catenated_string_emit
915 (struct sieve_binary_block *sblock, unsigned int elements)
916 {
917 	(void) sieve_operand_emit(sblock, NULL, &catenated_string_operand);
918 	(void) sieve_binary_emit_unsigned(sblock, elements);
919 }
920 
opr_catenated_string_dump(const struct sieve_dumptime_env * denv,const struct sieve_operand * oprnd,sieve_size_t * address)921 static bool opr_catenated_string_dump
922 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
923 	sieve_size_t *address)
924 {
925 	unsigned int elements = 0;
926 	unsigned int i;
927 
928 	if ( !sieve_binary_read_unsigned(denv->sblock, address, &elements) )
929 		return FALSE;
930 
931 	if ( oprnd->field_name != NULL )
932 		sieve_code_dumpf(denv, "%s: CAT-STR [%ld]:",
933 			oprnd->field_name, (long) elements);
934 	else
935 		sieve_code_dumpf(denv, "CAT-STR [%ld]:", (long) elements);
936 
937 	sieve_code_descend(denv);
938 	for ( i = 0; i < (unsigned int) elements; i++ ) {
939 		if ( !sieve_opr_string_dump(denv, address, NULL) )
940 			return FALSE;
941 	}
942 	sieve_code_ascend(denv);
943 
944 	return TRUE;
945 }
946 
opr_catenated_string_read(const struct sieve_runtime_env * renv,const struct sieve_operand * oprnd,sieve_size_t * address,string_t ** str)947 static int opr_catenated_string_read
948 (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
949 	sieve_size_t *address, string_t **str)
950 {
951 	unsigned int elements = 0;
952 	unsigned int i;
953 	int ret;
954 
955 	if ( !sieve_binary_read_unsigned(renv->sblock, address, &elements) ) {
956 		sieve_runtime_trace_operand_error(renv, oprnd,
957 			"catenated string corrupt: invalid element count data");
958 		return SIEVE_EXEC_BIN_CORRUPT;
959 	}
960 
961 	/* Parameter str can be NULL if we are requested to only skip and not
962 	 * actually read the argument.
963 	 */
964 	if ( str == NULL ) {
965 		for ( i = 0; i < (unsigned int) elements; i++ ) {
966 			if ( (ret=sieve_opr_string_read(renv, address, NULL, NULL)) <= 0 )
967 				return ret;
968 		}
969 	} else {
970 		string_t *strelm;
971 		string_t **elm = &strelm;
972 
973 		*str = t_str_new(128);
974 		for ( i = 0; i < (unsigned int) elements; i++ ) {
975 
976 			if ( (ret=sieve_opr_string_read(renv, address, NULL, elm)) <= 0 )
977 				return ret;
978 
979 			if ( elm != NULL ) {
980 				str_append_str(*str, strelm);
981 
982 				if ( str_len(*str) > SIEVE_MAX_STRING_LEN ) {
983 					str_truncate(*str, SIEVE_MAX_STRING_LEN);
984 					elm = NULL;
985 				}
986 			}
987 		}
988 	}
989 
990 	return SIEVE_EXEC_OK;
991 }
992 
993 /*
994  * Core operations
995  */
996 
997 /* Forward declarations */
998 
999 static bool opc_jmp_dump
1000 	(const struct sieve_dumptime_env *denv, sieve_size_t *address);
1001 
1002 static int opc_jmp_execute
1003 	(const struct sieve_runtime_env *renv, sieve_size_t *address);
1004 static int opc_jmptrue_execute
1005 	(const struct sieve_runtime_env *renv, sieve_size_t *address);
1006 static int opc_jmpfalse_execute
1007 	(const struct sieve_runtime_env *renv, sieve_size_t *address);
1008 
1009 /* Operation objects defined in this file */
1010 
1011 const struct sieve_operation_def sieve_jmp_operation = {
1012 	.mnemonic = "JMP",
1013 	.code = SIEVE_OPERATION_JMP,
1014 	.dump = opc_jmp_dump,
1015 	.execute = opc_jmp_execute
1016 };
1017 
1018 const struct sieve_operation_def sieve_jmptrue_operation = {
1019 	.mnemonic = "JMPTRUE",
1020 	.code = SIEVE_OPERATION_JMPTRUE,
1021 	.dump = opc_jmp_dump,
1022 	.execute = opc_jmptrue_execute
1023 };
1024 
1025 const struct sieve_operation_def sieve_jmpfalse_operation = {
1026 	.mnemonic = "JMPFALSE",
1027 	.code = SIEVE_OPERATION_JMPFALSE,
1028 	.dump = opc_jmp_dump,
1029 	.execute = opc_jmpfalse_execute
1030 };
1031 
1032 /* Operation objects defined in other files */
1033 
1034 extern const struct sieve_operation_def cmd_stop_operation;
1035 extern const struct sieve_operation_def cmd_keep_operation;
1036 extern const struct sieve_operation_def cmd_discard_operation;
1037 extern const struct sieve_operation_def cmd_redirect_operation;
1038 
1039 extern const struct sieve_operation_def tst_address_operation;
1040 extern const struct sieve_operation_def tst_header_operation;
1041 extern const struct sieve_operation_def tst_exists_operation;
1042 extern const struct sieve_operation_def tst_size_over_operation;
1043 extern const struct sieve_operation_def tst_size_under_operation;
1044 
1045 const struct sieve_operation_def *sieve_operations[] = {
1046 	NULL,
1047 
1048 	&sieve_jmp_operation,
1049 	&sieve_jmptrue_operation,
1050 	&sieve_jmpfalse_operation,
1051 
1052 	&cmd_stop_operation,
1053 	&cmd_keep_operation,
1054 	&cmd_discard_operation,
1055 	&cmd_redirect_operation,
1056 
1057 	&tst_address_operation,
1058 	&tst_header_operation,
1059 	&tst_exists_operation,
1060 	&tst_size_over_operation,
1061 	&tst_size_under_operation
1062 };
1063 
1064 const unsigned int sieve_operation_count =
1065 	N_ELEMENTS(sieve_operations);
1066 
1067 /*
1068  * Operation functions
1069  */
1070 
sieve_operation_emit(struct sieve_binary_block * sblock,const struct sieve_extension * ext,const struct sieve_operation_def * op_def)1071 sieve_size_t sieve_operation_emit
1072 (struct sieve_binary_block *sblock, const struct sieve_extension *ext,
1073 	const struct sieve_operation_def *op_def)
1074 {
1075 	sieve_size_t address;
1076 
1077   if ( ext != NULL ) {
1078 		i_assert( op_def->ext_def != NULL );
1079 		address = sieve_binary_emit_extension
1080 			(sblock, ext, sieve_operation_count);
1081 
1082 		sieve_binary_emit_extension_object
1083 			(sblock, &op_def->ext_def->operations, op_def->code);
1084 		return address;
1085   }
1086 
1087 	i_assert( op_def->ext_def == NULL );
1088   return sieve_binary_emit_byte(sblock, op_def->code);
1089 }
1090 
sieve_operation_read(struct sieve_binary_block * sblock,sieve_size_t * address,struct sieve_operation * oprtn)1091 bool sieve_operation_read
1092 (struct sieve_binary_block *sblock, sieve_size_t *address,
1093 	struct sieve_operation *oprtn)
1094 {
1095 	unsigned int code = sieve_operation_count;
1096 
1097 	oprtn->address = *address;
1098 	oprtn->def = NULL;
1099 	oprtn->ext = NULL;
1100 
1101 	if ( !sieve_binary_read_extension(sblock, address, &code, &oprtn->ext) )
1102 		return FALSE;
1103 
1104 	if ( oprtn->ext == NULL ) {
1105 		if ( code < sieve_operation_count ) {
1106 			oprtn->def = sieve_operations[code];
1107 		}
1108 
1109 		return ( oprtn->def != NULL );
1110 	}
1111 
1112 	oprtn->def = (const struct sieve_operation_def *)
1113 		sieve_binary_read_extension_object(sblock, address,
1114 			&oprtn->ext->def->operations);
1115 
1116 	return ( oprtn->def != NULL );
1117 }
1118 
1119 /*
1120  * Jump operations
1121  */
1122 
1123 /* Code dump */
1124 
opc_jmp_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address)1125 static bool opc_jmp_dump
1126 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
1127 {
1128 	const struct sieve_operation *oprtn = denv->oprtn;
1129 	unsigned int pc = *address;
1130 	sieve_offset_t offset;
1131 
1132 	if ( sieve_binary_read_offset(denv->sblock, address, &offset) )
1133 		sieve_code_dumpf(denv, "%s %d [%08x]",
1134 			sieve_operation_mnemonic(oprtn), offset, pc + offset);
1135 	else
1136 		return FALSE;
1137 
1138 	return TRUE;
1139 }
1140 
1141 /* Code execution */
1142 
opc_jmp_execute(const struct sieve_runtime_env * renv,sieve_size_t * address ATTR_UNUSED)1143 static int opc_jmp_execute
1144 (const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
1145 {
1146 	return sieve_interpreter_program_jump(renv->interp, TRUE, FALSE);
1147 }
1148 
opc_jmptrue_execute(const struct sieve_runtime_env * renv,sieve_size_t * address ATTR_UNUSED)1149 static int opc_jmptrue_execute
1150 (const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
1151 {
1152 	bool result = sieve_interpreter_get_test_result(renv->interp);
1153 
1154 	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is true");
1155 	sieve_runtime_trace_descend(renv);
1156 
1157 	return sieve_interpreter_program_jump(renv->interp, result, FALSE);
1158 }
1159 
opc_jmpfalse_execute(const struct sieve_runtime_env * renv,sieve_size_t * address ATTR_UNUSED)1160 static int opc_jmpfalse_execute
1161 (const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
1162 {
1163 	bool result = sieve_interpreter_get_test_result(renv->interp);
1164 
1165 	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is false");
1166 	sieve_runtime_trace_descend(renv);
1167 
1168 	return sieve_interpreter_program_jump(renv->interp, !result, FALSE);
1169 }
1170