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