{
const uschar * tlist = list;
int sep = 0;
-uschar dummy;
+/* Tainted mem for the throwaway element copies */
+uschar * dummy = store_get(2, TRUE);
if (field < 0)
{
- for (field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++;
+ for (field++; string_nextinlist(&tlist, &sep, dummy, 1); ) field++;
sep = 0;
}
if (field == 0) return NULL;
-while (--field > 0 && (string_nextinlist(&list, &sep, &dummy, 1))) ;
+while (--field > 0 && (string_nextinlist(&list, &sep, dummy, 1))) ;
return string_nextinlist(&list, &sep, NULL, 0);
}
if (sender_host_name)
g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")");
else if (host_lookup_deferred)
- g = string_catn(g, US";\n\tiprev=temperror", 19);
+ g = string_cat(g, US";\n\tiprev=temperror");
else if (host_lookup_failed)
- g = string_catn(g, US";\n\tiprev=fail", 13);
+ g = string_cat(g, US";\n\tiprev=fail");
else
return g;
}
+/* Expand a named list. Return false on failure. */
+static gstring *
+expand_listnamed(gstring * yield, const uschar * name, const uschar * listtype)
+{
+tree_node *t = NULL;
+const uschar * list;
+int sep = 0;
+uschar * item;
+uschar * suffix = US"";
+BOOL needsep = FALSE;
+#define LISTNAMED_BUF_SIZE 256
+uschar b[LISTNAMED_BUF_SIZE];
+uschar * buffer = b;
+
+if (*name == '+') name++;
+if (!listtype) /* no-argument version */
+ {
+ if ( !(t = tree_search(addresslist_anchor, name))
+ && !(t = tree_search(domainlist_anchor, name))
+ && !(t = tree_search(hostlist_anchor, name)))
+ t = tree_search(localpartlist_anchor, name);
+ }
+else switch(*listtype) /* specific list-type version */
+ {
+ case 'a': t = tree_search(addresslist_anchor, name); suffix = US"_a"; break;
+ case 'd': t = tree_search(domainlist_anchor, name); suffix = US"_d"; break;
+ case 'h': t = tree_search(hostlist_anchor, name); suffix = US"_h"; break;
+ case 'l': t = tree_search(localpartlist_anchor, name); suffix = US"_l"; break;
+ default:
+ expand_string_message = US"bad suffix on \"list\" operator";
+ return yield;
+ }
+
+if(!t)
+ {
+ expand_string_message = string_sprintf("\"%s\" is not a %snamed list",
+ name, !listtype?""
+ : *listtype=='a'?"address "
+ : *listtype=='d'?"domain "
+ : *listtype=='h'?"host "
+ : *listtype=='l'?"localpart "
+ : 0);
+ return yield;
+ }
+
+list = ((namedlist_block *)(t->data.ptr))->string;
+
+/* The list could be quite long so we (re)use a buffer for each element
+rather than getting each in new memory */
+
+if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, TRUE);
+while ((item = string_nextinlist(&list, &sep, buffer, LISTNAMED_BUF_SIZE)))
+ {
+ uschar * buf = US" : ";
+ if (needsep)
+ yield = string_catn(yield, buf, 3);
+ else
+ needsep = TRUE;
+
+ if (*item == '+') /* list item is itself a named list */
+ {
+ yield = expand_listnamed(yield, item, listtype);
+ if (expand_string_message)
+ return yield;
+ }
+
+ else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */
+ {
+ char tok[3];
+ tok[0] = sep; tok[1] = ':'; tok[2] = 0;
+
+ for(char * cp; cp = strpbrk(CCS item, tok); item = US cp)
+ {
+ yield = string_catn(yield, item, cp - CS item);
+ if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
+ yield = string_catn(yield, US"::", 2);
+ else /* sep in item; should already be doubled; emit once */
+ {
+ yield = string_catn(yield, US tok, 1);
+ if (*cp == sep) cp++;
+ }
+ }
+ yield = string_cat(yield, item);
+ }
+ else
+ yield = string_cat(yield, item);
+ }
+return yield;
+}
+
+
+
/*************************************************
* Expand string *
*************************************************/
{
expand_string_message =
string_sprintf("lookup of \"%s\" gave DEFER: %s",
- string_printing2(key, FALSE), search_error_message);
+ string_printing2(key, SP_TAB), search_error_message);
goto EXPAND_FAILED;
}
if (expand_setup > 0) expand_nmax = expand_setup;
if (!(f = Ufopen(sub_arg[0], "rb")))
{
- expand_string_message = string_open_failed(errno, "%s", sub_arg[0]);
+ expand_string_message = string_open_failed("%s", sub_arg[0]);
goto EXPAND_FAILED;
}
while ((item = string_nextinlist(&list, &sep, NULL, 0)))
g = string_append_listele(g, ',', item);
- /* possibly plus an EOL string */
+ /* possibly plus an EOL string. Process with escapes, to protect
+ from list-processing. The only current user of eol= in search
+ options is the readsock expansion. */
+
if (sub_arg[3] && *sub_arg[3])
g = string_append_listele(g, ',',
- string_sprintf("eol=%s", sub_arg[3]));
-
+ string_sprintf("eol=%s",
+ string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
}
/* Gat a (possibly cached) handle for the connection */
case EOP_LISTCOUNT:
{
- int cnt = 0;
- int sep = 0;
+ int cnt = 0, sep = 0;
+ uschar * buf = store_get(2, is_tainted(sub));
- while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++;
+ while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
yield = string_fmt_append(yield, "%d", cnt);
continue;
}
/* handles nested named lists; requotes as colon-sep list */
case EOP_LISTNAMED:
- {
- tree_node *t = NULL;
- const uschar * list;
- int sep = 0;
- uschar * item;
- uschar * suffix = US"";
- BOOL needsep = FALSE;
- uschar buffer[256];
-
- if (*sub == '+') sub++;
- if (!arg) /* no-argument version */
- {
- if (!(t = tree_search(addresslist_anchor, sub)) &&
- !(t = tree_search(domainlist_anchor, sub)) &&
- !(t = tree_search(hostlist_anchor, sub)))
- t = tree_search(localpartlist_anchor, sub);
- }
- else switch(*arg) /* specific list-type version */
- {
- case 'a': t = tree_search(addresslist_anchor, sub); suffix = US"_a"; break;
- case 'd': t = tree_search(domainlist_anchor, sub); suffix = US"_d"; break;
- case 'h': t = tree_search(hostlist_anchor, sub); suffix = US"_h"; break;
- case 'l': t = tree_search(localpartlist_anchor, sub); suffix = US"_l"; break;
- default:
- expand_string_message = US"bad suffix on \"list\" operator";
- goto EXPAND_FAILED;
- }
-
- if(!t)
- {
- expand_string_message = string_sprintf("\"%s\" is not a %snamed list",
- sub, !arg?""
- : *arg=='a'?"address "
- : *arg=='d'?"domain "
- : *arg=='h'?"host "
- : *arg=='l'?"localpart "
- : 0);
+ expand_string_message = NULL;
+ yield = expand_listnamed(yield, sub, arg);
+ if (expand_string_message)
goto EXPAND_FAILED;
- }
-
- list = ((namedlist_block *)(t->data.ptr))->string;
-
- while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
- {
- uschar * buf = US" : ";
- if (needsep)
- yield = string_catn(yield, buf, 3);
- else
- needsep = TRUE;
-
- if (*item == '+') /* list item is itself a named list */
- {
- uschar * sub = string_sprintf("${listnamed%s:%s}", suffix, item);
- item = expand_string_internal(sub, FALSE, NULL, FALSE, TRUE, &resetok);
- }
- else if (sep != ':') /* item from non-colon-sep list, re-quote for colon list-separator */
- {
- char * cp;
- char tok[3];
- tok[0] = sep; tok[1] = ':'; tok[2] = 0;
- while ((cp= strpbrk(CCS item, tok)))
- {
- yield = string_catn(yield, item, cp - CS item);
- if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
- {
- yield = string_catn(yield, US"::", 2);
- item = US cp;
- }
- else /* sep in item; should already be doubled; emit once */
- {
- yield = string_catn(yield, US tok, 1);
- if (*cp == sep) cp++;
- item = US cp;
- }
- }
- }
- yield = string_cat(yield, item);
- }
continue;
- }
/* quote a list-item for the given list-separator */
prescribed by the RFC, if there are characters that need to be encoded */
case EOP_RFC2047:
- {
- uschar buffer[2048];
yield = string_cat(yield,
parse_quote_2047(sub, Ustrlen(sub), headers_charset,
- buffer, sizeof(buffer), FALSE));
+ FALSE));
continue;
- }
/* RFC 2047 decode */