Coverage Report

Created: 2026-08-08 06:43

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