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 */
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_command] = "add",
207 [defer_command] = "defer",
208 [deliver_command] = "deliver",
209 [elif_command] = "elif",
210 [else_command] = "else",
211 [endif_command] = "endif",
212 [finish_command] = "finish",
213 [fail_command] = "fail",
214 [freeze_command] = "freeze",
215 [headers_command] = "headers",
217 [logfile_command] = "logfile",
218 [logwrite_command] = "logwrite",
219 [mail_command] = "mail",
220 [noerror_command] = "noerror",
221 [pipe_command] = "pipe",
222 [save_command] = "save",
223 [seen_command] = "seen",
224 [testprint_command] = "testprint",
225 [unseen_command] = "unseen",
226 [vacation_command] = "vacation"
229 static int command_list_count = nelem(command_list);
231 /* This table contains the number of expanded arguments in the bottom 4 bits.
232 If the top bit is set, it means that the default for the command is "seen". */
234 static uschar command_exparg_count[] = {
237 [deliver_command] = 128+2,
241 [finish_command] = 0,
243 [freeze_command] = 1,
244 [headers_command] = 1,
246 [logfile_command] = 1,
247 [logwrite_command] = 1,
248 [mail_command] = MAILARGS_STRING_COUNT,
249 [noerror_command] = 0,
250 [pipe_command] = 128+0,
251 [save_command] = 128+1,
253 [testprint_command] = 1,
254 [unseen_command] = 0,
255 [vacation_command] = MAILARGS_STRING_COUNT
260 /*************************************************
261 * Find next significant uschar *
262 *************************************************/
264 /* Function to skip over white space and, optionally, comments.
267 ptr pointer to next character
268 comment_allowed if TRUE, comments (# to \n) are skipped
270 Returns: pointer to next non-whitespace character
273 static const uschar *
274 nextsigchar(const uschar *ptr, BOOL comment_allowed)
278 while (isspace(*ptr))
280 if (*ptr == '\n') line_number++;
283 if (comment_allowed && *ptr == '#')
285 while (*(++ptr) != '\n' && *ptr != 0);
295 /*************************************************
297 *************************************************/
299 /* The terminator is white space unless bracket is TRUE, in which
300 case ( and ) terminate.
303 ptr pointer to next character
304 buffer where to put the word
306 bracket if TRUE, terminate on ( and ) as well as space
308 Returns: pointer to the next significant character after the word
311 static const uschar *
312 nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
315 while (*ptr != 0 && !isspace(*ptr) &&
316 (!bracket || (*ptr != '(' && *ptr != ')')))
318 if (bp - buffer < size - 1) *bp++ = *ptr++; else
320 *error_pointer = string_sprintf("word is too long in line %d of "
321 "filter file (max = %d chars)", line_number, size);
326 return nextsigchar(ptr, TRUE);
331 /*************************************************
333 *************************************************/
335 /* Might be a word, or might be a quoted string; in the latter case
339 ptr pointer to next character
340 buffer where to put the item
342 bracket if TRUE, terminate non-quoted on ( and ) as well as space
344 Returns: the next significant character after the item
347 static const uschar *
348 nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
351 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
353 while (*++ptr && *ptr != '\"' && *ptr != '\n')
355 if (bp - buffer >= size - 1)
357 *error_pointer = string_sprintf("string is too long in line %d of "
358 "filter file (max = %d chars)", line_number, size);
362 if (*ptr != '\\') *bp++ = *ptr; else
364 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
366 const uschar *p = ptr + 1;
367 while (*p != '\n' && isspace(*p)) p++;
372 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
377 *bp++ = string_interpret_escape(CUSS &ptr);
381 if (*ptr == '\"') ptr++;
382 else if (*error_pointer == NULL)
383 *error_pointer = string_sprintf("quote missing at end of string "
384 "in line %d", line_number);
387 return nextsigchar(ptr, TRUE);
393 /*************************************************
394 * Convert a string + K|M to a number *
395 *************************************************/
399 s points to text string
400 OK set TRUE if a valid number was read
402 Returns: the number, or 0 on error (with *OK FALSE)
406 get_number(const uschar *s, BOOL *ok)
410 if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
411 if (tolower(s[count]) == 'k') { value *= 1024; count++; }
412 if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
413 while (isspace((s[count]))) count++;
414 if (s[count] != 0) return 0;
421 /*************************************************
422 * Read one condition *
423 *************************************************/
425 /* A complete condition must be terminated by "then"; bracketed internal
426 conditions must be terminated by a closing bracket. They are read by calling
427 this function recursively.
430 ptr points to start of condition
431 condition_block where to hang the created condition block
432 toplevel TRUE when called at the top level
434 Returns: points to next character after "then"
437 static const uschar *
438 read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
442 condition_block *current_parent = NULL;
443 condition_block **current = cond;
447 /* Loop to read next condition */
453 /* reaching the end of the input is an error. */
457 *error_pointer = US"\"then\" missing at end of filter file";
461 /* Opening bracket at the start of a condition introduces a nested
462 condition, which must be terminated by a closing bracket. */
466 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
467 if (*error_pointer != NULL) break;
470 *error_pointer = string_sprintf("expected \")\" in line %d of "
471 "filter file", line_number);
476 c->testfor = !c->testfor;
479 ptr = nextsigchar(ptr+1, TRUE);
483 /* Closing bracket at the start of a condition is an error. Give an
484 explicit message, as otherwise "unknown condition" would be confusing. */
486 else if (*ptr == ')')
488 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
489 "filter file", line_number);
493 /* Otherwise we expect a word or a string. */
497 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
498 if (*error_pointer) break;
500 /* "Then" at the start of a condition is an error */
502 if (Ustrcmp(buffer, "then") == 0)
504 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
505 "filter file", line_number);
509 /* "Not" at the start of a condition negates the testing condition. */
511 if (Ustrcmp(buffer, "not") == 0)
517 /* Build a condition block from the specific word. */
519 c = store_get(sizeof(condition_block), GET_UNTAINTED);
520 c->left.u = c->right.u = NULL;
521 c->testfor = testfor;
524 /* Check for conditions that start with a keyword */
526 if (Ustrcmp(buffer, "delivered") == 0) c->type = cond_delivered;
527 else if (Ustrcmp(buffer, "error_message") == 0) c->type = cond_errormsg;
528 else if (Ustrcmp(buffer, "first_delivery") == 0) c->type = cond_firsttime;
529 else if (Ustrcmp(buffer, "manually_thawed") == 0) c->type = cond_manualthaw;
531 /* Personal can be followed by any number of aliases */
533 else if (Ustrcmp(buffer, "personal") == 0)
535 c->type = cond_personal;
539 const uschar * saveptr = ptr;
540 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
541 if (*error_pointer) break;
542 if (Ustrcmp(buffer, "alias") != 0)
547 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
548 if (*error_pointer) break;
549 aa = store_get(sizeof(string_item), GET_UNTAINTED);
550 aa->text = string_copy(buffer);
551 aa->next = c->left.a;
556 /* Foranyaddress must be followed by a string and a condition enclosed
557 in parentheses, which is handled as a subcondition. */
559 else if (Ustrcmp(buffer, "foranyaddress") == 0)
561 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
562 if (*error_pointer) break;
565 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
566 "near line %d of filter file", line_number);
570 c->type = cond_foranyaddress;
571 c->left.u = string_copy(buffer);
573 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
574 if (*error_pointer) break;
577 *error_pointer = string_sprintf("expected \")\" in line %d of "
578 "filter file", line_number);
581 ptr = nextsigchar(ptr+1, TRUE);
584 /* If it's not a word we recognize, then it must be the lefthand
585 operand of one of the comparison words. */
590 const uschar *isptr = NULL;
592 c->left.u = string_copy(buffer);
593 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
594 if (*error_pointer) break;
596 /* Handle "does|is [not]", preserving the pointer after "is" in
597 case it isn't that, but the form "is <string>". */
599 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
601 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
602 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
604 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
605 if (*error_pointer) break;
606 if (strcmpic(buffer, US"not") == 0)
608 c->testfor = !c->testfor;
609 if (isptr) isptr = ptr;
610 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
611 if (*error_pointer) break;
615 for (i = 0; i < cond_word_count; i++)
617 if (Ustrcmp(buffer, cond_words[i]) == 0)
619 c->type = cond_types[i];
624 /* If an unknown word follows "is" or "is not"
625 it's actually the argument. Reset to read it. */
627 if (i >= cond_word_count)
631 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
632 "near line %d of filter file", buffer, line_number);
638 /* Get the RH argument. */
640 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
641 if (*error_pointer) break;
642 c->right.u = string_copy(buffer);
646 /* We have read some new condition and set it up in the condition block
647 c; point the current pointer at it, and then deal with what follows. */
651 /* Closing bracket terminates if this is a lower-level condition. Otherwise
657 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
658 "filter file", line_number);
662 /* Opening bracket following a condition is an error; give an explicit
663 message to make it clearer what is wrong. */
665 else if (*ptr == '(')
667 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
668 "filter file", line_number);
672 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
676 // const uschar *saveptr = ptr;
677 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
678 if (*error_pointer) break;
680 /* "Then" terminates a toplevel condition; otherwise a closing bracket
681 has been omitted. Put a string terminator at the start of "then" so
682 that reflecting the condition can be done when testing. */
683 /*XXX This stops us doing a constification job in this file, unfortunately.
684 Comment it out and see if anything breaks.
685 With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
687 if (Ustrcmp(buffer, "then") == 0)
689 // if (toplevel) *saveptr = 0;
692 *error_pointer = string_sprintf("missing \")\" at end of "
693 "condition near line %d of filter file", line_number);
697 /* "And" causes a new condition block to replace the one we have
698 just read, which becomes the left sub-condition. The current pointer
699 is reset to the pointer for the right sub-condition. We have to keep
700 track of the tree of sequential "ands", so as to traverse back up it
701 if an "or" is met. */
703 else if (Ustrcmp(buffer, "and") == 0)
705 condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
706 andc->parent = current_parent;
707 andc->type = cond_and;
708 andc->testfor = TRUE;
710 andc->right.u = NULL; /* insurance */
712 current = &(andc->right.c);
713 current_parent = andc;
716 /* "Or" is similar, but has to be done a bit more carefully to
717 ensure that "and" is more binding. If there's a parent set, we
718 are following a sequence of "and"s and must track back to their
721 else if (Ustrcmp(buffer, "or") == 0)
723 condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
724 condition_block * or_parent = NULL;
728 while (current_parent->parent &&
729 current_parent->parent->type == cond_and)
730 current_parent = current_parent->parent;
732 /* If the parent has a parent, it must be an "or" parent. */
734 if (current_parent->parent)
735 or_parent = current_parent->parent;
738 orc->parent = or_parent;
739 if (!or_parent) *cond = orc;
740 else or_parent->right.c = orc;
743 orc->left.c = (current_parent == NULL)? c : current_parent;
744 orc->right.c = NULL; /* insurance */
745 current = &(orc->right.c);
746 current_parent = orc;
749 /* Otherwise there is a disaster */
753 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
754 "expected near line %d of filter file, but found \"%s\"",
755 toplevel? "then" : ")", line_number, buffer);
761 return nextsigchar(ptr, TRUE);
766 /*************************************************
767 * Output the current indent *
768 *************************************************/
774 for (i = 0; i < output_indent; i++) debug_printf(" ");
779 /*************************************************
780 * Condition printer: for debugging *
781 *************************************************/
785 c the block at the top of the tree
786 toplevel TRUE at toplevel - stops overall brackets
792 print_condition(condition_block *c, BOOL toplevel)
794 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
801 case cond_manualthaw:
802 debug_printf("%s", name);
817 debug_printf("%s %s %s", c->left.u, name, c->right.u);
821 if (!c->testfor) debug_printf("not (");
822 print_condition(c->left.c, FALSE);
823 debug_printf(" %s ", cond_names[c->type]);
824 print_condition(c->right.c, FALSE);
825 if (!c->testfor) debug_printf(")");
829 if (!c->testfor) debug_printf("not (");
830 else if (!toplevel) debug_printf("(");
831 print_condition(c->left.c, FALSE);
832 debug_printf(" %s ", cond_names[c->type]);
833 print_condition(c->right.c, FALSE);
834 if (!toplevel || !c->testfor) debug_printf(")");
837 case cond_foranyaddress:
838 debug_printf("%s %s (", name, c->left.u);
839 print_condition(c->right.c, FALSE);
848 /*************************************************
849 * Read one filtering command *
850 *************************************************/
854 pptr points to pointer to first character of command; the pointer
855 is updated to point after the last character read
856 lastcmdptr points to pointer to pointer to last command; used for hanging
857 on the newly read command
859 Returns: TRUE if command successfully read, else FALSE
863 read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
865 int command, i, cmd_bit;
866 filter_cmd *new, **newlastcmdptr;
868 BOOL was_seen_or_unseen = FALSE;
869 BOOL was_noerror = FALSE;
871 const uschar *ptr = *pptr;
872 const uschar *saveptr;
875 /* Read the next word and find which command it is. Command words are normally
876 terminated by white space, but there are two exceptions, which are the "if" and
877 "elif" commands. We must allow for them to be terminated by an opening bracket,
878 as brackets are allowed in conditions and users will expect not to require
881 *buffer = '\0'; /* compiler quietening */
883 if (Ustrncmp(ptr, "if(", 3) == 0)
885 Ustrcpy(buffer, US"if");
888 else if (Ustrncmp(ptr, "elif(", 5) == 0)
890 Ustrcpy(buffer, US"elif");
895 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
896 if (*error_pointer) return FALSE;
899 for (command = 0; command < command_list_count; command++)
900 if (Ustrcmp(buffer, command_list[command]) == 0) break;
902 /* Handle the individual commands */
906 /* Add takes two arguments, separated by the word "to". Headers has two
907 arguments, but the first must be "add", "remove", or "charset", and it gets
908 stored in the second argument slot. Neither may be preceded by seen, unseen
912 case headers_command:
913 if (seen_force || noerror_force)
915 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
916 "found before an \"%s\" command near line %d",
917 command_list[command], line_number);
922 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
923 and logfile can have an option second argument for the mode, and deliver can
924 have "errors_to <address>" in a system filter, or in a user filter if the
925 address is the current one. */
927 case deliver_command:
928 case logfile_command:
929 case logwrite_command:
932 case testprint_command:
934 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
936 *error_pointer = string_sprintf("\"%s\" requires an argument "
937 "near line %d of filter file", command_list[command], line_number);
939 if (*error_pointer) yield = FALSE; else
941 union argtypes argument, second_argument;
943 argument.u = second_argument.u = NULL;
945 if (command == add_command)
947 argument.u = string_copy(buffer);
948 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
949 if (!*buffer || Ustrcmp(buffer, "to") != 0)
950 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
951 "near line %d of filter file", line_number);
954 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
956 *error_pointer = string_sprintf("value missing after \"to\" "
957 "near line %d of filter file", line_number);
958 else second_argument.u = string_copy(buffer);
962 else if (command == headers_command)
964 if (Ustrcmp(buffer, "add") == 0)
965 second_argument.b = TRUE;
967 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
969 if (Ustrcmp(buffer, "charset") == 0)
970 second_argument.b = TRUE_UNSET;
973 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
974 "expected after \"headers\" near line %d of filter file",
979 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
981 *error_pointer = string_sprintf("header addition and removal is "
982 "available only in system filters: near line %d of filter file",
990 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
992 *error_pointer = string_sprintf("value missing after \"add\", "
993 "\"remove\", or \"charset\" near line %d of filter file",
995 else argument.u = string_copy(buffer);
999 /* The argument for the logwrite command must end in a newline, and the save
1000 and logfile commands can have an optional mode argument. The deliver
1001 command can have an optional "errors_to <address>" for a system filter,
1002 or for a user filter if the address is the user's address. Accept the
1003 syntax here - the check is later. */
1007 if (command == logwrite_command)
1009 int len = Ustrlen(buffer);
1010 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
1013 argument.u = string_copy(buffer);
1015 if (command == save_command || command == logfile_command)
1019 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1020 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
1022 else second_argument.i = -1;
1025 else if (command == deliver_command)
1027 const uschar *save_ptr = ptr;
1028 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1029 if (Ustrcmp(buffer, "errors_to") == 0)
1031 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1032 second_argument.u = string_copy(buffer);
1034 else ptr = save_ptr;
1038 /* Set up the command block. Seen defaults TRUE for delivery commands,
1039 FALSE for logging commands, and it doesn't matter for testprint, as
1040 that doesn't change the "delivered" status. */
1042 if (*error_pointer) yield = FALSE;
1045 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
1048 *lastcmdptr = &(new->next);
1049 new->command = command;
1050 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1051 new->noerror = noerror_force;
1052 new->args[0] = argument;
1053 new->args[1] = second_argument;
1059 /* Elif, else and endif just set a flag if expected. */
1064 if (seen_force || noerror_force)
1066 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1067 "near line %d is not followed by a command", line_number);
1071 if (expect_endif > 0)
1072 had_else_endif = (command == elif_command)? had_elif :
1073 (command == else_command)? had_else : had_endif;
1076 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1077 "line %d of filter file", buffer, line_number);
1083 /* Defer, freeze, and fail are available only if permitted. */
1086 cmd_bit = RDO_DEFER;
1087 goto DEFER_FREEZE_FAIL;
1091 goto DEFER_FREEZE_FAIL;
1093 case freeze_command:
1094 cmd_bit = RDO_FREEZE;
1097 if ((filter_options & cmd_bit) == 0)
1099 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1100 "near line %d of filter file", buffer, line_number);
1105 /* A text message can be provided after the "text" keyword, or
1106 as a string in quotes. */
1109 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1110 if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0))
1117 if (*saveptr != '\"')
1118 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1119 fmsg = string_copy(buffer);
1122 /* Drop through and treat as "finish", but never set "seen". */
1126 /* Finish has no arguments; fmsg defaults to NULL */
1128 case finish_command:
1129 new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
1132 *lastcmdptr = &(new->next);
1133 new->command = command;
1134 new->seen = seen_force ? seen_value : FALSE;
1135 new->args[0].u = fmsg;
1139 /* Seen, unseen, and noerror are not allowed before if, which takes a
1140 condition argument and then and else sub-commands. */
1143 if (seen_force || noerror_force)
1145 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1146 "found before an \"if\" command near line %d",
1151 /* Set up the command block for if */
1153 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1156 *lastcmdptr = &new->next;
1157 new->command = command;
1159 new->args[0].u = NULL;
1160 new->args[1].u = new->args[2].u = NULL;
1161 new->args[3].u = ptr;
1163 /* Read the condition */
1165 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1166 if (*error_pointer) { yield = FALSE; break; }
1168 /* Read the commands to be obeyed if the condition is true */
1170 newlastcmdptr = &(new->args[1].f);
1171 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1173 /* If commands were successfully read, handle the various possible
1174 terminators. There may be a number of successive "elif" sections. */
1178 while (had_else_endif == had_elif)
1180 filter_cmd *newnew =
1181 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1182 new->args[2].f = newnew;
1185 new->command = command;
1187 new->args[0].u = NULL;
1188 new->args[1].u = new->args[2].u = NULL;
1189 new->args[3].u = ptr;
1191 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1192 if (*error_pointer) { yield = FALSE; break; }
1193 newlastcmdptr = &(new->args[1].f);
1194 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1198 if (yield == FALSE) break;
1200 /* Handle termination by "else", possibly following one or more
1201 "elsif" sections. */
1203 if (had_else_endif == had_else)
1205 newlastcmdptr = &(new->args[2].f);
1206 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1208 else if (had_else_endif != had_endif)
1210 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1211 "filter file", line_number);
1216 /* Otherwise the terminator was "endif" - this is checked by
1217 read_command_list(). The pointer is already set to NULL. */
1220 /* Reset the terminator flag. */
1222 had_else_endif = had_neither;
1226 /* The mail & vacation commands have a whole slew of keyworded arguments.
1227 The final argument values are the file expand and return message booleans,
1228 whose offsets are defined in mailarg_index_{expand,return}. Although they
1229 are logically booleans, because they are stored in a uschar * value, we use
1230 NULL and not FALSE, to keep 64-bit compilers happy. */
1233 case vacation_command:
1234 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
1236 new->command = command;
1237 new->seen = seen_force ? seen_value : FALSE;
1238 new->noerror = noerror_force;
1239 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1241 /* Read keyword/value pairs until we hit one that isn't. The data
1242 must contain only printing chars plus tab, though the "text" value
1243 can also contain newlines. The "file" keyword can be preceded by the
1244 word "expand", and "return message" has no data. */
1248 const uschar *saveptr = ptr;
1249 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1251 { yield = FALSE; break; }
1253 /* Ensure "return" is followed by "message"; that's a complete option */
1255 if (Ustrcmp(buffer, "return") == 0)
1257 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1258 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1259 if (Ustrcmp(buffer, "message") != 0)
1261 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1262 " near line %d of filter file", line_number);
1269 /* Ensure "expand" is followed by "file", then fall through to process the
1272 if (Ustrcmp(buffer, "expand") == 0)
1274 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1275 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1276 if (Ustrcmp(buffer, "file") != 0)
1278 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1279 " near line %d of filter file", line_number);
1285 /* Scan for the keyword */
1287 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1288 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1290 /* Not found keyword; assume end of this command */
1292 if (i >= MAILARGS_STRING_COUNT)
1298 /* Found keyword, read the data item */
1300 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1302 { yield = FALSE; break; }
1303 else new->args[i].u = string_copy(buffer);
1306 /* If this is the vacation command, apply some default settings to
1307 some of the arguments. */
1309 if (command == vacation_command)
1311 if (!new->args[mailarg_index_file].u)
1313 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1314 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1316 if (!new->args[mailarg_index_log].u)
1317 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1318 if (!new->args[mailarg_index_once].u)
1319 new->args[mailarg_index_once].u = string_copy(US".vacation");
1320 if (!new->args[mailarg_index_once_repeat].u)
1321 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1322 if (!new->args[mailarg_index_subject].u)
1323 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1326 /* Join the address on to the chain of generated addresses */
1329 *lastcmdptr = &(new->next);
1333 /* Seen and unseen just set flags */
1336 case unseen_command:
1339 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1340 "near line %d is not followed by a command", line_number);
1345 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1346 "near line %d", line_number);
1349 seen_value = (command == seen_command);
1351 was_seen_or_unseen = TRUE;
1355 /* So does noerror */
1357 case noerror_command:
1360 *error_pointer = string_sprintf("\"noerror\" "
1361 "near line %d is not followed by a command", line_number);
1364 noerror_force = TRUE;
1372 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1373 "near line %d of filter file", buffer, line_number);
1378 if (!was_seen_or_unseen && !was_noerror)
1381 noerror_force = FALSE;
1390 /*************************************************
1391 * Read a list of commands *
1392 *************************************************/
1394 /* If conditional is TRUE, the list must be terminated
1395 by the words "else" or "endif".
1398 pptr points to pointer to next character; the pointer is updated
1399 lastcmdptr points to pointer to pointer to previously-read command; used
1400 for hanging on the new command
1401 conditional TRUE if this command is the subject of a condition
1403 Returns: TRUE on success
1407 read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1409 if (conditional) expect_endif++;
1410 had_else_endif = had_neither;
1411 while (**pptr && had_else_endif == had_neither)
1413 if (!read_command(pptr, lastcmdptr)) return FALSE;
1414 *pptr = nextsigchar(*pptr, TRUE);
1419 if (had_else_endif == had_neither)
1421 *error_pointer = US"\"endif\" missing at end of filter file";
1431 /*************************************************
1432 * Test a condition *
1433 *************************************************/
1437 c points to the condition block; c->testfor indicated whether
1438 it's a positive or negative condition
1439 toplevel TRUE if called from "if" directly; FALSE otherwise
1441 Returns: TRUE if the condition is met
1445 test_condition(condition_block * c, BOOL toplevel)
1447 BOOL yield = FALSE, textonly_re;
1448 const uschar * exp[2], * p, * pp;
1451 if (!c) return TRUE; /* does this ever occur? */
1456 yield = test_condition(c->left.c, FALSE) &&
1457 *error_pointer == NULL &&
1458 test_condition(c->right.c, FALSE);
1462 yield = test_condition(c->left.c, FALSE) ||
1463 (*error_pointer == NULL &&
1464 test_condition(c->right.c, FALSE));
1467 /* The personal test is meaningless in a system filter. The tests are now in
1468 a separate function (so Sieve can use them). However, an Exim filter does not
1469 scan Cc: (hence the FALSE argument). */
1472 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
1475 case cond_delivered:
1476 yield = filter_delivered;
1479 /* Only TRUE if a message is actually being processed; FALSE for address
1480 testing and verification. */
1483 yield = message_id[0] && (!sender_address || !*sender_address);
1486 /* Only FALSE if a message is actually being processed; TRUE for address
1487 and filter testing and verification. */
1489 case cond_firsttime:
1490 yield = filter_test != FTEST_NONE || !message_id[0] || f.deliver_firsttime;
1493 /* Only TRUE if a message is actually being processed; FALSE for address
1494 testing and verification. */
1496 case cond_manualthaw:
1497 yield = message_id[0] && f.deliver_manual_thaw;
1500 /* The foranyaddress condition loops through a list of addresses */
1502 case cond_foranyaddress:
1504 if (!(pp = expand_cstring(p)))
1506 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1507 "filter file: %s", p, expand_string_message);
1512 f.parse_allow_group = TRUE; /* Allow group syntax */
1517 int start, end, domain;
1520 p = parse_find_address_end(pp, FALSE);
1521 s = string_copyn(pp, p - pp);
1523 filter_thisaddress =
1524 parse_extract_address(s, &error, &start, &end, &domain, FALSE);
1526 if (filter_thisaddress)
1528 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1529 (debug_selector & D_filter) != 0)
1532 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
1534 yield = test_condition(c->right.c, FALSE);
1542 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1543 f.parse_found_group = FALSE;
1546 /* All other conditions have left and right values that need expanding;
1547 on error, it doesn't matter what value is returned. */
1551 for (int i = 0; i < 2; i++)
1553 if (!(exp[i] = expand_string_2(p, &textonly_re)))
1555 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1556 "filter file: %s", p, expand_string_message);
1562 /* Inner switch for the different cases */
1567 yield = strcmpic(exp[0], exp[1]) == 0;
1571 yield = Ustrcmp(exp[0], exp[1]) == 0;
1575 yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
1579 yield = Ustrstr(exp[0], exp[1]) != NULL;
1583 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1587 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1593 int len = Ustrlen(exp[1]);
1594 const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1597 : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1604 const pcre2_code * re;
1605 mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS;
1607 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1608 (debug_selector & D_filter) != 0)
1610 debug_printf_indent("Match expanded arguments:\n");
1611 debug_printf_indent(" Subject = %s\n", exp[0]);
1612 debug_printf_indent(" Pattern = %s\n", exp[1]);
1615 if (c->type == cond_matches) flags |= MCS_CASELESS;
1616 if (!(re = regex_compile(exp[1], flags, error_pointer, pcre_gen_cmp_ctx)))
1619 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1623 /* For above and below, convert the strings to numbers */
1627 for (int i = 0; i < 2; i++)
1629 val[i] = get_number(exp[i], &yield);
1632 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1637 yield = c->type == cond_above ? (val[0] > val[1]) : (val[0] < val[1]);
1643 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1644 (debug_selector & D_filter) != 0)
1647 debug_printf_indent("%sondition is %s: ",
1648 toplevel? "C" : "Sub-c",
1649 (yield == c->testfor)? "true" : "false");
1650 print_condition(c, TRUE);
1651 debug_printf_indent("\n");
1654 return yield == c->testfor;
1659 /*************************************************
1660 * Interpret chain of commands *
1661 *************************************************/
1663 /* In testing state, just say what would be done rather than doing it. The
1664 testprint command just expands and outputs its argument in testing state, and
1665 does nothing otherwise.
1668 commands points to chain of commands to interpret
1669 generated where to hang newly-generated addresses
1671 Returns: FF_DELIVERED success, a significant action was taken
1672 FF_NOTDELIVERED success, no significant action
1673 FF_DEFER defer requested
1674 FF_FAIL fail requested
1675 FF_FREEZE freeze requested
1676 FF_ERROR there was a problem
1680 interpret_commands(filter_cmd *commands, address_item **generated)
1685 BOOL condition_value;
1690 uschar *fmsg, *ff_name;
1691 const uschar *expargs[MAILARGS_STRING_COUNT];
1695 /* Expand the relevant number of arguments for the command that are
1698 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1700 const uschar *ss = commands->args[i].u;
1703 else if (!(expargs[i] = expand_cstring(ss)))
1705 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1706 "%s command: %s", ss, command_list[commands->command],
1707 expand_string_message);
1712 /* Now switch for each command, setting the "delivered" flag if any of them
1715 if (commands->seen) filter_delivered = TRUE;
1717 switch(commands->command)
1720 for (i = 0; i < 2; i++)
1722 const uschar *ss = expargs[i];
1725 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1727 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1728 "command", expargs[i]);
1732 /* Allow for "--" at the start of the value (from -$n0) for example */
1733 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1735 n[i] = (int)Ustrtol(ss, &end, 0);
1738 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1744 filter_n[n[1]] += n[0];
1745 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1748 /* A deliver command's argument must be a valid address. Its optional
1749 second argument (system filter only) must also be a valid address. */
1751 case deliver_command:
1752 for (i = 0; i < 2; i++)
1757 int start, end, domain;
1759 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1762 expargs[i] = filter_options & RDO_REWRITE
1763 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1765 : rewrite_address_qualify(ss, TRUE);
1768 *error_pointer = string_sprintf("malformed address \"%s\" in "
1769 "filter file: %s", s, error);
1775 /* Stick the errors address into a simple variable, as it will
1776 be referenced a few times. Check that the caller is permitted to
1781 if (s != NULL && !f.system_filtering)
1783 uschar *ownaddress = expand_string(US"$local_part@$domain");
1784 if (strcmpic(ownaddress, s) != 0)
1786 *error_pointer = US"errors_to must point to the caller's address";
1791 /* Test case: report what would happen */
1793 if (filter_test != FTEST_NONE)
1796 printf("%seliver message to: %s%s%s%s\n",
1797 (commands->seen)? "D" : "Unseen d",
1799 commands->noerror? " (noerror)" : "",
1800 (s != NULL)? " errors_to " : "",
1801 (s != NULL)? s : US"");
1808 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1809 (commands->seen)? "" : "unseen ",
1811 commands->noerror? " (noerror)" : "",
1812 (s != NULL)? " errors_to " : "",
1813 (s != NULL)? s : US"");
1815 /* Create the new address and add it to the chain, setting the
1816 af_ignore_error flag if necessary, and the errors address, which can be
1817 set in a system filter and to the local address in user filters. */
1819 addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
1820 addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1821 if (commands->noerror) addr->prop.ignore_error = TRUE;
1822 addr->next = *generated;
1829 mode = commands->args[1].i;
1831 /* Test case: report what would happen */
1833 if (filter_test != FTEST_NONE)
1837 printf("%save message to: %s%s\n", (commands->seen)?
1838 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1840 printf("%save message to: %s %04o%s\n", (commands->seen)?
1841 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1844 /* Real case: Ensure save argument starts with / if there is a home
1845 directory to prepend. */
1849 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1850 deliver_home != NULL && deliver_home[0] != 0)
1851 s = string_sprintf("%s/%s", deliver_home, s);
1852 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1853 (commands->seen)? "" : "unseen ", s,
1854 commands->noerror? " (noerror)" : "");
1856 /* Create the new address and add it to the chain, setting the
1857 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1860 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1861 setflag(addr, af_pfr);
1862 setflag(addr, af_file);
1863 if (commands->noerror) addr->prop.ignore_error = TRUE;
1865 addr->next = *generated;
1871 s = string_copy(commands->args[0].u);
1872 if (filter_test != FTEST_NONE)
1875 printf("%sipe message to: %s%s\n", (commands->seen)?
1876 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1878 else /* Ensure pipe command starts with | */
1880 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1881 commands->seen ? "" : "unseen ", s,
1882 commands->noerror ? " (noerror)" : "");
1883 if (s[0] != '|') s = string_sprintf("|%s", s);
1885 /* Create the new address and add it to the chain, setting the
1886 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1887 each command argument is expanded in the transport after the command
1888 has been split up into separate arguments. */
1890 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
1891 setflag(addr, af_pfr);
1892 setflag(addr, af_expand_pipe);
1893 if (commands->noerror) addr->prop.ignore_error = TRUE;
1894 addr->next = *generated;
1897 /* If there are any numeric variables in existence (e.g. after a regex
1898 condition), or if $thisaddress is set, take a copy for use in the
1899 expansion. Note that we can't pass NULL for filter_thisaddress, because
1900 NULL terminates the list. */
1902 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1904 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1905 uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1907 addr->pipe_expandn = ss;
1908 if (!filter_thisaddress) filter_thisaddress = US"";
1909 *ss++ = string_copy(filter_thisaddress);
1910 for (int i = 0; i <= expand_nmax; i++)
1911 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1917 /* Set up the file name and mode, and close any previously open
1920 case logfile_command:
1921 log_mode = commands->args[1].i;
1922 if (log_mode == -1) log_mode = 0600;
1925 (void)close(log_fd);
1928 log_filename = expargs[0];
1929 if (filter_test != FTEST_NONE)
1932 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1936 case logwrite_command:
1939 if (filter_test != FTEST_NONE)
1942 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1943 string_printing(s));
1946 /* Attempt to write to a log file only if configured as permissible.
1947 Logging may be forcibly skipped for verifying or testing. */
1949 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1952 debug_printf_indent("filter log command aborted: euid=%ld\n",
1953 (long int)geteuid());
1954 *error_pointer = US"logwrite command forbidden";
1957 else if ((filter_options & RDO_REALLOG) != 0)
1960 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1961 (long int)geteuid());
1966 *error_pointer = US"attempt to obey \"logwrite\" command "
1967 "without a previous \"logfile\"";
1970 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1973 *error_pointer = string_open_failed("filter log file \"%s\"",
1979 if (write(log_fd, s, len) != len)
1981 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1982 log_filename, strerror(errno));
1988 debug_printf_indent("skipping logwrite (verifying or testing)\n");
1991 /* Header addition and removal is available only in the system filter. The
1992 command is rejected at parse time otherwise. However "headers charset" is
1993 always permitted. */
1995 case headers_command:
1997 int subtype = commands->args[1].i;
2000 if (filter_test != FTEST_NONE)
2001 printf("Headers %s \"%s\"\n",
2002 subtype == TRUE ? "add"
2003 : subtype == FALSE ? "remove"
2005 string_printing(s));
2007 if (subtype == TRUE)
2009 while (isspace(*s)) s++;
2012 header_add(htype_other, "%s%s", s,
2013 s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2014 header_last->type = header_checkname(header_last, FALSE);
2015 if (header_last->type >= 'a') header_last->type = htype_other;
2019 else if (subtype == FALSE)
2022 const uschar * list = s;
2024 for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2025 header_remove(0, ss);
2028 /* This setting lasts only while the filter is running; on exit, the
2029 variable is reset to the previous value. */
2031 else headers_charset = s;
2035 /* Defer, freeze, and fail are available only when explicitly permitted.
2036 These commands are rejected at parse time otherwise. The message can get
2037 very long by the inclusion of message headers; truncate if it is, and also
2038 ensure printing characters so as not to mess up log files. */
2041 ff_name = US"defer";
2043 goto DEFERFREEZEFAIL;
2048 goto DEFERFREEZEFAIL;
2050 case freeze_command:
2051 ff_name = US"freeze";
2055 *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2056 ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2057 : string_copy(expargs[0]));
2058 for(uschar * s = fmsg; *s; s++)
2059 if (!s[1] && *s == '\n') { *s = '\0'; break; } /* drop trailing newline */
2061 if (filter_test != FTEST_NONE)
2064 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2067 DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2070 case finish_command:
2071 if (filter_test != FTEST_NONE)
2074 printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2077 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2078 commands->seen ? " Seen " : "");
2079 finish_obeyed = TRUE;
2080 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2084 uschar *save_address = filter_thisaddress;
2085 int ok = FF_DELIVERED;
2086 condition_value = test_condition(commands->args[0].c, TRUE);
2092 ok = interpret_commands(commands->args[condition_value? 1:2].f,
2096 filter_thisaddress = save_address;
2097 if (finish_obeyed || ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2103 /* To try to catch runaway loops, do not generate mail if the
2104 return path is unset or if a non-trusted user supplied -f <>
2105 as the return path. */
2108 case vacation_command:
2109 if (!return_path || !*return_path)
2111 if (filter_test != FTEST_NONE)
2112 printf("%s command ignored because return_path is empty\n",
2113 command_list[commands->command]);
2114 else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2115 "is empty\n", command_list[commands->command]);
2119 /* Check the contents of the strings. The type of string can be deduced
2120 from the value of i.
2122 . If i is equal to mailarg_index_text it's a text string for the body,
2123 where anything goes.
2125 . If i is > mailarg_index_text, we are dealing with a file name, which
2126 cannot contain non-printing characters.
2128 . If i is less than mailarg_index_headers we are dealing with something
2129 that will go in a single message header line, where newlines must be
2130 followed by white space.
2132 . If i is equal to mailarg_index_headers, we have a string that contains
2133 one or more headers. Newlines that are not followed by white space must
2134 be followed by a header name.
2137 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2139 const uschar *s = expargs[i];
2143 if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2146 if (i > mailarg_index_text)
2148 if (!mac_isprint(c))
2150 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2151 "in %s command", string_printing(s),
2152 command_list[commands->command]);
2157 /* i < mailarg_index_text */
2159 else if (c == '\n' && !isspace(p[1]))
2161 if (i < mailarg_index_headers)
2163 *error_pointer = string_sprintf("\\n not followed by space in "
2164 "\"%.1024s\" in %s command", string_printing(s),
2165 command_list[commands->command]);
2169 /* Check for the start of a new header line within the string */
2174 for (pp = p + 1;; pp++)
2177 if (c == ':' && pp != p + 1) break;
2178 if (!c || c == ':' || isspace(c))
2180 *error_pointer = string_sprintf("\\n not followed by space or "
2181 "valid header name in \"%.1024s\" in %s command",
2182 string_printing(s), command_list[commands->command]);
2189 } /* Loop to scan the string */
2191 /* The string is OK */
2193 commands->args[i].u = s;
2196 /* Proceed with mail or vacation command */
2198 if (filter_test != FTEST_NONE)
2200 const uschar *to = commands->args[mailarg_index_to].u;
2202 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2203 to ? to : US"<default>",
2204 commands->command == vacation_command ? " (vacation)" : "",
2205 commands->noerror ? " (noerror)" : "");
2206 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2208 const uschar *arg = commands->args[i].u;
2211 int len = Ustrlen(mailargs[i]);
2212 int indent = (debug_selector != 0)? output_indent : 0;
2213 while (len++ < 7 + indent) printf(" ");
2214 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2215 (commands->args[mailarg_index_expand].u != NULL &&
2216 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2219 if (commands->args[mailarg_index_return].u)
2220 printf("Return original message\n");
2225 const uschar *to = commands->args[mailarg_index_to].u;
2226 gstring * log_addr = NULL;
2228 if (!to) to = expand_string(US"$reply_address");
2229 while (isspace(*to)) to++;
2231 for (tt = to; *tt; tt++) /* Get rid of newlines */
2234 uschar * s = string_copy(to);
2235 for (uschar * ss = s; *ss; ss++)
2236 if (*ss == '\n') *ss = ' ';
2243 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2244 commands->seen ? "seen " : "",
2246 commands->command == vacation_command ? " (vacation)" : "",
2247 commands->noerror ? " (noerror)" : "");
2248 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2250 const uschar *arg = commands->args[i].u;
2253 int len = Ustrlen(mailargs[i]);
2254 while (len++ < 15) debug_printf_indent(" ");
2255 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2256 (commands->args[mailarg_index_expand].u != NULL &&
2257 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2262 /* Create the "address" for the autoreply. This is used only for logging,
2263 as the actual recipients are extracted from the To: line by -t. We use the
2264 same logic here to extract the working addresses (there may be more than
2265 one). Just in case there are a vast number of addresses, stop when the
2266 string gets too long. */
2271 uschar *ss = parse_find_address_end(tt, FALSE);
2272 uschar *recipient, *errmess;
2273 int start, end, domain;
2277 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2281 /* Ignore empty addresses and errors; an error will occur later if
2282 there's something really bad. */
2286 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2287 log_addr = string_cat (log_addr, recipient);
2292 if (log_addr && log_addr->ptr > 256)
2294 log_addr = string_catn(log_addr, US", ...", 5);
2298 /* Move on past this address */
2300 tt = ss + (*ss ? 1 : 0);
2301 while (isspace(*tt)) tt++;
2305 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2308 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2309 setflag(addr, af_bad_reply);
2312 setflag(addr, af_pfr);
2313 if (commands->noerror) addr->prop.ignore_error = TRUE;
2314 addr->next = *generated;
2317 addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2318 addr->reply->from = NULL;
2319 addr->reply->to = string_copy(to);
2320 addr->reply->file_expand =
2321 commands->args[mailarg_index_expand].u != NULL;
2322 addr->reply->expand_forbid = expand_forbid;
2323 addr->reply->return_message =
2324 commands->args[mailarg_index_return].u != NULL;
2325 addr->reply->once_repeat = 0;
2327 if (commands->args[mailarg_index_once_repeat].u != NULL)
2329 addr->reply->once_repeat =
2330 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2332 if (addr->reply->once_repeat < 0)
2334 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2335 "in mail or vacation command: %s",
2336 commands->args[mailarg_index_once_repeat].u);
2341 /* Set up all the remaining string arguments (those other than "to") */
2343 for (i = 1; i < mailargs_string_passed; i++)
2345 const uschar *ss = commands->args[i].u;
2346 *(USS((US addr->reply) + reply_offsets[i])) =
2347 ss ? string_copy(ss) : NULL;
2352 case testprint_command:
2353 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2355 const uschar *s = string_printing(expargs[0]);
2356 if (filter_test == FTEST_NONE)
2357 debug_printf_indent("Filter: testprint: %s\n", s);
2359 printf("Testprint: %s\n", s);
2363 commands = commands->next;
2366 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2371 /*************************************************
2372 * Test for a personal message *
2373 *************************************************/
2375 /* This function is global so that it can also be called from the code that
2376 implements Sieve filters.
2379 aliases a chain of aliases
2380 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2382 Returns: TRUE if the message is deemed to be personal
2386 filter_personal(string_item *aliases, BOOL scan_cc)
2388 const uschar *self, *self_from, *self_to;
2389 uschar *psself = NULL;
2390 const uschar *psself_from = NULL, *psself_to = NULL;
2391 rmark reset_point = store_mark();
2397 /* If any header line in the message is a defined "List-" header field, it is
2398 not a personal message. We used to check for any header line that started with
2399 "List-", but this was tightened up for release 4.54. The check is now for
2400 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2401 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2402 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2403 contain any value other than "no", the message is not personal (RFC 3834).
2404 Previously the test was for "auto-". */
2406 for (h = header_list; h; h = h->next)
2408 if (h->type == htype_old) continue;
2410 if (strncmpic(h->text, US"List-", 5) == 0)
2412 uschar * s = h->text + 5;
2413 if (strncmpic(s, US"Id:", 3) == 0 ||
2414 strncmpic(s, US"Help:", 5) == 0 ||
2415 strncmpic(s, US"Subscribe:", 10) == 0 ||
2416 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2417 strncmpic(s, US"Post:", 5) == 0 ||
2418 strncmpic(s, US"Owner:", 6) == 0 ||
2419 strncmpic(s, US"Archive:", 8) == 0)
2423 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2425 uschar * s = h->text + 15;
2426 Uskip_whitespace(&s);
2427 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2429 Uskip_whitespace(&s);
2430 if (*s) return FALSE;
2434 /* Set up "my" address */
2436 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2437 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2438 global_rewrite_rules);
2439 self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2440 global_rewrite_rules);
2443 if (!self_from) self_from = self;
2444 if (self_to) self_to = self;
2446 /* If there's a prefix or suffix set, we must include the prefixed/
2447 suffixed version of the local part in the tests. */
2449 if (deliver_localpart_prefix || deliver_localpart_suffix)
2451 psself = string_sprintf("%s%s%s@%s",
2452 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2454 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2456 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2457 global_rewrite_rules);
2458 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2459 global_rewrite_rules);
2460 if (psself_from == NULL) psself_from = psself;
2461 if (psself_to == NULL) psself_to = psself;
2466 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2470 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2474 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2477 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2483 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2484 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2485 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2487 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2489 (sender_address == NULL || sender_address[0] != 0);
2491 store_reset(reset_point);
2497 /*************************************************
2498 * Interpret a mail filter file *
2499 *************************************************/
2503 filter points to the entire file, read into store as a single string
2504 options controls whether various special things are allowed, and requests
2506 generated where to hang newly-generated addresses
2507 error where to pass back an error text
2509 Returns: FF_DELIVERED success, a significant action was taken
2510 FF_NOTDELIVERED success, no significant action
2511 FF_DEFER defer requested
2512 FF_FAIL fail requested
2513 FF_FREEZE freeze requested
2514 FF_ERROR there was a problem
2518 filter_interpret(const uschar *filter, int options, address_item **generated,
2522 int yield = FF_ERROR;
2523 const uschar *ptr = filter;
2524 const uschar *save_headers_charset = headers_charset;
2525 filter_cmd *commands = NULL;
2526 filter_cmd **lastcmdptr = &commands;
2528 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2531 /* Initialize "not in an if command", set the global flag that is always TRUE
2532 while filtering, and zero the variables. */
2536 f.filter_running = TRUE;
2537 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2539 /* To save having to pass certain values about all the time, make them static.
2540 Also initialize the line number, for error messages, and the log file
2543 filter_options = options;
2544 filter_delivered = FALSE;
2545 finish_obeyed = FALSE;
2546 error_pointer = error;
2547 *error_pointer = NULL;
2551 log_filename = NULL;
2553 /* Scan filter file for syntax and build up an interpretation thereof, and
2554 interpret the compiled commands, and if testing, say whether we ended up
2555 delivered or not, unless something went wrong. */
2558 ptr = nextsigchar(ptr, TRUE);
2560 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2561 yield = interpret_commands(commands, generated);
2563 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2569 s = US"Filtering ended by \"defer\".";
2573 s = US"Filtering ended by \"freeze\".";
2577 s = US"Filtering ended by \"fail\".";
2581 s = US"Filtering set up at least one significant delivery "
2582 "or other action.\n"
2583 "No other deliveries will occur.";
2586 case FF_NOTDELIVERED:
2587 s = US"Filtering did not set up a significant delivery.\n"
2588 "Normal delivery will occur.";
2592 s = string_sprintf("Filter error: %s", *error);
2596 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2597 else debug_printf_indent("%s\n", s);
2600 /* Close the log file if it was opened, and kill off any numerical variables
2601 before returning. Reset the header decoding charset. */
2603 if (log_fd >= 0) (void)close(log_fd);
2605 f.filter_running = FALSE;
2606 headers_charset = save_headers_charset;
2609 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2614 /* End of filter.c */