Update copyright dates
[exim.git] / src / src / lookups / dsearch.c
index a6b331edb6401e2932caf3d6d3543d3e7e2f4add..1229368baea66a4fe0a1d61fb8ae873553ac2cc7 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
 /* Copyright (c) University of Cambridge 1995 - 2015 */
-/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* The idea for this code came from Matthew Byng-Maddick, but his original has
 been heavily reworked a lot for Exim 4 (and it now uses stat() (more precisely:
@@ -69,6 +70,7 @@ return FALSE;
 #define FILTER_FILE    BIT(2)
 #define FILTER_DIR     BIT(3)
 #define FILTER_SUBDIR  BIT(4)
+#define ALLOW_PATH     BIT(5)
 
 /* 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
@@ -84,13 +86,6 @@ int save_errno;
 uschar * filename;
 unsigned flags = 0;
 
-if (Ustrchr(keystring, '/') != 0)
-  {
-  *errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
-    keystring);
-  return DEFER;
-  }
-
 if (opts)
   {
   int sep = ',';
@@ -109,6 +104,24 @@ if (opts)
       else if (Ustrcmp(ele, "subdir") == 0)
        flags |= FILTER_TYPE | FILTER_SUBDIR;   /* like dir but not "." or ".." */
       }
+    else if (Ustrcmp(ele, "key=path") == 0)
+      flags |= ALLOW_PATH;
+  }
+
+if (flags & ALLOW_PATH)
+  {
+  if (Ustrstr(keystring, "/../") != NULL || Ustrstr(keystring, "/./"))
+    {
+    *errmsg = string_sprintf(
+      "key for dsearch lookup contains bad component: %s", keystring);
+    return DEFER;
+    }
+  }
+else if (Ustrchr(keystring, '/') != NULL)
+  {
+  *errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
+    keystring);
+  return DEFER;
   }
 
 filename = string_sprintf("%s/%s", dirname, keystring);
@@ -119,12 +132,12 @@ if (  Ulstat(filename, &statbuf) >= 0
                 && S_ISDIR(statbuf.st_mode)
         && (  flags & FILTER_DIR
            || keystring[0] != '.'
-           || keystring[1] && keystring[1] != '.'
+           || keystring[1] && (keystring[1] != '.' || keystring[2])
    )  )  )  )
   {
   /* Since the filename exists in the filesystem, we can return a
   non-tainted result. */
-  *result = string_copy_taint(flags & RET_FULL ? filename : keystring, FALSE);
+  *result = string_copy_taint(flags & RET_FULL ? filename : keystring, GET_UNTAINTED);
   return OK;
   }
 
@@ -158,12 +171,13 @@ handle = handle;   /* Avoid compiler warning */
 
 #include "../version.h"
 
-void
-dsearch_version_report(FILE *f)
+gstring *
+dsearch_version_report(gstring * g)
 {
 #ifdef DYNLOOKUP
-fprintf(f, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
+g = string_fmt_append(g, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
 #endif
+return g;
 }
 
 
@@ -187,3 +201,5 @@ static lookup_info *_lookup_list[] = { &_lookup_info };
 lookup_module_info dsearch_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
 
 /* End of lookups/dsearch.c */
+/* vi: aw ai sw=2
+*/