* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2021 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Functions concerned with rewriting headers */
Returns: fully-qualified address
*/
-uschar *
-rewrite_address_qualify(uschar *s, BOOL is_recipient)
+const uschar *
+rewrite_address_qualify(const uschar *s, BOOL is_recipient)
{
-return (parse_find_at(s) != NULL)? s :
- string_sprintf("%s@%s", s,
- is_recipient? qualify_domain_recipient : qualify_domain_sender);
+return parse_find_at(s)
+ ? s : string_sprintf("%s@%s", s,
+ is_recipient ? qualify_domain_recipient : qualify_domain_sender);
}
rewritten address is returned, not just the active bit.
*/
-uschar *
-rewrite_one(uschar *s, int flag, BOOL *whole, BOOL add_header, uschar *name,
+const uschar *
+rewrite_one(const uschar *s, int flag, BOOL *whole, BOOL add_header, uschar *name,
rewrite_rule *rewrite_rules)
{
-uschar *yield = s;
-uschar *subject = s;
+const uschar *yield = s;
+const uschar *subject = s;
uschar *domain = NULL;
BOOL done = FALSE;
int rule_number = 1;
if (whole) *whole = FALSE;
-/* Scan the rewriting rules */
+/* Scan the rewriting rules, ignoring any without matching flag */
for (rewrite_rule * rule = rewrite_rules;
rule && !done;
- rule_number++, rule = rule->next)
+ rule_number++, rule = rule->next) if (rule->flags & flag)
{
int start, end, pdomain;
int count = 0;
- uschar *save_localpart;
- const uschar *save_domain;
- uschar *error, *new, *newparsed;
-
- /* Ensure that the flag matches the flags in the rule. */
-
- if (!(rule->flags & flag)) continue;
+ const uschar * save_localpart;
+ const uschar * save_domain;
+ uschar * error, * new;
+ const uschar * newparsed;
/* Come back here for a repeat after a successful rewrite. We do this
only so many times. */
if (flag & rewrite_smtp)
{
- uschar *key = expand_string(rule->key);
+ BOOL textonly_re;
+ const uschar * key = expand_string_2(rule->key, &textonly_re);
if (!key)
{
if (!f.expand_string_forcedfail)
"checking for SMTP rewriting: %s", rule->key, expand_string_message);
continue;
}
- if (match_check_string(subject, key, 0, TRUE, FALSE, FALSE, NULL) != OK)
+ if (match_check_string(subject, key, 0,
+ textonly_re ? MCS_CACHEABLE | MCS_PARTIAL : MCS_PARTIAL, NULL) != OK)
continue;
new = expand_string(rule->replacement);
}
set up as an expansion variable */
domain[-1] = 0;
- deliver_localpart = subject;
+ deliver_localpart = US subject;
deliver_domain = domain;
new = expand_string(rule->replacement);
Returns: possibly rewritten address
*/
-uschar *
-rewrite_address(uschar *s, BOOL is_recipient, BOOL add_header,
+const uschar *
+rewrite_address(const uschar *s, BOOL is_recipient, BOOL add_header,
rewrite_rule *rewrite_rules, int existflags)
{
-int flag = is_recipient? rewrite_envto : rewrite_envfrom;
+int flag = is_recipient ? rewrite_envto : rewrite_envfrom;
+
s = rewrite_address_qualify(s, is_recipient);
-if ((existflags & flag) != 0)
+if (existflags & flag)
{
- uschar *new = rewrite_one(s, flag, NULL, add_header, is_recipient?
+ const uschar *new = rewrite_one(s, flag, NULL, add_header, is_recipient?
US"original-recipient" : US"sender", rewrite_rules);
if (new != s) s = new;
}
header_line *newh = NULL;
rmark function_reset_point = store_mark();
uschar *s = Ustrchr(h->text, ':') + 1;
+
while (isspace(*s)) s++;
DEBUG(D_rewrite)
- debug_printf("rewrite_one_header: type=%c:\n %s", h->type, h->text);
+ debug_printf_indent("rewrite_one_header: type=%c:\n %s", h->type, h->text);
f.parse_allow_group = TRUE; /* Allow group syntax */
{
uschar *sprev;
uschar *ss = parse_find_address_end(s, FALSE);
- uschar *recipient, *new, *errmess;
+ uschar *recipient, *new;
rmark loop_reset_point = store_mark();
+ uschar *errmess = NULL;
BOOL changed = FALSE;
int terminator = *ss;
int start, end, domain;
the next address, saving the start of the old one. */
*ss = 0;
- recipient = parse_extract_address(s,&errmess,&start,&end,&domain,FALSE);
+ recipient = parse_extract_address(s, &errmess, &start, &end, &domain, FALSE);
*ss = terminator;
sprev = s;
- s = ss + (terminator? 1:0);
+ s = ss + (terminator ? 1 : 0);
while (isspace(*s)) s++;
/* There isn't much we can do for syntactic disasters at this stage.
- Pro tem (possibly for ever) ignore them. */
+ Pro tem (possibly for ever) ignore them.
+ If we got nothing, then there was any sort of error: non-parsable address,
+ empty address, overlong addres. Sometimes the result matters, sometimes not.
+ It seems this function is called for *any* header we see. */
if (!recipient)
{
+ /* Log unparesable addresses in the header. Slightly ugly because a
+ null output from the extract can also result from a header without an
+ address, "To: undisclosed recpients:;" being the classic case. Ignore
+ this one and carry on. */
+
+ if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0)
+ log_write(0, LOG_MAIN, "rewrite: %s", errmess);
+
loop_reset_point = store_reset(loop_reset_point);
continue;
}
as abc@xyz, which the DNS lookup turns into abc@xyz.foo.com). However, if no
change is made here, don't bother carrying on. */
- if (routed_old != NULL)
+ if (routed_old)
{
if (domain <= 0 || strcmpic(recipient+domain, routed_old) != 0) continue;
recipient[domain-1] = 0;
{
BOOL is_recipient =
(flag & (rewrite_sender | rewrite_from | rewrite_replyto)) == 0;
- new = rewrite_address_qualify(recipient, is_recipient);
+ /* deconst ok as recipient was notconst */
+ new = US rewrite_address_qualify(recipient, is_recipient);
changed = (new != recipient);
recipient = new;
"whole" flag set, adjust the pointers so that the whole address gets
replaced, except possibly a final \n. */
- if ((existflags & flag) != 0)
+ if (existflags & flag)
{
BOOL whole;
- new = rewrite_one(recipient, flag, &whole, FALSE, NULL, rewrite_rules);
+ /* deconst ok as recipient was notconst */
+ new = US rewrite_one(recipient, flag, &whole, FALSE, NULL, rewrite_rules);
if (new != recipient)
{
changed = TRUE;
int oldlen = end - start;
header_line * prev = newh ? newh : h;
- uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, TRUE);
+ uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, GET_TAINTED);
uschar * newtstart = newt;
int type = prev->type;
store_reset(function_reset_point);
function_reset_point = store_mark();
- newh = store_get(sizeof(header_line), FALSE);
+ newh = store_get(sizeof(header_line), GET_UNTAINTED);
newh->type = type;
newh->slen = slen;
newh->text = string_copyn(newtstart, slen);
/* Set up for scanning the rest of the header */
s = newh->text + remlen;
- DEBUG(D_rewrite) debug_printf("remainder: %s", (*s == 0)? US"\n" : s);
+ DEBUG(D_rewrite) debug_printf("remainder: %s", *s ? s : US"\n");
}
}
/* If a rewrite happened and "replace" is true, put the new header into the
chain following the old one, and mark the old one as replaced. */
-if (newh != NULL && replace)
+if (newh && replace)
{
newh->next = h->next;
- if (newh->next == NULL) header_last = newh;
+ if (!newh->next) header_last = newh;
h->type = htype_old;
h->next = newh;
}
Returns: nothing
*/
-void rewrite_test(uschar *s)
+void
+rewrite_test(const uschar *s)
{
uschar *recipient, *error;
int start, end, domain;
if ((rewrite_existflags & rewrite_smtp) != 0)
{
- uschar *new = rewrite_one(s, rewrite_smtp|rewrite_smtp_sender, NULL, FALSE,
- US"", global_rewrite_rules);
+ const uschar * new = rewrite_one(s, rewrite_smtp|rewrite_smtp_sender, NULL,
+ FALSE, US"", global_rewrite_rules);
if (new != s)
{
if (*new == 0)
{
BOOL whole = FALSE;
int flag = 1 << i;
- uschar *new = rewrite_one(recipient, flag, &whole, FALSE, US"",
+ const uschar * new = rewrite_one(recipient, flag, &whole, FALSE, US"",
global_rewrite_rules);
printf("%s: ", rrname[i]);
if (*new == 0)