Taint: fix dsearch result to be untainted
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 22 Mar 2020 00:55:59 +0000 (00:55 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 22 Mar 2020 09:49:46 +0000 (09:49 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/lookups/dsearch.c
test/confs/0153

index f91d51792d8907c60e58ca3e01d2f827d46aa7a8..cf15942dbfa8d02cfd4623a275260ca83dbff3bc 100644 (file)
@@ -6762,7 +6762,12 @@ by default, but has an option to omit them (see section &<<SECTdbmbuild>>&).
 whose name is the key by calling the &[lstat()]& function. The key may not
 contain any forward slash characters. If &[lstat()]& succeeds, the result of
 the lookup is the name of the entry, which may be a file, directory,
 whose name is the key by calling the &[lstat()]& function. The key may not
 contain any forward slash characters. If &[lstat()]& succeeds, the result of
 the lookup is the name of the entry, which may be a file, directory,
-symbolic link, or any other kind of directory entry. An example of how this
+symbolic link, or any other kind of directory entry.
+.new
+.cindex "tainted data" "dsearch result"
+It is regarded as untainted.
+.wen
+An example of how this
 lookup can be used to support virtual domains is given in section
 &<<SECTvirtualdomains>>&.
 .next
 lookup can be used to support virtual domains is given in section
 &<<SECTvirtualdomains>>&.
 .next
@@ -36771,12 +36776,18 @@ to a router of this form:
 virtual:
   driver = redirect
   domains = dsearch;/etc/mail/virtual
 virtual:
   driver = redirect
   domains = dsearch;/etc/mail/virtual
-  data = ${lookup{$local_part}lsearch{/etc/mail/virtual/$domain}}
+  data = ${lookup{$local_part}lsearch{/etc/mail/virtual/$domain_data}}
   no_more
 .endd
   no_more
 .endd
+.new
 The &%domains%& option specifies that the router is to be skipped, unless there
 is a file in the &_/etc/mail/virtual_& directory whose name is the same as the
 The &%domains%& option specifies that the router is to be skipped, unless there
 is a file in the &_/etc/mail/virtual_& directory whose name is the same as the
-domain that is being processed. When the router runs, it looks up the local
+domain that is being processed.
+The &(dsearch)& lookup used results in an untainted version of &$domain$&
+being placed into the &$domain_data$& variable.
+.wen
+
+When the router runs, it looks up the local
 part in the file to find a new address (or list of addresses). The &%no_more%&
 setting ensures that if the lookup fails (leading to &%data%& being an empty
 string), Exim gives up on the address without trying any subsequent routers.
 part in the file to find a new address (or list of addresses). The &%no_more%&
 setting ensures that if the lookup fails (leading to &%data%& being an empty
 string), Exim gives up on the address without trying any subsequent routers.
index 74568ce3f9371a46d8dc388cb70c8bcdc4af5aa5..be07ba625d8acf76b751d4e482b3cab5f3989a7f 100644 (file)
@@ -152,6 +152,10 @@ JH/31 Fix spurious detection of timeout while writing to transport filter.
 JH/32 Bug 2541: Fix segfault on bad cmdline -f (sender) argument.  Previously
       an attempt to copy the string was made before checking it.
 
 JH/32 Bug 2541: Fix segfault on bad cmdline -f (sender) argument.  Previously
       an attempt to copy the string was made before checking it.
 
+JH/33 Fix the dsearch lookup to return an untainted result.  Previously the
+      taint of the lookup key was maintained; we now regard the presence in the
+      filesystem as sufficient validation.
+
 
 Exim version 4.93
 -----------------
 
 Exim version 4.93
 -----------------
index c27f5d6e65203f9d01d984012ab3566c067bb997..1eb2924f01cd6a1677c821c9924dbf38acf9f186 100644 (file)
@@ -28,7 +28,7 @@ static void *
 dsearch_open(uschar *dirname, uschar **errmsg)
 {
 DIR *dp = opendir(CS dirname);
 dsearch_open(uschar *dirname, uschar **errmsg)
 {
 DIR *dp = opendir(CS dirname);
-if (dp == NULL)
+if (!dp)
   {
   int save_errno = errno;
   *errmsg = string_open_failed(errno, "%s for directory search", dirname);
   {
   int save_errno = errno;
   *errmsg = string_open_failed(errno, "%s for directory search", dirname);
@@ -47,8 +47,8 @@ return (void *)(-1);
 /* The handle will always be (void *)(-1), but don't try casting it to an
 integer as this gives warnings on 64-bit systems. */
 
 /* The handle will always be (void *)(-1), but don't try casting it to an
 integer as this gives warnings on 64-bit systems. */
 
-BOOL
-static dsearch_check(void *handle, uschar *filename, int modemask, uid_t *owners,
+static BOOL
+dsearch_check(void *handle, uschar *filename, int modemask, uid_t *owners,
   gid_t *owngroups, uschar **errmsg)
 {
 handle = handle;
   gid_t *owngroups, uschar **errmsg)
 {
 handle = handle;
@@ -87,7 +87,9 @@ if (Ustrchr(keystring, '/') != 0)
 filename = string_sprintf("%s/%s", dirname, keystring);
 if (Ulstat(filename, &statbuf) >= 0)
   {
 filename = string_sprintf("%s/%s", dirname, keystring);
 if (Ulstat(filename, &statbuf) >= 0)
   {
-  *result = string_copy(keystring);
+  /* Since the filename exists in the filesystem, we can return a
+  non-tainted result. */
+  *result = string_copy_taint(keystring, FALSE);
   return OK;
   }
 
   return OK;
   }
 
index 35a004a455a859f1443874ed74d80af95df9fd2e..24f499b41f1603723632326dd22d23ebfa2c9d3b 100644 (file)
@@ -13,10 +13,9 @@ begin routers
 virtual:
   driver = redirect
   domains = *.virt.test.ex
 virtual:
   driver = redirect
   domains = *.virt.test.ex
-  address_data = ${if match{$domain}{^(.*)\\.virt\\.test\\.ex\$}{${bless:$1}}}
-  data = ${if exists{DIR/aux-fixed/TESTNUM.alias.$address_data} \
-           {${lookup{$local_part}lsearch{DIR/aux-fixed/TESTNUM.alias.$address_data}}} \
-          fail}
+  address_data = ${lookup {TESTNUM.alias.${extract {1}{.}{$domain}}} \
+                       dsearch{DIR/aux-fixed} {$value}fail}
+  data = ${lookup{$local_part}lsearch{DIR/aux-fixed/$address_data}}
   no_more
 
 list:
   no_more
 
 list: