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