1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
10 /* Code for mail filtering functions. */
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. */
22 struct condition_block;
25 struct string_item *a;
27 struct condition_block *c;
33 /* Local structures used in this module */
35 typedef struct filter_cmd {
36 struct filter_cmd *next;
40 union argtypes args[1];
43 typedef struct condition_block {
44 struct condition_block *parent;
51 /* Miscellaneous other declarations */
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;
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;
68 enum { had_neither, had_else, had_elif, had_endif };
70 static BOOL read_command_list(const uschar **, filter_cmd ***, BOOL);
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
78 static const char *mailargs[] = { /* "to" must be first, and */
79 "to", /* "cc" and "bcc" must follow */
85 "extra_headers", /* miscellaneous added header lines */
93 /* The count of string arguments */
95 #define MAILARGS_STRING_COUNT (nelem(mailargs))
97 /* The count of string arguments that are actually passed over as strings
98 (once_repeat is converted to an int). */
100 #define mailargs_string_passed (MAILARGS_STRING_COUNT - 1)
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. */
105 enum { mailarg_index_to,
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 */
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 */
122 /* Offsets in the data structure for the string arguments (note that
123 once_repeat isn't a string argument at this point.) */
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),
139 /* Condition identities and names, with negated versions for some
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 };
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" };
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" };
164 /* Tables of binary condition words and their corresponding types. Not easy
165 to amalgamate with the above because of the different variants. */
167 static const char *cond_words[] = {
189 static int cond_word_count = nelem(cond_words);
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 };
196 /* Command identities: must be kept in step with the list of command words
197 and the list of expanded argument counts which follow. */
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 };
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"
211 static int command_list_count = nelem(command_list);
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". */
216 static uschar command_exparg_count[] = {
230 MAILARGS_STRING_COUNT, /* mail */
237 MAILARGS_STRING_COUNT /* vacation */
242 /*************************************************
243 * Find next significant uschar *
244 *************************************************/
246 /* Function to skip over white space and, optionally, comments.
249 ptr pointer to next character
250 comment_allowed if TRUE, comments (# to \n) are skipped
252 Returns: pointer to next non-whitespace character
255 static const uschar *
256 nextsigchar(const uschar *ptr, BOOL comment_allowed)
260 while (isspace(*ptr))
262 if (*ptr == '\n') line_number++;
265 if (comment_allowed && *ptr == '#')
267 while (*(++ptr) != '\n' && *ptr != 0);
277 /*************************************************
279 *************************************************/
281 /* The terminator is white space unless bracket is TRUE, in which
282 case ( and ) terminate.
285 ptr pointer to next character
286 buffer where to put the word
288 bracket if TRUE, terminate on ( and ) as well as space
290 Returns: pointer to the next significant character after the word
293 static const uschar *
294 nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
297 while (*ptr != 0 && !isspace(*ptr) &&
298 (!bracket || (*ptr != '(' && *ptr != ')')))
300 if (bp - buffer < size - 1) *bp++ = *ptr++; else
302 *error_pointer = string_sprintf("word is too long in line %d of "
303 "filter file (max = %d chars)", line_number, size);
308 return nextsigchar(ptr, TRUE);
313 /*************************************************
315 *************************************************/
317 /* Might be a word, or might be a quoted string; in the latter case
321 ptr pointer to next character
322 buffer where to put the item
324 bracket if TRUE, terminate non-quoted on ( and ) as well as space
326 Returns: the next significant character after the item
329 static const uschar *
330 nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
333 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
335 while (*++ptr && *ptr != '\"' && *ptr != '\n')
337 if (bp - buffer >= size - 1)
339 *error_pointer = string_sprintf("string is too long in line %d of "
340 "filter file (max = %d chars)", line_number, size);
344 if (*ptr != '\\') *bp++ = *ptr; else
346 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
348 const uschar *p = ptr + 1;
349 while (*p != '\n' && isspace(*p)) p++;
354 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
359 *bp++ = string_interpret_escape(CUSS &ptr);
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);
369 return nextsigchar(ptr, TRUE);
375 /*************************************************
376 * Convert a string + K|M to a number *
377 *************************************************/
381 s points to text string
382 OK set TRUE if a valid number was read
384 Returns: the number, or 0 on error (with *OK FALSE)
388 get_number(const uschar *s, BOOL *ok)
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;
403 /*************************************************
404 * Read one condition *
405 *************************************************/
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.
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
416 Returns: points to next character after "then"
419 static const uschar *
420 read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
424 condition_block *current_parent = NULL;
425 condition_block **current = cond;
429 /* Loop to read next condition */
435 /* reaching the end of the input is an error. */
439 *error_pointer = US"\"then\" missing at end of filter file";
443 /* Opening bracket at the start of a condition introduces a nested
444 condition, which must be terminated by a closing bracket. */
448 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
449 if (*error_pointer != NULL) break;
452 *error_pointer = string_sprintf("expected \")\" in line %d of "
453 "filter file", line_number);
458 c->testfor = !c->testfor;
461 ptr = nextsigchar(ptr+1, TRUE);
465 /* Closing bracket at the start of a condition is an error. Give an
466 explicit message, as otherwise "unknown condition" would be confusing. */
468 else if (*ptr == ')')
470 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
471 "filter file", line_number);
475 /* Otherwise we expect a word or a string. */
479 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
480 if (*error_pointer) break;
482 /* "Then" at the start of a condition is an error */
484 if (Ustrcmp(buffer, "then") == 0)
486 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
487 "filter file", line_number);
491 /* "Not" at the start of a condition negates the testing condition. */
493 if (Ustrcmp(buffer, "not") == 0)
499 /* Build a condition block from the specific word. */
501 c = store_get(sizeof(condition_block), GET_UNTAINTED);
502 c->left.u = c->right.u = NULL;
503 c->testfor = testfor;
506 /* Check for conditions that start with a keyword */
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;
513 /* Personal can be followed by any number of aliases */
515 else if (Ustrcmp(buffer, "personal") == 0)
517 c->type = cond_personal;
521 const uschar * saveptr = ptr;
522 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
523 if (*error_pointer) break;
524 if (Ustrcmp(buffer, "alias") != 0)
529 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
530 if (*error_pointer) break;
531 aa = store_get(sizeof(string_item), GET_UNTAINTED);
532 aa->text = string_copy(buffer);
533 aa->next = c->left.a;
538 /* Foranyaddress must be followed by a string and a condition enclosed
539 in parentheses, which is handled as a subcondition. */
541 else if (Ustrcmp(buffer, "foranyaddress") == 0)
543 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
544 if (*error_pointer) break;
547 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
548 "near line %d of filter file", line_number);
552 c->type = cond_foranyaddress;
553 c->left.u = string_copy(buffer);
555 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
556 if (*error_pointer) break;
559 *error_pointer = string_sprintf("expected \")\" in line %d of "
560 "filter file", line_number);
563 ptr = nextsigchar(ptr+1, TRUE);
566 /* If it's not a word we recognize, then it must be the lefthand
567 operand of one of the comparison words. */
572 const uschar *isptr = NULL;
574 c->left.u = string_copy(buffer);
575 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
576 if (*error_pointer) break;
578 /* Handle "does|is [not]", preserving the pointer after "is" in
579 case it isn't that, but the form "is <string>". */
581 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
583 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
584 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
586 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
587 if (*error_pointer) break;
588 if (strcmpic(buffer, US"not") == 0)
590 c->testfor = !c->testfor;
591 if (isptr) isptr = ptr;
592 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
593 if (*error_pointer) break;
597 for (i = 0; i < cond_word_count; i++)
599 if (Ustrcmp(buffer, cond_words[i]) == 0)
601 c->type = cond_types[i];
606 /* If an unknown word follows "is" or "is not"
607 it's actually the argument. Reset to read it. */
609 if (i >= cond_word_count)
613 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
614 "near line %d of filter file", buffer, line_number);
620 /* Get the RH argument. */
622 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
623 if (*error_pointer) break;
624 c->right.u = string_copy(buffer);
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. */
633 /* Closing bracket terminates if this is a lower-level condition. Otherwise
639 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
640 "filter file", line_number);
644 /* Opening bracket following a condition is an error; give an explicit
645 message to make it clearer what is wrong. */
647 else if (*ptr == '(')
649 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
650 "filter file", line_number);
654 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
658 // const uschar *saveptr = ptr;
659 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
660 if (*error_pointer) break;
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 /*XXX This stops us doing a constification job in this file, unfortunately.
666 Comment it out and see if anything breaks.
667 With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
669 if (Ustrcmp(buffer, "then") == 0)
671 // if (toplevel) *saveptr = 0;
674 *error_pointer = string_sprintf("missing \")\" at end of "
675 "condition near line %d of filter file", line_number);
679 /* "And" causes a new condition block to replace the one we have
680 just read, which becomes the left sub-condition. The current pointer
681 is reset to the pointer for the right sub-condition. We have to keep
682 track of the tree of sequential "ands", so as to traverse back up it
683 if an "or" is met. */
685 else if (Ustrcmp(buffer, "and") == 0)
687 condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
688 andc->parent = current_parent;
689 andc->type = cond_and;
690 andc->testfor = TRUE;
692 andc->right.u = NULL; /* insurance */
694 current = &(andc->right.c);
695 current_parent = andc;
698 /* "Or" is similar, but has to be done a bit more carefully to
699 ensure that "and" is more binding. If there's a parent set, we
700 are following a sequence of "and"s and must track back to their
703 else if (Ustrcmp(buffer, "or") == 0)
705 condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
706 condition_block * or_parent = NULL;
710 while (current_parent->parent &&
711 current_parent->parent->type == cond_and)
712 current_parent = current_parent->parent;
714 /* If the parent has a parent, it must be an "or" parent. */
716 if (current_parent->parent)
717 or_parent = current_parent->parent;
720 orc->parent = or_parent;
721 if (!or_parent) *cond = orc;
722 else or_parent->right.c = orc;
725 orc->left.c = (current_parent == NULL)? c : current_parent;
726 orc->right.c = NULL; /* insurance */
727 current = &(orc->right.c);
728 current_parent = orc;
731 /* Otherwise there is a disaster */
735 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
736 "expected near line %d of filter file, but found \"%s\"",
737 toplevel? "then" : ")", line_number, buffer);
743 return nextsigchar(ptr, TRUE);
748 /*************************************************
749 * Output the current indent *
750 *************************************************/
756 for (i = 0; i < output_indent; i++) debug_printf(" ");
761 /*************************************************
762 * Condition printer: for debugging *
763 *************************************************/
767 c the block at the top of the tree
768 toplevel TRUE at toplevel - stops overall brackets
774 print_condition(condition_block *c, BOOL toplevel)
776 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
783 case cond_manualthaw:
784 debug_printf("%s", name);
799 debug_printf("%s %s %s", c->left.u, name, c->right.u);
803 if (!c->testfor) debug_printf("not (");
804 print_condition(c->left.c, FALSE);
805 debug_printf(" %s ", cond_names[c->type]);
806 print_condition(c->right.c, FALSE);
807 if (!c->testfor) debug_printf(")");
811 if (!c->testfor) debug_printf("not (");
812 else if (!toplevel) debug_printf("(");
813 print_condition(c->left.c, FALSE);
814 debug_printf(" %s ", cond_names[c->type]);
815 print_condition(c->right.c, FALSE);
816 if (!toplevel || !c->testfor) debug_printf(")");
819 case cond_foranyaddress:
820 debug_printf("%s %s (", name, c->left.u);
821 print_condition(c->right.c, FALSE);
830 /*************************************************
831 * Read one filtering command *
832 *************************************************/
836 pptr points to pointer to first character of command; the pointer
837 is updated to point after the last character read
838 lastcmdptr points to pointer to pointer to last command; used for hanging
839 on the newly read command
841 Returns: TRUE if command successfully read, else FALSE
845 read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
847 int command, i, cmd_bit;
848 filter_cmd *new, **newlastcmdptr;
850 BOOL was_seen_or_unseen = FALSE;
851 BOOL was_noerror = FALSE;
853 const uschar *ptr = *pptr;
854 const uschar *saveptr;
857 /* Read the next word and find which command it is. Command words are normally
858 terminated by white space, but there are two exceptions, which are the "if" and
859 "elif" commands. We must allow for them to be terminated by an opening bracket,
860 as brackets are allowed in conditions and users will expect not to require
863 *buffer = '\0'; /* compiler quietening */
865 if (Ustrncmp(ptr, "if(", 3) == 0)
867 Ustrcpy(buffer, US"if");
870 else if (Ustrncmp(ptr, "elif(", 5) == 0)
872 Ustrcpy(buffer, US"elif");
877 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
878 if (*error_pointer) return FALSE;
881 for (command = 0; command < command_list_count; command++)
882 if (Ustrcmp(buffer, command_list[command]) == 0) break;
884 /* Handle the individual commands */
888 /* Add takes two arguments, separated by the word "to". Headers has two
889 arguments, but the first must be "add", "remove", or "charset", and it gets
890 stored in the second argument slot. Neither may be preceded by seen, unseen
894 case headers_command:
895 if (seen_force || noerror_force)
897 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
898 "found before an \"%s\" command near line %d",
899 command_list[command], line_number);
904 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
905 and logfile can have an option second argument for the mode, and deliver can
906 have "errors_to <address>" in a system filter, or in a user filter if the
907 address is the current one. */
909 case deliver_command:
910 case logfile_command:
911 case logwrite_command:
914 case testprint_command:
916 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
918 *error_pointer = string_sprintf("\"%s\" requires an argument "
919 "near line %d of filter file", command_list[command], line_number);
921 if (*error_pointer) yield = FALSE; else
923 union argtypes argument, second_argument;
925 argument.u = second_argument.u = NULL;
927 if (command == add_command)
929 argument.u = string_copy(buffer);
930 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
931 if (!*buffer || Ustrcmp(buffer, "to") != 0)
932 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
933 "near line %d of filter file", line_number);
936 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
938 *error_pointer = string_sprintf("value missing after \"to\" "
939 "near line %d of filter file", line_number);
940 else second_argument.u = string_copy(buffer);
944 else if (command == headers_command)
946 if (Ustrcmp(buffer, "add") == 0)
947 second_argument.b = TRUE;
949 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
951 if (Ustrcmp(buffer, "charset") == 0)
952 second_argument.b = TRUE_UNSET;
955 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
956 "expected after \"headers\" near line %d of filter file",
961 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
963 *error_pointer = string_sprintf("header addition and removal is "
964 "available only in system filters: near line %d of filter file",
972 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
974 *error_pointer = string_sprintf("value missing after \"add\", "
975 "\"remove\", or \"charset\" near line %d of filter file",
977 else argument.u = string_copy(buffer);
981 /* The argument for the logwrite command must end in a newline, and the save
982 and logfile commands can have an optional mode argument. The deliver
983 command can have an optional "errors_to <address>" for a system filter,
984 or for a user filter if the address is the user's address. Accept the
985 syntax here - the check is later. */
989 if (command == logwrite_command)
991 int len = Ustrlen(buffer);
992 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
995 argument.u = string_copy(buffer);
997 if (command == save_command || command == logfile_command)
1001 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1002 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
1004 else second_argument.i = -1;
1007 else if (command == deliver_command)
1009 const uschar *save_ptr = ptr;
1010 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1011 if (Ustrcmp(buffer, "errors_to") == 0)
1013 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1014 second_argument.u = string_copy(buffer);
1016 else ptr = save_ptr;
1020 /* Set up the command block. Seen defaults TRUE for delivery commands,
1021 FALSE for logging commands, and it doesn't matter for testprint, as
1022 that doesn't change the "delivered" status. */
1024 if (*error_pointer) yield = FALSE;
1027 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
1030 *lastcmdptr = &(new->next);
1031 new->command = command;
1032 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1033 new->noerror = noerror_force;
1034 new->args[0] = argument;
1035 new->args[1] = second_argument;
1041 /* Elif, else and endif just set a flag if expected. */
1046 if (seen_force || noerror_force)
1048 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1049 "near line %d is not followed by a command", line_number);
1053 if (expect_endif > 0)
1054 had_else_endif = (command == elif_command)? had_elif :
1055 (command == else_command)? had_else : had_endif;
1058 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1059 "line %d of filter file", buffer, line_number);
1065 /* Defer, freeze, and fail are available only if permitted. */
1068 cmd_bit = RDO_DEFER;
1069 goto DEFER_FREEZE_FAIL;
1073 goto DEFER_FREEZE_FAIL;
1075 case freeze_command:
1076 cmd_bit = RDO_FREEZE;
1079 if ((filter_options & cmd_bit) == 0)
1081 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1082 "near line %d of filter file", buffer, line_number);
1087 /* A text message can be provided after the "text" keyword, or
1088 as a string in quotes. */
1091 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1092 if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0))
1099 if (*saveptr != '\"')
1100 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1101 fmsg = string_copy(buffer);
1104 /* Drop through and treat as "finish", but never set "seen". */
1108 /* Finish has no arguments; fmsg defaults to NULL */
1110 case finish_command:
1111 new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
1114 *lastcmdptr = &(new->next);
1115 new->command = command;
1116 new->seen = seen_force ? seen_value : FALSE;
1117 new->args[0].u = fmsg;
1121 /* Seen, unseen, and noerror are not allowed before if, which takes a
1122 condition argument and then and else sub-commands. */
1125 if (seen_force || noerror_force)
1127 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1128 "found before an \"if\" command near line %d",
1133 /* Set up the command block for if */
1135 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1138 *lastcmdptr = &new->next;
1139 new->command = command;
1141 new->args[0].u = NULL;
1142 new->args[1].u = new->args[2].u = NULL;
1143 new->args[3].u = ptr;
1145 /* Read the condition */
1147 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1148 if (*error_pointer) { yield = FALSE; break; }
1150 /* Read the commands to be obeyed if the condition is true */
1152 newlastcmdptr = &(new->args[1].f);
1153 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1155 /* If commands were successfully read, handle the various possible
1156 terminators. There may be a number of successive "elif" sections. */
1160 while (had_else_endif == had_elif)
1162 filter_cmd *newnew =
1163 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1164 new->args[2].f = newnew;
1167 new->command = command;
1169 new->args[0].u = NULL;
1170 new->args[1].u = new->args[2].u = NULL;
1171 new->args[3].u = ptr;
1173 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1174 if (*error_pointer) { yield = FALSE; break; }
1175 newlastcmdptr = &(new->args[1].f);
1176 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1180 if (yield == FALSE) break;
1182 /* Handle termination by "else", possibly following one or more
1183 "elsif" sections. */
1185 if (had_else_endif == had_else)
1187 newlastcmdptr = &(new->args[2].f);
1188 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1190 else if (had_else_endif != had_endif)
1192 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1193 "filter file", line_number);
1198 /* Otherwise the terminator was "endif" - this is checked by
1199 read_command_list(). The pointer is already set to NULL. */
1202 /* Reset the terminator flag. */
1204 had_else_endif = had_neither;
1208 /* The mail & vacation commands have a whole slew of keyworded arguments.
1209 The final argument values are the file expand and return message booleans,
1210 whose offsets are defined in mailarg_index_{expand,return}. Although they
1211 are logically booleans, because they are stored in a uschar * value, we use
1212 NULL and not FALSE, to keep 64-bit compilers happy. */
1215 case vacation_command:
1216 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
1218 new->command = command;
1219 new->seen = seen_force ? seen_value : FALSE;
1220 new->noerror = noerror_force;
1221 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1223 /* Read keyword/value pairs until we hit one that isn't. The data
1224 must contain only printing chars plus tab, though the "text" value
1225 can also contain newlines. The "file" keyword can be preceded by the
1226 word "expand", and "return message" has no data. */
1230 const uschar *saveptr = ptr;
1231 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1233 { yield = FALSE; break; }
1235 /* Ensure "return" is followed by "message"; that's a complete option */
1237 if (Ustrcmp(buffer, "return") == 0)
1239 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1240 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1241 if (Ustrcmp(buffer, "message") != 0)
1243 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1244 " near line %d of filter file", line_number);
1251 /* Ensure "expand" is followed by "file", then fall through to process the
1254 if (Ustrcmp(buffer, "expand") == 0)
1256 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1257 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1258 if (Ustrcmp(buffer, "file") != 0)
1260 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1261 " near line %d of filter file", line_number);
1267 /* Scan for the keyword */
1269 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1270 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1272 /* Not found keyword; assume end of this command */
1274 if (i >= MAILARGS_STRING_COUNT)
1280 /* Found keyword, read the data item */
1282 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1284 { yield = FALSE; break; }
1285 else new->args[i].u = string_copy(buffer);
1288 /* If this is the vacation command, apply some default settings to
1289 some of the arguments. */
1291 if (command == vacation_command)
1293 if (!new->args[mailarg_index_file].u)
1295 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1296 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1298 if (!new->args[mailarg_index_log].u)
1299 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1300 if (!new->args[mailarg_index_once].u)
1301 new->args[mailarg_index_once].u = string_copy(US".vacation");
1302 if (!new->args[mailarg_index_once_repeat].u)
1303 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1304 if (!new->args[mailarg_index_subject].u)
1305 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1308 /* Join the address on to the chain of generated addresses */
1311 *lastcmdptr = &(new->next);
1315 /* Seen and unseen just set flags */
1318 case unseen_command:
1321 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1322 "near line %d is not followed by a command", line_number);
1327 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1328 "near line %d", line_number);
1331 seen_value = (command == seen_command);
1333 was_seen_or_unseen = TRUE;
1337 /* So does noerror */
1339 case noerror_command:
1342 *error_pointer = string_sprintf("\"noerror\" "
1343 "near line %d is not followed by a command", line_number);
1346 noerror_force = TRUE;
1354 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1355 "near line %d of filter file", buffer, line_number);
1360 if (!was_seen_or_unseen && !was_noerror)
1363 noerror_force = FALSE;
1372 /*************************************************
1373 * Read a list of commands *
1374 *************************************************/
1376 /* If conditional is TRUE, the list must be terminated
1377 by the words "else" or "endif".
1380 pptr points to pointer to next character; the pointer is updated
1381 lastcmdptr points to pointer to pointer to previously-read command; used
1382 for hanging on the new command
1383 conditional TRUE if this command is the subject of a condition
1385 Returns: TRUE on success
1389 read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1391 if (conditional) expect_endif++;
1392 had_else_endif = had_neither;
1393 while (**pptr && had_else_endif == had_neither)
1395 if (!read_command(pptr, lastcmdptr)) return FALSE;
1396 *pptr = nextsigchar(*pptr, TRUE);
1401 if (had_else_endif == had_neither)
1403 *error_pointer = US"\"endif\" missing at end of filter file";
1413 /*************************************************
1414 * Test a condition *
1415 *************************************************/
1419 c points to the condition block; c->testfor indicated whether
1420 it's a positive or negative condition
1421 toplevel TRUE if called from "if" directly; FALSE otherwise
1423 Returns: TRUE if the condition is met
1427 test_condition(condition_block *c, BOOL toplevel)
1430 const uschar *exp[2], * p, * pp;
1434 if (c == NULL) return TRUE; /* does this ever occur? */
1439 yield = test_condition(c->left.c, FALSE) &&
1440 *error_pointer == NULL &&
1441 test_condition(c->right.c, FALSE);
1445 yield = test_condition(c->left.c, FALSE) ||
1446 (*error_pointer == NULL &&
1447 test_condition(c->right.c, FALSE));
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). */
1455 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
1458 case cond_delivered:
1459 yield = filter_delivered;
1462 /* Only TRUE if a message is actually being processed; FALSE for address
1463 testing and verification. */
1466 yield = message_id[0] != 0 &&
1467 (sender_address == NULL || sender_address[0] == 0);
1470 /* Only FALSE if a message is actually being processed; TRUE for address
1471 and filter testing and verification. */
1473 case cond_firsttime:
1474 yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
1477 /* Only TRUE if a message is actually being processed; FALSE for address
1478 testing and verification. */
1480 case cond_manualthaw:
1481 yield = message_id[0] != 0 && f.deliver_manual_thaw;
1484 /* The foranyaddress condition loops through a list of addresses */
1486 case cond_foranyaddress:
1488 if (!(pp = expand_cstring(p)))
1490 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1491 "filter file: %s", p, expand_string_message);
1496 f.parse_allow_group = TRUE; /* Allow group syntax */
1501 int start, end, domain;
1504 p = parse_find_address_end(pp, FALSE);
1505 s = string_copyn(pp, p - pp);
1507 filter_thisaddress =
1508 parse_extract_address(s, &error, &start, &end, &domain, FALSE);
1510 if (filter_thisaddress)
1512 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1513 (debug_selector & D_filter) != 0)
1516 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
1518 yield = test_condition(c->right.c, FALSE);
1526 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1527 f.parse_found_group = FALSE;
1530 /* All other conditions have left and right values that need expanding;
1531 on error, it doesn't matter what value is returned. */
1535 for (i = 0; i < 2; i++)
1537 if (!(exp[i] = expand_cstring(p)))
1539 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1540 "filter file: %s", p, expand_string_message);
1546 /* Inner switch for the different cases */
1551 yield = strcmpic(exp[0], exp[1]) == 0;
1555 yield = Ustrcmp(exp[0], exp[1]) == 0;
1559 yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
1563 yield = Ustrstr(exp[0], exp[1]) != NULL;
1567 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1571 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1577 int len = Ustrlen(exp[1]);
1578 const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1581 : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1588 const pcre2_code *re;
1592 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1593 (debug_selector & D_filter) != 0)
1595 debug_printf_indent("Match expanded arguments:\n");
1596 debug_printf_indent(" Subject = %s\n", exp[0]);
1597 debug_printf_indent(" Pattern = %s\n", exp[1]);
1600 if (!(re = pcre2_compile((PCRE2_SPTR)exp[1], PCRE2_ZERO_TERMINATED,
1601 PCRE_COPT | (c->type == cond_matches ? PCRE2_CASELESS : 0),
1602 &err, &offset, pcre_gen_cmp_ctx)))
1605 pcre2_get_error_message(err, errbuf, sizeof(errbuf));
1606 *error_pointer = string_sprintf("error while compiling "
1607 "regular expression \"%s\": %s at offset %ld",
1608 exp[1], errbuf, (long)offset);
1612 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1616 /* For above and below, convert the strings to numbers */
1620 for (i = 0; i < 2; i++)
1622 val[i] = get_number(exp[i], &yield);
1625 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1630 yield = (c->type == cond_above)? (val[0] > val[1]) : (val[0] < val[1]);
1636 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1637 (debug_selector & D_filter) != 0)
1640 debug_printf_indent("%sondition is %s: ",
1641 toplevel? "C" : "Sub-c",
1642 (yield == c->testfor)? "true" : "false");
1643 print_condition(c, TRUE);
1644 debug_printf_indent("\n");
1647 return yield == c->testfor;
1652 /*************************************************
1653 * Interpret chain of commands *
1654 *************************************************/
1656 /* In testing state, just say what would be done rather than doing it. The
1657 testprint command just expands and outputs its argument in testing state, and
1658 does nothing otherwise.
1661 commands points to chain of commands to interpret
1662 generated where to hang newly-generated addresses
1664 Returns: FF_DELIVERED success, a significant action was taken
1665 FF_NOTDELIVERED success, no significant action
1666 FF_DEFER defer requested
1667 FF_FAIL fail requested
1668 FF_FREEZE freeze requested
1669 FF_ERROR there was a problem
1673 interpret_commands(filter_cmd *commands, address_item **generated)
1678 BOOL condition_value;
1683 uschar *fmsg, *ff_name;
1684 const uschar *expargs[MAILARGS_STRING_COUNT];
1688 /* Expand the relevant number of arguments for the command that are
1691 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1693 const uschar *ss = commands->args[i].u;
1696 else if (!(expargs[i] = expand_cstring(ss)))
1698 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1699 "%s command: %s", ss, command_list[commands->command],
1700 expand_string_message);
1705 /* Now switch for each command, setting the "delivered" flag if any of them
1708 if (commands->seen) filter_delivered = TRUE;
1710 switch(commands->command)
1713 for (i = 0; i < 2; i++)
1715 const uschar *ss = expargs[i];
1718 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1720 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1721 "command", expargs[i]);
1725 /* Allow for "--" at the start of the value (from -$n0) for example */
1726 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1728 n[i] = (int)Ustrtol(ss, &end, 0);
1731 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1737 filter_n[n[1]] += n[0];
1738 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1741 /* A deliver command's argument must be a valid address. Its optional
1742 second argument (system filter only) must also be a valid address. */
1744 case deliver_command:
1745 for (i = 0; i < 2; i++)
1750 int start, end, domain;
1752 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1755 expargs[i] = filter_options & RDO_REWRITE
1756 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1758 : rewrite_address_qualify(ss, TRUE);
1761 *error_pointer = string_sprintf("malformed address \"%s\" in "
1762 "filter file: %s", s, error);
1768 /* Stick the errors address into a simple variable, as it will
1769 be referenced a few times. Check that the caller is permitted to
1774 if (s != NULL && !f.system_filtering)
1776 uschar *ownaddress = expand_string(US"$local_part@$domain");
1777 if (strcmpic(ownaddress, s) != 0)
1779 *error_pointer = US"errors_to must point to the caller's address";
1784 /* Test case: report what would happen */
1786 if (filter_test != FTEST_NONE)
1789 printf("%seliver message to: %s%s%s%s\n",
1790 (commands->seen)? "D" : "Unseen d",
1792 commands->noerror? " (noerror)" : "",
1793 (s != NULL)? " errors_to " : "",
1794 (s != NULL)? s : US"");
1801 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1802 (commands->seen)? "" : "unseen ",
1804 commands->noerror? " (noerror)" : "",
1805 (s != NULL)? " errors_to " : "",
1806 (s != NULL)? s : US"");
1808 /* Create the new address and add it to the chain, setting the
1809 af_ignore_error flag if necessary, and the errors address, which can be
1810 set in a system filter and to the local address in user filters. */
1812 addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
1813 addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1814 if (commands->noerror) addr->prop.ignore_error = TRUE;
1815 addr->next = *generated;
1822 mode = commands->args[1].i;
1824 /* Test case: report what would happen */
1826 if (filter_test != FTEST_NONE)
1830 printf("%save message to: %s%s\n", (commands->seen)?
1831 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1833 printf("%save message to: %s %04o%s\n", (commands->seen)?
1834 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1837 /* Real case: Ensure save argument starts with / if there is a home
1838 directory to prepend. */
1842 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1843 deliver_home != NULL && deliver_home[0] != 0)
1844 s = string_sprintf("%s/%s", deliver_home, s);
1845 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1846 (commands->seen)? "" : "unseen ", s,
1847 commands->noerror? " (noerror)" : "");
1849 /* Create the new address and add it to the chain, setting the
1850 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1853 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1854 setflag(addr, af_pfr);
1855 setflag(addr, af_file);
1856 if (commands->noerror) addr->prop.ignore_error = TRUE;
1858 addr->next = *generated;
1864 s = string_copy(commands->args[0].u);
1865 if (filter_test != FTEST_NONE)
1868 printf("%sipe message to: %s%s\n", (commands->seen)?
1869 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1871 else /* Ensure pipe command starts with | */
1873 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1874 commands->seen ? "" : "unseen ", s,
1875 commands->noerror ? " (noerror)" : "");
1876 if (s[0] != '|') s = string_sprintf("|%s", s);
1878 /* Create the new address and add it to the chain, setting the
1879 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1880 each command argument is expanded in the transport after the command
1881 has been split up into separate arguments. */
1883 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1884 setflag(addr, af_pfr);
1885 setflag(addr, af_expand_pipe);
1886 if (commands->noerror) addr->prop.ignore_error = TRUE;
1887 addr->next = *generated;
1890 /* If there are any numeric variables in existence (e.g. after a regex
1891 condition), or if $thisaddress is set, take a copy for use in the
1892 expansion. Note that we can't pass NULL for filter_thisaddress, because
1893 NULL terminates the list. */
1895 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1897 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1898 uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1900 addr->pipe_expandn = ss;
1901 if (!filter_thisaddress) filter_thisaddress = US"";
1902 *ss++ = string_copy(filter_thisaddress);
1903 for (int i = 0; i <= expand_nmax; i++)
1904 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1910 /* Set up the file name and mode, and close any previously open
1913 case logfile_command:
1914 log_mode = commands->args[1].i;
1915 if (log_mode == -1) log_mode = 0600;
1918 (void)close(log_fd);
1921 log_filename = expargs[0];
1922 if (filter_test != FTEST_NONE)
1925 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1929 case logwrite_command:
1932 if (filter_test != FTEST_NONE)
1935 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1936 string_printing(s));
1939 /* Attempt to write to a log file only if configured as permissible.
1940 Logging may be forcibly skipped for verifying or testing. */
1942 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1945 debug_printf_indent("filter log command aborted: euid=%ld\n",
1946 (long int)geteuid());
1947 *error_pointer = US"logwrite command forbidden";
1950 else if ((filter_options & RDO_REALLOG) != 0)
1953 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1954 (long int)geteuid());
1959 *error_pointer = US"attempt to obey \"logwrite\" command "
1960 "without a previous \"logfile\"";
1963 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1966 *error_pointer = string_open_failed("filter log file \"%s\"",
1972 if (write(log_fd, s, len) != len)
1974 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1975 log_filename, strerror(errno));
1981 debug_printf_indent("skipping logwrite (verifying or testing)\n");
1984 /* Header addition and removal is available only in the system filter. The
1985 command is rejected at parse time otherwise. However "headers charset" is
1986 always permitted. */
1988 case headers_command:
1990 int subtype = commands->args[1].i;
1993 if (filter_test != FTEST_NONE)
1994 printf("Headers %s \"%s\"\n",
1995 subtype == TRUE ? "add"
1996 : subtype == FALSE ? "remove"
1998 string_printing(s));
2000 if (subtype == TRUE)
2002 while (isspace(*s)) s++;
2005 header_add(htype_other, "%s%s", s,
2006 s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2007 header_last->type = header_checkname(header_last, FALSE);
2008 if (header_last->type >= 'a') header_last->type = htype_other;
2012 else if (subtype == FALSE)
2015 const uschar * list = s;
2017 for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2018 header_remove(0, ss);
2021 /* This setting lasts only while the filter is running; on exit, the
2022 variable is reset to the previous value. */
2024 else headers_charset = s;
2028 /* Defer, freeze, and fail are available only when explicitly permitted.
2029 These commands are rejected at parse time otherwise. The message can get
2030 very long by the inclusion of message headers; truncate if it is, and also
2031 ensure printing characters so as not to mess up log files. */
2034 ff_name = US"defer";
2036 goto DEFERFREEZEFAIL;
2041 goto DEFERFREEZEFAIL;
2043 case freeze_command:
2044 ff_name = US"freeze";
2048 *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2049 ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2050 : string_copy(expargs[0]));
2051 for(uschar * s = fmsg; *s; s++)
2052 if (!s[1] && *s == '\n') { *s = '\0'; break; } /* drop trailing newline */
2054 if (filter_test != FTEST_NONE)
2057 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2060 DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2063 case finish_command:
2064 if (filter_test != FTEST_NONE)
2067 printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2070 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2071 commands->seen ? " Seen " : "");
2072 finish_obeyed = TRUE;
2073 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2077 uschar *save_address = filter_thisaddress;
2078 int ok = FF_DELIVERED;
2079 condition_value = test_condition(commands->args[0].c, TRUE);
2085 ok = interpret_commands(commands->args[condition_value? 1:2].f,
2089 filter_thisaddress = save_address;
2090 if (finish_obeyed || ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2096 /* To try to catch runaway loops, do not generate mail if the
2097 return path is unset or if a non-trusted user supplied -f <>
2098 as the return path. */
2101 case vacation_command:
2102 if (!return_path || !*return_path)
2104 if (filter_test != FTEST_NONE)
2105 printf("%s command ignored because return_path is empty\n",
2106 command_list[commands->command]);
2107 else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2108 "is empty\n", command_list[commands->command]);
2112 /* Check the contents of the strings. The type of string can be deduced
2113 from the value of i.
2115 . If i is equal to mailarg_index_text it's a text string for the body,
2116 where anything goes.
2118 . If i is > mailarg_index_text, we are dealing with a file name, which
2119 cannot contain non-printing characters.
2121 . If i is less than mailarg_index_headers we are dealing with something
2122 that will go in a single message header line, where newlines must be
2123 followed by white space.
2125 . If i is equal to mailarg_index_headers, we have a string that contains
2126 one or more headers. Newlines that are not followed by white space must
2127 be followed by a header name.
2130 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2132 const uschar *s = expargs[i];
2136 if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2139 if (i > mailarg_index_text)
2141 if (!mac_isprint(c))
2143 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2144 "in %s command", string_printing(s),
2145 command_list[commands->command]);
2150 /* i < mailarg_index_text */
2152 else if (c == '\n' && !isspace(p[1]))
2154 if (i < mailarg_index_headers)
2156 *error_pointer = string_sprintf("\\n not followed by space in "
2157 "\"%.1024s\" in %s command", string_printing(s),
2158 command_list[commands->command]);
2162 /* Check for the start of a new header line within the string */
2167 for (pp = p + 1;; pp++)
2170 if (c == ':' && pp != p + 1) break;
2171 if (!c || c == ':' || isspace(c))
2173 *error_pointer = string_sprintf("\\n not followed by space or "
2174 "valid header name in \"%.1024s\" in %s command",
2175 string_printing(s), command_list[commands->command]);
2182 } /* Loop to scan the string */
2184 /* The string is OK */
2186 commands->args[i].u = s;
2189 /* Proceed with mail or vacation command */
2191 if (filter_test != FTEST_NONE)
2193 const uschar *to = commands->args[mailarg_index_to].u;
2195 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2196 to ? to : US"<default>",
2197 commands->command == vacation_command ? " (vacation)" : "",
2198 commands->noerror ? " (noerror)" : "");
2199 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2201 const uschar *arg = commands->args[i].u;
2204 int len = Ustrlen(mailargs[i]);
2205 int indent = (debug_selector != 0)? output_indent : 0;
2206 while (len++ < 7 + indent) printf(" ");
2207 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2208 (commands->args[mailarg_index_expand].u != NULL &&
2209 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2212 if (commands->args[mailarg_index_return].u)
2213 printf("Return original message\n");
2218 const uschar *to = commands->args[mailarg_index_to].u;
2219 gstring * log_addr = NULL;
2221 if (!to) to = expand_string(US"$reply_address");
2222 while (isspace(*to)) to++;
2224 for (tt = to; *tt; tt++) /* Get rid of newlines */
2227 uschar * s = string_copy(to);
2228 for (uschar * ss = s; *ss; ss++)
2229 if (*ss == '\n') *ss = ' ';
2236 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2237 commands->seen ? "seen " : "",
2239 commands->command == vacation_command ? " (vacation)" : "",
2240 commands->noerror ? " (noerror)" : "");
2241 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2243 const uschar *arg = commands->args[i].u;
2246 int len = Ustrlen(mailargs[i]);
2247 while (len++ < 15) debug_printf_indent(" ");
2248 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2249 (commands->args[mailarg_index_expand].u != NULL &&
2250 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2255 /* Create the "address" for the autoreply. This is used only for logging,
2256 as the actual recipients are extracted from the To: line by -t. We use the
2257 same logic here to extract the working addresses (there may be more than
2258 one). Just in case there are a vast number of addresses, stop when the
2259 string gets too long. */
2264 uschar *ss = parse_find_address_end(tt, FALSE);
2265 uschar *recipient, *errmess;
2266 int start, end, domain;
2270 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2274 /* Ignore empty addresses and errors; an error will occur later if
2275 there's something really bad. */
2279 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2280 log_addr = string_cat (log_addr, recipient);
2285 if (log_addr && log_addr->ptr > 256)
2287 log_addr = string_catn(log_addr, US", ...", 5);
2291 /* Move on past this address */
2293 tt = ss + (*ss ? 1 : 0);
2294 while (isspace(*tt)) tt++;
2298 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2301 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2302 setflag(addr, af_bad_reply);
2305 setflag(addr, af_pfr);
2306 if (commands->noerror) addr->prop.ignore_error = TRUE;
2307 addr->next = *generated;
2310 addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2311 addr->reply->from = NULL;
2312 addr->reply->to = string_copy(to);
2313 addr->reply->file_expand =
2314 commands->args[mailarg_index_expand].u != NULL;
2315 addr->reply->expand_forbid = expand_forbid;
2316 addr->reply->return_message =
2317 commands->args[mailarg_index_return].u != NULL;
2318 addr->reply->once_repeat = 0;
2320 if (commands->args[mailarg_index_once_repeat].u != NULL)
2322 addr->reply->once_repeat =
2323 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2325 if (addr->reply->once_repeat < 0)
2327 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2328 "in mail or vacation command: %s",
2329 commands->args[mailarg_index_once_repeat].u);
2334 /* Set up all the remaining string arguments (those other than "to") */
2336 for (i = 1; i < mailargs_string_passed; i++)
2338 const uschar *ss = commands->args[i].u;
2339 *(USS((US addr->reply) + reply_offsets[i])) =
2340 ss ? string_copy(ss) : NULL;
2345 case testprint_command:
2346 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2348 const uschar *s = string_printing(expargs[0]);
2349 if (filter_test == FTEST_NONE)
2350 debug_printf_indent("Filter: testprint: %s\n", s);
2352 printf("Testprint: %s\n", s);
2356 commands = commands->next;
2359 return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
2364 /*************************************************
2365 * Test for a personal message *
2366 *************************************************/
2368 /* This function is global so that it can also be called from the code that
2369 implements Sieve filters.
2372 aliases a chain of aliases
2373 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2375 Returns: TRUE if the message is deemed to be personal
2379 filter_personal(string_item *aliases, BOOL scan_cc)
2381 const uschar *self, *self_from, *self_to;
2382 uschar *psself = NULL;
2383 const uschar *psself_from = NULL, *psself_to = NULL;
2384 rmark reset_point = store_mark();
2390 /* If any header line in the message is a defined "List-" header field, it is
2391 not a personal message. We used to check for any header line that started with
2392 "List-", but this was tightened up for release 4.54. The check is now for
2393 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2394 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2395 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2396 contain any value other than "no", the message is not personal (RFC 3834).
2397 Previously the test was for "auto-". */
2399 for (h = header_list; h; h = h->next)
2401 if (h->type == htype_old) continue;
2403 if (strncmpic(h->text, US"List-", 5) == 0)
2405 uschar * s = h->text + 5;
2406 if (strncmpic(s, US"Id:", 3) == 0 ||
2407 strncmpic(s, US"Help:", 5) == 0 ||
2408 strncmpic(s, US"Subscribe:", 10) == 0 ||
2409 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2410 strncmpic(s, US"Post:", 5) == 0 ||
2411 strncmpic(s, US"Owner:", 6) == 0 ||
2412 strncmpic(s, US"Archive:", 8) == 0)
2416 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2418 uschar * s = h->text + 15;
2419 Uskip_whitespace(&s);
2420 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2422 Uskip_whitespace(&s);
2423 if (*s) return FALSE;
2427 /* Set up "my" address */
2429 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2430 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2431 global_rewrite_rules);
2432 self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2433 global_rewrite_rules);
2436 if (!self_from) self_from = self;
2437 if (self_to) self_to = self;
2439 /* If there's a prefix or suffix set, we must include the prefixed/
2440 suffixed version of the local part in the tests. */
2442 if (deliver_localpart_prefix || deliver_localpart_suffix)
2444 psself = string_sprintf("%s%s%s@%s",
2445 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2447 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2449 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2450 global_rewrite_rules);
2451 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2452 global_rewrite_rules);
2453 if (psself_from == NULL) psself_from = psself;
2454 if (psself_to == NULL) psself_to = psself;
2459 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2463 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2467 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2470 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2476 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2477 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2478 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2480 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2482 (sender_address == NULL || sender_address[0] != 0);
2484 store_reset(reset_point);
2490 /*************************************************
2491 * Interpret a mail filter file *
2492 *************************************************/
2496 filter points to the entire file, read into store as a single string
2497 options controls whether various special things are allowed, and requests
2499 generated where to hang newly-generated addresses
2500 error where to pass back an error text
2502 Returns: FF_DELIVERED success, a significant action was taken
2503 FF_NOTDELIVERED success, no significant action
2504 FF_DEFER defer requested
2505 FF_FAIL fail requested
2506 FF_FREEZE freeze requested
2507 FF_ERROR there was a problem
2511 filter_interpret(const uschar *filter, int options, address_item **generated,
2515 int yield = FF_ERROR;
2516 const uschar *ptr = filter;
2517 const uschar *save_headers_charset = headers_charset;
2518 filter_cmd *commands = NULL;
2519 filter_cmd **lastcmdptr = &commands;
2521 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2524 /* Initialize "not in an if command", set the global flag that is always TRUE
2525 while filtering, and zero the variables. */
2529 f.filter_running = TRUE;
2530 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2532 /* To save having to pass certain values about all the time, make them static.
2533 Also initialize the line number, for error messages, and the log file
2536 filter_options = options;
2537 filter_delivered = FALSE;
2538 finish_obeyed = FALSE;
2539 error_pointer = error;
2540 *error_pointer = NULL;
2544 log_filename = NULL;
2546 /* Scan filter file for syntax and build up an interpretation thereof, and
2547 interpret the compiled commands, and if testing, say whether we ended up
2548 delivered or not, unless something went wrong. */
2551 ptr = nextsigchar(ptr, TRUE);
2553 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2554 yield = interpret_commands(commands, generated);
2556 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2562 s = US"Filtering ended by \"defer\".";
2566 s = US"Filtering ended by \"freeze\".";
2570 s = US"Filtering ended by \"fail\".";
2574 s = US"Filtering set up at least one significant delivery "
2575 "or other action.\n"
2576 "No other deliveries will occur.";
2579 case FF_NOTDELIVERED:
2580 s = US"Filtering did not set up a significant delivery.\n"
2581 "Normal delivery will occur.";
2585 s = string_sprintf("Filter error: %s", *error);
2589 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2590 else debug_printf_indent("%s\n", s);
2593 /* Close the log file if it was opened, and kill off any numerical variables
2594 before returning. Reset the header decoding charset. */
2596 if (log_fd >= 0) (void)close(log_fd);
2598 f.filter_running = FALSE;
2599 headers_charset = save_headers_charset;
2602 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2607 /* End of filter.c */