constify
[exim.git] / src / src / lookups / cdb.c
index e6b1541..c9a5de1 100644 (file)
@@ -1,5 +1,3 @@
-/* $Cambridge: exim/src/src/lookups/cdb.c,v 1.2 2005/06/07 15:20:56 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
@@ -20,6 +18,9 @@
  *   Changed over to using unsigned chars
  *   Makes use of lf_check_file() for file checking
  * --------------------------------------------------------------
+ * Modified by The Exim Maintainers 2015:
+ *   const propagation
+ * --------------------------------------------------------------
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -42,7 +43,7 @@
  * cdb.[ch] it does *not* link against an external cdb library.
  *
  *
- * There are 2 varients included within this code.  One uses MMAP and
+ * There are 2 variants included within this code.  One uses MMAP and
  * should give better performance especially for multiple lookups on a
  * modern machine.  The other is the default implementation which is
  * used in the case where the MMAP fails or if MMAP was not compiled
@@ -56,7 +57,6 @@
 
 #include "../exim.h"
 #include "lf_functions.h"
-#include "cdb.h"
 
 #ifdef HAVE_MMAP
 #  include <sys/mman.h>
@@ -94,7 +94,7 @@ typedef unsigned int uint32;
  * Internal function to make hash value */
 
 static uint32
-cdb_hash(uschar *buf, unsigned int len)
+cdb_hash(const uschar *buf, unsigned int len)
 {
   uint32 h;
 
@@ -131,112 +131,114 @@ cdb_bread(int fd,
 
 /*
  * cdb_bread()
- * Internal function to parse 4 byte number (endian independant) */
+ * Internal function to parse 4 byte number (endian independent) */
 
 static uint32
 cdb_unpack(uschar *buf)
 {
-  uint32 num;
-  num =  buf[3]; num <<= 8;
-  num += buf[2]; num <<= 8;
-  num += buf[1]; num <<= 8;
-  num += buf[0];
-  return num;
+uint32 num;
+num =  buf[3]; num <<= 8;
+num += buf[2]; num <<= 8;
+num += buf[1]; num <<= 8;
+num += buf[0];
+return num;
 }
 
-void *
-cdb_open(uschar *filename,
-         uschar **errmsg)
+static void cdb_close(void *handle);
+
+static void *
+cdb_open(const uschar * filename, uschar ** errmsg)
 {
-  int fileno;
-  struct cdb_state *cdbp;
-  struct stat statbuf;
-  void * mapbuf;
-
-  fileno = Uopen(filename, O_RDONLY, 0);
-  if (fileno == -1) {
-    int save_errno = errno;
-    *errmsg = string_open_failed(errno, "%s for cdb lookup", filename);
-    errno = save_errno;
-    return NULL;
+int fileno;
+struct cdb_state *cdbp;
+struct stat statbuf;
+void * mapbuf;
+
+if ((fileno = Uopen(filename, O_RDONLY, 0)) < 0)
+  {
+  int save_errno = errno;
+  *errmsg = string_open_failed(errno, "%s for cdb lookup", filename);
+  errno = save_errno;
+  return NULL;
   }
 
-  if (fstat(fileno, &statbuf) == 0) {
-    /* If this is a valid file, then it *must* be at least
-     * CDB_HASH_TABLE bytes long */
-    if (statbuf.st_size < CDB_HASH_TABLE) {
-      int save_errno = errno;
-      *errmsg = string_open_failed(errno,
-                                  "%s too short for cdb lookup",
-                                  filename);
-      errno = save_errno;
-      return NULL;
-    }
-  } else {
-    int save_errno = errno;
-    *errmsg = string_open_failed(errno,
-                                "fstat(%s) failed - cannot do cdb lookup",
-                                filename);
-    errno = save_errno;
-    return NULL;
+if (fstat(fileno, &statbuf) != 0)
+  {
+  int save_errno = errno;
+  *errmsg = string_open_failed(errno,
+                             "fstat(%s) failed - cannot do cdb lookup",
+                             filename);
+  errno = save_errno;
+  return NULL;
+  }
+
+/* If this is a valid file, then it *must* be at least
+CDB_HASH_TABLE bytes long */
+
+if (statbuf.st_size < CDB_HASH_TABLE)
+  {
+  int save_errno = errno;
+  *errmsg = string_open_failed(errno,
+                             "%s too short for cdb lookup",
+                             filename);
+  errno = save_errno;
+  return NULL;
   }
 
-  /* Having got a file open we need the structure to put things in */
-  cdbp = store_get(sizeof(struct cdb_state));
-  /* store_get() does not return if memory was not available... */
-  /* preload the structure.... */
-  cdbp->fileno = fileno;
-  cdbp->filelen = statbuf.st_size;
-  cdbp->cdb_map = NULL;
-  cdbp->cdb_offsets = NULL;
+/* Having got a file open we need the structure to put things in */
+cdbp = store_get(sizeof(struct cdb_state), FALSE);
+/* store_get() does not return if memory was not available... */
+/* preload the structure.... */
+cdbp->fileno = fileno;
+cdbp->filelen = statbuf.st_size;
+cdbp->cdb_map = NULL;
+cdbp->cdb_offsets = NULL;
 
-  /* if we are allowed to we use mmap here.... */
+/* if we are allowed to we use mmap here.... */
 #ifdef HAVE_MMAP
-  mapbuf = mmap(NULL,
-               statbuf.st_size,
-               PROT_READ,
-               MAP_SHARED,
-               fileno,
-               0);
-  if (mapbuf != MAP_FAILED) {
-    /* We have an mmap-ed section.  Now we can just use it */
-    cdbp->cdb_map = mapbuf;
-    /* The offsets can be set to the same value since they should
-     * effectively be cached as well
-     */
-    cdbp->cdb_offsets = mapbuf;
-
-    /* Now return the state struct */
-    return(cdbp);
-  } else {
-    /* If we got here the map failed.  Basically we can ignore
-     * this since we fall back to slower methods....
-     * However lets debug log it...
-     */
-    DEBUG(D_lookup) debug_printf("cdb mmap failed - %d\n", errno);
+if ((mapbuf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fileno, 0))
+    != MAP_FAILED)
+  {
+  /* We have an mmap-ed section.  Now we can just use it */
+  cdbp->cdb_map = mapbuf;
+  /* The offsets can be set to the same value since they should
+   * effectively be cached as well
+   */
+  cdbp->cdb_offsets = mapbuf;
+
+  /* Now return the state struct */
+  return(cdbp);
   }
+
+/* If we got here the map failed.  Basically we can ignore this since we fall
+back to slower methods....  However lets debug log it...  */
+
+DEBUG(D_lookup) debug_printf_indent("cdb mmap failed - %d\n", errno);
 #endif /* HAVE_MMAP */
 
-  /* In this case we have either not got MMAP allowed, or it failed */
-
-  /* get a buffer to stash the basic offsets in - this should speed
-   * things up a lot - especially on multiple lookups */
-  cdbp->cdb_offsets = store_get(CDB_HASH_TABLE);
-
-  /* now fill the buffer up... */
-  if (cdb_bread(fileno, cdbp->cdb_offsets, CDB_HASH_TABLE) == -1) {
-    /* read of hash table failed, oh dear, oh.....
-     * time to give up I think....
-     * call the close routine (deallocs the memory), and return NULL */
-    *errmsg = string_open_failed(errno,
-                                "cannot read header from %s for cdb lookup",
-                                filename);
-    cdb_close(cdbp);
-    return NULL;
+/* In this case we have either not got MMAP allowed, or it failed */
+
+/* get a buffer to stash the basic offsets in - this should speed
+things up a lot - especially on multiple lookups */
+
+cdbp->cdb_offsets = store_get(CDB_HASH_TABLE, FALSE);
+
+/* now fill the buffer up... */
+
+if (cdb_bread(fileno, cdbp->cdb_offsets, CDB_HASH_TABLE) == -1)
+  {
+  /* read of hash table failed, oh dear, oh.....  time to give up I think....
+  call the close routine (deallocs the memory), and return NULL */
+
+  *errmsg = string_open_failed(errno,
+                             "cannot read header from %s for cdb lookup",
+                             filename);
+  cdb_close(cdbp);
+  return NULL;
   }
 
-  /* Everything else done - return the cache structure */
-  return cdbp;
+/* Everything else done - return the cache structure */
+return cdbp;
 }
 
 
@@ -245,23 +247,13 @@ cdb_open(uschar *filename,
 *             Check entry point                  *
 *************************************************/
 
-BOOL
-cdb_check(void *handle,
-         uschar *filename,
-         int modemask,
-         uid_t *owners,
-         gid_t *owngroups,
-         uschar **errmsg)
+static BOOL
+cdb_check(void * handle, const uschar * filename, int modemask,
+  uid_t * owners, gid_t * owngroups, uschar ** errmsg)
 {
-  struct cdb_state * cdbp = handle;
-  return lf_check_file(cdbp->fileno,
-                       filename,
-                       S_IFREG,
-                       modemask,
-                       owners,
-                       owngroups,
-                       "cdb",
-                       errmsg) == 0;
+struct cdb_state * cdbp = handle;
+return lf_check_file(cdbp->fileno, filename, S_IFREG, modemask,
+                    owners, owngroups, "cdb", errmsg) == 0;
 }
 
 
@@ -270,144 +262,176 @@ cdb_check(void *handle,
 *              Find entry point                  *
 *************************************************/
 
-int
-cdb_find(void *handle,
-        uschar *filename,
-        uschar *keystring,
-        int  key_len,
-        uschar **result,
-        uschar **errmsg,
-        BOOL *do_cache)
+static int
+cdb_find(void * handle, const uschar * filename, const uschar * keystring,
+  int key_len, uschar ** result, uschar ** errmsg, uint * do_cache)
 {
-  struct cdb_state * cdbp = handle;
-  uint32 item_key_len,
-    item_dat_len,
-    key_hash,
-    item_hash,
-    item_posn,
-    cur_offset,
-    end_offset,
-    hash_offset_entry,
-    hash_offset,
-    hash_offlen,
-    hash_slotnm;
-  int loop;
-
-  /* Keep picky compilers happy */
-  do_cache = do_cache;
-
-  key_hash = cdb_hash((uschar *)keystring, key_len);
-
-  hash_offset_entry = CDB_HASH_ENTRY * (key_hash & CDB_HASH_MASK);
-  hash_offset = cdb_unpack(cdbp->cdb_offsets + hash_offset_entry);
-  hash_offlen = cdb_unpack(cdbp->cdb_offsets + hash_offset_entry + 4);
-
-  /* If the offset length is zero this key cannot be in the file */
-  if (hash_offlen == 0) {
-    return FAIL;
-  }
-  hash_slotnm = (key_hash >> 8) % hash_offlen;
-
-  /* check to ensure that the file is not corrupt
-   * if the hash_offset + (hash_offlen * CDB_HASH_ENTRY) is longer
-   * than the file, then we have problems.... */
-  if ((hash_offset + (hash_offlen * CDB_HASH_ENTRY)) > cdbp->filelen) {
-    *errmsg = string_sprintf("cdb: corrupt cdb file %s (too short)",
-                            filename);
-    DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
-    return DEFER;
+struct cdb_state * cdbp = handle;
+uint32 item_key_len,
+item_dat_len,
+key_hash,
+item_hash,
+item_posn,
+cur_offset,
+end_offset,
+hash_offset_entry,
+hash_offset,
+hash_offlen,
+hash_slotnm;
+
+/* Keep picky compilers happy */
+do_cache = do_cache;
+
+key_hash = cdb_hash(keystring, key_len);
+
+hash_offset_entry = CDB_HASH_ENTRY * (key_hash & CDB_HASH_MASK);
+hash_offset = cdb_unpack(cdbp->cdb_offsets + hash_offset_entry);
+hash_offlen = cdb_unpack(cdbp->cdb_offsets + hash_offset_entry + 4);
+
+/* If the offset length is zero this key cannot be in the file */
+
+if (hash_offlen == 0)
+  return FAIL;
+
+hash_slotnm = (key_hash >> 8) % hash_offlen;
+
+/* check to ensure that the file is not corrupt
+ * if the hash_offset + (hash_offlen * CDB_HASH_ENTRY) is longer
+ * than the file, then we have problems.... */
+
+if ((hash_offset + (hash_offlen * CDB_HASH_ENTRY)) > cdbp->filelen)
+  {
+  *errmsg = string_sprintf("cdb: corrupt cdb file %s (too short)",
+                     filename);
+  DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
+  return DEFER;
   }
 
-  cur_offset = hash_offset + (hash_slotnm * CDB_HASH_ENTRY);
-  end_offset = hash_offset + (hash_offlen * CDB_HASH_ENTRY);
-  /* if we are allowed to we use mmap here.... */
+cur_offset = hash_offset + (hash_slotnm * CDB_HASH_ENTRY);
+end_offset = hash_offset + (hash_offlen * CDB_HASH_ENTRY);
+
+/* if we are allowed to we use mmap here.... */
+
 #ifdef HAVE_MMAP
-  /* make sure the mmap was OK */
-  if (cdbp->cdb_map != NULL) {
-    uschar * cur_pos = cur_offset + cdbp->cdb_map;
-    uschar * end_pos = end_offset + cdbp->cdb_map;
-    for (loop = 0; (loop < hash_offlen); ++loop) {
-      item_hash = cdb_unpack(cur_pos);
-      cur_pos += 4;
-      item_posn = cdb_unpack(cur_pos);
-      cur_pos += 4;
-      /* if the position is zero then we have a definite miss */
-      if (item_posn == 0)
-       return FAIL;
-
-      if (item_hash == key_hash) {
-       /* matching hash value */
-       uschar * item_ptr = cdbp->cdb_map + item_posn;
-       item_key_len = cdb_unpack(item_ptr);
-       item_ptr += 4;
-       item_dat_len = cdb_unpack(item_ptr);
-       item_ptr += 4;
-       /* check key length matches */
-       if (item_key_len == key_len) {
-         /* finally check if key matches */
-         if (Ustrncmp(keystring, item_ptr, key_len) == 0) {
-           /* we have a match....
-            * make item_ptr point to data */
-           item_ptr += item_key_len;
-           /* ... and the returned result */
-           *result = store_get(item_dat_len + 1);
-           memcpy(*result, item_ptr, item_dat_len);
-           (*result)[item_dat_len] = 0;
-           return OK;
-         }
-       }
-      }
-      /* handle warp round of table */
-      if (cur_pos == end_pos)
-       cur_pos = cdbp->cdb_map + hash_offset;
-    }
-    /* looks like we failed... */
-    return FAIL;
-  }
-#endif /* HAVE_MMAP */
-  for (loop = 0; (loop < hash_offlen); ++loop) {
-    uschar packbuf[8];
-    if (lseek(cdbp->fileno, (off_t) cur_offset,SEEK_SET) == -1) return DEFER;
-    if (cdb_bread(cdbp->fileno, packbuf,8) == -1) return DEFER;
-    item_hash = cdb_unpack(packbuf);
-    item_posn = cdb_unpack(packbuf + 4);
+/* make sure the mmap was OK */
+if (cdbp->cdb_map != NULL)
+  {
+  uschar * cur_pos = cur_offset + cdbp->cdb_map;
+  uschar * end_pos = end_offset + cdbp->cdb_map;
+
+  for (int loop = 0; (loop < hash_offlen); ++loop)
+    {
+    item_hash = cdb_unpack(cur_pos);
+    cur_pos += 4;
+    item_posn = cdb_unpack(cur_pos);
+    cur_pos += 4;
+
     /* if the position is zero then we have a definite miss */
+
     if (item_posn == 0)
       return FAIL;
 
-    if (item_hash == key_hash) {
-      /* matching hash value */
-      if (lseek(cdbp->fileno, (off_t) item_posn, SEEK_SET) == -1) return DEFER;
-      if (cdb_bread(cdbp->fileno, packbuf, 8) == -1) return DEFER;
-      item_key_len = cdb_unpack(packbuf);
+    if (item_hash == key_hash)
+      {                                        /* matching hash value */
+      uschar * item_ptr = cdbp->cdb_map + item_posn;
+
+      item_key_len = cdb_unpack(item_ptr);
+      item_ptr += 4;
+      item_dat_len = cdb_unpack(item_ptr);
+      item_ptr += 4;
+
       /* check key length matches */
-      if (item_key_len == key_len) {
-       /* finally check if key matches */
-       uschar * item_key = store_get(key_len);
-       if (cdb_bread(cdbp->fileno, item_key, key_len) == -1) return DEFER;
-       if (Ustrncmp(keystring, item_key, key_len) == 0) {
-         /* Reclaim some store */
-         store_reset(item_key);
-         /* matches - get data length */
-         item_dat_len = cdb_unpack(packbuf + 4);
-         /* then we build a new result string */
-         *result = store_get(item_dat_len + 1);
-         if (cdb_bread(cdbp->fileno, *result, item_dat_len) == -1)
-           return DEFER;
-         (*result)[item_dat_len] = 0;
-         return OK;
-       }
-       /* Reclaim some store */
-       store_reset(item_key);
+
+      if (item_key_len == key_len)
+       {
+        /* finally check if key matches */
+        if (Ustrncmp(keystring, item_ptr, key_len) == 0)
+          {
+          /* we have a match....  * make item_ptr point to data */
+
+          item_ptr += item_key_len;
+
+          /* ... and the returned result.  Assume it is not
+          tainted, lacking any way of telling.  */
+
+          *result = store_get(item_dat_len + 1, FALSE);
+          memcpy(*result, item_ptr, item_dat_len);
+          (*result)[item_dat_len] = 0;
+          return OK;
+          }
+       }
       }
+    /* handle warp round of table */
+    if (cur_pos == end_pos)
+    cur_pos = cdbp->cdb_map + hash_offset;
     }
-    cur_offset += 8;
+  /* looks like we failed... */
+  return FAIL;
+  }
 
-    /* handle warp round of table */
-    if (cur_offset == end_offset)
-      cur_offset = hash_offset;
+#endif /* HAVE_MMAP */
+
+for (int loop = 0; (loop < hash_offlen); ++loop)
+  {
+  uschar packbuf[8];
+
+  if (lseek(cdbp->fileno, (off_t) cur_offset, SEEK_SET) == -1) return DEFER;
+  if (cdb_bread(cdbp->fileno, packbuf, 8) == -1) return DEFER;
+
+  item_hash = cdb_unpack(packbuf);
+  item_posn = cdb_unpack(packbuf + 4);
+
+  /* if the position is zero then we have a definite miss */
+
+  if (item_posn == 0)
+    return FAIL;
+
+  if (item_hash == key_hash)
+    {                                          /* matching hash value */
+    if (lseek(cdbp->fileno, (off_t) item_posn, SEEK_SET) == -1) return DEFER;
+    if (cdb_bread(cdbp->fileno, packbuf, 8) == -1) return DEFER;
+
+    item_key_len = cdb_unpack(packbuf);
+
+    /* check key length matches */
+
+    if (item_key_len == key_len)
+      {                                        /* finally check if key matches */
+      rmark reset_point = store_mark();
+      uschar * item_key = store_get(key_len, TRUE); /* keys liable to be tainted */
+
+      if (cdb_bread(cdbp->fileno, item_key, key_len) == -1) return DEFER;
+      if (Ustrncmp(keystring, item_key, key_len) == 0)
+        {
+        /* Reclaim some store */
+        store_reset(reset_point);
+
+        /* matches - get data length */
+        item_dat_len = cdb_unpack(packbuf + 4);
+
+        /* then we build a new result string.  We know we have enough
+        memory so disable Coverity errors about the tainted item_dat_ken */
+
+        *result = store_get(item_dat_len + 1, FALSE);
+        /* coverity[tainted_data] */
+        if (cdb_bread(cdbp->fileno, *result, item_dat_len) == -1)
+         return DEFER;
+
+        /* coverity[tainted_data] */
+        (*result)[item_dat_len] = 0;
+        return OK;
+        }
+      /* Reclaim some store */
+      store_reset(reset_point);
+      }
+    }
+  cur_offset += 8;
+
+  /* handle warp round of table */
+  if (cur_offset == end_offset)
+  cur_offset = hash_offset;
   }
-  return FAIL;
+return FAIL;
 }
 
 
@@ -418,20 +442,59 @@ cdb_find(void *handle,
 
 /* See local README for interface description */
 
-void
+static void
 cdb_close(void *handle)
 {
 struct cdb_state * cdbp = handle;
 
 #ifdef HAVE_MMAP
- if (cdbp->cdb_map) {
-   munmap(CS cdbp->cdb_map, cdbp->filelen);
-   if (cdbp->cdb_map == cdbp->cdb_offsets)
+if (cdbp->cdb_map)
+  {
+  munmap(CS cdbp->cdb_map, cdbp->filelen);
+  if (cdbp->cdb_map == cdbp->cdb_offsets)
      cdbp->cdb_offsets = NULL;
- }
 }
 #endif /* HAVE_MMAP */
 
- close(cdbp->fileno);
+(void)close(cdbp->fileno);
 }
 
+
+
+/*************************************************
+*         Version reporting entry point          *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+cdb_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: CDB: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
+lookup_info cdb_lookup_info = {
+  US"cdb",                       /* lookup name */
+  lookup_absfile,                /* uses absolute file name */
+  cdb_open,                      /* open function */
+  cdb_check,                     /* check function */
+  cdb_find,                      /* find function */
+  cdb_close,                     /* close function */
+  NULL,                          /* no tidy function */
+  NULL,                          /* no quoting function */
+  cdb_version_report             /* version reporting */
+};
+
+#ifdef DYNLOOKUP
+#define cdb_lookup_module_info _lookup_module_info
+#endif
+
+static lookup_info *_lookup_list[] = { &cdb_lookup_info };
+lookup_module_info cdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
+
 /* End of lookups/cdb.c */