1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
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 /* This defines the offsets for the arguments; first the string ones, and
75 then the non-string ones. The order must be as above. */
77 enum { mailarg_index_to,
81 mailarg_index_reply_to,
82 mailarg_index_subject,
83 mailarg_index_headers, /* misc headers must be last */
84 mailarg_index_text, /* text is first after headers */
85 mailarg_index_file, /* between text and expand are filenames */
88 mailarg_index_once_repeat, /* a time string */
89 mailarg_index_expand, /* first non-string argument */
91 mailargs_total /* total number of arguments */
94 /* The string arguments for the mail command. The header line ones (that are
95 permitted to include \n followed by white space) first, and then the body text
96 one (it can have \n anywhere). Then the file names and once_repeat, which may
99 static const char *mailargs[] = { /* "to" must be first, and */
100 [mailarg_index_to] = "to", /* "cc" and "bcc" must follow */
101 [mailarg_index_cc] = "cc",
102 [mailarg_index_bcc] = "bcc",
103 [mailarg_index_from] = "from",
104 [mailarg_index_reply_to] = "reply_to",
105 [mailarg_index_subject] = "subject",
106 [mailarg_index_headers] = "extra_headers", /* misc added header lines */
107 [mailarg_index_text] = "text",
108 [mailarg_index_file] = "file",
109 [mailarg_index_log] = "log",
110 [mailarg_index_once] = "once",
111 [mailarg_index_once_repeat] = "once_repeat"
114 /* The count of string arguments */
116 #define MAILARGS_STRING_COUNT (nelem(mailargs))
118 /* The count of string arguments that are actually passed over as strings
119 (once_repeat is converted to an int). */
121 #define mailargs_string_passed (MAILARGS_STRING_COUNT - 1)
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[] = {
127 [mailarg_index_to] = offsetof(reply_item, to),
128 [mailarg_index_cc] = offsetof(reply_item, cc),
129 [mailarg_index_bcc] = offsetof(reply_item, bcc),
130 [mailarg_index_from] = offsetof(reply_item, from),
131 [mailarg_index_reply_to] = offsetof(reply_item, reply_to),
132 [mailarg_index_subject] = offsetof(reply_item, subject),
133 [mailarg_index_headers] = offsetof(reply_item, headers),
134 [mailarg_index_text] = offsetof(reply_item, text),
135 [mailarg_index_file] = offsetof(reply_item, file),
136 [mailarg_index_log] = offsetof(reply_item, logfile),
137 [mailarg_index_once] = 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[] = {
152 [cond_personal] = "personal",
153 [cond_begins] = "begins",
154 [cond_BEGINS] = "BEGINS",
155 [cond_ends] = "ends",
156 [cond_ENDS] = "ENDS",
159 [cond_matches] = "matches",
160 [cond_MATCHES] = "MATCHES",
161 [cond_contains] = "contains",
162 [cond_CONTAINS] = "CONTAINS",
163 [cond_delivered] = "delivered",
164 [cond_above] = "above",
165 [cond_below] = "below",
166 [cond_errormsg] = "error_message",
167 [cond_firsttime] = "first_delivery",
168 [cond_manualthaw] = "manually_thawed",
169 [cond_foranyaddress] = "foranyaddress" };
171 static const char *cond_not_names[] = {
174 [cond_personal] = "not personal",
175 [cond_begins] = "does not begin",
176 [cond_BEGINS] = "does not BEGIN",
177 [cond_ends] = "does not end",
178 [cond_ENDS] = "does not END",
179 [cond_is] = "is not",
180 [cond_IS] = "IS not",
181 [cond_matches] = "does not match",
182 [cond_MATCHES] = "does not MATCH",
183 [cond_contains] = "does not contain",
184 [cond_CONTAINS] = "does not CONTAIN",
185 [cond_delivered] = "not delivered",
186 [cond_above] = "not above",
187 [cond_below] = "not below",
188 [cond_errormsg] = "not error_message",
189 [cond_firsttime] = "not first_delivery",
190 [cond_manualthaw] = "not manually_thawed",
191 [cond_foranyaddress] = "not foranyaddress" };
193 /* Tables of binary condition words and their corresponding types. Not easy
194 to amalgamate with the above because of the different variants. */
196 static const char *cond_words[] = {
218 static int cond_word_count = nelem(cond_words);
220 static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
221 cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
222 cond_above, cond_begins, cond_begins, cond_below, cond_contains,
223 cond_contains, cond_ends, cond_ends, cond_is, cond_matches, cond_matches };
225 /* Command identities */
227 enum { ADD_COMMAND, DEFER_COMMAND, DELIVER_COMMAND, ELIF_COMMAND, ELSE_COMMAND,
228 ENDIF_COMMAND, FINISH_COMMAND, FAIL_COMMAND, FREEZE_COMMAND,
229 HEADERS_COMMAND, IF_COMMAND, LOGFILE_COMMAND, LOGWRITE_COMMAND,
230 MAIL_COMMAND, NOERROR_COMMAND, PIPE_COMMAND, SAVE_COMMAND, SEEN_COMMAND,
231 TESTPRINT_COMMAND, UNSEEN_COMMAND, VACATION_COMMAND };
233 static const char * command_list[] = {
234 [ADD_COMMAND] = "add",
235 [DEFER_COMMAND] = "defer",
236 [DELIVER_COMMAND] = "deliver",
237 [ELIF_COMMAND] = "elif",
238 [ELSE_COMMAND] = "else",
239 [ENDIF_COMMAND] = "endif",
240 [FINISH_COMMAND] = "finish",
241 [FAIL_COMMAND] = "fail",
242 [FREEZE_COMMAND] = "freeze",
243 [HEADERS_COMMAND] = "headers",
245 [LOGFILE_COMMAND] = "logfile",
246 [LOGWRITE_COMMAND] = "logwrite",
247 [MAIL_COMMAND] = "mail",
248 [NOERROR_COMMAND] = "noerror",
249 [PIPE_COMMAND] = "pipe",
250 [SAVE_COMMAND] = "save",
251 [SEEN_COMMAND] = "seen",
252 [TESTPRINT_COMMAND] = "testprint",
253 [UNSEEN_COMMAND] = "unseen",
254 [VACATION_COMMAND] = "vacation"
257 static int command_list_count = nelem(command_list);
259 /* This table contains the number of expanded arguments in the bottom 4 bits.
260 If the top bit is set, it means that the default for the command is "seen". */
262 static uschar command_exparg_count[] = {
265 [DELIVER_COMMAND] = 128+2,
269 [FINISH_COMMAND] = 0,
271 [FREEZE_COMMAND] = 1,
272 [HEADERS_COMMAND] = 1,
274 [LOGFILE_COMMAND] = 1,
275 [LOGWRITE_COMMAND] = 1,
276 [MAIL_COMMAND] = MAILARGS_STRING_COUNT,
277 [NOERROR_COMMAND] = 0,
278 [PIPE_COMMAND] = 128+0,
279 [SAVE_COMMAND] = 128+1,
281 [TESTPRINT_COMMAND] = 1,
282 [UNSEEN_COMMAND] = 0,
283 [VACATION_COMMAND] = MAILARGS_STRING_COUNT
288 /*************************************************
289 * Find next significant uschar *
290 *************************************************/
292 /* Function to skip over white space and, optionally, comments.
295 ptr pointer to next character
296 comment_allowed if TRUE, comments (# to \n) are skipped
298 Returns: pointer to next non-whitespace character
301 static const uschar *
302 nextsigchar(const uschar *ptr, BOOL comment_allowed)
306 while (isspace(*ptr))
307 if (*ptr++ == '\n') line_number++;
308 if (comment_allowed && *ptr == '#')
309 while (*++ptr != '\n' && *ptr) ;
318 /*************************************************
320 *************************************************/
322 /* The terminator is white space unless bracket is TRUE, in which
323 case ( and ) terminate.
326 ptr pointer to next character
327 buffer where to put the word
329 bracket if TRUE, terminate on ( and ) as well as space
331 Returns: pointer to the next significant character after the word
334 static const uschar *
335 nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
337 uschar * bp = buffer;
338 while (*ptr && !isspace(*ptr) &&
339 (!bracket || (*ptr != '(' && *ptr != ')')))
340 if (bp - buffer < size - 1)
344 *error_pointer = string_sprintf("word is too long in line %d of "
345 "filter file (max = %d chars)", line_number, size);
350 return nextsigchar(ptr, TRUE);
355 /*************************************************
357 *************************************************/
359 /* Might be a word, or might be a quoted string; in the latter case
363 ptr pointer to next character
364 buffer where to put the item
366 bracket if TRUE, terminate non-quoted on ( and ) as well as space
368 Returns: the next significant character after the item
371 static const uschar *
372 nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
375 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
377 while (*++ptr && *ptr != '\"' && *ptr != '\n')
379 if (bp - buffer >= size - 1)
381 *error_pointer = string_sprintf("string is too long in line %d of "
382 "filter file (max = %d chars)", line_number, size);
386 if (*ptr != '\\') *bp++ = *ptr; else
388 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
390 const uschar *p = ptr + 1;
391 while (*p != '\n' && isspace(*p)) p++;
396 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
401 *bp++ = string_interpret_escape(CUSS &ptr);
405 if (*ptr == '\"') ptr++;
406 else if (*error_pointer == NULL)
407 *error_pointer = string_sprintf("quote missing at end of string "
408 "in line %d", line_number);
411 return nextsigchar(ptr, TRUE);
417 /*************************************************
418 * Convert a string + K|M to a number *
419 *************************************************/
423 s points to text string
424 OK set TRUE if a valid number was read
426 Returns: the number, or 0 on error (with *OK FALSE)
430 get_number(const uschar *s, BOOL *ok)
434 if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
435 if (tolower(s[count]) == 'k') { value *= 1024; count++; }
436 if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
437 while (isspace(s[count])) count++;
438 if (s[count]) return 0;
445 /*************************************************
446 * Read one condition *
447 *************************************************/
449 /* A complete condition must be terminated by "then"; bracketed internal
450 conditions must be terminated by a closing bracket. They are read by calling
451 this function recursively.
454 ptr points to start of condition
455 condition_block where to hang the created condition block
456 toplevel TRUE when called at the top level
458 Returns: points to next character after "then"
461 static const uschar *
462 read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
466 condition_block *current_parent = NULL;
467 condition_block **current = cond;
471 /* Loop to read next condition */
477 /* reaching the end of the input is an error. */
481 *error_pointer = US"\"then\" missing at end of filter file";
485 /* Opening bracket at the start of a condition introduces a nested
486 condition, which must be terminated by a closing bracket. */
490 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
491 if (*error_pointer != NULL) break;
494 *error_pointer = string_sprintf("expected \")\" in line %d of "
495 "filter file", line_number);
500 c->testfor = !c->testfor;
503 ptr = nextsigchar(ptr+1, TRUE);
507 /* Closing bracket at the start of a condition is an error. Give an
508 explicit message, as otherwise "unknown condition" would be confusing. */
510 else if (*ptr == ')')
512 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
513 "filter file", line_number);
517 /* Otherwise we expect a word or a string. */
521 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
522 if (*error_pointer) break;
524 /* "Then" at the start of a condition is an error */
526 if (Ustrcmp(buffer, "then") == 0)
528 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
529 "filter file", line_number);
533 /* "Not" at the start of a condition negates the testing condition. */
535 if (Ustrcmp(buffer, "not") == 0)
541 /* Build a condition block from the specific word. */
543 c = store_get(sizeof(condition_block), GET_UNTAINTED);
544 c->left.u = c->right.u = NULL;
545 c->testfor = testfor;
548 /* Check for conditions that start with a keyword */
550 if (Ustrcmp(buffer, "delivered") == 0) c->type = cond_delivered;
551 else if (Ustrcmp(buffer, "error_message") == 0) c->type = cond_errormsg;
552 else if (Ustrcmp(buffer, "first_delivery") == 0) c->type = cond_firsttime;
553 else if (Ustrcmp(buffer, "manually_thawed") == 0) c->type = cond_manualthaw;
555 /* Personal can be followed by any number of aliases */
557 else if (Ustrcmp(buffer, "personal") == 0)
559 c->type = cond_personal;
563 const uschar * saveptr = ptr;
564 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
565 if (*error_pointer) break;
566 if (Ustrcmp(buffer, "alias") != 0)
571 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
572 if (*error_pointer) break;
573 aa = store_get(sizeof(string_item), GET_UNTAINTED);
574 aa->text = string_copy(buffer);
575 aa->next = c->left.a;
580 /* Foranyaddress must be followed by a string and a condition enclosed
581 in parentheses, which is handled as a subcondition. */
583 else if (Ustrcmp(buffer, "foranyaddress") == 0)
585 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
586 if (*error_pointer) break;
589 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
590 "near line %d of filter file", line_number);
594 c->type = cond_foranyaddress;
595 c->left.u = string_copy(buffer);
597 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
598 if (*error_pointer) break;
601 *error_pointer = string_sprintf("expected \")\" in line %d of "
602 "filter file", line_number);
605 ptr = nextsigchar(ptr+1, TRUE);
608 /* If it's not a word we recognize, then it must be the lefthand
609 operand of one of the comparison words. */
614 const uschar *isptr = NULL;
616 c->left.u = string_copy(buffer);
617 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
618 if (*error_pointer) break;
620 /* Handle "does|is [not]", preserving the pointer after "is" in
621 case it isn't that, but the form "is <string>". */
623 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
625 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
626 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
628 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
629 if (*error_pointer) break;
630 if (strcmpic(buffer, US"not") == 0)
632 c->testfor = !c->testfor;
633 if (isptr) isptr = ptr;
634 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
635 if (*error_pointer) break;
639 for (i = 0; i < cond_word_count; i++)
641 if (Ustrcmp(buffer, cond_words[i]) == 0)
643 c->type = cond_types[i];
648 /* If an unknown word follows "is" or "is not"
649 it's actually the argument. Reset to read it. */
651 if (i >= cond_word_count)
655 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
656 "near line %d of filter file", buffer, line_number);
662 /* Get the RH argument. */
664 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
665 if (*error_pointer) break;
666 c->right.u = string_copy(buffer);
670 /* We have read some new condition and set it up in the condition block
671 c; point the current pointer at it, and then deal with what follows. */
675 /* Closing bracket terminates if this is a lower-level condition. Otherwise
681 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
682 "filter file", line_number);
686 /* Opening bracket following a condition is an error; give an explicit
687 message to make it clearer what is wrong. */
689 else if (*ptr == '(')
691 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
692 "filter file", line_number);
696 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
700 // const uschar *saveptr = ptr;
701 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
702 if (*error_pointer) break;
704 /* "Then" terminates a toplevel condition; otherwise a closing bracket
705 has been omitted. Put a string terminator at the start of "then" so
706 that reflecting the condition can be done when testing. */
707 /*XXX This stops us doing a constification job in this file, unfortunately.
708 Comment it out and see if anything breaks.
709 With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
711 if (Ustrcmp(buffer, "then") == 0)
713 // if (toplevel) *saveptr = 0;
716 *error_pointer = string_sprintf("missing \")\" at end of "
717 "condition near line %d of filter file", line_number);
721 /* "And" causes a new condition block to replace the one we have
722 just read, which becomes the left sub-condition. The current pointer
723 is reset to the pointer for the right sub-condition. We have to keep
724 track of the tree of sequential "ands", so as to traverse back up it
725 if an "or" is met. */
727 else if (Ustrcmp(buffer, "and") == 0)
729 condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
730 andc->parent = current_parent;
731 andc->type = cond_and;
732 andc->testfor = TRUE;
734 andc->right.u = NULL; /* insurance */
736 current = &(andc->right.c);
737 current_parent = andc;
740 /* "Or" is similar, but has to be done a bit more carefully to
741 ensure that "and" is more binding. If there's a parent set, we
742 are following a sequence of "and"s and must track back to their
745 else if (Ustrcmp(buffer, "or") == 0)
747 condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
748 condition_block * or_parent = NULL;
752 while (current_parent->parent &&
753 current_parent->parent->type == cond_and)
754 current_parent = current_parent->parent;
756 /* If the parent has a parent, it must be an "or" parent. */
758 if (current_parent->parent)
759 or_parent = current_parent->parent;
762 orc->parent = or_parent;
763 if (!or_parent) *cond = orc;
764 else or_parent->right.c = orc;
767 orc->left.c = (current_parent == NULL)? c : current_parent;
768 orc->right.c = NULL; /* insurance */
769 current = &(orc->right.c);
770 current_parent = orc;
773 /* Otherwise there is a disaster */
777 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
778 "expected near line %d of filter file, but found \"%s\"",
779 toplevel? "then" : ")", line_number, buffer);
785 return nextsigchar(ptr, TRUE);
790 /*************************************************
791 * Output the current indent *
792 *************************************************/
798 DEBUG(D_filter) for (i = 0; i < output_indent; i++) debug_printf(" ");
803 /*************************************************
804 * Condition printer: for debugging *
805 *************************************************/
809 c the block at the top of the tree
810 toplevel TRUE at toplevel - stops overall brackets
816 print_condition(condition_block *c, BOOL toplevel)
818 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
825 case cond_manualthaw:
826 debug_printf("%s", name);
841 debug_printf("%s %s %s", c->left.u, name, c->right.u);
845 if (!c->testfor) debug_printf("not (");
846 print_condition(c->left.c, FALSE);
847 debug_printf(" %s ", cond_names[c->type]);
848 print_condition(c->right.c, FALSE);
849 if (!c->testfor) debug_printf(")");
853 if (!c->testfor) debug_printf("not (");
854 else if (!toplevel) debug_printf("(");
855 print_condition(c->left.c, FALSE);
856 debug_printf(" %s ", cond_names[c->type]);
857 print_condition(c->right.c, FALSE);
858 if (!toplevel || !c->testfor) debug_printf(")");
861 case cond_foranyaddress:
862 debug_printf("%s %s (", name, c->left.u);
863 print_condition(c->right.c, FALSE);
872 /*************************************************
873 * Read one filtering command *
874 *************************************************/
878 pptr points to pointer to first character of command; the pointer
879 is updated to point after the last character read
880 lastcmdptr points to pointer to pointer to last command; used for hanging
881 on the newly read command
883 Returns: TRUE if command successfully read, else FALSE
887 read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
889 int command, i, cmd_bit;
890 filter_cmd *new, **newlastcmdptr;
892 BOOL was_seen_or_unseen = FALSE;
893 BOOL was_noerror = FALSE;
895 const uschar *ptr = *pptr;
896 const uschar *saveptr;
899 /* Read the next word and find which command it is. Command words are normally
900 terminated by white space, but there are two exceptions, which are the "if" and
901 "elif" commands. We must allow for them to be terminated by an opening bracket,
902 as brackets are allowed in conditions and users will expect not to require
905 *buffer = '\0'; /* compiler quietening */
907 if (Ustrncmp(ptr, "if(", 3) == 0)
909 Ustrcpy(buffer, US"if");
912 else if (Ustrncmp(ptr, "elif(", 5) == 0)
914 Ustrcpy(buffer, US"elif");
919 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
920 if (*error_pointer) return FALSE;
923 for (command = 0; command < command_list_count; command++)
924 if (Ustrcmp(buffer, command_list[command]) == 0) break;
926 /* Handle the individual commands */
930 /* Add takes two arguments, separated by the word "to". Headers has two
931 arguments, but the first must be "add", "remove", or "charset", and it gets
932 stored in the second argument slot. Neither may be preceded by seen, unseen
936 case HEADERS_COMMAND:
937 if (seen_force || noerror_force)
939 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
940 "found before an \"%s\" command near line %d",
941 command_list[command], line_number);
946 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
947 and logfile can have an option second argument for the mode, and deliver can
948 have "errors_to <address>" in a system filter, or in a user filter if the
949 address is the current one. */
951 case DELIVER_COMMAND:
952 case LOGFILE_COMMAND:
953 case LOGWRITE_COMMAND:
956 case TESTPRINT_COMMAND:
958 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
960 *error_pointer = string_sprintf("\"%s\" requires an argument "
961 "near line %d of filter file", command_list[command], line_number);
963 if (*error_pointer) yield = FALSE; else
965 union argtypes argument, second_argument;
967 argument.u = second_argument.u = NULL;
969 if (command == ADD_COMMAND)
971 argument.u = string_copy(buffer);
972 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
973 if (!*buffer || Ustrcmp(buffer, "to") != 0)
974 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
975 "near line %d of filter file", line_number);
978 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
980 *error_pointer = string_sprintf("value missing after \"to\" "
981 "near line %d of filter file", line_number);
982 else second_argument.u = string_copy(buffer);
986 else if (command == HEADERS_COMMAND)
988 if (Ustrcmp(buffer, "add") == 0)
989 second_argument.b = TRUE;
991 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
993 if (Ustrcmp(buffer, "charset") == 0)
994 second_argument.b = TRUE_UNSET;
997 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
998 "expected after \"headers\" near line %d of filter file",
1003 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
1005 *error_pointer = string_sprintf("header addition and removal is "
1006 "available only in system filters: near line %d of filter file",
1014 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1016 *error_pointer = string_sprintf("value missing after \"add\", "
1017 "\"remove\", or \"charset\" near line %d of filter file",
1019 else argument.u = string_copy(buffer);
1023 /* The argument for the logwrite command must end in a newline, and the save
1024 and logfile commands can have an optional mode argument. The deliver
1025 command can have an optional "errors_to <address>" for a system filter,
1026 or for a user filter if the address is the user's address. Accept the
1027 syntax here - the check is later. */
1031 if (command == LOGWRITE_COMMAND)
1033 int len = Ustrlen(buffer);
1034 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
1037 argument.u = string_copy(buffer);
1039 if (command == SAVE_COMMAND || command == LOGFILE_COMMAND)
1043 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1044 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
1046 else second_argument.i = -1;
1049 else if (command == DELIVER_COMMAND)
1051 const uschar *save_ptr = ptr;
1052 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1053 if (Ustrcmp(buffer, "errors_to") == 0)
1055 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1056 second_argument.u = string_copy(buffer);
1058 else ptr = save_ptr;
1062 /* Set up the command block. Seen defaults TRUE for delivery commands,
1063 FALSE for logging commands, and it doesn't matter for testprint, as
1064 that doesn't change the "delivered" status. */
1066 if (*error_pointer) yield = FALSE;
1069 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
1072 *lastcmdptr = &(new->next);
1073 new->command = command;
1074 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1075 new->noerror = noerror_force;
1076 new->args[0] = argument;
1077 new->args[1] = second_argument;
1083 /* Elif, else and endif just set a flag if expected. */
1088 if (seen_force || noerror_force)
1090 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1091 "near line %d is not followed by a command", line_number);
1095 if (expect_endif > 0)
1096 had_else_endif = (command == ELIF_COMMAND)? had_elif :
1097 (command == ELSE_COMMAND)? had_else : had_endif;
1100 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1101 "line %d of filter file", buffer, line_number);
1107 /* Defer, freeze, and fail are available only if permitted. */
1110 cmd_bit = RDO_DEFER;
1111 goto DEFER_FREEZE_FAIL;
1115 goto DEFER_FREEZE_FAIL;
1117 case FREEZE_COMMAND:
1118 cmd_bit = RDO_FREEZE;
1121 if (!(filter_options & cmd_bit))
1123 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1124 "near line %d of filter file", buffer, line_number);
1129 /* A text message can be provided after the "text" keyword, or
1130 as a string in quotes. */
1133 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1134 if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0))
1141 if (*saveptr != '\"')
1142 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1143 fmsg = string_copy(buffer);
1146 /* Drop through and treat as "finish", but never set "seen". */
1150 /* Finish has no arguments; fmsg defaults to NULL */
1152 case FINISH_COMMAND:
1153 new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
1156 *lastcmdptr = &(new->next);
1157 new->command = command;
1158 new->seen = seen_force ? seen_value : FALSE;
1159 new->args[0].u = fmsg;
1163 /* Seen, unseen, and noerror are not allowed before if, which takes a
1164 condition argument and then and else sub-commands. */
1167 if (seen_force || noerror_force)
1169 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1170 "found before an \"if\" command near line %d",
1175 /* Set up the command block for if */
1177 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1180 *lastcmdptr = &new->next;
1181 new->command = command;
1183 new->args[0].u = NULL;
1184 new->args[1].u = new->args[2].u = NULL;
1185 new->args[3].u = ptr;
1187 /* Read the condition */
1189 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1190 if (*error_pointer) { yield = FALSE; break; }
1192 /* Read the commands to be obeyed if the condition is true */
1194 newlastcmdptr = &(new->args[1].f);
1195 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1197 /* If commands were successfully read, handle the various possible
1198 terminators. There may be a number of successive "elif" sections. */
1202 while (had_else_endif == had_elif)
1204 filter_cmd *newnew =
1205 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1206 new->args[2].f = newnew;
1209 new->command = command;
1211 new->args[0].u = NULL;
1212 new->args[1].u = new->args[2].u = NULL;
1213 new->args[3].u = ptr;
1215 ptr = read_condition(ptr, &new->args[0].c, TRUE);
1216 if (*error_pointer) { yield = FALSE; break; }
1217 newlastcmdptr = &(new->args[1].f);
1218 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1222 if (yield == FALSE) break;
1224 /* Handle termination by "else", possibly following one or more
1225 "elsif" sections. */
1227 if (had_else_endif == had_else)
1229 newlastcmdptr = &(new->args[2].f);
1230 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1232 else if (had_else_endif != had_endif)
1234 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1235 "filter file", line_number);
1240 /* Otherwise the terminator was "endif" - this is checked by
1241 read_command_list(). The pointer is already set to NULL. */
1244 /* Reset the terminator flag. */
1246 had_else_endif = had_neither;
1250 /* The mail & vacation commands have a whole slew of keyworded arguments.
1251 The final argument values are the file expand and return message booleans,
1252 whose offsets are defined in mailarg_index_{expand,return}. Although they
1253 are logically booleans, because they are stored in a uschar * value, we use
1254 NULL and not FALSE, to keep 64-bit compilers happy. */
1257 case VACATION_COMMAND:
1258 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
1260 new->command = command;
1261 new->seen = seen_force ? seen_value : FALSE;
1262 new->noerror = noerror_force;
1263 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1265 /* Read keyword/value pairs until we hit one that isn't. The data
1266 must contain only printing chars plus tab, though the "text" value
1267 can also contain newlines. The "file" keyword can be preceded by the
1268 word "expand", and "return message" has no data. */
1272 const uschar *saveptr = ptr;
1273 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1275 { yield = FALSE; break; }
1277 /* Ensure "return" is followed by "message"; that's a complete option */
1279 if (Ustrcmp(buffer, "return") == 0)
1281 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1282 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1283 if (Ustrcmp(buffer, "message") != 0)
1285 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1286 " near line %d of filter file", line_number);
1293 /* Ensure "expand" is followed by "file", then fall through to process the
1296 if (Ustrcmp(buffer, "expand") == 0)
1298 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1299 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1300 if (Ustrcmp(buffer, "file") != 0)
1302 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1303 " near line %d of filter file", line_number);
1309 /* Scan for the keyword */
1311 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1312 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1314 /* Not found keyword; assume end of this command */
1316 if (i >= MAILARGS_STRING_COUNT)
1322 /* Found keyword, read the data item */
1324 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1326 { yield = FALSE; break; }
1327 else new->args[i].u = string_copy(buffer);
1330 /* If this is the vacation command, apply some default settings to
1331 some of the arguments. */
1333 if (command == VACATION_COMMAND)
1335 if (!new->args[mailarg_index_file].u)
1337 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1338 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1340 if (!new->args[mailarg_index_log].u)
1341 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1342 if (!new->args[mailarg_index_once].u)
1343 new->args[mailarg_index_once].u = string_copy(US".vacation");
1344 if (!new->args[mailarg_index_once_repeat].u)
1345 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1346 if (!new->args[mailarg_index_subject].u)
1347 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1350 /* Join the address on to the chain of generated addresses */
1353 *lastcmdptr = &(new->next);
1357 /* Seen and unseen just set flags */
1360 case UNSEEN_COMMAND:
1363 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1364 "near line %d is not followed by a command", line_number);
1369 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1370 "near line %d", line_number);
1373 seen_value = (command == SEEN_COMMAND);
1375 was_seen_or_unseen = TRUE;
1379 /* So does noerror */
1381 case NOERROR_COMMAND:
1384 *error_pointer = string_sprintf("\"noerror\" "
1385 "near line %d is not followed by a command", line_number);
1388 noerror_force = TRUE;
1396 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1397 "near line %d of filter file", buffer, line_number);
1402 if (!was_seen_or_unseen && !was_noerror)
1405 noerror_force = FALSE;
1414 /*************************************************
1415 * Read a list of commands *
1416 *************************************************/
1418 /* If conditional is TRUE, the list must be terminated
1419 by the words "else" or "endif".
1422 pptr points to pointer to next character; the pointer is updated
1423 lastcmdptr points to pointer to pointer to previously-read command; used
1424 for hanging on the new command
1425 conditional TRUE if this command is the subject of a condition
1427 Returns: TRUE on success
1431 read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1433 if (conditional) expect_endif++;
1434 had_else_endif = had_neither;
1435 while (**pptr && had_else_endif == had_neither)
1437 if (!read_command(pptr, lastcmdptr)) return FALSE;
1438 *pptr = nextsigchar(*pptr, TRUE);
1443 if (had_else_endif == had_neither)
1445 *error_pointer = US"\"endif\" missing at end of filter file";
1455 /*************************************************
1456 * Test for a personal message *
1457 *************************************************/
1459 /* Module API: This function is also called from the code that
1460 implements Sieve filters.
1463 aliases a chain of aliases
1464 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
1466 Returns: TRUE if the message is deemed to be personal
1470 filter_personal(string_item *aliases, BOOL scan_cc)
1472 const uschar *self, *self_from, *self_to;
1473 uschar *psself = NULL;
1474 const uschar *psself_from = NULL, *psself_to = NULL;
1475 rmark reset_point = store_mark();
1481 /* If any header line in the message is a defined "List-" header field, it is
1482 not a personal message. We used to check for any header line that started with
1483 "List-", but this was tightened up for release 4.54. The check is now for
1484 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
1485 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
1486 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
1487 contain any value other than "no", the message is not personal (RFC 3834).
1488 Previously the test was for "auto-". */
1490 for (h = header_list; h; h = h->next)
1492 if (h->type == htype_old) continue;
1494 if (strncmpic(h->text, US"List-", 5) == 0)
1496 uschar * s = h->text + 5;
1497 if (strncmpic(s, US"Id:", 3) == 0 ||
1498 strncmpic(s, US"Help:", 5) == 0 ||
1499 strncmpic(s, US"Subscribe:", 10) == 0 ||
1500 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
1501 strncmpic(s, US"Post:", 5) == 0 ||
1502 strncmpic(s, US"Owner:", 6) == 0 ||
1503 strncmpic(s, US"Archive:", 8) == 0)
1507 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
1509 uschar * s = h->text + 15;
1510 Uskip_whitespace(&s);
1511 if (strncmpic(s, US"no", 2) != 0) return FALSE;
1513 Uskip_whitespace(&s);
1514 if (*s) return FALSE;
1518 /* Set up "my" address */
1520 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
1521 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
1522 global_rewrite_rules);
1523 self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
1524 global_rewrite_rules);
1527 if (!self_from) self_from = self;
1528 if (self_to) self_to = self;
1530 /* If there's a prefix or suffix set, we must include the prefixed/
1531 suffixed version of the local part in the tests. */
1533 if (deliver_localpart_prefix || deliver_localpart_suffix)
1535 psself = string_sprintf("%s%s%s@%s",
1536 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
1538 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
1540 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
1541 global_rewrite_rules);
1542 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
1543 global_rewrite_rules);
1544 if (psself_from == NULL) psself_from = psself;
1545 if (psself_to == NULL) psself_to = psself;
1550 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
1554 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
1558 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
1561 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
1567 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
1568 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
1569 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
1571 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
1573 (sender_address == NULL || sender_address[0] != 0);
1575 store_reset(reset_point);
1581 /*************************************************
1582 * Test a condition *
1583 *************************************************/
1587 c points to the condition block; c->testfor indicated whether
1588 it's a positive or negative condition
1589 toplevel TRUE if called from "if" directly; FALSE otherwise
1591 Returns: TRUE if the condition is met
1595 test_condition(condition_block * c, BOOL toplevel)
1597 BOOL yield = FALSE, textonly_re;
1598 const uschar * exp[2], * p, * pp;
1601 if (!c) return TRUE; /* does this ever occur? */
1606 yield = test_condition(c->left.c, FALSE) &&
1607 *error_pointer == NULL &&
1608 test_condition(c->right.c, FALSE);
1612 yield = test_condition(c->left.c, FALSE) ||
1613 (*error_pointer == NULL &&
1614 test_condition(c->right.c, FALSE));
1617 /* The personal test is meaningless in a system filter. The tests are now in
1618 a separate function (so Sieve can use them). However, an Exim filter does not
1619 scan Cc: (hence the FALSE argument). */
1622 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
1625 case cond_delivered:
1626 yield = filter_delivered;
1629 /* Only TRUE if a message is actually being processed; FALSE for address
1630 testing and verification. */
1633 yield = message_id[0] && (!sender_address || !*sender_address);
1636 /* Only FALSE if a message is actually being processed; TRUE for address
1637 and filter testing and verification. */
1639 case cond_firsttime:
1640 yield = filter_test != FTEST_NONE || !message_id[0] || f.deliver_firsttime;
1643 /* Only TRUE if a message is actually being processed; FALSE for address
1644 testing and verification. */
1646 case cond_manualthaw:
1647 yield = message_id[0] && f.deliver_manual_thaw;
1650 /* The foranyaddress condition loops through a list of addresses */
1652 case cond_foranyaddress:
1654 if (!(pp = expand_cstring(p)))
1656 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1657 "filter file: %s", p, expand_string_message);
1662 f.parse_allow_group = TRUE; /* Allow group syntax */
1667 int start, end, domain;
1670 p = parse_find_address_end(pp, FALSE);
1671 s = string_copyn(pp, p - pp);
1673 filter_thisaddress =
1674 parse_extract_address(s, &error, &start, &end, &domain, FALSE);
1676 if (filter_thisaddress)
1678 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1679 (debug_selector & D_filter) != 0)
1682 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
1684 yield = test_condition(c->right.c, FALSE);
1692 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1693 f.parse_found_group = FALSE;
1696 /* All other conditions have left and right values that need expanding;
1697 on error, it doesn't matter what value is returned. */
1701 for (int i = 0; i < 2; i++)
1703 if (!(exp[i] = expand_string_2(p, &textonly_re)))
1705 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1706 "filter file: %s", p, expand_string_message);
1712 /* Inner switch for the different cases */
1717 yield = strcmpic(exp[0], exp[1]) == 0;
1721 yield = Ustrcmp(exp[0], exp[1]) == 0;
1725 yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
1729 yield = Ustrstr(exp[0], exp[1]) != NULL;
1733 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1737 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1743 int len = Ustrlen(exp[1]);
1744 const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1747 : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1754 const pcre2_code * re;
1755 mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS;
1757 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1758 (debug_selector & D_filter) != 0)
1760 debug_printf_indent("Match expanded arguments:\n");
1761 debug_printf_indent(" Subject = %s\n", exp[0]);
1762 debug_printf_indent(" Pattern = %s\n", exp[1]);
1765 if (c->type == cond_matches) flags |= MCS_CASELESS;
1766 if (!(re = regex_compile(exp[1], flags, error_pointer, pcre_gen_cmp_ctx)))
1769 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1773 /* For above and below, convert the strings to numbers */
1777 for (int i = 0; i < 2; i++)
1779 val[i] = get_number(exp[i], &yield);
1782 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1787 yield = c->type == cond_above ? (val[0] > val[1]) : (val[0] < val[1]);
1793 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1794 (debug_selector & D_filter) != 0)
1797 debug_printf_indent("%sondition is %s: ",
1798 toplevel ? "C" : "Sub-c",
1799 yield == c->testfor ? "true" : "false");
1800 print_condition(c, TRUE);
1801 debug_printf_indent("\n");
1804 return yield == c->testfor;
1809 /*************************************************
1810 * Interpret chain of commands *
1811 *************************************************/
1813 /* In testing state, just say what would be done rather than doing it. The
1814 testprint command just expands and outputs its argument in testing state, and
1815 does nothing otherwise.
1818 commands points to chain of commands to interpret
1819 generated where to hang newly-generated addresses
1821 Returns: FF_DELIVERED success, a significant action was taken
1822 FF_NOTDELIVERED success, no significant action
1823 FF_DEFER defer requested
1824 FF_FAIL fail requested
1825 FF_FREEZE freeze requested
1826 FF_ERROR there was a problem
1830 interpret_commands(filter_cmd *commands, address_item **generated)
1835 BOOL condition_value;
1840 uschar *fmsg, *ff_name;
1841 const uschar *expargs[MAILARGS_STRING_COUNT];
1845 /* Expand the relevant number of arguments for the command that are
1848 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1850 const uschar *ss = commands->args[i].u;
1853 else if (!(expargs[i] = expand_cstring(ss)))
1855 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1856 "%s command: %s", ss, command_list[commands->command],
1857 expand_string_message);
1862 /* Now switch for each command, setting the "delivered" flag if any of them
1865 if (commands->seen) filter_delivered = TRUE;
1867 switch(commands->command)
1870 for (i = 0; i < 2; i++)
1872 const uschar *ss = expargs[i];
1875 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1877 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1878 "command", expargs[i]);
1882 /* Allow for "--" at the start of the value (from -$n0) for example */
1883 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1885 n[i] = (int)Ustrtol(ss, &end, 0);
1888 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1894 filter_n[n[1]] += n[0];
1895 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1898 /* A deliver command's argument must be a valid address. Its optional
1899 second argument (system filter only) must also be a valid address. */
1901 case DELIVER_COMMAND:
1902 for (i = 0; i < 2; i++)
1907 int start, end, domain;
1909 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1912 expargs[i] = filter_options & RDO_REWRITE
1913 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1915 : rewrite_address_qualify(ss, TRUE);
1918 *error_pointer = string_sprintf("malformed address \"%s\" in "
1919 "filter file: %s", s, error);
1925 /* Stick the errors address into a simple variable, as it will
1926 be referenced a few times. Check that the caller is permitted to
1931 if (s != NULL && !f.system_filtering)
1933 uschar *ownaddress = expand_string(US"$local_part@$domain");
1934 if (strcmpic(ownaddress, s) != 0)
1936 *error_pointer = US"errors_to must point to the caller's address";
1941 /* Test case: report what would happen */
1943 if (filter_test != FTEST_NONE)
1946 printf("%seliver message to: %s%s%s%s\n",
1947 commands->seen ? "D" : "Unseen d",
1949 commands->noerror? " (noerror)" : "",
1950 s ? " errors_to " : "",
1958 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1959 commands->seen ? "" : "unseen ",
1961 commands->noerror ? " (noerror)" : "",
1962 s ? " errors_to " : "",
1965 /* Create the new address and add it to the chain, setting the
1966 af_ignore_error flag if necessary, and the errors address, which can be
1967 set in a system filter and to the local address in user filters. */
1969 addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
1970 addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1971 if (commands->noerror) addr->prop.ignore_error = TRUE;
1972 addr->next = *generated;
1979 mode = commands->args[1].i;
1981 /* Test case: report what would happen */
1983 if (filter_test != FTEST_NONE)
1987 printf("%save message to: %s%s\n",
1988 commands->seen ? "S" : "Unseen s",
1989 s, commands->noerror ? " (noerror)" : "");
1991 printf("%save message to: %s %04o%s\n",
1992 commands->seen ? "S" : "Unseen s",
1993 s, mode, commands->noerror ? " (noerror)" : "");
1996 /* Real case: Ensure save argument starts with / if there is a home
1997 directory to prepend. */
2001 if (s[0] != '/' && filter_options & RDO_PREPEND_HOME &&
2002 deliver_home && *deliver_home)
2003 s = string_sprintf("%s/%s", deliver_home, s);
2004 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
2005 commands->seen ? "" : "unseen ",
2006 s, commands->noerror ? " (noerror)" : "");
2008 /* Create the new address and add it to the chain, setting the
2009 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
2012 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
2013 setflag(addr, af_pfr);
2014 setflag(addr, af_file);
2015 if (commands->noerror) addr->prop.ignore_error = TRUE;
2017 addr->next = *generated;
2023 s = string_copy(commands->args[0].u);
2024 if (filter_test != FTEST_NONE)
2027 printf("%sipe message to: %s%s\n",
2028 commands->seen ? "P" : "Unseen p",
2029 s, commands->noerror? " (noerror)" : "");
2031 else /* Ensure pipe command starts with | */
2033 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
2034 commands->seen ? "" : "unseen ", s,
2035 commands->noerror ? " (noerror)" : "");
2036 if (s[0] != '|') s = string_sprintf("|%s", s);
2038 /* Create the new address and add it to the chain, setting the
2039 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
2040 each command argument is expanded in the transport after the command
2041 has been split up into separate arguments. */
2043 addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
2044 setflag(addr, af_pfr);
2045 setflag(addr, af_expand_pipe);
2046 if (commands->noerror) addr->prop.ignore_error = TRUE;
2047 addr->next = *generated;
2050 /* If there are any numeric variables in existence (e.g. after a regex
2051 condition), or if $thisaddress is set, take a copy for use in the
2052 expansion. Note that we can't pass NULL for filter_thisaddress, because
2053 NULL terminates the list. */
2055 if (expand_nmax >= 0 || filter_thisaddress != NULL)
2057 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
2058 uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
2060 addr->pipe_expandn = ss;
2061 if (!filter_thisaddress) filter_thisaddress = US"";
2062 *ss++ = string_copy(filter_thisaddress);
2063 for (int i = 0; i <= expand_nmax; i++)
2064 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
2070 /* Set up the file name and mode, and close any previously open
2073 case LOGFILE_COMMAND:
2074 log_mode = commands->args[1].i;
2075 if (log_mode == -1) log_mode = 0600;
2078 (void)close(log_fd);
2081 log_filename = expargs[0];
2082 if (filter_test != FTEST_NONE)
2085 printf("%sogfile %s\n", commands->seen ? "Seen l" : "L", log_filename);
2089 case LOGWRITE_COMMAND:
2092 if (filter_test != FTEST_NONE)
2095 printf("%sogwrite \"%s\"\n", commands->seen ? "Seen l" : "L",
2096 string_printing(s));
2099 /* Attempt to write to a log file only if configured as permissible.
2100 Logging may be forcibly skipped for verifying or testing. */
2102 else if (filter_options & RDO_LOG) /* Locked out */
2105 debug_printf_indent("filter log command aborted: euid=%ld\n",
2106 (long int)geteuid());
2107 *error_pointer = US"logwrite command forbidden";
2110 else if (filter_options & RDO_REALLOG)
2113 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
2114 (long int)geteuid());
2119 *error_pointer = US"attempt to obey \"logwrite\" command "
2120 "without a previous \"logfile\"";
2123 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
2126 *error_pointer = string_open_failed("filter log file \"%s\"",
2132 if (write(log_fd, s, len) != len)
2134 *error_pointer = string_sprintf("write error on file \"%s\": %s",
2135 log_filename, strerror(errno));
2141 debug_printf_indent("skipping logwrite (verifying or testing)\n");
2144 /* Header addition and removal is available only in the system filter. The
2145 command is rejected at parse time otherwise. However "headers charset" is
2146 always permitted. */
2148 case HEADERS_COMMAND:
2150 int subtype = commands->args[1].i;
2153 if (filter_test != FTEST_NONE)
2154 printf("Headers %s \"%s\"\n",
2155 subtype == TRUE ? "add"
2156 : subtype == FALSE ? "remove"
2158 string_printing(s));
2160 if (subtype == TRUE)
2162 if (Uskip_whitespace(&s))
2164 header_add(htype_other, "%s%s", s,
2165 s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2166 header_last->type = header_checkname(header_last, FALSE);
2167 if (header_last->type >= 'a') header_last->type = htype_other;
2171 else if (subtype == FALSE)
2174 const uschar * list = s;
2176 for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2177 header_remove(0, ss);
2180 /* This setting lasts only while the filter is running; on exit, the
2181 variable is reset to the previous value. */
2183 else headers_charset = s;
2187 /* Defer, freeze, and fail are available only when explicitly permitted.
2188 These commands are rejected at parse time otherwise. The message can get
2189 very long by the inclusion of message headers; truncate if it is, and also
2190 ensure printing characters so as not to mess up log files. */
2193 ff_name = US"defer";
2195 goto DEFERFREEZEFAIL;
2200 goto DEFERFREEZEFAIL;
2202 case FREEZE_COMMAND:
2203 ff_name = US"freeze";
2207 *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2208 ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2209 : string_copy(expargs[0]));
2210 for(uschar * s = fmsg; *s; s++)
2211 if (!s[1] && *s == '\n') { *s = '\0'; break; } /* drop trailing newline */
2213 if (filter_test != FTEST_NONE)
2216 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2219 DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2222 case FINISH_COMMAND:
2223 if (filter_test != FTEST_NONE)
2226 printf("%sinish\n", commands->seen ? "Seen f" : "F");
2229 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2230 commands->seen ? " Seen " : "");
2231 finish_obeyed = TRUE;
2232 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2236 uschar *save_address = filter_thisaddress;
2237 int ok = FF_DELIVERED;
2238 condition_value = test_condition(commands->args[0].c, TRUE);
2244 ok = interpret_commands(commands->args[condition_value ? 1:2].f,
2248 filter_thisaddress = save_address;
2249 if (finish_obeyed || ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2255 /* To try to catch runaway loops, do not generate mail if the
2256 return path is unset or if a non-trusted user supplied -f <>
2257 as the return path. */
2260 case VACATION_COMMAND:
2261 if (!return_path || !*return_path)
2263 if (filter_test != FTEST_NONE)
2264 printf("%s command ignored because return_path is empty\n",
2265 command_list[commands->command]);
2266 else DEBUG(D_filter)
2267 debug_printf_indent("%s command ignored because return_path "
2268 "is empty\n", command_list[commands->command]);
2272 /* Check the contents of the strings. The type of string can be deduced
2273 from the value of i.
2275 . If i is equal to mailarg_index_text it's a text string for the body,
2276 where anything goes.
2278 . If i is > mailarg_index_text, we are dealing with a file name, which
2279 cannot contain non-printing characters.
2281 . If i is less than mailarg_index_headers we are dealing with something
2282 that will go in a single message header line, where newlines must be
2283 followed by white space.
2285 . If i is equal to mailarg_index_headers, we have a string that contains
2286 one or more headers. Newlines that are not followed by white space must
2287 be followed by a header name.
2290 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2292 const uschar *s = expargs[i];
2296 if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2299 if (i > mailarg_index_text)
2301 if (!mac_isprint(c))
2303 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2304 "in %s command", string_printing(s),
2305 command_list[commands->command]);
2310 /* i < mailarg_index_text */
2312 else if (c == '\n' && !isspace(p[1]))
2314 if (i < mailarg_index_headers)
2316 *error_pointer = string_sprintf("\\n not followed by space in "
2317 "\"%.1024s\" in %s command", string_printing(s),
2318 command_list[commands->command]);
2322 /* Check for the start of a new header line within the string */
2327 for (pp = p + 1;; pp++)
2330 if (c == ':' && pp != p + 1) break;
2331 if (!c || c == ':' || isspace(c))
2333 *error_pointer = string_sprintf("\\n not followed by space or "
2334 "valid header name in \"%.1024s\" in %s command",
2335 string_printing(s), command_list[commands->command]);
2342 } /* Loop to scan the string */
2344 /* The string is OK */
2346 commands->args[i].u = s;
2349 /* Proceed with mail or vacation command */
2351 if (filter_test != FTEST_NONE)
2353 const uschar *to = commands->args[mailarg_index_to].u;
2355 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2356 to ? to : US"<default>",
2357 commands->command == VACATION_COMMAND ? " (vacation)" : "",
2358 commands->noerror ? " (noerror)" : "");
2359 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2361 const uschar * arg = commands->args[i].u;
2364 int len = Ustrlen(mailargs[i]);
2365 int indent = debug_selector != 0 ? output_indent : 0;
2366 while (len++ < 7 + indent) printf(" ");
2367 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2368 ( commands->args[mailarg_index_expand].u
2369 && Ustrcmp(mailargs[i], "file") == 0) ? " (expanded)" : "");
2372 if (commands->args[mailarg_index_return].u)
2373 printf("Return original message\n");
2378 const uschar *to = commands->args[mailarg_index_to].u;
2379 gstring * log_addr = NULL;
2381 if (!to) to = expand_string(US"$reply_address");
2382 Uskip_whitespace(&to);
2384 for (tt = to; *tt; tt++) /* Get rid of newlines */
2387 uschar * s = string_copy(to);
2388 for (uschar * ss = s; *ss; ss++)
2389 if (*ss == '\n') *ss = ' ';
2396 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2397 commands->seen ? "seen " : "",
2399 commands->command == VACATION_COMMAND ? " (vacation)" : "",
2400 commands->noerror ? " (noerror)" : "");
2401 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2403 const uschar *arg = commands->args[i].u;
2406 int len = Ustrlen(mailargs[i]);
2407 while (len++ < 15) debug_printf_indent(" ");
2408 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2409 (commands->args[mailarg_index_expand].u != NULL &&
2410 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2415 /* Create the "address" for the autoreply. This is used only for logging,
2416 as the actual recipients are extracted from the To: line by -t. We use the
2417 same logic here to extract the working addresses (there may be more than
2418 one). Just in case there are a vast number of addresses, stop when the
2419 string gets too long. */
2424 uschar *ss = parse_find_address_end(tt, FALSE);
2425 uschar *recipient, *errmess;
2426 int start, end, domain;
2430 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2434 /* Ignore empty addresses and errors; an error will occur later if
2435 there's something really bad. */
2439 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2440 log_addr = string_cat (log_addr, recipient);
2445 if (log_addr && log_addr->ptr > 256)
2447 log_addr = string_catn(log_addr, US", ...", 5);
2451 /* Move on past this address */
2453 tt = ss + (*ss ? 1 : 0);
2454 Uskip_whitespace(&tt);
2458 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2461 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2462 setflag(addr, af_bad_reply);
2465 setflag(addr, af_pfr);
2466 if (commands->noerror) addr->prop.ignore_error = TRUE;
2467 addr->next = *generated;
2470 addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2471 addr->reply->from = NULL;
2472 addr->reply->to = string_copy(to);
2473 addr->reply->file_expand =
2474 commands->args[mailarg_index_expand].u != NULL;
2475 addr->reply->expand_forbid = expand_forbid;
2476 addr->reply->return_message =
2477 commands->args[mailarg_index_return].u != NULL;
2478 addr->reply->once_repeat = 0;
2480 if (commands->args[mailarg_index_once_repeat].u != NULL)
2482 addr->reply->once_repeat =
2483 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2485 if (addr->reply->once_repeat < 0)
2487 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2488 "in mail or vacation command: %s",
2489 commands->args[mailarg_index_once_repeat].u);
2494 /* Set up all the remaining string arguments (those other than "to") */
2496 for (i = 1; i < mailargs_string_passed; i++)
2498 const uschar *ss = commands->args[i].u;
2499 *(USS((US addr->reply) + reply_offsets[i])) =
2500 ss ? string_copy(ss) : NULL;
2505 case TESTPRINT_COMMAND:
2506 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2508 const uschar *s = string_printing(expargs[0]);
2509 if (filter_test == FTEST_NONE)
2510 debug_printf_indent("Filter: testprint: %s\n", s);
2512 printf("Testprint: %s\n", s);
2516 commands = commands->next;
2519 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2524 /*************************************************
2525 * Interpret a mail filter file *
2526 *************************************************/
2530 filter points to the entire file, read into store as a single string
2531 options controls whether various special things are allowed, and requests
2533 generated where to hang newly-generated addresses
2534 error where to pass back an error text
2536 Returns: FF_DELIVERED success, a significant action was taken
2537 FF_NOTDELIVERED success, no significant action
2538 FF_DEFER defer requested
2539 FF_FAIL fail requested
2540 FF_FREEZE freeze requested
2541 FF_ERROR there was a problem
2545 filter_interpret(const uschar *filter, int options, address_item **generated,
2549 int yield = FF_ERROR;
2550 const uschar *ptr = filter;
2551 const uschar *save_headers_charset = headers_charset;
2552 filter_cmd *commands = NULL;
2553 filter_cmd **lastcmdptr = &commands;
2555 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2558 /* Initialize "not in an if command", set the global flag that is always TRUE
2559 while filtering, and zero the variables. */
2563 f.filter_running = TRUE;
2564 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2566 /* To save having to pass certain values about all the time, make them static.
2567 Also initialize the line number, for error messages, and the log file
2570 filter_options = options;
2571 filter_delivered = FALSE;
2572 finish_obeyed = FALSE;
2573 error_pointer = error;
2574 *error_pointer = NULL;
2578 log_filename = NULL;
2580 /* Scan filter file for syntax and build up an interpretation thereof, and
2581 interpret the compiled commands, and if testing, say whether we ended up
2582 delivered or not, unless something went wrong. */
2585 ptr = nextsigchar(ptr, TRUE);
2587 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2588 yield = interpret_commands(commands, generated);
2590 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2596 s = US"Filtering ended by \"defer\".";
2600 s = US"Filtering ended by \"freeze\".";
2604 s = US"Filtering ended by \"fail\".";
2608 s = US"Filtering set up at least one significant delivery "
2609 "or other action.\n"
2610 "No other deliveries will occur.";
2613 case FF_NOTDELIVERED:
2614 s = US"Filtering did not set up a significant delivery.\n"
2615 "Normal delivery will occur.";
2619 s = string_sprintf("Filter error: %s", *error);
2623 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2624 else debug_printf_indent("%s\n", s);
2627 /* Close the log file if it was opened, and kill off any numerical variables
2628 before returning. Reset the header decoding charset. */
2630 if (log_fd >= 0) (void)close(log_fd);
2632 f.filter_running = FALSE;
2633 headers_charset = save_headers_charset;
2636 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2643 /******************************************************************************/
2646 static void * exim_functions[] = {
2647 [EXIM_INTERPRET] = filter_interpret,
2648 [EXIM_FILTER_PERSONAL] = filter_personal,
2651 misc_module_info exim_filter_module_info =
2653 .name = US"exim_filter",
2655 .dyn_magic = MISC_MODULE_MAGIC,
2658 .functions = exim_functions,
2659 .functions_count = nelem(exim_functions),
2662 /* End of filter.c */