1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
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. */
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(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
256 nextsigchar(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
294 nextword(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
330 nextitem(uschar *ptr, uschar *buffer, int size, BOOL bracket)
333 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
335 while (*(++ptr) != 0 && *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 */
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(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"
420 read_condition(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 != NULL) 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), FALSE);
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 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), FALSE);
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 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 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. */
666 if (Ustrcmp(buffer, "then") == 0)
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);
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. */
680 else if (Ustrcmp(buffer, "and") == 0)
682 condition_block *andc = store_get(sizeof(condition_block), FALSE);
683 andc->parent = current_parent;
684 andc->type = cond_and;
685 andc->testfor = TRUE;
687 andc->right.u = NULL; /* insurance */
689 current = &(andc->right.c);
690 current_parent = andc;
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
698 else if (Ustrcmp(buffer, "or") == 0)
700 condition_block *orc = store_get(sizeof(condition_block), FALSE);
701 condition_block *or_parent = NULL;
705 while (current_parent->parent &&
706 current_parent->parent->type == cond_and)
707 current_parent = current_parent->parent;
709 /* If the parent has a parent, it must be an "or" parent. */
711 if (current_parent->parent)
712 or_parent = current_parent->parent;
715 orc->parent = or_parent;
716 if (!or_parent) *cond = orc;
717 else or_parent->right.c = orc;
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;
726 /* Otherwise there is a disaster */
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);
738 return nextsigchar(ptr, TRUE);
743 /*************************************************
744 * Output the current indent *
745 *************************************************/
751 for (i = 0; i < output_indent; i++) debug_printf(" ");
756 /*************************************************
757 * Condition printer: for debugging *
758 *************************************************/
762 c the block at the top of the tree
763 toplevel TRUE at toplevel - stops overall brackets
769 print_condition(condition_block *c, BOOL toplevel)
771 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
778 case cond_manualthaw:
779 debug_printf("%s", name);
794 debug_printf("%s %s %s", c->left.u, name, c->right.u);
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(")");
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(")");
814 case cond_foranyaddress:
815 debug_printf("%s %s (", name, c->left.u);
816 print_condition(c->right.c, FALSE);
825 /*************************************************
826 * Read one filtering command *
827 *************************************************/
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
836 Returns: TRUE if command successfully read, else FALSE
840 read_command(uschar **pptr, filter_cmd ***lastcmdptr)
842 int command, i, cmd_bit;
843 filter_cmd *new, **newlastcmdptr;
845 BOOL was_seen_or_unseen = FALSE;
846 BOOL was_noerror = FALSE;
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
858 if (Ustrncmp(ptr, "if(", 3) == 0)
860 Ustrcpy(buffer, US"if");
863 else if (Ustrncmp(ptr, "elif(", 5) == 0)
865 Ustrcpy(buffer, US"elif");
870 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
871 if (*error_pointer != NULL) return FALSE;
874 for (command = 0; command < command_list_count; command++)
875 if (Ustrcmp(buffer, command_list[command]) == 0) break;
877 /* Handle the individual commands */
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
887 case headers_command:
888 if (seen_force || noerror_force)
890 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
891 "found before an \"%s\" command near line %d",
892 command_list[command], line_number);
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. */
902 case deliver_command:
903 case logfile_command:
904 case logwrite_command:
907 case testprint_command:
909 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
911 *error_pointer = string_sprintf("\"%s\" requires an argument "
912 "near line %d of filter file", command_list[command], line_number);
914 if (*error_pointer != NULL) yield = FALSE; else
916 union argtypes argument, second_argument;
918 argument.u = second_argument.u = NULL;
920 if (command == add_command)
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);
929 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
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);
937 else if (command == headers_command)
939 if (Ustrcmp(buffer, "add") == 0)
940 second_argument.b = TRUE;
942 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
944 if (Ustrcmp(buffer, "charset") == 0)
945 second_argument.b = TRUE_UNSET;
948 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
949 "expected after \"headers\" near line %d of filter file",
954 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
956 *error_pointer = string_sprintf("header addition and removal is "
957 "available only in system filters: near line %d of filter file",
965 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
967 *error_pointer = string_sprintf("value missing after \"add\", "
968 "\"remove\", or \"charset\" near line %d of filter file",
970 else argument.u = string_copy(buffer);
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. */
982 if (command == logwrite_command)
984 int len = Ustrlen(buffer);
985 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
988 argument.u = string_copy(buffer);
990 if (command == save_command || command == logfile_command)
994 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
995 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
997 else second_argument.i = -1;
1000 else if (command == deliver_command)
1002 uschar *save_ptr = ptr;
1003 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1004 if (Ustrcmp(buffer, "errors_to") == 0)
1006 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1007 second_argument.u = string_copy(buffer);
1009 else ptr = save_ptr;
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. */
1017 if (*error_pointer != NULL) yield = FALSE; else
1019 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), FALSE);
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;
1033 /* Elif, else and endif just set a flag if expected. */
1038 if (seen_force || noerror_force)
1040 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1041 "near line %d is not followed by a command", line_number);
1045 if (expect_endif > 0)
1046 had_else_endif = (command == elif_command)? had_elif :
1047 (command == else_command)? had_else : had_endif;
1050 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1051 "line %d of filter file", buffer, line_number);
1057 /* Defer, freeze, and fail are available only if permitted. */
1060 cmd_bit = RDO_DEFER;
1061 goto DEFER_FREEZE_FAIL;
1065 goto DEFER_FREEZE_FAIL;
1067 case freeze_command:
1068 cmd_bit = RDO_FREEZE;
1071 if ((filter_options & cmd_bit) == 0)
1073 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1074 "near line %d of filter file", buffer, line_number);
1079 /* A text message can be provided after the "text" keyword, or
1080 as a string in quotes. */
1083 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1084 if (*saveptr != '\"' && (*buffer == 0 || Ustrcmp(buffer, "text") != 0))
1091 if (*saveptr != '\"')
1092 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1093 fmsg = string_copy(buffer);
1096 /* Drop through and treat as "finish", but never set "seen". */
1100 /* Finish has no arguments; fmsg defaults to NULL */
1102 case finish_command:
1103 new = store_get(sizeof(filter_cmd), FALSE);
1106 *lastcmdptr = &(new->next);
1107 new->command = command;
1108 new->seen = seen_force? seen_value : FALSE;
1109 new->args[0].u = fmsg;
1113 /* Seen, unseen, and noerror are not allowed before if, which takes a
1114 condition argument and then and else sub-commands. */
1117 if (seen_force || noerror_force)
1119 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1120 "found before an \"if\" command near line %d",
1125 /* Set up the command block for if */
1127 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
1130 *lastcmdptr = &(new->next);
1131 new->command = command;
1133 new->args[0].u = NULL;
1134 new->args[1].u = new->args[2].u = NULL;
1135 new->args[3].u = ptr;
1137 /* Read the condition */
1139 ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1140 if (*error_pointer != NULL) { yield = FALSE; break; }
1142 /* Read the commands to be obeyed if the condition is true */
1144 newlastcmdptr = &(new->args[1].f);
1145 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1147 /* If commands were successfully read, handle the various possible
1148 terminators. There may be a number of successive "elif" sections. */
1152 while (had_else_endif == had_elif)
1154 filter_cmd *newnew =
1155 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
1156 new->args[2].f = newnew;
1159 new->command = command;
1161 new->args[0].u = NULL;
1162 new->args[1].u = new->args[2].u = NULL;
1163 new->args[3].u = ptr;
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))
1172 if (yield == FALSE) break;
1174 /* Handle termination by "else", possibly following one or more
1175 "elsif" sections. */
1177 if (had_else_endif == had_else)
1179 newlastcmdptr = &(new->args[2].f);
1180 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1182 else if (had_else_endif != had_endif)
1184 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1185 "filter file", line_number);
1190 /* Otherwise the terminator was "endif" - this is checked by
1191 read_command_list(). The pointer is already set to NULL. */
1194 /* Reset the terminator flag. */
1196 had_else_endif = had_neither;
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. */
1207 case vacation_command:
1208 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), FALSE);
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;
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. */
1222 uschar *saveptr = ptr;
1223 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1224 if (*error_pointer != NULL)
1230 /* Ensure "return" is followed by "message"; that's a complete option */
1232 if (Ustrcmp(buffer, "return") == 0)
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)
1238 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1239 " near line %d of filter file", line_number);
1246 /* Ensure "expand" is followed by "file", then fall through to process the
1249 if (Ustrcmp(buffer, "expand") == 0)
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)
1255 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1256 " near line %d of filter file", line_number);
1262 /* Scan for the keyword */
1264 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1265 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1267 /* Not found keyword; assume end of this command */
1269 if (i >= MAILARGS_STRING_COUNT)
1275 /* Found keyword, read the data item */
1277 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1278 if (*error_pointer != NULL)
1283 else new->args[i].u = string_copy(buffer);
1286 /* If this is the vacation command, apply some default settings to
1287 some of the arguments. */
1289 if (command == vacation_command)
1291 if (new->args[mailarg_index_file].u == NULL)
1293 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1294 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
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");
1306 /* Join the address on to the chain of generated addresses */
1309 *lastcmdptr = &(new->next);
1313 /* Seen and unseen just set flags */
1316 case unseen_command:
1319 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1320 "near line %d is not followed by a command", line_number);
1325 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1326 "near line %d", line_number);
1329 seen_value = (command == seen_command);
1331 was_seen_or_unseen = TRUE;
1335 /* So does noerror */
1337 case noerror_command:
1340 *error_pointer = string_sprintf("\"noerror\" "
1341 "near line %d is not followed by a command", line_number);
1344 noerror_force = TRUE;
1352 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1353 "near line %d of filter file", buffer, line_number);
1358 if (!was_seen_or_unseen && !was_noerror)
1361 noerror_force = FALSE;
1370 /*************************************************
1371 * Read a list of commands *
1372 *************************************************/
1374 /* If conditional is TRUE, the list must be terminated
1375 by the words "else" or "endif".
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
1383 Returns: TRUE on success
1387 read_command_list(uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1389 if (conditional) expect_endif++;
1390 had_else_endif = had_neither;
1391 while (**pptr != 0 && had_else_endif == had_neither)
1393 if (!read_command(pptr, lastcmdptr)) return FALSE;
1394 *pptr = nextsigchar(*pptr, TRUE);
1399 if (had_else_endif == had_neither)
1401 *error_pointer = US"\"endif\" missing at end of filter file";
1411 /*************************************************
1412 * Test a condition *
1413 *************************************************/
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
1421 Returns: TRUE if the condition is met
1425 test_condition(condition_block *c, BOOL toplevel)
1428 uschar *exp[2], *p, *pp;
1432 if (c == NULL) return TRUE; /* does this ever occur? */
1437 yield = test_condition(c->left.c, FALSE) &&
1438 *error_pointer == NULL &&
1439 test_condition(c->right.c, FALSE);
1443 yield = test_condition(c->left.c, FALSE) ||
1444 (*error_pointer == NULL &&
1445 test_condition(c->right.c, FALSE));
1448 /* The personal test is meaningless in a system filter. The tests are now in
1449 a separate function (so Sieve can use them). However, an Exim filter does not
1450 scan Cc: (hence the FALSE argument). */
1453 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
1456 case cond_delivered:
1457 yield = filter_delivered;
1460 /* Only TRUE if a message is actually being processed; FALSE for address
1461 testing and verification. */
1464 yield = message_id[0] != 0 &&
1465 (sender_address == NULL || sender_address[0] == 0);
1468 /* Only FALSE if a message is actually being processed; TRUE for address
1469 and filter testing and verification. */
1471 case cond_firsttime:
1472 yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
1475 /* Only TRUE if a message is actually being processed; FALSE for address
1476 testing and verification. */
1478 case cond_manualthaw:
1479 yield = message_id[0] != 0 && f.deliver_manual_thaw;
1482 /* The foranyaddress condition loops through a list of addresses */
1484 case cond_foranyaddress:
1486 pp = expand_string(p);
1489 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1490 "filter file: %s", p, expand_string_message);
1495 f.parse_allow_group = TRUE; /* Allow group syntax */
1500 int start, end, domain;
1503 p = parse_find_address_end(pp, FALSE);
1507 filter_thisaddress =
1508 parse_extract_address(pp, &error, &start, &end, &domain, FALSE);
1511 if (filter_thisaddress)
1513 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1514 (debug_selector & D_filter) != 0)
1517 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
1519 yield = test_condition(c->right.c, FALSE);
1523 if (saveend == 0) break;
1527 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1528 f.parse_found_group = FALSE;
1531 /* All other conditions have left and right values that need expanding;
1532 on error, it doesn't matter what value is returned. */
1536 for (i = 0; i < 2; i++)
1538 exp[i] = expand_string(p);
1541 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1542 "filter file: %s", p, expand_string_message);
1548 /* Inner switch for the different cases */
1553 yield = strcmpic(exp[0], exp[1]) == 0;
1557 yield = Ustrcmp(exp[0], exp[1]) == 0;
1561 yield = strstric(exp[0], exp[1], FALSE) != NULL;
1565 yield = Ustrstr(exp[0], exp[1]) != NULL;
1569 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1573 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1579 int len = Ustrlen(exp[1]);
1580 uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1581 yield = (s < exp[0])? FALSE :
1582 ((c->type == cond_ends)? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1589 const pcre2_code *re;
1593 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1594 (debug_selector & D_filter) != 0)
1596 debug_printf_indent("Match expanded arguments:\n");
1597 debug_printf_indent(" Subject = %s\n", exp[0]);
1598 debug_printf_indent(" Pattern = %s\n", exp[1]);
1601 if (!(re = pcre2_compile((PCRE2_SPTR)exp[1], PCRE2_ZERO_TERMINATED,
1602 PCRE_COPT | (c->type == cond_matches ? PCRE2_CASELESS : 0),
1603 &err, &offset, pcre_cmp_ctx)))
1606 pcre2_get_error_message(err, errbuf, sizeof(errbuf));
1607 *error_pointer = string_sprintf("error while compiling "
1608 "regular expression \"%s\": %s at offset %ld",
1609 exp[1], errbuf, (long)offset);
1613 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1617 /* For above and below, convert the strings to numbers */
1621 for (i = 0; i < 2; i++)
1623 val[i] = get_number(exp[i], &yield);
1626 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1631 yield = (c->type == cond_above)? (val[0] > val[1]) : (val[0] < val[1]);
1637 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1638 (debug_selector & D_filter) != 0)
1641 debug_printf_indent("%sondition is %s: ",
1642 toplevel? "C" : "Sub-c",
1643 (yield == c->testfor)? "true" : "false");
1644 print_condition(c, TRUE);
1645 debug_printf_indent("\n");
1648 return yield == c->testfor;
1653 /*************************************************
1654 * Interpret chain of commands *
1655 *************************************************/
1657 /* In testing state, just say what would be done rather than doing it. The
1658 testprint command just expands and outputs its argument in testing state, and
1659 does nothing otherwise.
1662 commands points to chain of commands to interpret
1663 generated where to hang newly-generated addresses
1665 Returns: FF_DELIVERED success, a significant action was taken
1666 FF_NOTDELIVERED success, no significant action
1667 FF_DEFER defer requested
1668 FF_FAIL fail requested
1669 FF_FREEZE freeze requested
1670 FF_ERROR there was a problem
1674 interpret_commands(filter_cmd *commands, address_item **generated)
1679 BOOL condition_value;
1684 uschar *fmsg, *ff_name;
1685 const uschar *expargs[MAILARGS_STRING_COUNT];
1689 /* Expand the relevant number of arguments for the command that are
1692 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1694 uschar *ss = commands->args[i].u;
1698 if (!(expargs[i] = expand_string(ss)))
1700 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1701 "%s command: %s", ss, command_list[commands->command],
1702 expand_string_message);
1707 /* Now switch for each command, setting the "delivered" flag if any of them
1710 if (commands->seen) filter_delivered = TRUE;
1712 switch(commands->command)
1715 for (i = 0; i < 2; i++)
1717 const uschar *ss = expargs[i];
1720 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1722 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1723 "command", expargs[i]);
1727 /* Allow for "--" at the start of the value (from -$n0) for example */
1728 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1730 n[i] = (int)Ustrtol(ss, &end, 0);
1733 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1739 filter_n[n[1]] += n[0];
1740 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1743 /* A deliver command's argument must be a valid address. Its optional
1744 second argument (system filter only) must also be a valid address. */
1746 case deliver_command:
1747 for (i = 0; i < 2; i++)
1752 int start, end, domain;
1754 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1757 expargs[i] = filter_options & RDO_REWRITE
1758 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1760 : rewrite_address_qualify(ss, TRUE);
1763 *error_pointer = string_sprintf("malformed address \"%s\" in "
1764 "filter file: %s", s, error);
1770 /* Stick the errors address into a simple variable, as it will
1771 be referenced a few times. Check that the caller is permitted to
1776 if (s != NULL && !f.system_filtering)
1778 uschar *ownaddress = expand_string(US"$local_part@$domain");
1779 if (strcmpic(ownaddress, s) != 0)
1781 *error_pointer = US"errors_to must point to the caller's address";
1786 /* Test case: report what would happen */
1788 if (filter_test != FTEST_NONE)
1791 printf("%seliver message to: %s%s%s%s\n",
1792 (commands->seen)? "D" : "Unseen d",
1794 commands->noerror? " (noerror)" : "",
1795 (s != NULL)? " errors_to " : "",
1796 (s != NULL)? s : US"");
1803 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1804 (commands->seen)? "" : "unseen ",
1806 commands->noerror? " (noerror)" : "",
1807 (s != NULL)? " errors_to " : "",
1808 (s != NULL)? s : US"");
1810 /* Create the new address and add it to the chain, setting the
1811 af_ignore_error flag if necessary, and the errors address, which can be
1812 set in a system filter and to the local address in user filters. */
1814 addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
1815 addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1816 if (commands->noerror) addr->prop.ignore_error = TRUE;
1817 addr->next = *generated;
1824 mode = commands->args[1].i;
1826 /* Test case: report what would happen */
1828 if (filter_test != FTEST_NONE)
1832 printf("%save message to: %s%s\n", (commands->seen)?
1833 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1835 printf("%save message to: %s %04o%s\n", (commands->seen)?
1836 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1839 /* Real case: Ensure save argument starts with / if there is a home
1840 directory to prepend. */
1844 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1845 deliver_home != NULL && deliver_home[0] != 0)
1846 s = string_sprintf("%s/%s", deliver_home, s);
1847 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1848 (commands->seen)? "" : "unseen ", s,
1849 commands->noerror? " (noerror)" : "");
1851 /* Create the new address and add it to the chain, setting the
1852 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1855 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1856 setflag(addr, af_pfr);
1857 setflag(addr, af_file);
1858 if (commands->noerror) addr->prop.ignore_error = TRUE;
1860 addr->next = *generated;
1866 s = string_copy(commands->args[0].u);
1867 if (filter_test != FTEST_NONE)
1870 printf("%sipe message to: %s%s\n", (commands->seen)?
1871 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1873 else /* Ensure pipe command starts with | */
1875 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1876 commands->seen ? "" : "unseen ", s,
1877 commands->noerror ? " (noerror)" : "");
1878 if (s[0] != '|') s = string_sprintf("|%s", s);
1880 /* Create the new address and add it to the chain, setting the
1881 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1882 each command argument is expanded in the transport after the command
1883 has been split up into separate arguments. */
1885 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1886 setflag(addr, af_pfr);
1887 setflag(addr, af_expand_pipe);
1888 if (commands->noerror) addr->prop.ignore_error = TRUE;
1889 addr->next = *generated;
1892 /* If there are any numeric variables in existence (e.g. after a regex
1893 condition), or if $thisaddress is set, take a copy for use in the
1894 expansion. Note that we can't pass NULL for filter_thisaddress, because
1895 NULL terminates the list. */
1897 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1899 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1900 uschar **ss = store_get(sizeof(uschar *) * (ecount + 3), FALSE);
1902 addr->pipe_expandn = ss;
1903 if (!filter_thisaddress) filter_thisaddress = US"";
1904 *ss++ = string_copy(filter_thisaddress);
1905 for (int i = 0; i <= expand_nmax; i++)
1906 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1912 /* Set up the file name and mode, and close any previously open
1915 case logfile_command:
1916 log_mode = commands->args[1].i;
1917 if (log_mode == -1) log_mode = 0600;
1920 (void)close(log_fd);
1923 log_filename = expargs[0];
1924 if (filter_test != FTEST_NONE)
1927 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1931 case logwrite_command:
1934 if (filter_test != FTEST_NONE)
1937 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1938 string_printing(s));
1941 /* Attempt to write to a log file only if configured as permissible.
1942 Logging may be forcibly skipped for verifying or testing. */
1944 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1947 debug_printf_indent("filter log command aborted: euid=%ld\n",
1948 (long int)geteuid());
1949 *error_pointer = US"logwrite command forbidden";
1952 else if ((filter_options & RDO_REALLOG) != 0)
1955 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1956 (long int)geteuid());
1961 *error_pointer = US"attempt to obey \"logwrite\" command "
1962 "without a previous \"logfile\"";
1965 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1968 *error_pointer = string_open_failed("filter log file \"%s\"",
1974 if (write(log_fd, s, len) != len)
1976 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1977 log_filename, strerror(errno));
1983 debug_printf_indent("skipping logwrite (verifying or testing)\n");
1986 /* Header addition and removal is available only in the system filter. The
1987 command is rejected at parse time otherwise. However "headers charset" is
1988 always permitted. */
1990 case headers_command:
1992 int subtype = commands->args[1].i;
1995 if (filter_test != FTEST_NONE)
1996 printf("Headers %s \"%s\"\n",
1997 subtype == TRUE ? "add"
1998 : subtype == FALSE ? "remove"
2000 string_printing(s));
2002 if (subtype == TRUE)
2004 while (isspace(*s)) s++;
2007 header_add(htype_other, "%s%s", s,
2008 s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2009 header_last->type = header_checkname(header_last, FALSE);
2010 if (header_last->type >= 'a') header_last->type = htype_other;
2014 else if (subtype == FALSE)
2017 const uschar * list = s;
2019 for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2020 header_remove(0, ss);
2023 /* This setting lasts only while the filter is running; on exit, the
2024 variable is reset to the previous value. */
2026 else headers_charset = s;
2030 /* Defer, freeze, and fail are available only when explicitly permitted.
2031 These commands are rejected at parse time otherwise. The message can get
2032 very long by the inclusion of message headers; truncate if it is, and also
2033 ensure printing characters so as not to mess up log files. */
2036 ff_name = US"defer";
2038 goto DEFERFREEZEFAIL;
2043 goto DEFERFREEZEFAIL;
2045 case freeze_command:
2046 ff_name = US"freeze";
2050 *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2051 ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2052 : string_copy(expargs[0]));
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++)
2133 const uschar *s = expargs[i];
2137 if (i != mailarg_index_text) for (p = s; *p != 0; p++)
2140 if (i > mailarg_index_text)
2142 if (!mac_isprint(c))
2144 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2145 "in %s command", string_printing(s),
2146 command_list[commands->command]);
2151 /* i < mailarg_index_text */
2153 else if (c == '\n' && !isspace(p[1]))
2155 if (i < mailarg_index_headers)
2157 *error_pointer = string_sprintf("\\n not followed by space in "
2158 "\"%.1024s\" in %s command", string_printing(s),
2159 command_list[commands->command]);
2163 /* Check for the start of a new header line within the string */
2168 for (pp = p + 1;; pp++)
2171 if (c == ':' && pp != p + 1) break;
2172 if (!c || c == ':' || isspace(c))
2174 *error_pointer = string_sprintf("\\n not followed by space or "
2175 "valid header name in \"%.1024s\" in %s command",
2176 string_printing(s), command_list[commands->command]);
2183 } /* Loop to scan the string */
2185 /* The string is OK */
2187 commands->args[i].u = s; /*XXX loses track of const */
2190 /* Proceed with mail or vacation command */
2192 if (filter_test != FTEST_NONE)
2194 uschar *to = commands->args[mailarg_index_to].u;
2196 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2197 to ? to : US"<default>",
2198 commands->command == vacation_command ? " (vacation)" : "",
2199 commands->noerror ? " (noerror)" : "");
2200 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2202 const uschar *arg = commands->args[i].u;
2205 int len = Ustrlen(mailargs[i]);
2206 int indent = (debug_selector != 0)? output_indent : 0;
2207 while (len++ < 7 + indent) printf(" ");
2208 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2209 (commands->args[mailarg_index_expand].u != NULL &&
2210 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2213 if (commands->args[mailarg_index_return].u)
2214 printf("Return original message\n");
2219 uschar *to = commands->args[mailarg_index_to].u;
2220 gstring * log_addr = NULL;
2222 if (!to) to = expand_string(US"$reply_address");
2223 while (isspace(*to)) to++;
2225 for (tt = to; *tt != 0; tt++) /* Get rid of newlines */
2226 if (*tt == '\n') *tt = ' ';
2230 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2231 commands->seen ? "seen " : "",
2233 commands->command == vacation_command ? " (vacation)" : "",
2234 commands->noerror ? " (noerror)" : "");
2235 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2237 uschar *arg = commands->args[i].u;
2240 int len = Ustrlen(mailargs[i]);
2241 while (len++ < 15) debug_printf_indent(" ");
2242 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2243 (commands->args[mailarg_index_expand].u != NULL &&
2244 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2249 /* Create the "address" for the autoreply. This is used only for logging,
2250 as the actual recipients are extracted from the To: line by -t. We use the
2251 same logic here to extract the working addresses (there may be more than
2252 one). Just in case there are a vast number of addresses, stop when the
2253 string gets too long. */
2258 uschar *ss = parse_find_address_end(tt, FALSE);
2259 uschar *recipient, *errmess;
2260 int start, end, domain;
2264 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2268 /* Ignore empty addresses and errors; an error will occur later if
2269 there's something really bad. */
2273 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2274 log_addr = string_cat (log_addr, recipient);
2279 if (log_addr && log_addr->ptr > 256)
2281 log_addr = string_catn(log_addr, US", ...", 5);
2285 /* Move on past this address */
2287 tt = ss + (*ss ? 1 : 0);
2288 while (isspace(*tt)) tt++;
2292 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2295 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2296 setflag(addr, af_bad_reply);
2299 setflag(addr, af_pfr);
2300 if (commands->noerror) addr->prop.ignore_error = TRUE;
2301 addr->next = *generated;
2304 addr->reply = store_get(sizeof(reply_item), FALSE);
2305 addr->reply->from = NULL;
2306 addr->reply->to = string_copy(to);
2307 addr->reply->file_expand =
2308 commands->args[mailarg_index_expand].u != NULL;
2309 addr->reply->expand_forbid = expand_forbid;
2310 addr->reply->return_message =
2311 commands->args[mailarg_index_return].u != NULL;
2312 addr->reply->once_repeat = 0;
2314 if (commands->args[mailarg_index_once_repeat].u != NULL)
2316 addr->reply->once_repeat =
2317 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2319 if (addr->reply->once_repeat < 0)
2321 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2322 "in mail or vacation command: %s",
2323 commands->args[mailarg_index_once_repeat].u);
2328 /* Set up all the remaining string arguments (those other than "to") */
2330 for (i = 1; i < mailargs_string_passed; i++)
2332 uschar *ss = commands->args[i].u;
2333 *(USS((US addr->reply) + reply_offsets[i])) =
2334 ss ? string_copy(ss) : NULL;
2339 case testprint_command:
2340 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2342 const uschar *s = string_printing(expargs[0]);
2343 if (filter_test == FTEST_NONE)
2344 debug_printf_indent("Filter: testprint: %s\n", s);
2346 printf("Testprint: %s\n", s);
2350 commands = commands->next;
2353 return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
2358 /*************************************************
2359 * Test for a personal message *
2360 *************************************************/
2362 /* This function is global so that it can also be called from the code that
2363 implements Sieve filters.
2366 aliases a chain of aliases
2367 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2369 Returns: TRUE if the message is deemed to be personal
2373 filter_personal(string_item *aliases, BOOL scan_cc)
2375 const uschar *self, *self_from, *self_to;
2376 uschar *psself = NULL;
2377 const uschar *psself_from = NULL, *psself_to = NULL;
2378 rmark reset_point = store_mark();
2384 /* If any header line in the message is a defined "List-" header field, it is
2385 not a personal message. We used to check for any header line that started with
2386 "List-", but this was tightened up for release 4.54. The check is now for
2387 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2388 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2389 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2390 contain any value other than "no", the message is not personal (RFC 3834).
2391 Previously the test was for "auto-". */
2393 for (h = header_list; h; h = h->next)
2395 if (h->type == htype_old) continue;
2397 if (strncmpic(h->text, US"List-", 5) == 0)
2399 uschar * s = h->text + 5;
2400 if (strncmpic(s, US"Id:", 3) == 0 ||
2401 strncmpic(s, US"Help:", 5) == 0 ||
2402 strncmpic(s, US"Subscribe:", 10) == 0 ||
2403 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2404 strncmpic(s, US"Post:", 5) == 0 ||
2405 strncmpic(s, US"Owner:", 6) == 0 ||
2406 strncmpic(s, US"Archive:", 8) == 0)
2410 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2412 uschar * s = h->text + 15;
2413 Uskip_whitespace(&s);
2414 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2416 Uskip_whitespace(&s);
2417 if (*s) return FALSE;
2421 /* Set up "my" address */
2423 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2424 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2425 global_rewrite_rules);
2426 self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2427 global_rewrite_rules);
2430 if (!self_from) self_from = self;
2431 if (self_to) self_to = self;
2433 /* If there's a prefix or suffix set, we must include the prefixed/
2434 suffixed version of the local part in the tests. */
2436 if (deliver_localpart_prefix || deliver_localpart_suffix)
2438 psself = string_sprintf("%s%s%s@%s",
2439 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2441 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2443 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2444 global_rewrite_rules);
2445 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2446 global_rewrite_rules);
2447 if (psself_from == NULL) psself_from = psself;
2448 if (psself_to == NULL) psself_to = psself;
2453 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2457 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2461 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2464 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2470 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2471 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2472 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2474 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2476 (sender_address == NULL || sender_address[0] != 0);
2478 store_reset(reset_point);
2484 /*************************************************
2485 * Interpret a mail filter file *
2486 *************************************************/
2490 filter points to the entire file, read into store as a single string
2491 options controls whether various special things are allowed, and requests
2493 generated where to hang newly-generated addresses
2494 error where to pass back an error text
2496 Returns: FF_DELIVERED success, a significant action was taken
2497 FF_NOTDELIVERED success, no significant action
2498 FF_DEFER defer requested
2499 FF_FAIL fail requested
2500 FF_FREEZE freeze requested
2501 FF_ERROR there was a problem
2505 filter_interpret(uschar *filter, int options, address_item **generated,
2509 int yield = FF_ERROR;
2510 uschar *ptr = filter;
2511 const uschar *save_headers_charset = headers_charset;
2512 filter_cmd *commands = NULL;
2513 filter_cmd **lastcmdptr = &commands;
2515 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2518 /* Initialize "not in an if command", set the global flag that is always TRUE
2519 while filtering, and zero the variables. */
2523 f.filter_running = TRUE;
2524 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2526 /* To save having to pass certain values about all the time, make them static.
2527 Also initialize the line number, for error messages, and the log file
2530 filter_options = options;
2531 filter_delivered = FALSE;
2532 finish_obeyed = FALSE;
2533 error_pointer = error;
2534 *error_pointer = NULL;
2538 log_filename = NULL;
2540 /* Scan filter file for syntax and build up an interpretation thereof, and
2541 interpret the compiled commands, and if testing, say whether we ended up
2542 delivered or not, unless something went wrong. */
2545 ptr = nextsigchar(ptr, TRUE);
2547 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2548 yield = interpret_commands(commands, generated);
2550 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2556 s = US"Filtering ended by \"defer\".";
2560 s = US"Filtering ended by \"freeze\".";
2564 s = US"Filtering ended by \"fail\".";
2568 s = US"Filtering set up at least one significant delivery "
2569 "or other action.\n"
2570 "No other deliveries will occur.";
2573 case FF_NOTDELIVERED:
2574 s = US"Filtering did not set up a significant delivery.\n"
2575 "Normal delivery will occur.";
2579 s = string_sprintf("Filter error: %s", *error);
2583 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2584 else debug_printf_indent("%s\n", s);
2587 /* Close the log file if it was opened, and kill off any numerical variables
2588 before returning. Reset the header decoding charset. */
2590 if (log_fd >= 0) (void)close(log_fd);
2592 f.filter_running = FALSE;
2593 headers_charset = save_headers_charset;
2596 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2601 /* End of filter.c */