Copyright updates:
[exim.git] / src / src / dbfn.c
index 336cfe73e262119c53f3322c73af77c336de9a03..bbf20a1d5ba12ac602b7105b106142a0e2db35ae 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -72,6 +73,7 @@ Arguments:
   dbblock  Points to an open_db block to be filled in.
   lof      If TRUE, write to the log for actual open failures (locking failures
            are always logged).
+  panic           If TRUE, panic on failure to create the db directory
 
 Returns:   NULL if the open failed, or the locking failed. After locking
            failures, errno is zero.
@@ -85,7 +87,7 @@ moment I haven't changed them.
 */
 
 open_db *
-dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof)
+dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic)
 {
 int rc, save_errno;
 BOOL read_only = flags == O_RDONLY;
@@ -114,7 +116,7 @@ snprintf(CS filename, sizeof(filename), "%s/%s.lockfile", dirname, name);
 if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
   {
   created = TRUE;
-  (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, TRUE);
+  (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, panic);
   dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
   }
 
@@ -193,26 +195,29 @@ but creation of the database file failed. */
 
 if (created && geteuid() == root_uid)
   {
-  DIR *dd;
-  struct dirent *ent;
+  DIR * dd;
   uschar *lastname = Ustrrchr(filename, '/') + 1;
   int namelen = Ustrlen(name);
 
   *lastname = 0;
-  dd = opendir(CS filename);
 
-  while ((ent = readdir(dd)))
-    if (Ustrncmp(ent->d_name, name, namelen) == 0)
-      {
-      struct stat statbuf;
-      Ustrcpy(lastname, ent->d_name);
-      if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
-        {
-        DEBUG(D_hints_lookup) debug_printf_indent("ensuring %s is owned by exim\n", filename);
-        if (Uchown(filename, exim_uid, exim_gid))
-          DEBUG(D_hints_lookup) debug_printf_indent("failed setting %s to owned by exim\n", filename);
-        }
-      }
+  if ((dd = exim_opendir(filename)))
+    for (struct dirent *ent; ent = readdir(dd); )
+      if (Ustrncmp(ent->d_name, name, namelen) == 0)
+       {
+       struct stat statbuf;
+       /* Filenames from readdir() are trusted,
+       so use a taint-nonchecking copy */
+       strcpy(CS lastname, CCS ent->d_name);
+       if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
+         {
+         DEBUG(D_hints_lookup)
+           debug_printf_indent("ensuring %s is owned by exim\n", filename);
+         if (exim_chown(filename, exim_uid, exim_gid))
+           DEBUG(D_hints_lookup)
+             debug_printf_indent("failed setting %s to owned by exim\n", filename);
+         }
+       }
 
   closedir(dd);
   }
@@ -302,7 +307,7 @@ dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length)
 void *yield;
 EXIM_DATUM key_datum, result_datum;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen);
+uschar * key_copy = store_get(klen, is_tainted(key));
 
 memcpy(key_copy, key, klen);
 
@@ -315,7 +320,10 @@ EXIM_DATUM_SIZE(key_datum) = klen;
 
 if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
 
-yield = store_get(EXIM_DATUM_SIZE(result_datum));
+/* Assume the data store could have been tainted.  Properly, we should
+store the taint status with the data. */
+
+yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
 memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
 if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum);
 
@@ -346,7 +354,7 @@ dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length)
 EXIM_DATUM key_datum, value_datum;
 dbdata_generic *gptr = (dbdata_generic *)ptr;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen);
+uschar * key_copy = store_get(klen, is_tainted(key));
 
 memcpy(key_copy, key, klen);
 gptr->time_stamp = time(NULL);
@@ -380,7 +388,7 @@ int
 dbfn_delete(open_db *dbblock, const uschar *key)
 {
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen);
+uschar * key_copy = store_get(klen, is_tainted(key));
 
 DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key);
 
@@ -536,7 +544,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
       }
 
     start = clock();
-    odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE);
+    odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE, TRUE);
     stop = clock();
 
     if (odb)