[exim-cvs] dsearch: filter-matches option

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] dsearch: filter-matches option
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

>