Experimental: ESMTP LIMITS extension
[exim.git] / src / src / dbfn.c
index bbf20a1d5ba12ac602b7105b106142a0e2db35ae..0f56ad5a61fa88187b2ffb4fde187cb9dcfb37ad 100644 (file)
@@ -9,6 +9,11 @@
 
 #include "exim.h"
 
+/* We have buffers holding path names for database files.
+PATH_MAX could be used here, but would be wasting memory, as we deal
+with database files like $spooldirectory/db/<name> */
+#define PATHLEN 256
+
 
 /* Functions for accessing Exim's hints database, which consists of a number of
 different DBM files. This module does not contain code for reading DBM files
@@ -93,7 +98,7 @@ int rc, save_errno;
 BOOL read_only = flags == O_RDONLY;
 BOOL created = FALSE;
 flock_t lock_data;
-uschar dirname[256], filename[256];
+uschar dirname[PATHLEN], filename[PATHLEN];
 
 DEBUG(D_hints_lookup) acl_level++;
 
@@ -123,7 +128,7 @@ if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
 if (dbblock->lockfd < 0)
   {
   log_write(0, LOG_MAIN, "%s",
-    string_open_failed(errno, "database lock file %s", filename));
+    string_open_failed("database lock file %s", filename));
   errno = 0;      /* Indicates locking failure */
   DEBUG(D_hints_lookup) acl_level--;
   return NULL;
@@ -196,12 +201,15 @@ but creation of the database file failed. */
 if (created && geteuid() == root_uid)
   {
   DIR * dd;
-  uschar *lastname = Ustrrchr(filename, '/') + 1;
+  uschar path[PATHLEN];
+  uschar *lastname;
   int namelen = Ustrlen(name);
 
+  Ustrcpy(path, filename);
+  lastname = Ustrrchr(path, '/') + 1;
   *lastname = 0;
 
-  if ((dd = exim_opendir(filename)))
+  if ((dd = exim_opendir(path)))
     for (struct dirent *ent; ent = readdir(dd); )
       if (Ustrncmp(ent->d_name, name, namelen) == 0)
        {
@@ -209,13 +217,13 @@ if (created && geteuid() == root_uid)
        /* 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)
+       if (Ustat(path, &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_printf_indent("ensuring %s is owned by exim\n", path);
+         if (exim_chown(path, exim_uid, exim_gid))
            DEBUG(D_hints_lookup)
-             debug_printf_indent("failed setting %s to owned by exim\n", filename);
+             debug_printf_indent("failed setting %s to owned by exim\n", path);
          }
        }
 
@@ -228,12 +236,13 @@ exist. */
 
 if (!dbblock->dbptr)
   {
+  errno = save_errno;
   if (lof && save_errno != ENOENT)
-    log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
+    log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s",
         filename));
   else
     DEBUG(D_hints_lookup)
-      debug_printf_indent("%s\n", CS string_open_failed(save_errno, "DB file %s",
+      debug_printf_indent("%s\n", CS string_open_failed("DB file %s",
           filename));
   (void)close(dbblock->lockfd);
   errno = save_errno;
@@ -332,6 +341,34 @@ return yield;
 }
 
 
+/* Read a record.  If the length is not as expected then delete it, write
+an error log line, delete the record and return NULL.
+Use this for fixed-size records (so not retry or wait records).
+
+Arguments:
+  dbblock   a pointer to an open database block
+  key       the key of the record to be read
+  length    the expected record length
+
+Returns: a pointer to the retrieved record, or
+         NULL if the record is not found/bad
+*/
+
+void *
+dbfn_read_enforce_length(open_db * dbblock, const uschar * key, size_t length)
+{
+int rlen;
+void * yield = dbfn_read_with_length(dbblock, key, &rlen);
+
+if (yield)
+  {
+  if (rlen == length) return yield;
+  log_write(0, LOG_MAIN|LOG_PANIC, "Bad db record size for '%s'", key);
+  dbfn_delete(dbblock, key);
+  }
+return NULL;
+}
+
 
 /*************************************************
 *             Write to database file             *
@@ -423,7 +460,6 @@ dbfn_scan(open_db *dbblock, BOOL start, EXIM_CURSOR **cursor)
 {
 EXIM_DATUM key_datum, value_datum;
 uschar *yield;
-value_datum = value_datum;    /* dummy; not all db libraries use this */
 
 DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n");