Taint: check on supplied buffer vs. list when extracting elements
[exim.git] / src / src / filter.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8
9/* Code for mail filtering functions. */
10
11#include "exim.h"
12
13
14/* Command arguments and left/right points in conditions can contain different
15types of data, depending on the particular command or condition. Originally,
16(void *) was used as "any old type", with casts, but this gives trouble and
17warnings in some environments. So now it is done "properly", with a union. We
18need to declare the structures first because some of them are recursive. */
19
20struct filter_cmd;
21struct condition_block;
22
23union argtypes {
24 struct string_item *a;
25 BOOL b;
26 struct condition_block *c;
27 struct filter_cmd *f;
28 int i;
29 uschar *u;
30};
31
32/* Local structures used in this module */
33
34typedef struct filter_cmd {
35 struct filter_cmd *next;
36 int command;
37 BOOL seen;
38 BOOL noerror;
39 union argtypes args[1];
40} filter_cmd;
41
42typedef struct condition_block {
43 struct condition_block *parent;
44 int type;
45 BOOL testfor;
46 union argtypes left;
47 union argtypes right;
48} condition_block;
49
50/* Miscellaneous other declarations */
51
52static uschar **error_pointer;
53static uschar *log_filename;
54static int filter_options;
55static int line_number;
56static int expect_endif;
57static int had_else_endif;
58static int log_fd;
59static int log_mode;
60static int output_indent;
61static BOOL filter_delivered;
62static BOOL finish_obeyed;
63static BOOL seen_force;
64static BOOL seen_value;
65static BOOL noerror_force;
66
67enum { had_neither, had_else, had_elif, had_endif };
68
69static BOOL read_command_list(uschar **, filter_cmd ***, BOOL);
70
71
72/* The string arguments for the mail command. The header line ones (that are
73permitted to include \n followed by white space) first, and then the body text
74one (it can have \n anywhere). Then the file names and once_repeat, which may
75not contain \n. */
76
1ba28e2b
PP
77static const char *mailargs[] = { /* "to" must be first, and */
78 "to", /* "cc" and "bcc" must follow */
059ec3d9
PH
79 "cc",
80 "bcc",
81 "from",
82 "reply_to",
83 "subject",
84 "extra_headers", /* miscellaneous added header lines */
85 "text",
86 "file",
87 "log",
88 "once",
89 "once_repeat"
90};
91
92/* The count of string arguments */
93
5903c6ff 94#define MAILARGS_STRING_COUNT (nelem(mailargs))
059ec3d9
PH
95
96/* The count of string arguments that are actually passed over as strings
97(once_repeat is converted to an int). */
98
99#define mailargs_string_passed (MAILARGS_STRING_COUNT - 1)
100
101/* This defines the offsets for the arguments; first the string ones, and
102then the non-string ones. The order must be as above. */
103
104enum { mailarg_index_to,
105 mailarg_index_cc,
106 mailarg_index_bcc,
107 mailarg_index_from,
108 mailarg_index_reply_to,
109 mailarg_index_subject,
110 mailarg_index_headers, /* misc headers must be last */
111 mailarg_index_text, /* text is first after headers */
112 mailarg_index_file, /* between text and expand are filenames */
113 mailarg_index_log,
114 mailarg_index_once,
115 mailarg_index_once_repeat, /* a time string */
116 mailarg_index_expand, /* first non-string argument */
117 mailarg_index_return,
118 mailargs_total /* total number of arguments */
119 };
120
121/* Offsets in the data structure for the string arguments (note that
122once_repeat isn't a string argument at this point.) */
123
124static int reply_offsets[] = { /* must be in same order as above */
125 offsetof(reply_item, to),
126 offsetof(reply_item, cc),
127 offsetof(reply_item, bcc),
128 offsetof(reply_item, from),
129 offsetof(reply_item, reply_to),
130 offsetof(reply_item, subject),
131 offsetof(reply_item, headers),
132 offsetof(reply_item, text),
133 offsetof(reply_item, file),
134 offsetof(reply_item, logfile),
135 offsetof(reply_item, oncelog),
136};
137
138/* Condition identities and names, with negated versions for some
139of them. */
140
141enum { cond_and, cond_or, cond_personal, cond_begins, cond_BEGINS,
142 cond_ends, cond_ENDS, cond_is, cond_IS, cond_matches,
143 cond_MATCHES, cond_contains, cond_CONTAINS, cond_delivered,
144 cond_above, cond_below, cond_errormsg, cond_firsttime,
145 cond_manualthaw, cond_foranyaddress };
146
1ba28e2b 147static const char *cond_names[] = {
059ec3d9
PH
148 "and", "or", "personal",
149 "begins", "BEGINS", "ends", "ENDS",
150 "is", "IS", "matches", "MATCHES", "contains",
151 "CONTAINS", "delivered", "above", "below", "error_message",
152 "first_delivery", "manually_thawed", "foranyaddress" };
153
1ba28e2b 154static const char *cond_not_names[] = {
059ec3d9
PH
155 "", "", "not personal",
156 "does not begin", "does not BEGIN",
157 "does not end", "does not END",
158 "is not", "IS not", "does not match",
159 "does not MATCH", "does not contain", "does not CONTAIN",
160 "not delivered", "not above", "not below", "not error_message",
161 "not first_delivery", "not manually_thawed", "not foranyaddress" };
162
163/* Tables of binary condition words and their corresponding types. Not easy
164to amalgamate with the above because of the different variants. */
165
1ba28e2b 166static const char *cond_words[] = {
059ec3d9
PH
167 "BEGIN",
168 "BEGINS",
169 "CONTAIN",
170 "CONTAINS",
171 "END",
172 "ENDS",
173 "IS",
174 "MATCH",
175 "MATCHES",
176 "above",
177 "begin",
178 "begins",
179 "below",
180 "contain",
181 "contains",
182 "end",
183 "ends",
184 "is",
185 "match",
186 "matches"};
187
5903c6ff 188static int cond_word_count = nelem(cond_words);
059ec3d9
PH
189
190static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
191 cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
192 cond_above, cond_begins, cond_begins, cond_below, cond_contains,
193 cond_contains, cond_ends, cond_ends, cond_is, cond_matches, cond_matches };
194
195/* Command identities: must be kept in step with the list of command words
196and the list of expanded argument counts which follow. */
197
198enum { add_command, defer_command, deliver_command, elif_command, else_command,
199 endif_command, finish_command, fail_command, freeze_command,
200 headers_command, if_command, logfile_command, logwrite_command,
201 mail_command, noerror_command, pipe_command, save_command, seen_command,
202 testprint_command, unseen_command, vacation_command };
203
1ba28e2b 204static const char *command_list[] = {
059ec3d9
PH
205 "add", "defer", "deliver", "elif", "else", "endif", "finish",
206 "fail", "freeze", "headers", "if", "logfile", "logwrite", "mail",
207 "noerror", "pipe", "save", "seen", "testprint", "unseen", "vacation"
208};
209
5903c6ff 210static int command_list_count = nelem(command_list);
059ec3d9
PH
211
212/* This table contains the number of expanded arguments in the bottom 4 bits.
213If the top bit is set, it means that the default for the command is "seen". */
214
215static uschar command_exparg_count[] = {
216 2, /* add */
217 1, /* defer */
218 128+2, /* deliver */
219 0, /* elif */
220 0, /* else */
221 0, /* endif */
222 0, /* finish */
223 1, /* fail */
224 1, /* freeze */
225 1, /* headers */
226 0, /* if */
227 1, /* logfile */
228 1, /* logwrite */
229 MAILARGS_STRING_COUNT, /* mail */
230 0, /* noerror */
231 128+0, /* pipe */
232 128+1, /* save */
233 0, /* seen */
234 1, /* testprint */
235 0, /* unseen */
236 MAILARGS_STRING_COUNT /* vacation */
237};
238
239
240
241/*************************************************
242* Find next significant uschar *
243*************************************************/
244
245/* Function to skip over white space and, optionally, comments.
246
247Arguments:
248 ptr pointer to next character
249 comment_allowed if TRUE, comments (# to \n) are skipped
250
251Returns: pointer to next non-whitespace character
252*/
253
254static uschar *
255nextsigchar(uschar *ptr, BOOL comment_allowed)
256{
257for (;;)
258 {
259 while (isspace(*ptr))
260 {
261 if (*ptr == '\n') line_number++;
262 ptr++;
263 }
264 if (comment_allowed && *ptr == '#')
265 {
266 while (*(++ptr) != '\n' && *ptr != 0);
267 continue;
268 }
269 else break;
270 }
271return ptr;
272}
273
274
275
276/*************************************************
277* Read one word *
278*************************************************/
279
280/* The terminator is white space unless bracket is TRUE, in which
281case ( and ) terminate.
282
283Arguments
284 ptr pointer to next character
285 buffer where to put the word
286 size size of buffer
287 bracket if TRUE, terminate on ( and ) as well as space
288
289Returns: pointer to the next significant character after the word
290*/
291
292static uschar *
293nextword(uschar *ptr, uschar *buffer, int size, BOOL bracket)
294{
295uschar *bp = buffer;
296while (*ptr != 0 && !isspace(*ptr) &&
297 (!bracket || (*ptr != '(' && *ptr != ')')))
298 {
299 if (bp - buffer < size - 1) *bp++ = *ptr++; else
300 {
301 *error_pointer = string_sprintf("word is too long in line %d of "
302 "filter file (max = %d chars)", line_number, size);
303 break;
304 }
305 }
306*bp = 0;
307return nextsigchar(ptr, TRUE);
308}
309
310
311
312/*************************************************
313* Read one item *
314*************************************************/
315
316/* Might be a word, or might be a quoted string; in the latter case
317do the escape stuff.
318
319Arguments:
320 ptr pointer to next character
321 buffer where to put the item
322 size size of buffer
323 bracket if TRUE, terminate non-quoted on ( and ) as well as space
324
325Returns: the next significant character after the item
326*/
327
328static uschar *
329nextitem(uschar *ptr, uschar *buffer, int size, BOOL bracket)
330{
331uschar *bp = buffer;
332if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
333
334while (*(++ptr) != 0 && *ptr != '\"' && *ptr != '\n')
335 {
336 if (bp - buffer >= size - 1)
337 {
338 *error_pointer = string_sprintf("string is too long in line %d of "
339 "filter file (max = %d chars)", line_number, size);
340 break;
341 }
342
343 if (*ptr != '\\') *bp++ = *ptr; else
344 {
345 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
346 {
347 uschar *p = ptr + 1;
348 while (*p != '\n' && isspace(*p)) p++;
349 if (*p == '\n')
350 {
351 line_number++;
352 ptr = p;
353 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
354 continue;
355 }
356 }
357
55414b25 358 *bp++ = string_interpret_escape(CUSS &ptr);
059ec3d9
PH
359 }
360 }
361
362if (*ptr == '\"') ptr++;
363 else if (*error_pointer == NULL)
364 *error_pointer = string_sprintf("quote missing at end of string "
365 "in line %d", line_number);
366
367*bp = 0;
368return nextsigchar(ptr, TRUE);
369}
370
371
372
373
374/*************************************************
375* Convert a string + K|M to a number *
376*************************************************/
377
378/*
379Arguments:
380 s points to text string
381 OK set TRUE if a valid number was read
382
383Returns: the number, or 0 on error (with *OK FALSE)
384*/
385
386static int
387get_number(uschar *s, BOOL *ok)
388{
389int value, count;
390*ok = FALSE;
391if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
392if (tolower(s[count]) == 'k') { value *= 1024; count++; }
393if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
394while (isspace((s[count]))) count++;
395if (s[count] != 0) return 0;
396*ok = TRUE;
397return value;
398}
399
400
401
402/*************************************************
403* Read one condition *
404*************************************************/
405
406/* A complete condition must be terminated by "then"; bracketed internal
407conditions must be terminated by a closing bracket. They are read by calling
408this function recursively.
409
410Arguments:
411 ptr points to start of condition
412 condition_block where to hang the created condition block
413 toplevel TRUE when called at the top level
414
415Returns: points to next character after "then"
416*/
417
418static uschar *
419read_condition(uschar *ptr, condition_block **cond, BOOL toplevel)
420{
421uschar buffer[1024];
422BOOL testfor = TRUE;
423condition_block *current_parent = NULL;
424condition_block **current = cond;
425
426*current = NULL;
427
428/* Loop to read next condition */
429
430for (;;)
431 {
432 condition_block *c;
433
434 /* reaching the end of the input is an error. */
435
436 if (*ptr == 0)
437 {
f3ebb786 438 *error_pointer = US"\"then\" missing at end of filter file";
059ec3d9
PH
439 break;
440 }
441
442 /* Opening bracket at the start of a condition introduces a nested
443 condition, which must be terminated by a closing bracket. */
444
445 if (*ptr == '(')
446 {
447 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
448 if (*error_pointer != NULL) break;
449 if (*ptr != ')')
450 {
451 *error_pointer = string_sprintf("expected \")\" in line %d of "
452 "filter file", line_number);
453 break;
454 }
455 if (!testfor)
456 {
457 c->testfor = !c->testfor;
458 testfor = TRUE;
459 }
460 ptr = nextsigchar(ptr+1, TRUE);
461 }
462
463
464 /* Closing bracket at the start of a condition is an error. Give an
465 explicit message, as otherwise "unknown condition" would be confusing. */
466
467 else if (*ptr == ')')
468 {
469 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
470 "filter file", line_number);
471 break;
472 }
473
474 /* Otherwise we expect a word or a string. */
475
476 else
477 {
478 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
479 if (*error_pointer != NULL) break;
480
481 /* "Then" at the start of a condition is an error */
482
483 if (Ustrcmp(buffer, "then") == 0)
484 {
485 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
486 "filter file", line_number);
487 break;
488 }
489
490 /* "Not" at the start of a condition negates the testing condition. */
491
492 if (Ustrcmp(buffer, "not") == 0)
493 {
494 testfor = !testfor;
495 continue;
496 }
497
498 /* Build a condition block from the specific word. */
499
f3ebb786 500 c = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
501 c->left.u = c->right.u = NULL;
502 c->testfor = testfor;
503 testfor = TRUE;
504
505 /* Check for conditions that start with a keyword */
506
507 if (Ustrcmp(buffer, "delivered") == 0) c->type = cond_delivered;
508 else if (Ustrcmp(buffer, "error_message") == 0) c->type = cond_errormsg;
509 else if (Ustrcmp(buffer, "first_delivery") == 0) c->type = cond_firsttime;
510 else if (Ustrcmp(buffer, "manually_thawed") == 0) c->type = cond_manualthaw;
511
512 /* Personal can be followed by any number of aliases */
513
514 else if (Ustrcmp(buffer, "personal") == 0)
515 {
516 c->type = cond_personal;
517 for (;;)
518 {
519 string_item *aa;
520 uschar *saveptr = ptr;
521 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 522 if (*error_pointer) break;
059ec3d9
PH
523 if (Ustrcmp(buffer, "alias") != 0)
524 {
525 ptr = saveptr;
526 break;
527 }
528 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 529 if (*error_pointer) break;
f3ebb786 530 aa = store_get(sizeof(string_item), FALSE);
059ec3d9
PH
531 aa->text = string_copy(buffer);
532 aa->next = c->left.a;
533 c->left.a = aa;
534 }
535 }
536
537 /* Foranyaddress must be followed by a string and a condition enclosed
538 in parentheses, which is handled as a subcondition. */
539
540 else if (Ustrcmp(buffer, "foranyaddress") == 0)
541 {
542 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 543 if (*error_pointer) break;
059ec3d9
PH
544 if (*ptr != '(')
545 {
546 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
547 "near line %d of filter file", line_number);
548 break;
549 }
550
551 c->type = cond_foranyaddress;
552 c->left.u = string_copy(buffer);
553
554 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
4dc2379a 555 if (*error_pointer) break;
059ec3d9
PH
556 if (*ptr != ')')
557 {
558 *error_pointer = string_sprintf("expected \")\" in line %d of "
559 "filter file", line_number);
560 break;
561 }
059ec3d9
PH
562 ptr = nextsigchar(ptr+1, TRUE);
563 }
564
565 /* If it's not a word we recognize, then it must be the lefthand
566 operand of one of the comparison words. */
567
568 else
569 {
570 int i;
571 uschar *isptr = NULL;
572
573 c->left.u = string_copy(buffer);
574 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 575 if (*error_pointer) break;
059ec3d9
PH
576
577 /* Handle "does|is [not]", preserving the pointer after "is" in
578 case it isn't that, but the form "is <string>". */
579
580 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
581 {
582 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
583 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
584
585 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 586 if (*error_pointer) break;
059ec3d9
PH
587 if (strcmpic(buffer, US"not") == 0)
588 {
589 c->testfor = !c->testfor;
4dc2379a 590 if (isptr) isptr = ptr;
059ec3d9 591 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 592 if (*error_pointer) break;
059ec3d9
PH
593 }
594 }
595
596 for (i = 0; i < cond_word_count; i++)
597 {
598 if (Ustrcmp(buffer, cond_words[i]) == 0)
599 {
600 c->type = cond_types[i];
601 break;
602 }
603 }
604
605 /* If an unknown word follows "is" or "is not"
606 it's actually the argument. Reset to read it. */
607
608 if (i >= cond_word_count)
609 {
4dc2379a 610 if (!isptr)
059ec3d9
PH
611 {
612 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
613 "near line %d of filter file", buffer, line_number);
614 break;
615 }
4dc2379a 616 ptr = isptr;
059ec3d9
PH
617 }
618
619 /* Get the RH argument. */
620
621 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 622 if (*error_pointer) break;
059ec3d9
PH
623 c->right.u = string_copy(buffer);
624 }
625 }
626
627 /* We have read some new condition and set it up in the condition block
628 c; point the current pointer at it, and then deal with what follows. */
629
630 *current = c;
631
632 /* Closing bracket terminates if this is a lower-level condition. Otherwise
633 it is unexpected. */
634
635 if (*ptr == ')')
636 {
637 if (toplevel)
638 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
639 "filter file", line_number);
640 break;
641 }
642
643 /* Opening bracket following a condition is an error; give an explicit
644 message to make it clearer what is wrong. */
645
646 else if (*ptr == '(')
647 {
648 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
649 "filter file", line_number);
650 break;
651 }
652
653 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
654
655 else
656 {
657 uschar *saveptr = ptr;
658 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
4dc2379a 659 if (*error_pointer) break;
059ec3d9
PH
660
661 /* "Then" terminates a toplevel condition; otherwise a closing bracket
662 has been omitted. Put a string terminator at the start of "then" so
663 that reflecting the condition can be done when testing. */
664
665 if (Ustrcmp(buffer, "then") == 0)
666 {
667 if (toplevel) *saveptr = 0;
4dc2379a 668 else *error_pointer = string_sprintf("missing \")\" at end of "
059ec3d9
PH
669 "condition near line %d of filter file", line_number);
670 break;
671 }
672
673 /* "And" causes a new condition block to replace the one we have
674 just read, which becomes the left sub-condition. The current pointer
675 is reset to the pointer for the right sub-condition. We have to keep
676 track of the tree of sequential "ands", so as to traverse back up it
677 if an "or" is met. */
678
679 else if (Ustrcmp(buffer, "and") == 0)
680 {
f3ebb786 681 condition_block *andc = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
682 andc->parent = current_parent;
683 andc->type = cond_and;
684 andc->testfor = TRUE;
685 andc->left.c = c;
686 andc->right.u = NULL; /* insurance */
687 *current = andc;
688 current = &(andc->right.c);
689 current_parent = andc;
690 }
691
692 /* "Or" is similar, but has to be done a bit more carefully to
693 ensure that "and" is more binding. If there's a parent set, we
694 are following a sequence of "and"s and must track back to their
695 start. */
696
697 else if (Ustrcmp(buffer, "or") == 0)
698 {
f3ebb786 699 condition_block *orc = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
700 condition_block *or_parent = NULL;
701
4dc2379a 702 if (current_parent)
059ec3d9 703 {
4dc2379a 704 while (current_parent->parent &&
059ec3d9
PH
705 current_parent->parent->type == cond_and)
706 current_parent = current_parent->parent;
707
708 /* If the parent has a parent, it must be an "or" parent. */
709
4dc2379a 710 if (current_parent->parent)
059ec3d9
PH
711 or_parent = current_parent->parent;
712 }
713
714 orc->parent = or_parent;
4dc2379a
JH
715 if (!or_parent) *cond = orc;
716 else or_parent->right.c = orc;
059ec3d9
PH
717 orc->type = cond_or;
718 orc->testfor = TRUE;
719 orc->left.c = (current_parent == NULL)? c : current_parent;
720 orc->right.c = NULL; /* insurance */
721 current = &(orc->right.c);
722 current_parent = orc;
723 }
724
725 /* Otherwise there is a disaster */
726
727 else
728 {
729 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
730 "expected near line %d of filter file, but found \"%s\"",
731 toplevel? "then" : ")", line_number, buffer);
732 break;
733 }
734 }
735 }
736
737return nextsigchar(ptr, TRUE);
738}
739
740
741
742/*************************************************
4c04137d 743* Output the current indent *
059ec3d9
PH
744*************************************************/
745
746static void
747indent(void)
748{
749int i;
750for (i = 0; i < output_indent; i++) debug_printf(" ");
751}
752
753
754
755/*************************************************
756* Condition printer: for debugging *
757*************************************************/
758
759/*
760Arguments:
761 c the block at the top of the tree
762 toplevel TRUE at toplevel - stops overall brackets
763
764Returns: nothing
765*/
766
767static void
768print_condition(condition_block *c, BOOL toplevel)
769{
1ba28e2b 770const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
059ec3d9
PH
771switch(c->type)
772 {
773 case cond_personal:
774 case cond_delivered:
775 case cond_errormsg:
776 case cond_firsttime:
777 case cond_manualthaw:
778 debug_printf("%s", name);
779 break;
780
781 case cond_is:
782 case cond_IS:
783 case cond_matches:
784 case cond_MATCHES:
785 case cond_contains:
786 case cond_CONTAINS:
787 case cond_begins:
788 case cond_BEGINS:
789 case cond_ends:
790 case cond_ENDS:
791 case cond_above:
792 case cond_below:
1ba28e2b 793 debug_printf("%s %s %s", c->left.u, name, c->right.u);
059ec3d9
PH
794 break;
795
796 case cond_and:
797 if (!c->testfor) debug_printf("not (");
798 print_condition(c->left.c, FALSE);
799 debug_printf(" %s ", cond_names[c->type]);
800 print_condition(c->right.c, FALSE);
801 if (!c->testfor) debug_printf(")");
802 break;
803
804 case cond_or:
805 if (!c->testfor) debug_printf("not (");
806 else if (!toplevel) debug_printf("(");
807 print_condition(c->left.c, FALSE);
808 debug_printf(" %s ", cond_names[c->type]);
809 print_condition(c->right.c, FALSE);
810 if (!toplevel || !c->testfor) debug_printf(")");
811 break;
812
813 case cond_foranyaddress:
814 debug_printf("%s %s (", name, c->left.u);
815 print_condition(c->right.c, FALSE);
816 debug_printf(")");
817 break;
818 }
819}
820
821
822
823
824/*************************************************
825* Read one filtering command *
826*************************************************/
827
828/*
829Arguments:
830 pptr points to pointer to first character of command; the pointer
831 is updated to point after the last character read
832 lastcmdptr points to pointer to pointer to last command; used for hanging
833 on the newly read command
834
835Returns: TRUE if command successfully read, else FALSE
836*/
837
838static BOOL
839read_command(uschar **pptr, filter_cmd ***lastcmdptr)
840{
841int command, i, cmd_bit;
842filter_cmd *new, **newlastcmdptr;
843BOOL yield = TRUE;
844BOOL was_seen_or_unseen = FALSE;
845BOOL was_noerror = FALSE;
846uschar buffer[1024];
847uschar *ptr = *pptr;
848uschar *saveptr;
849uschar *fmsg = NULL;
850
851/* Read the next word and find which command it is. Command words are normally
852terminated by white space, but there are two exceptions, which are the "if" and
853"elif" commands. We must allow for them to be terminated by an opening bracket,
854as brackets are allowed in conditions and users will expect not to require
855white space here. */
856
857if (Ustrncmp(ptr, "if(", 3) == 0)
858 {
f3ebb786 859 Ustrcpy(buffer, US"if");
059ec3d9
PH
860 ptr += 2;
861 }
862else if (Ustrncmp(ptr, "elif(", 5) == 0)
863 {
f3ebb786 864 Ustrcpy(buffer, US"elif");
059ec3d9
PH
865 ptr += 4;
866 }
867else
868 {
869 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
870 if (*error_pointer != NULL) return FALSE;
871 }
872
873for (command = 0; command < command_list_count; command++)
874 if (Ustrcmp(buffer, command_list[command]) == 0) break;
875
876/* Handle the individual commands */
877
878switch (command)
879 {
880 /* Add takes two arguments, separated by the word "to". Headers has two
881 arguments, but the first must be "add", "remove", or "charset", and it gets
882 stored in the second argument slot. Neither may be preceded by seen, unseen
883 or noerror. */
884
885 case add_command:
886 case headers_command:
887 if (seen_force || noerror_force)
888 {
889 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
890 "found before an \"%s\" command near line %d",
891 command_list[command], line_number);
892 yield = FALSE;
893 }
894 /* Fall through */
895
896 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
897 and logfile can have an option second argument for the mode, and deliver can
898 have "errors_to <address>" in a system filter, or in a user filter if the
899 address is the current one. */
900
901 case deliver_command:
902 case logfile_command:
903 case logwrite_command:
904 case pipe_command:
905 case save_command:
906 case testprint_command:
907
908 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
909 if (*buffer == 0)
910 *error_pointer = string_sprintf("\"%s\" requires an argument "
911 "near line %d of filter file", command_list[command], line_number);
912
913 if (*error_pointer != NULL) yield = FALSE; else
914 {
915 union argtypes argument, second_argument;
916
917 argument.u = second_argument.u = NULL;
918
919 if (command == add_command)
920 {
921 argument.u = string_copy(buffer);
922 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
923 if (*buffer == 0 || Ustrcmp(buffer, "to") != 0)
924 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
925 "near line %d of filter file", line_number);
926 else
927 {
928 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
929 if (*buffer == 0)
930 *error_pointer = string_sprintf("value missing after \"to\" "
931 "near line %d of filter file", line_number);
932 else second_argument.u = string_copy(buffer);
933 }
934 }
935
936 else if (command == headers_command)
937 {
938 if (Ustrcmp(buffer, "add") == 0)
939 second_argument.b = TRUE;
940 else
941 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
942 else
943 if (Ustrcmp(buffer, "charset") == 0)
944 second_argument.b = TRUE_UNSET;
945 else
946 {
947 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
948 "expected after \"headers\" near line %d of filter file",
949 line_number);
950 yield = FALSE;
951 }
952
8768d548 953 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
059ec3d9
PH
954 {
955 *error_pointer = string_sprintf("header addition and removal is "
956 "available only in system filters: near line %d of filter file",
957 line_number);
958 yield = FALSE;
959 break;
960 }
961
962 if (yield)
963 {
964 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
965 if (*buffer == 0)
966 *error_pointer = string_sprintf("value missing after \"add\", "
967 "\"remove\", or \"charset\" near line %d of filter file",
968 line_number);
969 else argument.u = string_copy(buffer);
970 }
971 }
972
973 /* The argument for the logwrite command must end in a newline, and the save
974 and logfile commands can have an optional mode argument. The deliver
975 command can have an optional "errors_to <address>" for a system filter,
976 or for a user filter if the address is the user's address. Accept the
977 syntax here - the check is later. */
978
979 else
980 {
981 if (command == logwrite_command)
982 {
983 int len = Ustrlen(buffer);
f3ebb786 984 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
059ec3d9
PH
985 }
986
987 argument.u = string_copy(buffer);
988
989 if (command == save_command || command == logfile_command)
990 {
991 if (isdigit(*ptr))
992 {
993 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
994 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
995 }
996 else second_argument.i = -1;
997 }
998
999 else if (command == deliver_command)
1000 {
1001 uschar *save_ptr = ptr;
1002 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1003 if (Ustrcmp(buffer, "errors_to") == 0)
1004 {
1005 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1006 second_argument.u = string_copy(buffer);
1007 }
1008 else ptr = save_ptr;
1009 }
1010 }
1011
1012 /* Set up the command block. Seen defaults TRUE for delivery commands,
1013 FALSE for logging commands, and it doesn't matter for testprint, as
1014 that doesn't change the "delivered" status. */
1015
1016 if (*error_pointer != NULL) yield = FALSE; else
1017 {
f3ebb786 1018 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), FALSE);
059ec3d9
PH
1019 new->next = NULL;
1020 **lastcmdptr = new;
1021 *lastcmdptr = &(new->next);
1022 new->command = command;
1023 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1024 new->noerror = noerror_force;
1025 new->args[0] = argument;
1026 new->args[1] = second_argument;
1027 }
1028 }
1029 break;
1030
1031
1032 /* Elif, else and endif just set a flag if expected. */
1033
1034 case elif_command:
1035 case else_command:
1036 case endif_command:
41609df5
PH
1037 if (seen_force || noerror_force)
1038 {
1039 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1040 "near line %d is not followed by a command", line_number);
1041 yield = FALSE;
1042 }
1043
059ec3d9
PH
1044 if (expect_endif > 0)
1045 had_else_endif = (command == elif_command)? had_elif :
1046 (command == else_command)? had_else : had_endif;
1047 else
1048 {
1049 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1050 "line %d of filter file", buffer, line_number);
1051 yield = FALSE;
1052 }
1053 break;
1054
1055
1056 /* Defer, freeze, and fail are available only if permitted. */
1057
1058 case defer_command:
1059 cmd_bit = RDO_DEFER;
1060 goto DEFER_FREEZE_FAIL;
1061
1062 case fail_command:
1063 cmd_bit = RDO_FAIL;
1064 goto DEFER_FREEZE_FAIL;
1065
1066 case freeze_command:
1067 cmd_bit = RDO_FREEZE;
1068
1069 DEFER_FREEZE_FAIL:
1070 if ((filter_options & cmd_bit) == 0)
1071 {
1072 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1073 "near line %d of filter file", buffer, line_number);
1074 yield = FALSE;
1075 break;
1076 }
1077
1078 /* A text message can be provided after the "text" keyword, or
1079 as a string in quotes. */
1080
1081 saveptr = ptr;
1082 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1083 if (*saveptr != '\"' && (*buffer == 0 || Ustrcmp(buffer, "text") != 0))
1084 {
1085 ptr = saveptr;
1086 fmsg = US"";
1087 }
1088 else
1089 {
1090 if (*saveptr != '\"')
1091 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1092 fmsg = string_copy(buffer);
1093 }
1094
1095 /* Drop through and treat as "finish", but never set "seen". */
1096
1097 seen_value = FALSE;
1098
1099 /* Finish has no arguments; fmsg defaults to NULL */
1100
1101 case finish_command:
f3ebb786 1102 new = store_get(sizeof(filter_cmd), FALSE);
059ec3d9
PH
1103 new->next = NULL;
1104 **lastcmdptr = new;
1105 *lastcmdptr = &(new->next);
1106 new->command = command;
1107 new->seen = seen_force? seen_value : FALSE;
1108 new->args[0].u = fmsg;
1109 break;
1110
1111
1112 /* Seen, unseen, and noerror are not allowed before if, which takes a
1113 condition argument and then and else sub-commands. */
1114
1115 case if_command:
1116 if (seen_force || noerror_force)
1117 {
1118 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1119 "found before an \"if\" command near line %d",
1120 line_number);
1121 yield = FALSE;
1122 }
1123
1124 /* Set up the command block for if */
1125
f3ebb786 1126 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
059ec3d9
PH
1127 new->next = NULL;
1128 **lastcmdptr = new;
1129 *lastcmdptr = &(new->next);
1130 new->command = command;
1131 new->seen = FALSE;
1132 new->args[0].u = NULL;
1133 new->args[1].u = new->args[2].u = NULL;
1134 new->args[3].u = ptr;
1135
1136 /* Read the condition */
1137
1138 ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1139 if (*error_pointer != NULL) { yield = FALSE; break; }
1140
1141 /* Read the commands to be obeyed if the condition is true */
1142
1143 newlastcmdptr = &(new->args[1].f);
1144 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1145
1146 /* If commands were successfully read, handle the various possible
1147 terminators. There may be a number of successive "elif" sections. */
1148
1149 else
1150 {
1151 while (had_else_endif == had_elif)
1152 {
1153 filter_cmd *newnew =
f3ebb786 1154 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
059ec3d9
PH
1155 new->args[2].f = newnew;
1156 new = newnew;
1157 new->next = NULL;
1158 new->command = command;
1159 new->seen = FALSE;
1160 new->args[0].u = NULL;
1161 new->args[1].u = new->args[2].u = NULL;
1162 new->args[3].u = ptr;
1163
1164 ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1165 if (*error_pointer != NULL) { yield = FALSE; break; }
1166 newlastcmdptr = &(new->args[1].f);
1167 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1168 yield = FALSE;
1169 }
1170
1171 if (yield == FALSE) break;
1172
1173 /* Handle termination by "else", possibly following one or more
1174 "elsif" sections. */
1175
1176 if (had_else_endif == had_else)
1177 {
1178 newlastcmdptr = &(new->args[2].f);
1179 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1180 yield = FALSE;
1181 else if (had_else_endif != had_endif)
1182 {
1183 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1184 "filter file", line_number);
1185 yield = FALSE;
1186 }
1187 }
1188
1189 /* Otherwise the terminator was "endif" - this is checked by
1190 read_command_list(). The pointer is already set to NULL. */
1191 }
1192
1193 /* Reset the terminator flag. */
1194
1195 had_else_endif = had_neither;
1196 break;
1197
1198
1199 /* The mail & vacation commands have a whole slew of keyworded arguments.
1200 The final argument values are the file expand and return message booleans,
1201 whose offsets are defined in mailarg_index_{expand,return}. Although they
1202 are logically booleans, because they are stored in a uschar * value, we use
1203 NULL and not FALSE, to keep 64-bit compilers happy. */
1204
1205 case mail_command:
1206 case vacation_command:
f3ebb786 1207 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), FALSE);
059ec3d9
PH
1208 new->next = NULL;
1209 new->command = command;
1210 new->seen = seen_force? seen_value : FALSE;
1211 new->noerror = noerror_force;
1212 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1213
1214 /* Read keyword/value pairs until we hit one that isn't. The data
1215 must contain only printing chars plus tab, though the "text" value
1216 can also contain newlines. The "file" keyword can be preceded by the
1217 word "expand", and "return message" has no data. */
1218
1219 for (;;)
1220 {
1221 uschar *saveptr = ptr;
1222 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1223 if (*error_pointer != NULL)
1224 {
1225 yield = FALSE;
1226 break;
1227 }
1228
1229 /* Ensure "return" is followed by "message"; that's a complete option */
1230
1231 if (Ustrcmp(buffer, "return") == 0)
1232 {
1233 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1234 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1235 if (Ustrcmp(buffer, "message") != 0)
1236 {
1237 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1238 " near line %d of filter file", line_number);
1239 yield = FALSE;
1240 break;
1241 }
1242 continue;
1243 }
1244
1245 /* Ensure "expand" is followed by "file", then fall through to process the
1246 file keyword. */
1247
1248 if (Ustrcmp(buffer, "expand") == 0)
1249 {
1250 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1251 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1252 if (Ustrcmp(buffer, "file") != 0)
1253 {
1254 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1255 " near line %d of filter file", line_number);
1256 yield = FALSE;
1257 break;
1258 }
1259 }
1260
1261 /* Scan for the keyword */
1262
1263 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1264 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1265
1266 /* Not found keyword; assume end of this command */
1267
1268 if (i >= MAILARGS_STRING_COUNT)
1269 {
1270 ptr = saveptr;
1271 break;
1272 }
1273
1274 /* Found keyword, read the data item */
1275
1276 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1277 if (*error_pointer != NULL)
1278 {
1279 yield = FALSE;
1280 break;
1281 }
1282 else new->args[i].u = string_copy(buffer);
1283 }
1284
1285 /* If this is the vacation command, apply some default settings to
1286 some of the arguments. */
1287
1288 if (command == vacation_command)
1289 {
1290 if (new->args[mailarg_index_file].u == NULL)
1291 {
1292 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1293 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1294 }
1295 if (new->args[mailarg_index_log].u == NULL)
1296 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1297 if (new->args[mailarg_index_once].u == NULL)
1298 new->args[mailarg_index_once].u = string_copy(US".vacation");
1299 if (new->args[mailarg_index_once_repeat].u == NULL)
1300 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1301 if (new->args[mailarg_index_subject].u == NULL)
1302 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1303 }
1304
1305 /* Join the address on to the chain of generated addresses */
1306
1307 **lastcmdptr = new;
1308 *lastcmdptr = &(new->next);
1309 break;
1310
1311
1312 /* Seen and unseen just set flags */
1313
1314 case seen_command:
1315 case unseen_command:
41609df5
PH
1316 if (*ptr == 0)
1317 {
1318 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1319 "near line %d is not followed by a command", line_number);
1320 yield = FALSE;
1321 }
059ec3d9
PH
1322 if (seen_force)
1323 {
1324 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1325 "near line %d", line_number);
1326 yield = FALSE;
1327 }
1328 seen_value = (command == seen_command);
1329 seen_force = TRUE;
1330 was_seen_or_unseen = TRUE;
1331 break;
1332
1333
1334 /* So does noerror */
1335
1336 case noerror_command:
41609df5
PH
1337 if (*ptr == 0)
1338 {
1339 *error_pointer = string_sprintf("\"noerror\" "
1340 "near line %d is not followed by a command", line_number);
1341 yield = FALSE;
1342 }
059ec3d9
PH
1343 noerror_force = TRUE;
1344 was_noerror = TRUE;
1345 break;
1346
1347
1348 /* Oops */
1349
1350 default:
1351 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1352 "near line %d of filter file", buffer, line_number);
1353 yield = FALSE;
1354 break;
1355 }
1356
1357if (!was_seen_or_unseen && !was_noerror)
1358 {
1359 seen_force = FALSE;
1360 noerror_force = FALSE;
1361 }
1362
1363*pptr = ptr;
1364return yield;
1365}
1366
1367
1368
1369/*************************************************
1370* Read a list of commands *
1371*************************************************/
1372
4c04137d 1373/* If conditional is TRUE, the list must be terminated
059ec3d9
PH
1374by the words "else" or "endif".
1375
1376Arguments:
1377 pptr points to pointer to next character; the pointer is updated
1378 lastcmdptr points to pointer to pointer to previously-read command; used
1379 for hanging on the new command
1380 conditional TRUE if this command is the subject of a condition
1381
1382Returns: TRUE on success
1383*/
1384
1385static BOOL
1386read_command_list(uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1387{
1388if (conditional) expect_endif++;
1389had_else_endif = had_neither;
1390while (**pptr != 0 && had_else_endif == had_neither)
1391 {
1392 if (!read_command(pptr, lastcmdptr)) return FALSE;
1393 *pptr = nextsigchar(*pptr, TRUE);
1394 }
1395if (conditional)
1396 {
1397 expect_endif--;
1398 if (had_else_endif == had_neither)
1399 {
1400 *error_pointer = US"\"endif\" missing at end of filter file";
1401 return FALSE;
1402 }
1403 }
1404return TRUE;
1405}
1406
1407
1408
1409
1410/*************************************************
1411* Test a condition *
1412*************************************************/
1413
1414/*
1415Arguments:
1416 c points to the condition block; c->testfor indicated whether
1417 it's a positive or negative condition
1418 toplevel TRUE if called from "if" directly; FALSE otherwise
1419
1420Returns: TRUE if the condition is met
1421*/
1422
1423static BOOL
1424test_condition(condition_block *c, BOOL toplevel)
1425{
91ecef39 1426BOOL yield = FALSE;
059ec3d9
PH
1427const pcre *re;
1428uschar *exp[2], *p, *pp;
1429const uschar *regcomp_error = NULL;
1430int regcomp_error_offset;
1431int val[2];
1432int i;
1433
1434if (c == NULL) return TRUE; /* does this ever occur? */
1435
1436switch (c->type)
1437 {
1438 case cond_and:
1439 yield = test_condition(c->left.c, FALSE) &&
1440 *error_pointer == NULL &&
1441 test_condition(c->right.c, FALSE);
1442 break;
1443
1444 case cond_or:
1445 yield = test_condition(c->left.c, FALSE) ||
1446 (*error_pointer == NULL &&
1447 test_condition(c->right.c, FALSE));
1448 break;
1449
1450 /* The personal test is meaningless in a system filter. The tests are now in
1451 a separate function (so Sieve can use them). However, an Exim filter does not
1452 scan Cc: (hence the FALSE argument). */
1453
1454 case cond_personal:
8768d548 1455 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
059ec3d9
PH
1456 break;
1457
1458 case cond_delivered:
1459 yield = filter_delivered;
1460 break;
1461
1462 /* Only TRUE if a message is actually being processed; FALSE for address
1463 testing and verification. */
1464
1465 case cond_errormsg:
1466 yield = message_id[0] != 0 &&
1467 (sender_address == NULL || sender_address[0] == 0);
1468 break;
1469
1470 /* Only FALSE if a message is actually being processed; TRUE for address
1471 and filter testing and verification. */
1472
1473 case cond_firsttime:
8768d548 1474 yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
059ec3d9
PH
1475 break;
1476
1477 /* Only TRUE if a message is actually being processed; FALSE for address
1478 testing and verification. */
1479
1480 case cond_manualthaw:
8768d548 1481 yield = message_id[0] != 0 && f.deliver_manual_thaw;
059ec3d9
PH
1482 break;
1483
1484 /* The foranyaddress condition loops through a list of addresses */
1485
1486 case cond_foranyaddress:
1487 p = c->left.u;
1488 pp = expand_string(p);
1489 if (pp == NULL)
1490 {
1491 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1492 "filter file: %s", p, expand_string_message);
1493 return FALSE;
1494 }
1495
1496 yield = FALSE;
8768d548 1497 f.parse_allow_group = TRUE; /* Allow group syntax */
059ec3d9
PH
1498
1499 while (*pp != 0)
1500 {
1501 uschar *error;
1502 int start, end, domain;
1503 int saveend;
1504
1505 p = parse_find_address_end(pp, FALSE);
1506 saveend = *p;
1507
1508 *p = 0;
1509 filter_thisaddress =
1510 parse_extract_address(pp, &error, &start, &end, &domain, FALSE);
1511 *p = saveend;
1512
5fcc791a 1513 if (filter_thisaddress)
059ec3d9 1514 {
f05da2e8 1515 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1516 (debug_selector & D_filter) != 0)
1517 {
1518 indent();
f3ebb786 1519 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
059ec3d9
PH
1520 }
1521 yield = test_condition(c->right.c, FALSE);
1522 }
1523
1524 if (yield) break;
1525 if (saveend == 0) break;
1526 pp = p + 1;
1527 }
1528
8768d548
JH
1529 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1530 f.parse_found_group = FALSE;
059ec3d9
PH
1531 break;
1532
1533 /* All other conditions have left and right values that need expanding;
1534 on error, it doesn't matter what value is returned. */
1535
1536 default:
1537 p = c->left.u;
1538 for (i = 0; i < 2; i++)
1539 {
1540 exp[i] = expand_string(p);
1541 if (exp[i] == NULL)
1542 {
1543 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1544 "filter file: %s", p, expand_string_message);
1545 return FALSE;
1546 }
1547 p = c->right.u;
1548 }
1549
1550 /* Inner switch for the different cases */
1551
1552 switch(c->type)
1553 {
1554 case cond_is:
1555 yield = strcmpic(exp[0], exp[1]) == 0;
1556 break;
1557
1558 case cond_IS:
1559 yield = Ustrcmp(exp[0], exp[1]) == 0;
1560 break;
1561
1562 case cond_contains:
1563 yield = strstric(exp[0], exp[1], FALSE) != NULL;
1564 break;
1565
1566 case cond_CONTAINS:
1567 yield = Ustrstr(exp[0], exp[1]) != NULL;
1568 break;
1569
1570 case cond_begins:
1571 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1572 break;
1573
1574 case cond_BEGINS:
1575 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1576 break;
1577
1578 case cond_ends:
1579 case cond_ENDS:
1580 {
1581 int len = Ustrlen(exp[1]);
1582 uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1583 yield = (s < exp[0])? FALSE :
1584 ((c->type == cond_ends)? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1585 }
1586 break;
1587
1588 case cond_matches:
1589 case cond_MATCHES:
f05da2e8 1590 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1591 (debug_selector & D_filter) != 0)
1592 {
f3ebb786
JH
1593 debug_printf_indent("Match expanded arguments:\n");
1594 debug_printf_indent(" Subject = %s\n", exp[0]);
1595 debug_printf_indent(" Pattern = %s\n", exp[1]);
059ec3d9
PH
1596 }
1597
3d2e82c5 1598 if (!(re = pcre_compile(CS exp[1],
059ec3d9 1599 PCRE_COPT | ((c->type == cond_matches)? PCRE_CASELESS : 0),
3d2e82c5 1600 CCSS &regcomp_error, &regcomp_error_offset, NULL)))
059ec3d9
PH
1601 {
1602 *error_pointer = string_sprintf("error while compiling "
1603 "regular expression \"%s\": %s at offset %d",
1604 exp[1], regcomp_error, regcomp_error_offset);
1605 return FALSE;
1606 }
1607
1608 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1609 break;
1610
1611 /* For above and below, convert the strings to numbers */
1612
1613 case cond_above:
1614 case cond_below:
1615 for (i = 0; i < 2; i++)
1616 {
1617 val[i] = get_number(exp[i], &yield);
1618 if (!yield)
1619 {
1620 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1621 exp[i]);
1622 return FALSE;
1623 }
1624 }
1625 yield = (c->type == cond_above)? (val[0] > val[1]) : (val[0] < val[1]);
1626 break;
1627 }
1628 break;
1629 }
1630
f05da2e8 1631if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1632 (debug_selector & D_filter) != 0)
1633 {
1634 indent();
f3ebb786 1635 debug_printf_indent("%sondition is %s: ",
059ec3d9
PH
1636 toplevel? "C" : "Sub-c",
1637 (yield == c->testfor)? "true" : "false");
1638 print_condition(c, TRUE);
f3ebb786 1639 debug_printf_indent("\n");
059ec3d9
PH
1640 }
1641
1642return yield == c->testfor;
1643}
1644
1645
1646
1647/*************************************************
1648* Interpret chain of commands *
1649*************************************************/
1650
1651/* In testing state, just say what would be done rather than doing it. The
1652testprint command just expands and outputs its argument in testing state, and
1653does nothing otherwise.
1654
1655Arguments:
1656 commands points to chain of commands to interpret
1657 generated where to hang newly-generated addresses
1658
1659Returns: FF_DELIVERED success, a significant action was taken
1660 FF_NOTDELIVERED success, no significant action
1661 FF_DEFER defer requested
1662 FF_FAIL fail requested
1663 FF_FREEZE freeze requested
1664 FF_ERROR there was a problem
1665*/
1666
1667static int
1668interpret_commands(filter_cmd *commands, address_item **generated)
1669{
1670uschar *s;
1671int mode;
1672address_item *addr;
1673BOOL condition_value;
1674
f3ebb786 1675while (commands)
059ec3d9
PH
1676 {
1677 int ff_ret;
1678 uschar *fmsg, *ff_name;
1679 uschar *expargs[MAILARGS_STRING_COUNT];
1680
1681 int i, n[2];
1682
1683 /* Expand the relevant number of arguments for the command that are
1684 not NULL. */
1685
1686 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1687 {
1688 uschar *ss = commands->args[i].u;
f3ebb786 1689 if (!ss)
059ec3d9 1690 expargs[i] = NULL;
059ec3d9 1691 else
f3ebb786 1692 if (!(expargs[i] = expand_string(ss)))
059ec3d9
PH
1693 {
1694 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1695 "%s command: %s", ss, command_list[commands->command],
1696 expand_string_message);
1697 return FF_ERROR;
1698 }
059ec3d9
PH
1699 }
1700
1701 /* Now switch for each command, setting the "delivered" flag if any of them
1702 have "seen" set. */
1703
1704 if (commands->seen) filter_delivered = TRUE;
1705
1706 switch(commands->command)
1707 {
1708 case add_command:
f3ebb786
JH
1709 for (i = 0; i < 2; i++)
1710 {
1711 uschar *ss = expargs[i];
1712 uschar *end;
059ec3d9 1713
f3ebb786
JH
1714 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1715 {
1716 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1717 "command", expargs[i]);
1718 return FF_ERROR;
1719 }
059ec3d9 1720
f3ebb786
JH
1721 /* Allow for "--" at the start of the value (from -$n0) for example */
1722 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
059ec3d9 1723
f3ebb786
JH
1724 n[i] = (int)Ustrtol(ss, &end, 0);
1725 if (*end != 0)
1726 {
1727 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1728 "command", ss);
1729 return FF_ERROR;
1730 }
1731 }
059ec3d9 1732
f3ebb786
JH
1733 filter_n[n[1]] += n[0];
1734 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1735 break;
059ec3d9 1736
f3ebb786
JH
1737 /* A deliver command's argument must be a valid address. Its optional
1738 second argument (system filter only) must also be a valid address. */
059ec3d9
PH
1739
1740 case deliver_command:
f3ebb786
JH
1741 for (i = 0; i < 2; i++)
1742 {
1743 s = expargs[i];
1744 if (s != NULL)
1745 {
1746 int start, end, domain;
1747 uschar *error;
1748 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1749 FALSE);
5fcc791a
JH
1750 if (ss)
1751 expargs[i] = filter_options & RDO_REWRITE
1752 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1753 rewrite_existflags)
1754 : rewrite_address_qualify(ss, TRUE);
f3ebb786
JH
1755 else
1756 {
1757 *error_pointer = string_sprintf("malformed address \"%s\" in "
1758 "filter file: %s", s, error);
1759 return FF_ERROR;
1760 }
1761 }
1762 }
059ec3d9 1763
f3ebb786
JH
1764 /* Stick the errors address into a simple variable, as it will
1765 be referenced a few times. Check that the caller is permitted to
1766 specify it. */
059ec3d9 1767
f3ebb786 1768 s = expargs[1];
059ec3d9 1769
f3ebb786
JH
1770 if (s != NULL && !f.system_filtering)
1771 {
1772 uschar *ownaddress = expand_string(US"$local_part@$domain");
1773 if (strcmpic(ownaddress, s) != 0)
1774 {
1775 *error_pointer = US"errors_to must point to the caller's address";
1776 return FF_ERROR;
1777 }
1778 }
059ec3d9 1779
f3ebb786 1780 /* Test case: report what would happen */
059ec3d9 1781
f3ebb786
JH
1782 if (filter_test != FTEST_NONE)
1783 {
1784 indent();
1785 printf("%seliver message to: %s%s%s%s\n",
1786 (commands->seen)? "D" : "Unseen d",
1787 expargs[0],
1788 commands->noerror? " (noerror)" : "",
1789 (s != NULL)? " errors_to " : "",
1790 (s != NULL)? s : US"");
1791 }
059ec3d9 1792
f3ebb786 1793 /* Real case. */
059ec3d9 1794
f3ebb786
JH
1795 else
1796 {
1797 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1798 (commands->seen)? "" : "unseen ",
1799 expargs[0],
1800 commands->noerror? " (noerror)" : "",
1801 (s != NULL)? " errors_to " : "",
1802 (s != NULL)? s : US"");
1803
1804 /* Create the new address and add it to the chain, setting the
1805 af_ignore_error flag if necessary, and the errors address, which can be
1806 set in a system filter and to the local address in user filters. */
1807
1808 addr = deliver_make_addr(expargs[0], TRUE); /* TRUE => copy s */
1809 addr->prop.errors_address = (s == NULL)?
1810 s : string_copy(s); /* Default is NULL */
1811 if (commands->noerror) addr->prop.ignore_error = TRUE;
1812 addr->next = *generated;
1813 *generated = addr;
1814 }
1815 break;
059ec3d9
PH
1816
1817 case save_command:
f3ebb786
JH
1818 s = expargs[0];
1819 mode = commands->args[1].i;
059ec3d9 1820
f3ebb786 1821 /* Test case: report what would happen */
059ec3d9 1822
f3ebb786
JH
1823 if (filter_test != FTEST_NONE)
1824 {
1825 indent();
1826 if (mode < 0)
1827 printf("%save message to: %s%s\n", (commands->seen)?
1828 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1829 else
1830 printf("%save message to: %s %04o%s\n", (commands->seen)?
1831 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1832 }
059ec3d9 1833
f3ebb786
JH
1834 /* Real case: Ensure save argument starts with / if there is a home
1835 directory to prepend. */
059ec3d9 1836
f3ebb786
JH
1837 else
1838 {
1839 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1840 deliver_home != NULL && deliver_home[0] != 0)
1841 s = string_sprintf("%s/%s", deliver_home, s);
1842 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1843 (commands->seen)? "" : "unseen ", s,
1844 commands->noerror? " (noerror)" : "");
1845
1846 /* Create the new address and add it to the chain, setting the
1847 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1848 mode value. */
1849
1850 addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
1851 setflag(addr, af_pfr);
1852 setflag(addr, af_file);
1853 if (commands->noerror) addr->prop.ignore_error = TRUE;
1854 addr->mode = mode;
1855 addr->next = *generated;
1856 *generated = addr;
1857 }
1858 break;
059ec3d9
PH
1859
1860 case pipe_command:
f3ebb786
JH
1861 s = string_copy(commands->args[0].u);
1862 if (filter_test != FTEST_NONE)
1863 {
1864 indent();
1865 printf("%sipe message to: %s%s\n", (commands->seen)?
1866 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1867 }
1868 else /* Ensure pipe command starts with | */
1869 {
1870 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1871 commands->seen ? "" : "unseen ", s,
1872 commands->noerror ? " (noerror)" : "");
1873 if (s[0] != '|') s = string_sprintf("|%s", s);
059ec3d9 1874
f3ebb786
JH
1875 /* Create the new address and add it to the chain, setting the
1876 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1877 each command argument is expanded in the transport after the command
1878 has been split up into separate arguments. */
1879
1880 addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
1881 setflag(addr, af_pfr);
1882 setflag(addr, af_expand_pipe);
1883 if (commands->noerror) addr->prop.ignore_error = TRUE;
1884 addr->next = *generated;
1885 *generated = addr;
1886
1887 /* If there are any numeric variables in existence (e.g. after a regex
1888 condition), or if $thisaddress is set, take a copy for use in the
1889 expansion. Note that we can't pass NULL for filter_thisaddress, because
1890 NULL terminates the list. */
1891
1892 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1893 {
1894 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1895 uschar **ss = store_get(sizeof(uschar *) * (ecount + 3), FALSE);
1896
1897 addr->pipe_expandn = ss;
1898 if (!filter_thisaddress) filter_thisaddress = US"";
1899 *ss++ = string_copy(filter_thisaddress);
1900 for (int i = 0; i <= expand_nmax; i++)
1901 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1902 *ss = NULL;
1903 }
1904 }
1905 break;
1906
1907 /* Set up the file name and mode, and close any previously open
1908 file. */
059ec3d9
PH
1909
1910 case logfile_command:
f3ebb786
JH
1911 log_mode = commands->args[1].i;
1912 if (log_mode == -1) log_mode = 0600;
1913 if (log_fd >= 0)
1914 {
1915 (void)close(log_fd);
1916 log_fd = -1;
1917 }
1918 log_filename = expargs[0];
1919 if (filter_test != FTEST_NONE)
1920 {
1921 indent();
1922 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1923 }
1924 break;
059ec3d9
PH
1925
1926 case logwrite_command:
f3ebb786 1927 s = expargs[0];
059ec3d9 1928
f3ebb786
JH
1929 if (filter_test != FTEST_NONE)
1930 {
1931 indent();
1932 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1933 string_printing(s));
1934 }
059ec3d9 1935
f3ebb786
JH
1936 /* Attempt to write to a log file only if configured as permissible.
1937 Logging may be forcibly skipped for verifying or testing. */
059ec3d9 1938
f3ebb786
JH
1939 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1940 {
1941 DEBUG(D_filter)
1942 debug_printf_indent("filter log command aborted: euid=%ld\n",
1943 (long int)geteuid());
1944 *error_pointer = US"logwrite command forbidden";
1945 return FF_ERROR;
1946 }
1947 else if ((filter_options & RDO_REALLOG) != 0)
1948 {
1949 int len;
1950 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1951 (long int)geteuid());
1952 if (log_fd < 0)
1953 {
1954 if (log_filename == NULL)
1955 {
1956 *error_pointer = US"attempt to obey \"logwrite\" command "
1957 "without a previous \"logfile\"";
1958 return FF_ERROR;
1959 }
1960 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1961 if (log_fd < 0)
1962 {
1963 *error_pointer = string_open_failed(errno, "filter log file \"%s\"",
1964 log_filename);
1965 return FF_ERROR;
1966 }
1967 }
1968 len = Ustrlen(s);
1969 if (write(log_fd, s, len) != len)
1970 {
1971 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1972 log_filename, strerror(errno));
1973 return FF_ERROR;
1974 }
1975 }
1976 else
1977 {
1978 DEBUG(D_filter) debug_printf_indent("skipping logwrite (verifying or testing)\n");
1979 }
1980 break;
059ec3d9 1981
f3ebb786
JH
1982 /* Header addition and removal is available only in the system filter. The
1983 command is rejected at parse time otherwise. However "headers charset" is
1984 always permitted. */
059ec3d9
PH
1985
1986 case headers_command:
f3ebb786
JH
1987 {
1988 int subtype = commands->args[1].i;
1989 s = expargs[0];
059ec3d9 1990
f3ebb786
JH
1991 if (filter_test != FTEST_NONE)
1992 printf("Headers %s \"%s\"\n", (subtype == TRUE)? "add" :
1993 (subtype == FALSE)? "remove" : "charset", string_printing(s));
059ec3d9 1994
f3ebb786
JH
1995 if (subtype == TRUE)
1996 {
1997 while (isspace(*s)) s++;
1998 if (s[0] != 0)
1999 {
2000 header_add(htype_other, "%s%s", s, (s[Ustrlen(s)-1] == '\n')?
2001 "" : "\n");
2002 header_last->type = header_checkname(header_last, FALSE);
2003 if (header_last->type >= 'a') header_last->type = htype_other;
2004 }
2005 }
059ec3d9 2006
f3ebb786
JH
2007 else if (subtype == FALSE)
2008 {
2009 int sep = 0;
2010 uschar *ss;
2011 const uschar *list = s;
2012 uschar buffer[128];
2013 while ((ss = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
2014 != NULL)
2015 header_remove(0, ss);
2016 }
059ec3d9 2017
f3ebb786
JH
2018 /* This setting lasts only while the filter is running; on exit, the
2019 variable is reset to the previous value. */
059ec3d9 2020
f3ebb786
JH
2021 else headers_charset = s;
2022 }
2023 break;
059ec3d9 2024
f3ebb786
JH
2025 /* Defer, freeze, and fail are available only when explicitly permitted.
2026 These commands are rejected at parse time otherwise. The message can get
2027 very long by the inclusion of message headers; truncate if it is, and also
2028 ensure printing characters so as not to mess up log files. */
059ec3d9
PH
2029
2030 case defer_command:
f3ebb786
JH
2031 ff_name = US"defer";
2032 ff_ret = FF_DEFER;
2033 goto DEFERFREEZEFAIL;
059ec3d9
PH
2034
2035 case fail_command:
f3ebb786
JH
2036 ff_name = US"fail";
2037 ff_ret = FF_FAIL;
2038 goto DEFERFREEZEFAIL;
059ec3d9
PH
2039
2040 case freeze_command:
f3ebb786
JH
2041 ff_name = US"freeze";
2042 ff_ret = FF_FREEZE;
059ec3d9 2043
f3ebb786
JH
2044 DEFERFREEZEFAIL:
2045 fmsg = expargs[0];
2046 if (Ustrlen(fmsg) > 1024) Ustrcpy(fmsg + 1000, US" ... (truncated)");
2047 fmsg = US string_printing(fmsg);
2048 *error_pointer = fmsg;
059ec3d9 2049
f3ebb786
JH
2050 if (filter_test != FTEST_NONE)
2051 {
2052 indent();
2053 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2054 }
2055 else DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2056 return ff_ret;
059ec3d9
PH
2057
2058 case finish_command:
f3ebb786
JH
2059 if (filter_test != FTEST_NONE)
2060 {
2061 indent();
2062 printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2063 }
2064 else
2065 {
2066 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2067 (commands->seen)? " Seen " : "");
2068 }
2069 finish_obeyed = TRUE;
2070 return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
059ec3d9
PH
2071
2072 case if_command:
f3ebb786
JH
2073 {
2074 uschar *save_address = filter_thisaddress;
2075 int ok = FF_DELIVERED;
2076 condition_value = test_condition(commands->args[0].c, TRUE);
2077 if (*error_pointer != NULL) ok = FF_ERROR; else
2078 {
2079 output_indent += 2;
2080 ok = interpret_commands(commands->args[condition_value? 1:2].f,
2081 generated);
2082 output_indent -= 2;
2083 }
2084 filter_thisaddress = save_address;
2085 if (finish_obeyed || (ok != FF_DELIVERED && ok != FF_NOTDELIVERED))
2086 return ok;
2087 }
2088 break;
059ec3d9
PH
2089
2090
f3ebb786
JH
2091 /* To try to catch runaway loops, do not generate mail if the
2092 return path is unset or if a non-trusted user supplied -f <>
2093 as the return path. */
059ec3d9
PH
2094
2095 case mail_command:
2096 case vacation_command:
f3ebb786
JH
2097 if (return_path == NULL || return_path[0] == 0)
2098 {
2099 if (filter_test != FTEST_NONE)
2100 printf("%s command ignored because return_path is empty\n",
2101 command_list[commands->command]);
2102 else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2103 "is empty\n", command_list[commands->command]);
2104 break;
2105 }
acec9514 2106
f3ebb786
JH
2107 /* Check the contents of the strings. The type of string can be deduced
2108 from the value of i.
acec9514 2109
f3ebb786
JH
2110 . If i is equal to mailarg_index_text it's a text string for the body,
2111 where anything goes.
acec9514 2112
f3ebb786
JH
2113 . If i is > mailarg_index_text, we are dealing with a file name, which
2114 cannot contain non-printing characters.
acec9514 2115
f3ebb786
JH
2116 . If i is less than mailarg_index_headers we are dealing with something
2117 that will go in a single message header line, where newlines must be
2118 followed by white space.
acec9514 2119
f3ebb786
JH
2120 . If i is equal to mailarg_index_headers, we have a string that contains
2121 one or more headers. Newlines that are not followed by white space must
2122 be followed by a header name.
2123 */
acec9514 2124
f3ebb786
JH
2125 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2126 {
2127 uschar *p;
2128 uschar *s = expargs[i];
acec9514 2129
f3ebb786 2130 if (s == NULL) continue;
acec9514 2131
f3ebb786 2132 if (i != mailarg_index_text) for (p = s; *p != 0; p++)
acec9514 2133 {
f3ebb786
JH
2134 int c = *p;
2135 if (i > mailarg_index_text)
acec9514 2136 {
f3ebb786
JH
2137 if (!mac_isprint(c))
2138 {
2139 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2140 "in %s command", string_printing(s),
2141 command_list[commands->command]);
2142 return FF_ERROR;
2143 }
acec9514 2144 }
acec9514 2145
f3ebb786 2146 /* i < mailarg_index_text */
acec9514 2147
f3ebb786 2148 else if (c == '\n' && !isspace(p[1]))
acec9514 2149 {
f3ebb786
JH
2150 if (i < mailarg_index_headers)
2151 {
2152 *error_pointer = string_sprintf("\\n not followed by space in "
2153 "\"%.1024s\" in %s command", string_printing(s),
2154 command_list[commands->command]);
2155 return FF_ERROR;
2156 }
acec9514 2157
f3ebb786 2158 /* Check for the start of a new header line within the string */
acec9514 2159
f3ebb786 2160 else
acec9514 2161 {
f3ebb786
JH
2162 uschar *pp;
2163 for (pp = p + 1;; pp++)
acec9514 2164 {
f3ebb786
JH
2165 c = *pp;
2166 if (c == ':' && pp != p + 1) break;
2167 if (c == 0 || c == ':' || isspace(*pp))
2168 {
2169 *error_pointer = string_sprintf("\\n not followed by space or "
2170 "valid header name in \"%.1024s\" in %s command",
2171 string_printing(s), command_list[commands->command]);
2172 return FF_ERROR;
2173 }
acec9514 2174 }
f3ebb786 2175 p = pp;
acec9514 2176 }
acec9514 2177 }
f3ebb786 2178 } /* Loop to scan the string */
acec9514 2179
f3ebb786 2180 /* The string is OK */
acec9514 2181
f3ebb786 2182 commands->args[i].u = s;
acec9514 2183 }
acec9514 2184
f3ebb786 2185 /* Proceed with mail or vacation command */
acec9514 2186
f3ebb786 2187 if (filter_test != FTEST_NONE)
acec9514 2188 {
f3ebb786
JH
2189 uschar *to = commands->args[mailarg_index_to].u;
2190 indent();
2191 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2192 to ? to : US"<default>",
acec9514
JH
2193 commands->command == vacation_command ? " (vacation)" : "",
2194 commands->noerror ? " (noerror)" : "");
2195 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2196 {
2197 uschar *arg = commands->args[i].u;
f3ebb786 2198 if (arg)
acec9514
JH
2199 {
2200 int len = Ustrlen(mailargs[i]);
f3ebb786
JH
2201 int indent = (debug_selector != 0)? output_indent : 0;
2202 while (len++ < 7 + indent) printf(" ");
2203 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
acec9514
JH
2204 (commands->args[mailarg_index_expand].u != NULL &&
2205 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2206 }
2207 }
f3ebb786
JH
2208 if (commands->args[mailarg_index_return].u)
2209 printf("Return original message\n");
acec9514 2210 }
f3ebb786 2211 else
acec9514 2212 {
f3ebb786
JH
2213 uschar *tt;
2214 uschar *to = commands->args[mailarg_index_to].u;
2215 gstring * log_addr = NULL;
acec9514 2216
f3ebb786
JH
2217 if (!to) to = expand_string(US"$reply_address");
2218 while (isspace(*to)) to++;
acec9514 2219
f3ebb786
JH
2220 for (tt = to; *tt != 0; tt++) /* Get rid of newlines */
2221 if (*tt == '\n') *tt = ' ';
acec9514 2222
f3ebb786 2223 DEBUG(D_filter)
acec9514 2224 {
f3ebb786
JH
2225 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2226 commands->seen ? "seen " : "",
2227 to,
2228 commands->command == vacation_command ? " (vacation)" : "",
2229 commands->noerror ? " (noerror)" : "");
2230 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2231 {
2232 uschar *arg = commands->args[i].u;
2233 if (arg != NULL)
2234 {
2235 int len = Ustrlen(mailargs[i]);
2236 while (len++ < 15) debug_printf_indent(" ");
2237 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2238 (commands->args[mailarg_index_expand].u != NULL &&
2239 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2240 }
2241 }
acec9514
JH
2242 }
2243
f3ebb786
JH
2244 /* Create the "address" for the autoreply. This is used only for logging,
2245 as the actual recipients are extracted from the To: line by -t. We use the
2246 same logic here to extract the working addresses (there may be more than
2247 one). Just in case there are a vast number of addresses, stop when the
2248 string gets too long. */
acec9514 2249
f3ebb786
JH
2250 tt = to;
2251 while (*tt != 0)
acec9514 2252 {
f3ebb786
JH
2253 uschar *ss = parse_find_address_end(tt, FALSE);
2254 uschar *recipient, *errmess;
2255 int start, end, domain;
2256 int temp = *ss;
acec9514 2257
f3ebb786
JH
2258 *ss = 0;
2259 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2260 FALSE);
2261 *ss = temp;
acec9514 2262
f3ebb786
JH
2263 /* Ignore empty addresses and errors; an error will occur later if
2264 there's something really bad. */
acec9514 2265
f3ebb786
JH
2266 if (recipient)
2267 {
2268 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2269 log_addr = string_cat (log_addr, recipient);
2270 }
acec9514 2271
f3ebb786 2272 /* Check size */
acec9514 2273
f3ebb786
JH
2274 if (log_addr && log_addr->ptr > 256)
2275 {
2276 log_addr = string_catn(log_addr, US", ...", 5);
2277 break;
2278 }
2279
2280 /* Move on past this address */
2281
2282 tt = ss + (*ss ? 1 : 0);
2283 while (isspace(*tt)) tt++;
2284 }
2285
2286 if (log_addr)
2287 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2288 else
acec9514 2289 {
f3ebb786
JH
2290 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2291 setflag(addr, af_bad_reply);
acec9514 2292 }
acec9514 2293
f3ebb786
JH
2294 setflag(addr, af_pfr);
2295 if (commands->noerror) addr->prop.ignore_error = TRUE;
2296 addr->next = *generated;
2297 *generated = addr;
2298
2299 addr->reply = store_get(sizeof(reply_item), FALSE);
2300 addr->reply->from = NULL;
2301 addr->reply->to = string_copy(to);
2302 addr->reply->file_expand =
2303 commands->args[mailarg_index_expand].u != NULL;
2304 addr->reply->expand_forbid = expand_forbid;
2305 addr->reply->return_message =
2306 commands->args[mailarg_index_return].u != NULL;
2307 addr->reply->once_repeat = 0;
2308
2309 if (commands->args[mailarg_index_once_repeat].u != NULL)
2310 {
2311 addr->reply->once_repeat =
2312 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2313 FALSE);
2314 if (addr->reply->once_repeat < 0)
2315 {
2316 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2317 "in mail or vacation command: %s",
2318 commands->args[mailarg_index_once_repeat].u);
2319 return FF_ERROR;
2320 }
2321 }
acec9514 2322
f3ebb786
JH
2323 /* Set up all the remaining string arguments (those other than "to") */
2324
2325 for (i = 1; i < mailargs_string_passed; i++)
2326 {
2327 uschar *ss = commands->args[i].u;
2328 *(USS((US addr->reply) + reply_offsets[i])) =
2329 ss ? string_copy(ss) : NULL;
2330 }
acec9514 2331 }
f3ebb786 2332 break;
059ec3d9
PH
2333
2334 case testprint_command:
f3ebb786
JH
2335 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2336 {
2337 const uschar *s = string_printing(expargs[0]);
2338 if (filter_test == FTEST_NONE)
2339 debug_printf_indent("Filter: testprint: %s\n", s);
2340 else
2341 printf("Testprint: %s\n", s);
2342 }
059ec3d9
PH
2343 }
2344
2345 commands = commands->next;
2346 }
2347
2348return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
2349}
2350
2351
2352
2353/*************************************************
2354* Test for a personal message *
2355*************************************************/
2356
2357/* This function is global so that it can also be called from the code that
2358implements Sieve filters.
2359
2360Arguments:
2361 aliases a chain of aliases
2362 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2363
2364Returns: TRUE if the message is deemed to be personal
2365*/
2366
2367BOOL
2368filter_personal(string_item *aliases, BOOL scan_cc)
2369{
2370uschar *self, *self_from, *self_to;
2371uschar *psself = NULL, *psself_from = NULL, *psself_to = NULL;
f3ebb786 2372rmark reset_point = store_mark();
059ec3d9
PH
2373BOOL yield;
2374header_line *h;
2375int to_count = 2;
2376int from_count = 9;
2377
4b233853
PH
2378/* If any header line in the message is a defined "List-" header field, it is
2379not a personal message. We used to check for any header line that started with
2380"List-", but this was tightened up for release 4.54. The check is now for
2381"List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2382Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2383defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2384contain any value other than "no", the message is not personal (RFC 3834).
2385Previously the test was for "auto-". */
059ec3d9 2386
f3ebb786 2387for (h = header_list; h; h = h->next)
059ec3d9 2388 {
4b233853
PH
2389 if (h->type == htype_old) continue;
2390
2391 if (strncmpic(h->text, US"List-", 5) == 0)
2392 {
137ae145 2393 uschar * s = h->text + 5;
4b233853
PH
2394 if (strncmpic(s, US"Id:", 3) == 0 ||
2395 strncmpic(s, US"Help:", 5) == 0 ||
2396 strncmpic(s, US"Subscribe:", 10) == 0 ||
2397 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2398 strncmpic(s, US"Post:", 5) == 0 ||
2399 strncmpic(s, US"Owner:", 6) == 0 ||
2400 strncmpic(s, US"Archive:", 8) == 0)
2401 return FALSE;
2402 }
2403
2404 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2405 {
137ae145
JH
2406 uschar * s = h->text + 15;
2407 Uskip_whitespace(&s);
4b233853
PH
2408 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2409 s += 2;
137ae145
JH
2410 Uskip_whitespace(&s);
2411 if (*s) return FALSE;
4b233853 2412 }
059ec3d9
PH
2413 }
2414
2415/* Set up "my" address */
2416
2417self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2418self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2419 global_rewrite_rules);
2420self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2421 global_rewrite_rules);
2422
2423
137ae145
JH
2424if (!self_from) self_from = self;
2425if (self_to) self_to = self;
059ec3d9
PH
2426
2427/* If there's a prefix or suffix set, we must include the prefixed/
2428suffixed version of the local part in the tests. */
2429
137ae145 2430if (deliver_localpart_prefix || deliver_localpart_suffix)
059ec3d9
PH
2431 {
2432 psself = string_sprintf("%s%s%s@%s",
2433 (deliver_localpart_prefix == NULL)? US"" : deliver_localpart_prefix,
2434 deliver_localpart,
2435 (deliver_localpart_suffix == NULL)? US"" : deliver_localpart_suffix,
2436 deliver_domain);
2437 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2438 global_rewrite_rules);
2439 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2440 global_rewrite_rules);
2441 if (psself_from == NULL) psself_from = psself;
2442 if (psself_to == NULL) psself_to = psself;
2443 to_count += 2;
2444 from_count += 2;
2445 }
2446
2447/* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2448
2449yield =
2450 (
2451 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2452 psself_to) ||
2453 (scan_cc &&
2454 (
2455 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2456 psself, psself_to)
2457 ||
2458 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2459 psself, psself_to)
2460 )
2461 )
2462 ) &&
2463
2464 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2465 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2466 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2467
059ec3d9
PH
2468 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2469
2470 (sender_address == NULL || sender_address[0] != 0);
2471
2472store_reset(reset_point);
2473return yield;
2474}
2475
2476
2477
2478/*************************************************
2479* Interpret a mail filter file *
2480*************************************************/
2481
2482/*
2483Arguments:
2484 filter points to the entire file, read into store as a single string
2485 options controls whether various special things are allowed, and requests
2486 special actions
2487 generated where to hang newly-generated addresses
2488 error where to pass back an error text
2489
2490Returns: FF_DELIVERED success, a significant action was taken
2491 FF_NOTDELIVERED success, no significant action
2492 FF_DEFER defer requested
2493 FF_FAIL fail requested
2494 FF_FREEZE freeze requested
2495 FF_ERROR there was a problem
2496*/
2497
2498int
2499filter_interpret(uschar *filter, int options, address_item **generated,
2500 uschar **error)
2501{
2502int i;
2503int yield = FF_ERROR;
2504uschar *ptr = filter;
2505uschar *save_headers_charset = headers_charset;
2506filter_cmd *commands = NULL;
2507filter_cmd **lastcmdptr = &commands;
2508
2509DEBUG(D_route) debug_printf("Filter: start of processing\n");
f3ebb786 2510acl_level++;
059ec3d9
PH
2511
2512/* Initialize "not in an if command", set the global flag that is always TRUE
2513while filtering, and zero the variables. */
2514
2515expect_endif = 0;
2516output_indent = 0;
8768d548 2517f.filter_running = TRUE;
059ec3d9
PH
2518for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2519
2520/* To save having to pass certain values about all the time, make them static.
2521Also initialize the line number, for error messages, and the log file
2522variables. */
2523
2524filter_options = options;
2525filter_delivered = FALSE;
2526finish_obeyed = FALSE;
2527error_pointer = error;
2528*error_pointer = NULL;
2529line_number = 1;
2530log_fd = -1;
2531log_mode = 0600;
2532log_filename = NULL;
2533
2534/* Scan filter file for syntax and build up an interpretation thereof, and
2535interpret the compiled commands, and if testing, say whether we ended up
2536delivered or not, unless something went wrong. */
2537
2538seen_force = FALSE;
2539ptr = nextsigchar(ptr, TRUE);
2540
2541if (read_command_list(&ptr, &lastcmdptr, FALSE))
2542 yield = interpret_commands(commands, generated);
2543
f05da2e8 2544if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
059ec3d9
PH
2545 {
2546 uschar *s = US"";
2547 switch(yield)
2548 {
2549 case FF_DEFER:
f3ebb786
JH
2550 s = US"Filtering ended by \"defer\".";
2551 break;
059ec3d9
PH
2552
2553 case FF_FREEZE:
f3ebb786
JH
2554 s = US"Filtering ended by \"freeze\".";
2555 break;
059ec3d9
PH
2556
2557 case FF_FAIL:
f3ebb786
JH
2558 s = US"Filtering ended by \"fail\".";
2559 break;
059ec3d9
PH
2560
2561 case FF_DELIVERED:
f3ebb786
JH
2562 s = US"Filtering set up at least one significant delivery "
2563 "or other action.\n"
2564 "No other deliveries will occur.";
2565 break;
059ec3d9
PH
2566
2567 case FF_NOTDELIVERED:
f3ebb786
JH
2568 s = US"Filtering did not set up a significant delivery.\n"
2569 "Normal delivery will occur.";
2570 break;
059ec3d9
PH
2571
2572 case FF_ERROR:
f3ebb786
JH
2573 s = string_sprintf("Filter error: %s", *error);
2574 break;
059ec3d9
PH
2575 }
2576
f05da2e8 2577 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
f3ebb786 2578 else debug_printf_indent("%s\n", s);
059ec3d9
PH
2579 }
2580
2581/* Close the log file if it was opened, and kill off any numerical variables
2582before returning. Reset the header decoding charset. */
2583
f1e894f3 2584if (log_fd >= 0) (void)close(log_fd);
059ec3d9 2585expand_nmax = -1;
8768d548 2586f.filter_running = FALSE;
059ec3d9
PH
2587headers_charset = save_headers_charset;
2588
f3ebb786 2589acl_level--;
059ec3d9
PH
2590DEBUG(D_route) debug_printf("Filter: end of processing\n");
2591return yield;
2592}
2593
2594
2595/* End of filter.c */