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. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
11 /* Code for mail filtering functions. */
16 /* Command arguments and left/right points in conditions can contain different
17 types of data, depending on the particular command or condition. Originally,
18 (void *) was used as "any old type", with casts, but this gives trouble and
19 warnings in some environments. So now it is done "properly", with a union. We
20 need to declare the structures first because some of them are recursive. */
23 struct condition_block;
26 struct string_item *a;
28 struct condition_block *c;
34 /* Local structures used in this module */
36 typedef struct filter_cmd {
37 struct filter_cmd *next;
41 union argtypes args[1];
44 typedef struct condition_block {
45 struct condition_block *parent;
52 /* Miscellaneous other declarations */
54 static uschar **error_pointer;
55 static const uschar *log_filename;
56 static int filter_options;
57 static int line_number;
58 static int expect_endif;
59 static int had_else_endif;
62 static int output_indent;
63 static BOOL filter_delivered;
64 static BOOL finish_obeyed;
65 static BOOL seen_force;
66 static BOOL seen_value;
67 static BOOL noerror_force;
69 enum { had_neither, had_else, had_elif, had_endif };
71 static BOOL read_command_list(const uschar **, filter_cmd ***, BOOL);
74 /* The string arguments for the mail command. The header line ones (that are
75 permitted to include \n followed by white space) first, and then the body text
76 one (it can have \n anywhere). Then the file names and once_repeat, which may
79 static const char *mailargs[] = { /* "to" must be first, and */
80 "to", /* "cc" and "bcc" must follow */
86 "extra_headers", /* miscellaneous added header lines */
94 /* The count of string arguments */
96 #define MAILARGS_STRING_COUNT (nelem(mailargs))
98 /* The count of string arguments that are actually passed over as strings
99 (once_repeat is converted to an int). */
101 #define mailargs_string_passed (MAILARGS_STRING_COUNT - 1)
103 /* This defines the offsets for the arguments; first the string ones, and
104 then the non-string ones. The order must be as above. */
106 enum { mailarg_index_to,
110 mailarg_index_reply_to,
111 mailarg_index_subject,
112 mailarg_index_headers, /* misc headers must be last */
113 mailarg_index_text, /* text is first after headers */
114 mailarg_index_file, /* between text and expand are filenames */
117 mailarg_index_once_repeat, /* a time string */
118 mailarg_index_expand, /* first non-string argument */
119 mailarg_index_return,
120 mailargs_total /* total number of arguments */
123 /* Offsets in the data structure for the string arguments (note that
124 once_repeat isn't a string argument at this point.) */
126 static int reply_offsets[] = { /* must be in same order as above */
127 offsetof(reply_item, to),
128 offsetof(reply_item, cc),
129 offsetof(reply_item, bcc),
130 offsetof(reply_item, from),
131 offsetof(reply_item, reply_to),
132 offsetof(reply_item, subject),
133 offsetof(reply_item, headers),
134 offsetof(reply_item, text),
135 offsetof(reply_item, file),
136 offsetof(reply_item, logfile),
137 offsetof(reply_item, oncelog),
140 /* Condition identities and names, with negated versions for some
143 enum { cond_and, cond_or, cond_personal, cond_begins, cond_BEGINS,
144 cond_ends, cond_ENDS, cond_is, cond_IS, cond_matches,
145 cond_MATCHES, cond_contains, cond_CONTAINS, cond_delivered,
146 cond_above, cond_below, cond_errormsg, cond_firsttime,
147 cond_manualthaw, cond_foranyaddress };
149 static const char *cond_names[] = {
150 "and", "or", "personal",
151 "begins", "BEGINS", "ends", "ENDS",
152 "is", "IS", "matches", "MATCHES", "contains",
153 "CONTAINS", "delivered", "above", "below", "error_message",
154 "first_delivery", "manually_thawed", "foranyaddress" };
156 static const char *cond_not_names[] = {
157 "", "", "not personal",
158 "does not begin", "does not BEGIN",
159 "does not end", "does not END",
160 "is not", "IS not", "does not match",
161 "does not MATCH", "does not contain", "does not CONTAIN",
162 "not delivered", "not above", "not below", "not error_message",
163 "not first_delivery", "not manually_thawed", "not foranyaddress" };
165 /* Tables of binary condition words and their corresponding types. Not easy
166 to amalgamate with the above because of the different variants. */
168 static const char *cond_words[] = {
190 static int cond_word_count = nelem(cond_words);
192 static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
193 cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
194 cond_above, cond_begins, cond_begins, cond_below, cond_contains,
195 cond_contains, cond_ends, cond_ends, cond_is, cond_matches, cond_matches };
197 /* Command identities: must be kept in step with the list of command words
198 and the list of expanded argument counts which follow. */
200 enum { add_command, defer_command, deliver_command, elif_command, else_command,
201 endif_command, finish_command, fail_command, freeze_command,
202 headers_command, if_command, logfile_command, logwrite_command,
203 mail_command, noerror_command, pipe_command, save_command, seen_command,
204 testprint_command, unseen_command, vacation_command };
206 static const char *command_list[] = {
207 "add", "defer", "deliver", "elif", "else", "endif", "finish",
208 "fail", "freeze", "headers", "if", "logfile", "logwrite", "mail",
209 "noerror", "pipe", "save", "seen", "testprint", "unseen", "vacation"
212 static int command_list_count = nelem(command_list);
214 /* This table contains the number of expanded arguments in the bottom 4 bits.
215 If the top bit is set, it means that the default for the command is "seen". */
217 static uschar command_exparg_count[] = {
231 MAILARGS_STRING_COUNT, /* mail */
238 MAILARGS_STRING_COUNT /* vacation */
243 /*************************************************
244 * Find next significant uschar *
245 *************************************************/
247 /* Function to skip over white space and, optionally, comments.
250 ptr pointer to next character
251 comment_allowed if TRUE, comments (# to \n) are skipped
253 Returns: pointer to next non-whitespace character
256 static const uschar *
257 nextsigchar(const uschar *ptr, BOOL comment_allowed)
261 while (isspace(*ptr))
263 if (*ptr == '\n') line_number++;
266 if (comment_allowed && *ptr == '#')
268 while (*(++ptr) != '\n' && *ptr != 0);
278 /*************************************************
280 *************************************************/
282 /* The terminator is white space unless bracket is TRUE, in which
283 case ( and ) terminate.
286 ptr pointer to next character
287 buffer where to put the word
289 bracket if TRUE, terminate on ( and ) as well as space
291 Returns: pointer to the next significant character after the word
294 static const uschar *
295 nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
298 while (*ptr != 0 && !isspace(*ptr) &&
299 (!bracket || (*ptr != '(' && *ptr != ')')))
301 if (bp - buffer < size - 1) *bp++ = *ptr++; else
303 *error_pointer = string_sprintf("word is too long in line %d of "
304 "filter file (max = %d chars)", line_number, size);
309 return nextsigchar(ptr, TRUE);
314 /*************************************************
316 *************************************************/
318 /* Might be a word, or might be a quoted string; in the latter case
322 ptr pointer to next character
323 buffer where to put the item
325 bracket if TRUE, terminate non-quoted on ( and ) as well as space
327 Returns: the next significant character after the item
330 static const uschar *
331 nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
334 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
336 while (*++ptr && *ptr != '\"' && *ptr != '\n')
338 if (bp - buffer >= size - 1)
340 *error_pointer = string_sprintf("string is too long in line %d of "
341 "filter file (max = %d chars)", line_number, size);
345 if (*ptr != '\\') *bp++ = *ptr; else
347 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
349 const uschar *p = ptr + 1;
350 while (*p != '\n' && isspace(*p)) p++;
355 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
360 *bp++ = string_interpret_escape(CUSS &ptr);
364 if (*ptr == '\"') ptr++;
365 else if (*error_pointer == NULL)
366 *error_pointer = string_sprintf("quote missing at end of string "
367 "in line %d", line_number);
370 return nextsigchar(ptr, TRUE);
376 /*************************************************
377 * Convert a string + K|M to a number *
378 *************************************************/
382 s points to text string
383 OK set TRUE if a valid number was read
385 Returns: the number, or 0 on error (with *OK FALSE)
389 get_number(const uschar *s, BOOL *ok)
393 if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
394 if (tolower(s[count]) == 'k') { value *= 1024; count++; }
395 if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
396 while (isspace((s[count]))) count++;
397 if (s[count] != 0) return 0;
404 /*************************************************
405 * Read one condition *
406 *************************************************/
408 /* A complete condition must be terminated by "then"; bracketed internal
409 conditions must be terminated by a closing bracket. They are read by calling
410 this function recursively.
413 ptr points to start of condition
414 condition_block where to hang the created condition block
415 toplevel TRUE when called at the top level
417 Returns: points to next character after "then"
420 static const uschar *
421 read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
425 condition_block *current_parent = NULL;
426 condition_block **current = cond;
430 /* Loop to read next condition */
436 /* reaching the end of the input is an error. */
440 *error_pointer = US"\"then\" missing at end of filter file";
444 /* Opening bracket at the start of a condition introduces a nested
445 condition, which must be terminated by a closing bracket. */
449 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
450 if (*error_pointer != NULL) break;
453 *error_pointer = string_sprintf("expected \")\" in line %d of "
454 "filter file", line_number);
459 c->testfor = !c->testfor;
462 ptr = nextsigchar(ptr+1, TRUE);
466 /* Closing bracket at the start of a condition is an error. Give an
467 explicit message, as otherwise "unknown condition" would be confusing. */
469 else if (*ptr == ')')
471 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
472 "filter file", line_number);
476 /* Otherwise we expect a word or a string. */
480 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
481 if (*error_pointer) break;
483 /* "Then" at the start of a condition is an error */
485 if (Ustrcmp(buffer, "then") == 0)
487 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
488 "filter file", line_number);
492 /* "Not" at the start of a condition negates the testing condition. */
494 if (Ustrcmp(buffer, "not") == 0)
500 /* Build a condition block from the specific word. */
502 c = store_get(sizeof(condition_block), GET_UNTAINTED);
503 c->left.u = c->right.u = NULL;
504 c->testfor = testfor;
507 /* Check for conditions that start with a keyword */
509 if (Ustrcmp(buffer, "delivered") == 0) c->type = cond_delivered;
510 else if (Ustrcmp(buffer, "error_message") == 0) c->type = cond_errormsg;
511 else if (Ustrcmp(buffer, "first_delivery") == 0) c->type = cond_firsttime;
512 else if (Ustrcmp(buffer, "manually_thawed") == 0) c->type = cond_manualthaw;
514 /* Personal can be followed by any number of aliases */
516 else if (Ustrcmp(buffer, "personal") == 0)
518 c->type = cond_personal;
522 const uschar * saveptr = ptr;
523 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
524 if (*error_pointer) break;
525 if (Ustrcmp(buffer, "alias") != 0)
530 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
531 if (*error_pointer) break;
532 aa = store_get(sizeof(string_item), GET_UNTAINTED);
533 aa->text = string_copy(buffer);
534 aa->next = c->left.a;
539 /* Foranyaddress must be followed by a string and a condition enclosed
540 in parentheses, which is handled as a subcondition. */
542 else if (Ustrcmp(buffer, "foranyaddress") == 0)
544 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
545 if (*error_pointer) break;
548 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
549 "near line %d of filter file", line_number);
553 c->type = cond_foranyaddress;
554 c->left.u = string_copy(buffer);
556 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
557 if (*error_pointer) break;
560 *error_pointer = string_sprintf("expected \")\" in line %d of "
561 "filter file", line_number);
564 ptr = nextsigchar(ptr+1, TRUE);
567 /* If it's not a word we recognize, then it must be the lefthand
568 operand of one of the comparison words. */
573 const uschar *isptr = NULL;
575 c->left.u = string_copy(buffer);
576 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
577 if (*error_pointer) break;
579 /* Handle "does|is [not]", preserving the pointer after "is" in
580 case it isn't that, but the form "is <string>". */
582 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
584 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
585 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
587 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
588 if (*error_pointer) break;
589 if (strcmpic(buffer, US"not") == 0)
591 c->testfor = !c->testfor;
592 if (isptr) isptr = ptr;
593 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
594 if (*error_pointer) break;
598 for (i = 0; i < cond_word_count; i++)
600 if (Ustrcmp(buffer, cond_words[i]) == 0)
602 c->type = cond_types[i];
607 /* If an unknown word follows "is" or "is not"
608 it's actually the argument. Reset to read it. */
610 if (i >= cond_word_count)
614 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
615 "near line %d of filter file", buffer, line_number);
621 /* Get the RH argument. */
623 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
624 if (*error_pointer) break;
625 c->right.u = string_copy(buffer);
629 /* We have read some new condition and set it up in the condition block
630 c; point the current pointer at it, and then deal with what follows. */
634 /* Closing bracket terminates if this is a lower-level condition. Otherwise
640 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
641 "filter file", line_number);
645 /* Opening bracket following a condition is an error; give an explicit
646 message to make it clearer what is wrong. */
648 else if (*ptr == '(')
650 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
651 "filter file", line_number);
655 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
659 // const uschar *saveptr = ptr;
660 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
661 if (*error_pointer) break;
663 /* "Then" terminates a toplevel condition; otherwise a closing bracket
664 has been omitted. Put a string terminator at the start of "then" so
665 that reflecting the condition can be done when testing. */
666 /*XXX This stops us doing a constification job in this file, unfortunately.
667 Comment it out and see if anything breaks.
668 With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
670 if (Ustrcmp(buffer, "then") == 0)
672 // if (toplevel) *saveptr = 0;
675 *error_pointer = string_sprintf("missing \")\" at end of "
676 "condition near line %d of filter file", line_number);
680 /* "And" causes a new condition block to replace the one we have
681 just read, which becomes the left sub-condition. The current pointer
682 is reset to the pointer for the right sub-condition. We have to keep
683 track of the tree of sequential "ands", so as to traverse back up it
684 if an "or" is met. */
686 else if (Ustrcmp(buffer, "and") == 0)
688 condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
689 andc->parent = current_parent;
690 andc->type = cond_and;
691 andc->testfor = TRUE;
693 andc->right.u = NULL; /* insurance */
695 current = &(andc->right.c);
696 current_parent = andc;
699 /* "Or" is similar, but has to be done a bit more carefully to
700 ensure that "and" is more binding. If there's a parent set, we
701 are following a sequence of "and"s and must track back to their
704 else if (Ustrcmp(buffer, "or") == 0)
706 condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
707 condition_block * or_parent = NULL;
711 while (current_parent->parent &&
712 current_parent->parent->type == cond_and)
713 current_parent = current_parent->parent;
715 /* If the parent has a parent, it must be an "or" parent. */
717 if (current_parent->parent)
718 or_parent = current_parent->parent;
721 orc->parent = or_parent;
722 if (!or_parent) *cond = orc;
723 else or_parent->right.c = orc;
726 orc->left.c = (current_parent == NULL)? c : current_parent;
727 orc->right.c = NULL; /* insurance */
728 current = &(orc->right.c);
729 current_parent = orc;
732 /* Otherwise there is a disaster */
736 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
737 "expected near line %d of filter file, but found \"%s\"",
738 toplevel? "then" : ")", line_number, buffer);
744 return nextsigchar(ptr, TRUE);
749 /*************************************************
750 * Output the current indent *
751 *************************************************/
757 for (i = 0; i < output_indent; i++) debug_printf(" ");
762 /*************************************************
763 * Condition printer: for debugging *
764 *************************************************/
768 c the block at the top of the tree
769 toplevel TRUE at toplevel - stops overall brackets
775 print_condition(condition_block *c, BOOL toplevel)
777 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
784 case cond_manualthaw:
785 debug_printf("%s", name);
800 debug_printf("%s %s %s", c->left.u, name, c->right.u);
804 if (!c->testfor) debug_printf("not (");
805 print_condition(c->left.c, FALSE);
806 debug_printf(" %s ", cond_names[c->type]);
807 print_condition(c->right.c, FALSE);
808 if (!c->testfor) debug_printf(")");
812 if (!c->testfor) debug_printf("not (");
813 else if (!toplevel) debug_printf("(");
814 print_condition(c->left.c, FALSE);
815 debug_printf(" %s ", cond_names[c->type]);
816 print_condition(c->right.c, FALSE);
817 if (!toplevel || !c->testfor) debug_printf(")");
820 case cond_foranyaddress:
821 debug_printf("%s %s (", name, c->left.u);
822 print_condition(c->right.c, FALSE);
831 /*************************************************
832 * Read one filtering command *
833 *************************************************/
837 pptr points to pointer to first character of command; the pointer
838 is updated to point after the last character read
839 lastcmdptr points to pointer to pointer to last command; used for hanging
840 on the newly read command
842 Returns: TRUE if command successfully read, else FALSE
846 read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
848 int command, i, cmd_bit;
849 filter_cmd *new, **newlastcmdptr;
851 BOOL was_seen_or_unseen = FALSE;
852 BOOL was_noerror = FALSE;
854 const uschar *ptr = *pptr;
855 const uschar *saveptr;
858 /* Read the next word and find which command it is. Command words are normally
859 terminated by white space, but there are two exceptions, which are the "if" and
860 "elif" commands. We must allow for them to be terminated by an opening bracket,
861 as brackets are allowed in conditions and users will expect not to require
864 *buffer = '\0'; /* compiler quietening */
866 if (Ustrncmp(ptr, "if(", 3) == 0)
868 Ustrcpy(buffer, US"if");
871 else if (Ustrncmp(ptr, "elif(", 5) == 0)
873 Ustrcpy(buffer, US"elif");
878 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
879 if (*error_pointer) return FALSE;
882 for (command = 0; command < command_list_count; command++)
883 if (Ustrcmp(buffer, command_list[command]) == 0) break;
885 /* Handle the individual commands */
889 /* Add takes two arguments, separated by the word "to". Headers has two
890 arguments, but the first must be "add", "remove", or "charset", and it gets
891 stored in the second argument slot. Neither may be preceded by seen, unseen
895 case headers_command:
896 if (seen_force || noerror_force)
898 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
899 "found before an \"%s\" command near line %d",
900 command_list[command], line_number);
905 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
906 and logfile can have an option second argument for the mode, and deliver can
907 have "errors_to <address>" in a system filter, or in a user filter if the
908 address is the current one. */
910 case deliver_command:
911 case logfile_command:
912 case logwrite_command:
915 case testprint_command:
917 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
919 *error_pointer = string_sprintf("\"%s\" requires an argument "
920 "near line %d of filter file", command_list[command], line_number);
922 if (*error_pointer) yield = FALSE; else
924 union argtypes argument, second_argument;
926 argument.u = second_argument.u = NULL;
928 if (command == add_command)
930 argument.u = string_copy(buffer);
931 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
932 if (!*buffer || Ustrcmp(buffer, "to") != 0)
933 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
934 "near line %d of filter file", line_number);
937 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
939 *error_pointer = string_sprintf("value missing after \"to\" "
940 "near line %d of filter file", line_number);
941 else second_argument.u = string_copy(buffer);
945 else if (command == headers_command)
947 if (Ustrcmp(buffer, "add") == 0)
948 second_argument.b = TRUE;
950 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
952 if (Ustrcmp(buffer, "charset") == 0)
953 second_argument.b = TRUE_UNSET;
956 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
957 "expected after \"headers\" near line %d of filter file",
962 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
964 *error_pointer = string_sprintf("header addition and removal is "
965 "available only in system filters: near line %d of filter file",
973 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
975 *error_pointer = string_sprintf("value missing after \"add\", "
976 "\"remove\", or \"charset\" near line %d of filter file",
978 else argument.u = string_copy(buffer);
982 /* The argument for the logwrite command must end in a newline, and the save
983 and logfile commands can have an optional mode argument. The deliver
984 command can have an optional "errors_to <address>" for a system filter,
985 or for a user filter if the address is the user's address. Accept the
986 syntax here - the check is later. */
990 if (command == logwrite_command)
992 int len = Ustrlen(buffer);
993 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
996 argument.u = string_copy(buffer);
998 if (command == save_command || command == logfile_command)
1002 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1003 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
1005 else second_argument.i = -1;
1008 else if (command == deliver_command)
1010 const uschar *save_ptr = ptr;
1011 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1012 if (Ustrcmp(buffer, "errors_to") == 0)
1014 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1015 second_argument.u = string_copy(buffer);
1017 else ptr = save_ptr;
1021 /* Set up the command block. Seen defaults TRUE for delivery commands,
1022 FALSE for logging commands, and it doesn't matter for testprint, as
1023 that doesn't change the "delivered" status. */
1025 if (*error_pointer) yield = FALSE;
1028 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
1031 *lastcmdptr = &(new->next);
1032 new->command = command;
1033 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1034 new->noerror = noerror_force;
1035 new->args[0] = argument;
1036 new->args[1] = second_argument;
1042 /* Elif, else and endif just set a flag if expected. */
1047 if (seen_force || noerror_force)
1049 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1050 "near line %d is not followed by a command", line_number);
1054 if (expect_endif > 0)
1055 had_else_endif = (command == elif_command)? had_elif :
1056 (command == else_command)? had_else : had_endif;
1059 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1060 "line %d of filter file", buffer, line_number);
1066 /* Defer, freeze, and fail are available only if permitted. */
1069 cmd_bit = RDO_DEFER;
1070 goto DEFER_FREEZE_FAIL;
1074 goto DEFER_FREEZE_FAIL;
1076 case freeze_command:
1077 cmd_bit = RDO_FREEZE;
1080 if ((filter_options & cmd_bit) == 0)
1082 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1083 "near line %d of filter file", buffer, line_number);
1088 /* A text message can be provided after the "text" keyword, or
1089 as a string in quotes. */
1092 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1093 if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0))
1100 if (*saveptr != '\"')
1101 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1102 fmsg = string_copy(buffer);
1105 /* Drop through and treat as "finish", but never set "seen". */
1109 /* Finish has no arguments; fmsg defaults to NULL */
1111 case finish_command:
1112 new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
1115 *lastcmdptr = &(new->next);
1116 new->command = command;
1117 new->seen = seen_force ? seen_value : FALSE;
1118 new->args[0].u = fmsg;
1122 /* Seen, unseen, and noerror are not allowed before if, which takes a
1123 condition argument and then and else sub-commands. */
1126 if (seen_force || noerror_force)
1128 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1129 "found before an \"if\" command near line %d",
1134 /* Set up the command block for if */
1136 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1139 *lastcmdptr = &new->next;
1140 new->command = command;
1142 new->args[0].u = NULL;
1143 new->args[1].u = new->args[2].u = NULL;
1144 new->args[3].u = ptr;
1146 /* Read the condition */
1148 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1149 if (*error_pointer) { yield = FALSE; break; }
1151 /* Read the commands to be obeyed if the condition is true */
1153 newlastcmdptr = &(new->args[1].f);
1154 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1156 /* If commands were successfully read, handle the various possible
1157 terminators. There may be a number of successive "elif" sections. */
1161 while (had_else_endif == had_elif)
1163 filter_cmd *newnew =
1164 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1165 new->args[2].f = newnew;
1168 new->command = command;
1170 new->args[0].u = NULL;
1171 new->args[1].u = new->args[2].u = NULL;
1172 new->args[3].u = ptr;
1174 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1175 if (*error_pointer) { yield = FALSE; break; }
1176 newlastcmdptr = &(new->args[1].f);
1177 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1181 if (yield == FALSE) break;
1183 /* Handle termination by "else", possibly following one or more
1184 "elsif" sections. */
1186 if (had_else_endif == had_else)
1188 newlastcmdptr = &(new->args[2].f);
1189 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1191 else if (had_else_endif != had_endif)
1193 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1194 "filter file", line_number);
1199 /* Otherwise the terminator was "endif" - this is checked by
1200 read_command_list(). The pointer is already set to NULL. */
1203 /* Reset the terminator flag. */
1205 had_else_endif = had_neither;
1209 /* The mail & vacation commands have a whole slew of keyworded arguments.
1210 The final argument values are the file expand and return message booleans,
1211 whose offsets are defined in mailarg_index_{expand,return}. Although they
1212 are logically booleans, because they are stored in a uschar * value, we use
1213 NULL and not FALSE, to keep 64-bit compilers happy. */
1216 case vacation_command:
1217 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
1219 new->command = command;
1220 new->seen = seen_force ? seen_value : FALSE;
1221 new->noerror = noerror_force;
1222 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1224 /* Read keyword/value pairs until we hit one that isn't. The data
1225 must contain only printing chars plus tab, though the "text" value
1226 can also contain newlines. The "file" keyword can be preceded by the
1227 word "expand", and "return message" has no data. */
1231 const uschar *saveptr = ptr;
1232 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1234 { yield = FALSE; break; }
1236 /* Ensure "return" is followed by "message"; that's a complete option */
1238 if (Ustrcmp(buffer, "return") == 0)
1240 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1241 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1242 if (Ustrcmp(buffer, "message") != 0)
1244 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1245 " near line %d of filter file", line_number);
1252 /* Ensure "expand" is followed by "file", then fall through to process the
1255 if (Ustrcmp(buffer, "expand") == 0)
1257 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1258 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1259 if (Ustrcmp(buffer, "file") != 0)
1261 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1262 " near line %d of filter file", line_number);
1268 /* Scan for the keyword */
1270 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1271 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1273 /* Not found keyword; assume end of this command */
1275 if (i >= MAILARGS_STRING_COUNT)
1281 /* Found keyword, read the data item */
1283 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1285 { yield = FALSE; break; }
1286 else new->args[i].u = string_copy(buffer);
1289 /* If this is the vacation command, apply some default settings to
1290 some of the arguments. */
1292 if (command == vacation_command)
1294 if (!new->args[mailarg_index_file].u)
1296 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1297 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1299 if (!new->args[mailarg_index_log].u)
1300 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1301 if (!new->args[mailarg_index_once].u)
1302 new->args[mailarg_index_once].u = string_copy(US".vacation");
1303 if (!new->args[mailarg_index_once_repeat].u)
1304 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1305 if (!new->args[mailarg_index_subject].u)
1306 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1309 /* Join the address on to the chain of generated addresses */
1312 *lastcmdptr = &(new->next);
1316 /* Seen and unseen just set flags */
1319 case unseen_command:
1322 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1323 "near line %d is not followed by a command", line_number);
1328 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1329 "near line %d", line_number);
1332 seen_value = (command == seen_command);
1334 was_seen_or_unseen = TRUE;
1338 /* So does noerror */
1340 case noerror_command:
1343 *error_pointer = string_sprintf("\"noerror\" "
1344 "near line %d is not followed by a command", line_number);
1347 noerror_force = TRUE;
1355 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1356 "near line %d of filter file", buffer, line_number);
1361 if (!was_seen_or_unseen && !was_noerror)
1364 noerror_force = FALSE;
1373 /*************************************************
1374 * Read a list of commands *
1375 *************************************************/
1377 /* If conditional is TRUE, the list must be terminated
1378 by the words "else" or "endif".
1381 pptr points to pointer to next character; the pointer is updated
1382 lastcmdptr points to pointer to pointer to previously-read command; used
1383 for hanging on the new command
1384 conditional TRUE if this command is the subject of a condition
1386 Returns: TRUE on success
1390 read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1392 if (conditional) expect_endif++;
1393 had_else_endif = had_neither;
1394 while (**pptr && had_else_endif == had_neither)
1396 if (!read_command(pptr, lastcmdptr)) return FALSE;
1397 *pptr = nextsigchar(*pptr, TRUE);
1402 if (had_else_endif == had_neither)
1404 *error_pointer = US"\"endif\" missing at end of filter file";
1414 /*************************************************
1415 * Test a condition *
1416 *************************************************/
1420 c points to the condition block; c->testfor indicated whether
1421 it's a positive or negative condition
1422 toplevel TRUE if called from "if" directly; FALSE otherwise
1424 Returns: TRUE if the condition is met
1428 test_condition(condition_block * c, BOOL toplevel)
1430 BOOL yield = FALSE, textonly_re;
1431 const uschar * exp[2], * p, * pp;
1434 if (!c) 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 (int i = 0; i < 2; i++)
1537 if (!(exp[i] = expand_string_2(p, &textonly_re)))
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;
1589 mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS;
1591 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1592 (debug_selector & D_filter) != 0)
1594 debug_printf_indent("Match expanded arguments:\n");
1595 debug_printf_indent(" Subject = %s\n", exp[0]);
1596 debug_printf_indent(" Pattern = %s\n", exp[1]);
1599 if (c->type == cond_matches) flags |= MCS_CASELESS;
1600 if (!(re = regex_compile(exp[1], flags, error_pointer, pcre_gen_cmp_ctx)))
1603 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1607 /* For above and below, convert the strings to numbers */
1611 for (int i = 0; i < 2; i++)
1613 val[i] = get_number(exp[i], &yield);
1616 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1621 yield = c->type == cond_above ? (val[0] > val[1]) : (val[0] < val[1]);
1627 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1628 (debug_selector & D_filter) != 0)
1631 debug_printf_indent("%sondition is %s: ",
1632 toplevel? "C" : "Sub-c",
1633 (yield == c->testfor)? "true" : "false");
1634 print_condition(c, TRUE);
1635 debug_printf_indent("\n");
1638 return yield == c->testfor;
1643 /*************************************************
1644 * Interpret chain of commands *
1645 *************************************************/
1647 /* In testing state, just say what would be done rather than doing it. The
1648 testprint command just expands and outputs its argument in testing state, and
1649 does nothing otherwise.
1652 commands points to chain of commands to interpret
1653 generated where to hang newly-generated addresses
1655 Returns: FF_DELIVERED success, a significant action was taken
1656 FF_NOTDELIVERED success, no significant action
1657 FF_DEFER defer requested
1658 FF_FAIL fail requested
1659 FF_FREEZE freeze requested
1660 FF_ERROR there was a problem
1664 interpret_commands(filter_cmd *commands, address_item **generated)
1669 BOOL condition_value;
1674 uschar *fmsg, *ff_name;
1675 const uschar *expargs[MAILARGS_STRING_COUNT];
1679 /* Expand the relevant number of arguments for the command that are
1682 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1684 const uschar *ss = commands->args[i].u;
1687 else if (!(expargs[i] = expand_cstring(ss)))
1689 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1690 "%s command: %s", ss, command_list[commands->command],
1691 expand_string_message);
1696 /* Now switch for each command, setting the "delivered" flag if any of them
1699 if (commands->seen) filter_delivered = TRUE;
1701 switch(commands->command)
1704 for (i = 0; i < 2; i++)
1706 const uschar *ss = expargs[i];
1709 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1711 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1712 "command", expargs[i]);
1716 /* Allow for "--" at the start of the value (from -$n0) for example */
1717 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1719 n[i] = (int)Ustrtol(ss, &end, 0);
1722 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1728 filter_n[n[1]] += n[0];
1729 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1732 /* A deliver command's argument must be a valid address. Its optional
1733 second argument (system filter only) must also be a valid address. */
1735 case deliver_command:
1736 for (i = 0; i < 2; i++)
1741 int start, end, domain;
1743 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1746 expargs[i] = filter_options & RDO_REWRITE
1747 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1749 : rewrite_address_qualify(ss, TRUE);
1752 *error_pointer = string_sprintf("malformed address \"%s\" in "
1753 "filter file: %s", s, error);
1759 /* Stick the errors address into a simple variable, as it will
1760 be referenced a few times. Check that the caller is permitted to
1765 if (s != NULL && !f.system_filtering)
1767 uschar *ownaddress = expand_string(US"$local_part@$domain");
1768 if (strcmpic(ownaddress, s) != 0)
1770 *error_pointer = US"errors_to must point to the caller's address";
1775 /* Test case: report what would happen */
1777 if (filter_test != FTEST_NONE)
1780 printf("%seliver message to: %s%s%s%s\n",
1781 (commands->seen)? "D" : "Unseen d",
1783 commands->noerror? " (noerror)" : "",
1784 (s != NULL)? " errors_to " : "",
1785 (s != NULL)? s : US"");
1792 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1793 (commands->seen)? "" : "unseen ",
1795 commands->noerror? " (noerror)" : "",
1796 (s != NULL)? " errors_to " : "",
1797 (s != NULL)? s : US"");
1799 /* Create the new address and add it to the chain, setting the
1800 af_ignore_error flag if necessary, and the errors address, which can be
1801 set in a system filter and to the local address in user filters. */
1803 addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
1804 addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1805 if (commands->noerror) addr->prop.ignore_error = TRUE;
1806 addr->next = *generated;
1813 mode = commands->args[1].i;
1815 /* Test case: report what would happen */
1817 if (filter_test != FTEST_NONE)
1821 printf("%save message to: %s%s\n", (commands->seen)?
1822 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1824 printf("%save message to: %s %04o%s\n", (commands->seen)?
1825 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1828 /* Real case: Ensure save argument starts with / if there is a home
1829 directory to prepend. */
1833 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1834 deliver_home != NULL && deliver_home[0] != 0)
1835 s = string_sprintf("%s/%s", deliver_home, s);
1836 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1837 (commands->seen)? "" : "unseen ", s,
1838 commands->noerror? " (noerror)" : "");
1840 /* Create the new address and add it to the chain, setting the
1841 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1844 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1845 setflag(addr, af_pfr);
1846 setflag(addr, af_file);
1847 if (commands->noerror) addr->prop.ignore_error = TRUE;
1849 addr->next = *generated;
1855 s = string_copy(commands->args[0].u);
1856 if (filter_test != FTEST_NONE)
1859 printf("%sipe message to: %s%s\n", (commands->seen)?
1860 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1862 else /* Ensure pipe command starts with | */
1864 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1865 commands->seen ? "" : "unseen ", s,
1866 commands->noerror ? " (noerror)" : "");
1867 if (s[0] != '|') s = string_sprintf("|%s", s);
1869 /* Create the new address and add it to the chain, setting the
1870 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1871 each command argument is expanded in the transport after the command
1872 has been split up into separate arguments. */
1874 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1875 setflag(addr, af_pfr);
1876 setflag(addr, af_expand_pipe);
1877 if (commands->noerror) addr->prop.ignore_error = TRUE;
1878 addr->next = *generated;
1881 /* If there are any numeric variables in existence (e.g. after a regex
1882 condition), or if $thisaddress is set, take a copy for use in the
1883 expansion. Note that we can't pass NULL for filter_thisaddress, because
1884 NULL terminates the list. */
1886 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1888 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1889 uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1891 addr->pipe_expandn = ss;
1892 if (!filter_thisaddress) filter_thisaddress = US"";
1893 *ss++ = string_copy(filter_thisaddress);
1894 for (int i = 0; i <= expand_nmax; i++)
1895 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1901 /* Set up the file name and mode, and close any previously open
1904 case logfile_command:
1905 log_mode = commands->args[1].i;
1906 if (log_mode == -1) log_mode = 0600;
1909 (void)close(log_fd);
1912 log_filename = expargs[0];
1913 if (filter_test != FTEST_NONE)
1916 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1920 case logwrite_command:
1923 if (filter_test != FTEST_NONE)
1926 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1927 string_printing(s));
1930 /* Attempt to write to a log file only if configured as permissible.
1931 Logging may be forcibly skipped for verifying or testing. */
1933 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1936 debug_printf_indent("filter log command aborted: euid=%ld\n",
1937 (long int)geteuid());
1938 *error_pointer = US"logwrite command forbidden";
1941 else if ((filter_options & RDO_REALLOG) != 0)
1944 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1945 (long int)geteuid());
1950 *error_pointer = US"attempt to obey \"logwrite\" command "
1951 "without a previous \"logfile\"";
1954 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1957 *error_pointer = string_open_failed("filter log file \"%s\"",
1963 if (write(log_fd, s, len) != len)
1965 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1966 log_filename, strerror(errno));
1972 debug_printf_indent("skipping logwrite (verifying or testing)\n");
1975 /* Header addition and removal is available only in the system filter. The
1976 command is rejected at parse time otherwise. However "headers charset" is
1977 always permitted. */
1979 case headers_command:
1981 int subtype = commands->args[1].i;
1984 if (filter_test != FTEST_NONE)
1985 printf("Headers %s \"%s\"\n",
1986 subtype == TRUE ? "add"
1987 : subtype == FALSE ? "remove"
1989 string_printing(s));
1991 if (subtype == TRUE)
1993 while (isspace(*s)) s++;
1996 header_add(htype_other, "%s%s", s,
1997 s[Ustrlen(s)-1] == '\n' ? "" : "\n");
1998 header_last->type = header_checkname(header_last, FALSE);
1999 if (header_last->type >= 'a') header_last->type = htype_other;
2003 else if (subtype == FALSE)
2006 const uschar * list = s;
2008 for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2009 header_remove(0, ss);
2012 /* This setting lasts only while the filter is running; on exit, the
2013 variable is reset to the previous value. */
2015 else headers_charset = s;
2019 /* Defer, freeze, and fail are available only when explicitly permitted.
2020 These commands are rejected at parse time otherwise. The message can get
2021 very long by the inclusion of message headers; truncate if it is, and also
2022 ensure printing characters so as not to mess up log files. */
2025 ff_name = US"defer";
2027 goto DEFERFREEZEFAIL;
2032 goto DEFERFREEZEFAIL;
2034 case freeze_command:
2035 ff_name = US"freeze";
2039 *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2040 ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2041 : string_copy(expargs[0]));
2042 for(uschar * s = fmsg; *s; s++)
2043 if (!s[1] && *s == '\n') { *s = '\0'; break; } /* drop trailing newline */
2045 if (filter_test != FTEST_NONE)
2048 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2051 DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2054 case finish_command:
2055 if (filter_test != FTEST_NONE)
2058 printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2061 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2062 commands->seen ? " Seen " : "");
2063 finish_obeyed = TRUE;
2064 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2068 uschar *save_address = filter_thisaddress;
2069 int ok = FF_DELIVERED;
2070 condition_value = test_condition(commands->args[0].c, TRUE);
2076 ok = interpret_commands(commands->args[condition_value? 1:2].f,
2080 filter_thisaddress = save_address;
2081 if (finish_obeyed || ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2087 /* To try to catch runaway loops, do not generate mail if the
2088 return path is unset or if a non-trusted user supplied -f <>
2089 as the return path. */
2092 case vacation_command:
2093 if (!return_path || !*return_path)
2095 if (filter_test != FTEST_NONE)
2096 printf("%s command ignored because return_path is empty\n",
2097 command_list[commands->command]);
2098 else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2099 "is empty\n", command_list[commands->command]);
2103 /* Check the contents of the strings. The type of string can be deduced
2104 from the value of i.
2106 . If i is equal to mailarg_index_text it's a text string for the body,
2107 where anything goes.
2109 . If i is > mailarg_index_text, we are dealing with a file name, which
2110 cannot contain non-printing characters.
2112 . If i is less than mailarg_index_headers we are dealing with something
2113 that will go in a single message header line, where newlines must be
2114 followed by white space.
2116 . If i is equal to mailarg_index_headers, we have a string that contains
2117 one or more headers. Newlines that are not followed by white space must
2118 be followed by a header name.
2121 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2123 const uschar *s = expargs[i];
2127 if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2130 if (i > mailarg_index_text)
2132 if (!mac_isprint(c))
2134 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2135 "in %s command", string_printing(s),
2136 command_list[commands->command]);
2141 /* i < mailarg_index_text */
2143 else if (c == '\n' && !isspace(p[1]))
2145 if (i < mailarg_index_headers)
2147 *error_pointer = string_sprintf("\\n not followed by space in "
2148 "\"%.1024s\" in %s command", string_printing(s),
2149 command_list[commands->command]);
2153 /* Check for the start of a new header line within the string */
2158 for (pp = p + 1;; pp++)
2161 if (c == ':' && pp != p + 1) break;
2162 if (!c || c == ':' || isspace(c))
2164 *error_pointer = string_sprintf("\\n not followed by space or "
2165 "valid header name in \"%.1024s\" in %s command",
2166 string_printing(s), command_list[commands->command]);
2173 } /* Loop to scan the string */
2175 /* The string is OK */
2177 commands->args[i].u = s;
2180 /* Proceed with mail or vacation command */
2182 if (filter_test != FTEST_NONE)
2184 const uschar *to = commands->args[mailarg_index_to].u;
2186 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2187 to ? to : US"<default>",
2188 commands->command == vacation_command ? " (vacation)" : "",
2189 commands->noerror ? " (noerror)" : "");
2190 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2192 const uschar *arg = commands->args[i].u;
2195 int len = Ustrlen(mailargs[i]);
2196 int indent = (debug_selector != 0)? output_indent : 0;
2197 while (len++ < 7 + indent) printf(" ");
2198 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2199 (commands->args[mailarg_index_expand].u != NULL &&
2200 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2203 if (commands->args[mailarg_index_return].u)
2204 printf("Return original message\n");
2209 const uschar *to = commands->args[mailarg_index_to].u;
2210 gstring * log_addr = NULL;
2212 if (!to) to = expand_string(US"$reply_address");
2213 while (isspace(*to)) to++;
2215 for (tt = to; *tt; tt++) /* Get rid of newlines */
2218 uschar * s = string_copy(to);
2219 for (uschar * ss = s; *ss; ss++)
2220 if (*ss == '\n') *ss = ' ';
2227 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2228 commands->seen ? "seen " : "",
2230 commands->command == vacation_command ? " (vacation)" : "",
2231 commands->noerror ? " (noerror)" : "");
2232 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2234 const uschar *arg = commands->args[i].u;
2237 int len = Ustrlen(mailargs[i]);
2238 while (len++ < 15) debug_printf_indent(" ");
2239 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2240 (commands->args[mailarg_index_expand].u != NULL &&
2241 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2246 /* Create the "address" for the autoreply. This is used only for logging,
2247 as the actual recipients are extracted from the To: line by -t. We use the
2248 same logic here to extract the working addresses (there may be more than
2249 one). Just in case there are a vast number of addresses, stop when the
2250 string gets too long. */
2255 uschar *ss = parse_find_address_end(tt, FALSE);
2256 uschar *recipient, *errmess;
2257 int start, end, domain;
2261 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2265 /* Ignore empty addresses and errors; an error will occur later if
2266 there's something really bad. */
2270 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2271 log_addr = string_cat (log_addr, recipient);
2276 if (log_addr && log_addr->ptr > 256)
2278 log_addr = string_catn(log_addr, US", ...", 5);
2282 /* Move on past this address */
2284 tt = ss + (*ss ? 1 : 0);
2285 while (isspace(*tt)) tt++;
2289 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2292 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2293 setflag(addr, af_bad_reply);
2296 setflag(addr, af_pfr);
2297 if (commands->noerror) addr->prop.ignore_error = TRUE;
2298 addr->next = *generated;
2301 addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2302 addr->reply->from = NULL;
2303 addr->reply->to = string_copy(to);
2304 addr->reply->file_expand =
2305 commands->args[mailarg_index_expand].u != NULL;
2306 addr->reply->expand_forbid = expand_forbid;
2307 addr->reply->return_message =
2308 commands->args[mailarg_index_return].u != NULL;
2309 addr->reply->once_repeat = 0;
2311 if (commands->args[mailarg_index_once_repeat].u != NULL)
2313 addr->reply->once_repeat =
2314 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2316 if (addr->reply->once_repeat < 0)
2318 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2319 "in mail or vacation command: %s",
2320 commands->args[mailarg_index_once_repeat].u);
2325 /* Set up all the remaining string arguments (those other than "to") */
2327 for (i = 1; i < mailargs_string_passed; i++)
2329 const uschar *ss = commands->args[i].u;
2330 *(USS((US addr->reply) + reply_offsets[i])) =
2331 ss ? string_copy(ss) : NULL;
2336 case testprint_command:
2337 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2339 const uschar *s = string_printing(expargs[0]);
2340 if (filter_test == FTEST_NONE)
2341 debug_printf_indent("Filter: testprint: %s\n", s);
2343 printf("Testprint: %s\n", s);
2347 commands = commands->next;
2350 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2355 /*************************************************
2356 * Test for a personal message *
2357 *************************************************/
2359 /* This function is global so that it can also be called from the code that
2360 implements Sieve filters.
2363 aliases a chain of aliases
2364 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2366 Returns: TRUE if the message is deemed to be personal
2370 filter_personal(string_item *aliases, BOOL scan_cc)
2372 const uschar *self, *self_from, *self_to;
2373 uschar *psself = NULL;
2374 const uschar *psself_from = NULL, *psself_to = NULL;
2375 rmark reset_point = store_mark();
2381 /* If any header line in the message is a defined "List-" header field, it is
2382 not a personal message. We used to check for any header line that started with
2383 "List-", but this was tightened up for release 4.54. The check is now for
2384 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2385 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2386 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2387 contain any value other than "no", the message is not personal (RFC 3834).
2388 Previously the test was for "auto-". */
2390 for (h = header_list; h; h = h->next)
2392 if (h->type == htype_old) continue;
2394 if (strncmpic(h->text, US"List-", 5) == 0)
2396 uschar * s = h->text + 5;
2397 if (strncmpic(s, US"Id:", 3) == 0 ||
2398 strncmpic(s, US"Help:", 5) == 0 ||
2399 strncmpic(s, US"Subscribe:", 10) == 0 ||
2400 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2401 strncmpic(s, US"Post:", 5) == 0 ||
2402 strncmpic(s, US"Owner:", 6) == 0 ||
2403 strncmpic(s, US"Archive:", 8) == 0)
2407 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2409 uschar * s = h->text + 15;
2410 Uskip_whitespace(&s);
2411 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2413 Uskip_whitespace(&s);
2414 if (*s) return FALSE;
2418 /* Set up "my" address */
2420 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2421 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2422 global_rewrite_rules);
2423 self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2424 global_rewrite_rules);
2427 if (!self_from) self_from = self;
2428 if (self_to) self_to = self;
2430 /* If there's a prefix or suffix set, we must include the prefixed/
2431 suffixed version of the local part in the tests. */
2433 if (deliver_localpart_prefix || deliver_localpart_suffix)
2435 psself = string_sprintf("%s%s%s@%s",
2436 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2438 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2440 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2441 global_rewrite_rules);
2442 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2443 global_rewrite_rules);
2444 if (psself_from == NULL) psself_from = psself;
2445 if (psself_to == NULL) psself_to = psself;
2450 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2454 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2458 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2461 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2467 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2468 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2469 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2471 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2473 (sender_address == NULL || sender_address[0] != 0);
2475 store_reset(reset_point);
2481 /*************************************************
2482 * Interpret a mail filter file *
2483 *************************************************/
2487 filter points to the entire file, read into store as a single string
2488 options controls whether various special things are allowed, and requests
2490 generated where to hang newly-generated addresses
2491 error where to pass back an error text
2493 Returns: FF_DELIVERED success, a significant action was taken
2494 FF_NOTDELIVERED success, no significant action
2495 FF_DEFER defer requested
2496 FF_FAIL fail requested
2497 FF_FREEZE freeze requested
2498 FF_ERROR there was a problem
2502 filter_interpret(const uschar *filter, int options, address_item **generated,
2506 int yield = FF_ERROR;
2507 const uschar *ptr = filter;
2508 const uschar *save_headers_charset = headers_charset;
2509 filter_cmd *commands = NULL;
2510 filter_cmd **lastcmdptr = &commands;
2512 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2515 /* Initialize "not in an if command", set the global flag that is always TRUE
2516 while filtering, and zero the variables. */
2520 f.filter_running = TRUE;
2521 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2523 /* To save having to pass certain values about all the time, make them static.
2524 Also initialize the line number, for error messages, and the log file
2527 filter_options = options;
2528 filter_delivered = FALSE;
2529 finish_obeyed = FALSE;
2530 error_pointer = error;
2531 *error_pointer = NULL;
2535 log_filename = NULL;
2537 /* Scan filter file for syntax and build up an interpretation thereof, and
2538 interpret the compiled commands, and if testing, say whether we ended up
2539 delivered or not, unless something went wrong. */
2542 ptr = nextsigchar(ptr, TRUE);
2544 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2545 yield = interpret_commands(commands, generated);
2547 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2553 s = US"Filtering ended by \"defer\".";
2557 s = US"Filtering ended by \"freeze\".";
2561 s = US"Filtering ended by \"fail\".";
2565 s = US"Filtering set up at least one significant delivery "
2566 "or other action.\n"
2567 "No other deliveries will occur.";
2570 case FF_NOTDELIVERED:
2571 s = US"Filtering did not set up a significant delivery.\n"
2572 "Normal delivery will occur.";
2576 s = string_sprintf("Filter error: %s", *error);
2580 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2581 else debug_printf_indent("%s\n", s);
2584 /* Close the log file if it was opened, and kill off any numerical variables
2585 before returning. Reset the header decoding charset. */
2587 if (log_fd >= 0) (void)close(log_fd);
2589 f.filter_running = FALSE;
2590 headers_charset = save_headers_charset;
2593 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2598 /* End of filter.c */