Gitweb:
https://git.exim.org/exim.git/commitdiff/4aaeaddeaa130a227a694d32b7214689e982a39e
Commit: 4aaeaddeaa130a227a694d32b7214689e982a39e
Parent: a5dc727afcc92deab722a84ae5cf3d00ae74c5f6
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Fri Apr 3 14:38:31 2020 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Fri Apr 3 15:44:22 2020 +0100
dsearch: filter-matches option
---
doc/doc-docbook/spec.xfpt | 27 +++++++++++++++++++--------
doc/doc-txt/NewStuff | 2 ++
src/src/lookups/dsearch.c | 26 +++++++++++++++++++++++++-
test/aux-fixed/2500.dir/regfile | 0
test/scripts/2500-dsearch/2500 | 9 ++++++++-
test/stderr/2200 | 2 +-
test/stderr/2201 | 2 +-
test/stderr/2600 | 4 ++--
test/stdout/2500 | 7 +++++++
9 files changed, 65 insertions(+), 14 deletions(-)
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 295835d..9a7f911 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -6780,22 +6780,31 @@ The key may not
contain any forward slash characters.
If &[lstat()]& succeeds then so does the lookup.
.new
+.cindex "tainted data" "dsearch result"
+The result is regarded as untainted.
+
Options for the lookup can be given by appending them after the word "dsearch",
-separated by a comma. Options, if present, are a comma-separated list with
+separated by a comma. Options, if present, are a comma-separated list having
each element starting with a tag name and an equals.
-The only option currently supported requests an alternate output value of
+Two options are supported, for the return value and for filtering match
+candidates.
+The "ret" option requests an alternate result value of
the entire path for the entry. Example:
.code
${lookup {passwd} dsearch,ret=full {/etc}}
.endd
The default result is just the requested entry.
-
-The matching entry may be a file, directory,
-symbolic link, or any other kind of directory entry.
-.cindex "tainted data" "dsearch result"
-The result is regarded as untainted.
+The "filter" option requests that only directory entries of a given type
+are matched. The match value is one of "file", "dir" or "subdir" (the latter
+not matching "." or ".."). Example:
+.code
+${lookup {passwd} dsearch,filter=file {/etc}}
+.endd
+The default matching is for any entry type, including directories
+and symlinks.
.wen
+
An example of how this
lookup can be used to support virtual domains is given in section
&<<SECTvirtualdomains>>&.
@@ -8100,8 +8109,8 @@ daemon as in the other SQL databases.
.oindex &%sqlite_dbfile%&
The preferred way of specifying the file is by using the
&%sqlite_dbfile%& option, set to
-.wen
an absolute path.
+.wen
A deprecated method is available, prefixing the query with the filename
separated by white space.
This means that the path name cannot contain white space.
@@ -8110,6 +8119,7 @@ It also means that the query cannot use any tainted values, as that taints
the entire query including the filename - resulting in a refusal to open
the file.
+.new
Here is a lookup expansion example:
.code
sqlite_dbfile = /some/thing/sqlitedb
@@ -8121,6 +8131,7 @@ In a list, the syntax is similar. For example:
domainlist relay_to_domains = sqlite;\
select * from relays where ip='$sender_host_address';
.endd
+.wen
The only character affected by the &%quote_sqlite%& operator is a single
quote, which it doubles.
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 9a06fea..1573f34 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -48,6 +48,8 @@ Version 4.94
in the lookup, as the filename becomes tainted. The new method keeps the
filename separate.
12. An option on the dsearch lookup, to return the full path.
+12. Options on the dsearch lookup, to return the full path and to filter
+ filetypes for matching.
diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c
index 0509a76..9bb76cc 100644
--- a/src/src/lookups/dsearch.c
+++ b/src/src/lookups/dsearch.c
@@ -65,6 +65,11 @@ return FALSE;
*************************************************/
#define RET_FULL BIT(0)
+#define FILTER_TYPE BIT(1)
+#define FILTER_ALL BIT(1)
+#define FILTER_FILE BIT(2)
+#define FILTER_DIR BIT(3)
+#define FILTER_SUBDIR BIT(4)
/* See local README for interface description. We use lstat() instead of
scanning the directory, as it is hopefully faster to let the OS do the scanning
@@ -99,10 +104,29 @@ if (opts)
while ((ele = string_nextinlist(&opts, &sep, NULL, 0)))
if (Ustrcmp(ele, "ret=full") == 0)
flags |= RET_FULL;
+ else if (Ustrncmp(ele, "filter=", 7) == 0)
+ {
+ ele += 7;
+ if (Ustrcmp(ele, "file") == 0)
+ flags |= FILTER_TYPE | FILTER_FILE;
+ else if (Ustrcmp(ele, "dir") == 0)
+ flags |= FILTER_TYPE | FILTER_DIR;
+ else if (Ustrcmp(ele, "subdir") == 0)
+ flags |= FILTER_TYPE | FILTER_SUBDIR; /* like dir but not "." or ".." */
+ }
}
filename = string_sprintf("%s/%s", dirname, keystring);
-if (Ulstat(filename, &statbuf) >= 0)
+if ( Ulstat(filename, &statbuf) >= 0
+ && ( !(flags & FILTER_TYPE)
+ || (flags & FILTER_FILE && S_ISREG(statbuf.st_mode))
+ || ( flags & (FILTER_DIR | FILTER_SUBDIR)
+ && S_ISDIR(statbuf.st_mode)
+ && ( flags & FILTER_DIR
+ || keystring[0] != '.'
+ || keystring[1] != '.'
+ || keystring[1] && keystring[2]
+ ) ) ) )
{
/* Since the filename exists in the filesystem, we can return a
non-tainted result. */
diff --git a/test/aux-fixed/2500.dir/regfile b/test/aux-fixed/2500.dir/regfile
new file mode 100644
index 0000000..e69de29
diff --git a/test/scripts/2500-dsearch/2500 b/test/scripts/2500-dsearch/2500
index 14cf31b..5886903 100644
--- a/test/scripts/2500-dsearch/2500
+++ b/test/scripts/2500-dsearch/2500
@@ -7,7 +7,14 @@ fail: ${lookup{TESTNUM.tst} dsearch{DIR/dir_not_here}{$value}{FAIL}}
fail(case): ${lookup{TESTNUM.TST} dsearch{DIR/aux-fixed}{$value}{FAIL}}
fail(case): ${lookup{TESTNUM.TST} dsearch{DIR/AUX-fixed}{$value}{FAIL}}
fail(path): ${lookup{TESTNUM.tst} dsearch{.}{$value}{OTHER}}
-ok,full: ${lookup{TESTNUM.tst} dsearch,ret=full {DIR/aux-fixed}{$value}{FAIL}}
+ok,full: ${lookup{TESTNUM.tst} dsearch,ret=full {DIR/aux-fixed}{$value}{FAIL}}
+ok,file: ${lookup{TESTNUM.tst} dsearch,filter=file {DIR/aux-fixed}{$value}{FAIL}}
+fail,file: ${lookup{TESTNUM.dir} dsearch,filter=file {DIR/aux-fixed}{$value}{FAIL}}
+ok,dir: ${lookup{TESTNUM.dir} dsearch,filter=dir {DIR/aux-fixed}{$value}{FAIL}}
+fail,dir: ${lookup{TESTNUM.tst} dsearch,filter=dir {DIR/aux-fixed}{$value}{FAIL}}
+ok,subdir: ${lookup{TESTNUM.dir} dsearch,filter=subdir {DIR/aux-fixed}{$value}{FAIL}}
+fail,subdir:${lookup{..} dsearch,filter=subdir {DIR/aux-fixed}{$value}{FAIL}}
+fail,subdir:${lookup{TESTNUM.tst} dsearch,filter=subdir {DIR/aux-fixed}{$value}{FAIL}}
****
#
1
diff --git a/test/stderr/2200 b/test/stderr/2200
index 8efc38f..c832032 100644
--- a/test/stderr/2200
+++ b/test/stderr/2200
@@ -43,7 +43,7 @@ search_tidyup called
LRU list:
internal_search_find: file="NULL"
type=dnsdb key="a=shorthost.test.ex" opts=NULL
- cached data found but past valid time; database lookup required for a=shorthost.test.ex
+ cached data found but either wrong opts or dated; database lookup required for a=shorthost.test.ex
dnsdb key: shorthost.test.ex
lookup yielded: 127.0.0.1
LOG: MAIN
diff --git a/test/stderr/2201 b/test/stderr/2201
index 9764069..fb618fc 100644
--- a/test/stderr/2201
+++ b/test/stderr/2201
@@ -176,7 +176,7 @@ search_find: file="NULL"
LRU list:
internal_search_find: file="NULL"
type=dnsdb key="a=shorthost.test.ex" opts=NULL
-cached data found but past valid time; database lookup required for a=shorthost.test.ex
+cached data found but either wrong opts or dated; database lookup required for a=shorthost.test.ex
dnsdb key: shorthost.test.ex
lookup yielded: 127.0.0.1
LOG: MAIN
diff --git a/test/stderr/2600 b/test/stderr/2600
index 3c4a592..627e477 100644
--- a/test/stderr/2600
+++ b/test/stderr/2600
@@ -495,10 +495,10 @@ admin user
dropping to exim gid; retaining priv uid
search_open: sqlite "NULL"
search_find: file="NULL"
- key="select name from them where id='userx';" partial=-1 affix=NULL starflags=0
+ key="select name from them where id='userx';" partial=-1 affix=NULL starflags=0 opts=NULL
LRU list:
internal_search_find: file="NULL"
- type=sqlite key="select name from them where id='userx';"
+ type=sqlite key="select name from them where id='userx';" opts=NULL
database lookup required for select name from them where id='userx';
lookup yielded: Ayen Other
search_tidyup called
diff --git a/test/stdout/2500 b/test/stdout/2500
index d10a5f8..ef5b2a1 100644
--- a/test/stdout/2500
+++ b/test/stdout/2500
@@ -5,4 +5,11 @@
> Failed: failed to open TESTSUITE/AUX-fixed for directory search: No such file or directory
> Failed: dirname '.' for dsearch is not absolute
> ok,full: TESTSUITE/aux-fixed/2500.tst
+> ok,file: 2500.tst
+> fail,file: FAIL
+> ok,dir: 2500.dir
+> fail,dir: FAIL
+> ok,subdir: 2500.dir
+> fail,subdir:FAIL
+> fail,subdir:FAIL
>