diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-11-10 00:21:13 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-11-10 00:52:54 +0200 |
commit | 4926ea635ee23341615c351db3e4949553ca4dfb (patch) | |
tree | a1a8c4aede69cf55b5e27fa1dc1630aeeda70329 /src | |
parent | 7e4d54bd39368b36e8451d52975052c00e745f7a (diff) | |
download | mailfromd-4926ea635ee23341615c351db3e4949553ca4dfb.tar.gz mailfromd-4926ea635ee23341615c351db3e4949553ca4dfb.tar.bz2 |
Switch to libmu_dbm for DBM support.
* configure.ac (DEFAULT_DB_TYPE): New variable.
Use mu info to determine which DBM is supported.
* lib/Makefile.am (noinst_LIBRARIES): Remove libdbm.a
* lib/mf-dbm.c: remove.
* lib/mf-dbm.h: remove.
* lib/cache.c: Use libmu_dbm functions.
* lib/db.c: Likewise.
* lib/dbcfg.c: Likewise.
* lib/greylist.c: Likewise.
* lib/rate.c: Likewise.
* lib/tbf_rate.c: Likewise.
* src/builtin/db.bi: Likewise.
* src/savsrv.c: Likewise.
* src/srvcfg.c (srv_cfg_param) <database-type>: New statement.
* lib/libmf.h (config_cb_ignore): New proto.
* lib/mfdb.h (db_item_printer_t): Change signature.
* lib/utils.c (config_cb_ignore): New function.
* po/POTFILES.in: Update.
* src/Makefile.am (mailfromd_LDADD)
(calloutd_LDADD): Remove libdbm.a.
* src/calloutd.c: Update.
* src/main.c (mf_cfg_param): lock-retry-count and
lock-retry-timeout are no-op now.
* src/mfdbtool.c: Likewise.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/builtin/db.bi | 410 | ||||
-rw-r--r-- | src/calloutd.c | 2 | ||||
-rw-r--r-- | src/main.c | 52 | ||||
-rw-r--r-- | src/mfdbtool.c | 76 | ||||
-rw-r--r-- | src/savsrv.c | 1 | ||||
-rw-r--r-- | src/srvcfg.c | 19 |
7 files changed, 328 insertions, 235 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4400f8d4..af404ca5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,59 +39,56 @@ mailfromd_SOURCES = \ pragma.c\ prog.c\ prog.h\ spf.c\ stack.c\ symbols.c mailfromd_LDADD = \ ./libcallout.a\ builtin/libbuiltin.a\ ../lib/libmfdb.a\ ../lib/libmf.a\ - ../lib/libdbm.a\ ../gnu/libgnu.a\ $(MAILUTILS_LIBS)\ $(MILTER)\ $(GEOIP_LIBS)\ $(DSPAM_LIBS) noinst_HEADERS = \ bitmask.h\ callout-dbgmod.h\ mailfromd.h\ spf.h\ drivers.c\ mfd-dbgmod.h\ srvcfg.h calloutd_SOURCES = \ calloutd.c calloutd_LDADD = \ ./libcallout.a\ ../lib/libmfdb.a\ ../lib/libmf.a\ - ../lib/libdbm.a\ ../gnu/libgnu.a\ $(MAILUTILS_LIBS)\ $(MILTER) mfdbtool_SOURCES = \ mfdbtool.c mfdbtool_LDADD = \ ../lib/libmfdb.a\ ../lib/libmf.a\ - ../lib/libdbm.a\ ../gnu/libgnu.a\ $(MAILUTILS_LIBS) EXTRA_DIST = \ dbgmod.awk\ drv.awk\ gram.h\ node-tab.c\ node-type.h\ opcode.awk\ opcodes\ optab.opc\ diff --git a/src/builtin/db.bi b/src/builtin/db.bi index a734dc10..90d926eb 100644 --- a/src/builtin/db.bi +++ b/src/builtin/db.bi @@ -7,25 +7,24 @@ any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define DEFAULT_DB_MODE 0640 #include <fnmatch.h> -#include "mf-dbm.h" struct db_prop { /* Database properties */ char *pat; /* Database name pattern */ mode_t mode; /* File mode */ int null; /* Null byte */ }; static mu_list_t db_prop_list; static int db_prop_compare(const void *item, const void *data) { @@ -134,76 +133,112 @@ db_prop_lookup(const char *name) const struct db_prop *p; mu_iterator_current(itr, (void**)&p); if (strcmp(p->pat, name) == 0) { found = p; break; } else if (fnmatch(p->pat, name, 0) == 0) found = p; } mu_iterator_destroy(&itr); } return found; } + +int +_mf_dbm_open(mu_dbm_file_t *pdb, char *dbname, int access, int mode) +{ + mu_dbm_file_t db; + int rc; + int sflg = MU_FILE_SAFETY_LINKED_WRDIR | + MU_FILE_SAFETY_DIR_IWOTH; + + rc = mu_dbm_create(dbname, &db); + if (rc) + return rc; + + mu_dbm_safety_set_flags(db, + sflg | mf_file_mode_to_safety_criteria(mode)); + rc = mu_dbm_safety_check(db); + if (rc && rc != ENOENT) { + mu_error(_("%s fails safety check: %s"), + dbname, mu_strerror(rc)); + mu_dbm_destroy(&db); + return rc; + } + /* FIXME: Safety checking */ + rc = mu_dbm_open(db, access, mode); + if (rc) + return rc; + *pdb = db; + return rc; +} #define LOOKUP_NULL_BYTE 0x1 #define LOOKUP_TEST_ONLY 0x2 MF_DSEXP_SUPPRESS([<dbmap_lookup>],[< static int dbmap_lookup(eval_environ_t env, char *dbname, const char *keystr, const char *defval, int flags) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; if (!defval) defval = ""; - if (mf_dbm_open(dbname, &db, MU_STREAM_READ, 0, NULL)) + rc = _mf_dbm_open(&db, dbname, MU_STREAM_READ, 0); + if (rc) MF_THROW(mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), dbname, - mf_dbm_strerror()); + mu_strerror(rc)); memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(key) = (void*) keystr; - MF_DATUM_SIZE(key) = strlen(keystr); + key.mu_dptr = (void*) keystr; + key.mu_dsize = strlen(keystr); if (flags & LOOKUP_NULL_BYTE) - MF_DATUM_SIZE(key)++; - rc = mf_dbm_fetch(&db, key, &contents) == 0; + key.mu_dsize++; + rc = mu_dbm_fetch(db, &key, &contents); + if (rc && rc != MU_ERR_NOENT) { + mu_dbm_destroy(&db); + MF_THROW(mfe_dbfailure, + _("cannot fetch data: %s"), + mu_dbm_strerror(db)); + } MF_DEBUG(MU_DEBUG_TRACE5, - ("Looking up %s: %s", keystr, rc ? "true" : "false")); + ("Looking up %s: %s", keystr, rc ? "false" : "true")); if (flags & LOOKUP_TEST_ONLY) push(env, (STKVAL)rc); else { if (!rc) { if (defval) pushs(env, (STKVAL)defval); else push(env, 0); - } else if (((char*)MF_DATUM_PTR(contents))[MF_DATUM_SIZE(contents)-1]) { + } else if (((char*)contents.mu_dptr)[contents.mu_dsize-1]) { size_t off; - size_t len = MF_DATUM_SIZE(contents); + size_t len = contents.mu_dsize; char *s = MF_ALLOC_HEAP(off, len + 1); - memcpy(s, MF_DATUM_PTR(contents), len); + memcpy(s, contents.mu_dptr, len); s[len] = 0; push(env, (STKVAL) off); } else - pushs(env, MF_DATUM_PTR(contents)); + pushs(env, contents.mu_dptr); } - mf_dbm_datum_free(&contents); - mf_dbm_close(&db); + mu_dbm_datum_free(&contents); + mu_dbm_destroy(&db); return rc; } >]) MF_DSEXP MF_DEFUN(dbmap, NUMBER, STRING dbname, STRING key, OPTIONAL, NUMBER null) { const struct db_prop *prop = db_prop_lookup(dbname); dbmap_lookup(env, dbname, key, NULL, LOOKUP_TEST_ONLY | (MF_OPTVAL(null, prop && prop->null) ? LOOKUP_NULL_BYTE : 0)); @@ -216,151 +251,163 @@ MF_DEFUN(dbget, STRING, STRING dbname, STRING key, OPTIONAL, const struct db_prop *prop = db_prop_lookup(dbname); dbmap_lookup(env, dbname, key, MF_OPTVAL(defval), MF_OPTVAL(null, prop && prop->null) ? LOOKUP_NULL_BYTE : 0); } END MF_DEFUN(dbput, VOID, STRING dbname, STRING keystr, STRING value, OPTIONAL, NUMBER null, NUMBER mode) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; const struct db_prop *prop = db_prop_lookup(dbname); - if (mf_dbm_open(dbname, &db, MU_STREAM_RDWR, - MF_OPTVAL(mode, (prop ? prop->mode : DEFAULT_DB_MODE)), - NULL)) + rc = _mf_dbm_open(&db, dbname, MU_STREAM_RDWR, + MF_OPTVAL(mode, + (prop ? prop->mode : DEFAULT_DB_MODE))); + if (rc) MF_THROW(mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), dbname, - mf_dbm_strerror()); + mu_strerror(rc)); memset(&key, 0, sizeof key); - MF_DATUM_PTR(key) = keystr; - MF_DATUM_SIZE(key) = strlen(keystr); + key.mu_dptr = keystr; + key.mu_dsize = strlen(keystr); if (MF_OPTVAL(null, prop && prop->null)) - MF_DATUM_SIZE(key)++; + key.mu_dsize++; memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(contents) = value; - MF_DATUM_SIZE(contents) = strlen(value) + 1; + contents.mu_dptr = value; + contents.mu_dsize = strlen(value) + 1; - rc = mf_dbm_insert(&db, key, contents, 1); - mf_dbm_close(&db); - MF_ASSERT(rc == 0, - mfe_dbfailure, - _("failed to insert data to %s: %s %s: %s"), - dbname, - keystr, - value, - mf_dbm_strerror()); + rc = mu_dbm_store(db, &key, &contents, 1); + if (rc) { + const char *errstr = mu_dbm_strerror(db); + mu_dbm_destroy(&db); + MF_THROW(mfe_dbfailure, + _("failed to insert data to %s: %s %s: %s"), + dbname, + keystr, + value, + errstr); + } + mu_dbm_destroy(&db); } END MF_DEFUN(dbinsert, VOID, STRING dbname, STRING keystr, STRING value, OPTIONAL, NUMBER replace, NUMBER null, NUMBER mode) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; const struct db_prop *prop = db_prop_lookup(dbname); + const char *errstr; - if (mf_dbm_open(dbname, &db, MU_STREAM_RDWR, - MF_OPTVAL(mode, (prop ? prop->mode : DEFAULT_DB_MODE)), - NULL)) + rc = _mf_dbm_open(&db, dbname, MU_STREAM_RDWR, + MF_OPTVAL(mode, + (prop ? prop->mode : DEFAULT_DB_MODE))); + if (rc) MF_THROW(mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), dbname, - mf_dbm_strerror()); + mu_strerror(rc)); memset(&key, 0, sizeof key); - MF_DATUM_PTR(key) = keystr; - MF_DATUM_SIZE(key) = strlen(keystr); + key.mu_dptr = keystr; + key.mu_dsize = strlen(keystr); if (MF_OPTVAL(null, prop && prop->null)) - MF_DATUM_SIZE(key)++; + key.mu_dsize++; memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(contents) = value; - MF_DATUM_SIZE(contents) = strlen(value) + 1; + contents.mu_dptr = value; + contents.mu_dsize = strlen(value) + 1; - rc = mf_dbm_insert(&db, key, contents, MF_OPTVAL(replace)); - mf_dbm_close(&db); + rc = mu_dbm_store(db, &key, &contents, MF_OPTVAL(replace)); + if (rc && rc != MU_ERR_EXISTS) + errstr = mu_dbm_strerror(db); + mu_dbm_destroy(&db); if (rc == MU_ERR_EXISTS) MF_THROW(mfe_exists, _("record already exists")); MF_ASSERT(rc == 0, mfe_dbfailure, _("failed to insert data to %s: %s %s: %s"), dbname, keystr, value, - mf_dbm_strerror()); + errstr); } END MF_DEFUN(dbdel, VOID, STRING dbname, STRING keystr, OPTIONAL, NUMBER null, NUMBER mode) { - MF_DBM_FILE db; - MF_DBM_DATUM key; + mu_dbm_file_t db; + struct mu_dbm_datum key; int rc; const struct db_prop *prop = db_prop_lookup(dbname); - if (mf_dbm_open(dbname, &db, MU_STREAM_RDWR, - MF_OPTVAL(mode, (prop ? prop->mode : DEFAULT_DB_MODE)), - NULL)) - MF_THROW(mfe_dbfailure, - _("mf_dbm_open(%s) failed: %s"), - dbname, - mf_dbm_strerror()); + rc = _mf_dbm_open(&db, dbname, MU_STREAM_RDWR, + MF_OPTVAL(mode, + (prop ? prop->mode : DEFAULT_DB_MODE))); + MF_ASSERT(rc == 0, + mfe_dbfailure, + _("mf_dbm_open(%s) failed: %s"), + dbname, + mu_strerror(rc)); memset(&key, 0, sizeof key); - MF_DATUM_PTR(key) = keystr; - MF_DATUM_SIZE(key) = strlen(keystr); + key.mu_dptr = keystr; + key.mu_dsize = strlen(keystr); if (MF_OPTVAL(null, prop && prop->null)) - MF_DATUM_SIZE(key)++; - rc = mf_dbm_delete(&db, key); - mf_dbm_close(&db); + key.mu_dsize++; + rc = mu_dbm_delete(db, &key); + if (rc && rc != MU_ERR_FAILURE) + mu_error(_("error deleting %s from %s: %s"), + keystr, dbname, mu_dbm_strerror(db)); + mu_dbm_destroy(&db); MF_ASSERT(rc == 0, mfe_dbfailure, _("failed to delete data `%s' from `%s': %s"), keystr, dbname, - mf_dbm_strerror()); + mu_strerror(rc)); } END #define NUMDB 128 struct db_tab { int used; - MF_DBM_FILE db; - MF_DBM_DATUM key; + mu_dbm_file_t db; + struct mu_dbm_datum key; }; static void * alloc_db_tab() { return xcalloc(NUMDB, sizeof(struct db_tab)); } static void close_db_tab(struct db_tab *dbt) { if (dbt->used) { - mf_dbm_datum_free(&dbt->key); - mf_dbm_close(&dbt->db); + mu_dbm_datum_free(&dbt->key); + mu_dbm_destroy(&dbt->db); dbt->used = 0; } } static void destroy_db_tab(void *data) { int i; struct db_tab *db = data; for (i = 0; i < NUMDB; i++) close_db_tab(db + i); free(db); @@ -378,110 +425,124 @@ new_db_tab(struct db_tab *dbt) return i; } return -1; } MF_DEFUN(dbfirst, NUMBER, STRING dbname) { int rc; int n; struct db_tab *dbt = MF_GET_DATA; - MF_DBM_FILE db; - MF_DBM_DATUM key; - - if (mf_dbm_open(dbname, &db, MU_STREAM_READ, 0, NULL)) - MF_THROW(mfe_dbfailure, - _("mf_dbm_open(%s) failed: %s"), - dbname, - mf_dbm_strerror()); - rc = mf_dbm_firstkey(&db, &key); - MF_ASSERT(rc == 0, mfe_dbfailure, - _("mf_dbm_firstkey failed: %s"), - mf_dbm_strerror()); + mu_dbm_file_t db; + struct mu_dbm_datum key; + + rc = _mf_dbm_open(&db, dbname, MU_STREAM_READ, 0); + MF_ASSERT(rc == 0, + mfe_dbfailure, + _("mf_dbm_open(%s) failed: %s"), + dbname, + mu_strerror(rc)); + memset(&key, 0, sizeof key); + rc = mu_dbm_firstkey(db, &key); + if (rc) { + if (rc == MU_ERR_NOENT) { + mu_dbm_destroy(&db); + MF_RETURN(0); + } else if (rc) { + mu_dbm_destroy(&db); + MF_THROW(mfe_dbfailure, + _("mf_dbm_firstkey failed: %s"), + mu_strerror(rc)); + } + } n = new_db_tab(dbt); MF_ASSERT(n >= 0, mfe_failure, _("no more database entries available")); dbt += n; dbt->db = db; dbt->key = key; MF_RETURN(n); } END MF_DEFUN(dbnext, NUMBER, NUMBER dn) { struct db_tab *dbt = MF_GET_DATA + dn; - MF_DBM_DATUM nextkey; + struct mu_dbm_datum nextkey; int rc; MF_ASSERT(dn >= 0 && dn < NUMDB && dbt->used, mfe_range, _("invalid database descriptor")); - rc = mf_dbm_nextkey(&dbt->db, dbt->key, &nextkey); + rc = mu_dbm_nextkey(dbt->db, &nextkey); if (rc) { + if (rc == MU_ERR_FAILURE) + mu_error(_("mu_dbm_nextkey: %s"), + mu_dbm_strerror(dbt->db)); close_db_tab(dbt); MF_RETURN(0); } - mf_dbm_datum_free(&dbt->key); + mu_dbm_datum_free(&nextkey); dbt->key = nextkey; MF_RETURN(1); } END MF_DEFUN(dbkey, STRING, NUMBER dn) { size_t off, len; char *s; struct db_tab *dbt = MF_GET_DATA + dn; MF_ASSERT(dn >= 0 && dn < NUMDB && dbt->used, mfe_range, _("invalid database descriptor")); - len = MF_DATUM_SIZE(dbt->key); + len = dbt->key.mu_dsize; s = MF_ALLOC_HEAP(off, len + 1); - memcpy(s, MF_DATUM_PTR(dbt->key), len); + memcpy(s, dbt->key.mu_dptr, len); s[len] = 0; MF_RETURN(off); } END MF_DEFUN(dbvalue, STRING, NUMBER dn) { int rc; size_t off, len; char *s; struct db_tab *dbt = MF_GET_DATA + dn; - MF_DBM_DATUM contents; + struct mu_dbm_datum contents; MF_ASSERT(dn >= 0 && dn < NUMDB && dbt->used, mfe_range, _("invalid database descriptor")); memset(&contents, 0, sizeof contents); - rc = mf_dbm_fetch(&dbt->db, dbt->key, &contents); + rc = mu_dbm_fetch(dbt->db, &dbt->key, &contents); MF_ASSERT(rc == 0, mfe_dbfailure, - _("key not found: %s"), - mf_dbm_strerror()); + _("cannot fetch key: %s"), + rc == MU_ERR_FAILURE ? + mu_dbm_strerror(dbt->db) : mu_strerror (rc)); - len = MF_DATUM_SIZE(contents); + len = contents.mu_dsize; s = MF_ALLOC_HEAP(off, len + 1); - memcpy(s, MF_DATUM_PTR(contents), len); + memcpy(s, contents.mu_dptr, len); s[len] = 0; - mf_dbm_datum_free(&contents); + mu_dbm_datum_free(&contents); MF_RETURN(off); } END enum greylist_semantics { greylist_traditional, greylist_ct }; static enum greylist_semantics greylist_semantics = greylist_traditional; @@ -513,113 +574,122 @@ format_timestr(time_t timestamp, char *timebuf, size_t bufsize) return timebuf; } MF_VAR(greylist_seconds_left, NUMBER); /* The traditional (aka gray's) greylist implementation: the greylist database keeps the time the greylisting was activated. */ static int do_greylist_traditional(eval_environ_t env, char *email, long interval) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; - int readonly; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; + int readonly = 0; time_t now; - rc = mf_dbm_open(greylist_format->dbname, &db, MU_STREAM_RDWR, 0600, - &readonly); + rc = _mf_dbm_open(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600); + if (rc) { + rc = _mf_dbm_open(&db, greylist_format->dbname, + MU_STREAM_READ, 0); + readonly = 1; + } MF_ASSERT(rc == 0, mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), - greylist_format->dbname, mf_dbm_strerror()); + greylist_format->dbname, mu_strerror(rc)); memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(key) = email; - MF_DATUM_SIZE(key) = strlen(email)+1; + key.mu_dptr = email; + key.mu_dsize = strlen(email)+1; time(&now); - if (mf_dbm_fetch(&db, key, &contents) == 0) { + rc = mu_dbm_fetch(db, &key, &contents); + if (rc == 0) { time_t timestamp, diff; - MF_ASSERT(MF_DATUM_SIZE(contents) == sizeof timestamp, + MF_ASSERT(contents.mu_dsize == sizeof timestamp, mfe_dbfailure, _("greylist database %s has wrong data size"), - greylist_format->dbname); + greylist_format->dbname); - timestamp = *(time_t*) MF_DATUM_PTR(contents); + timestamp = *(time_t*) contents.mu_dptr; diff = now - timestamp; if (mu_debug_level_p(debug_handle, MU_DEBUG_TRACE5)) { char timebuf[32]; mu_debug_log("%s entered greylist database on %s, " "%ld seconds ago", email, format_timestr(timestamp, timebuf, sizeof timebuf), (long) diff); } - + if (diff < interval) { diff = interval - diff; - + MF_VAR_REF(greylist_seconds_left, diff); MF_DEBUG(MU_DEBUG_TRACE6, ("%s still greylisted (for %lu sec.)", email, (unsigned long) diff)); rc = 1; } else if (diff > greylist_format->expire_interval) { MF_DEBUG(MU_DEBUG_TRACE6, ("greylist record for %s expired", email)); MF_VAR_REF(greylist_seconds_left, interval); if (!readonly) { - memcpy(MF_DATUM_PTR(contents), - &now, sizeof now); - if (mf_dbm_insert(&db, key, contents, 1)) + memcpy(contents.mu_dptr, &now, sizeof now); + rc = mu_dbm_store(db, &key, &contents, 1); + if (rc) mu_error(_("cannot insert datum `%-.*s' in " "greylist database %s: %s"), - MF_DATUM_SIZE(key), - (char*)MF_DATUM_PTR(key), + key.mu_dsize, + (char*)key.mu_dptr, greylist_format->dbname, - mf_dbm_strerror()); + rc == MU_ERR_FAILURE ? + mu_dbm_strerror(db) : + mu_strerror(rc)); } else MF_DEBUG(MU_DEBUG_TRACE6, ("database opened in readonly mode: " "not updating")); rc = 1; } else { MF_DEBUG(MU_DEBUG_TRACE6, ("%s finished greylisting period", email)); rc = 0; } - mf_dbm_datum_free(&contents); + mu_dbm_datum_free(&contents); } else if (!readonly) { MF_DEBUG(MU_DEBUG_TRACE6, ("greylisting %s", email)); MF_VAR_REF(greylist_seconds_left, interval); - MF_DATUM_PTR(contents) = (void*)&now; - MF_DATUM_SIZE(contents) = sizeof now; - if (mf_dbm_insert(&db, key, contents, 1)) + contents.mu_dptr = (void*)&now; + contents.mu_dsize = sizeof now; + rc = mu_dbm_store(db, &key, &contents, 1); + if (rc) mu_error(_("Cannot insert datum `%-.*s' in greylist " "database %s: %s"), - MF_DATUM_SIZE(key), (char*)MF_DATUM_PTR(key), + key.mu_dsize, (char*)key.mu_dptr, greylist_format->dbname, - mf_dbm_strerror()); + rc == MU_ERR_FAILURE ? + mu_dbm_strerror(db) : mu_strerror(rc)); rc = 1; } else rc = 0; - mf_dbm_close(&db); + mu_dbm_destroy(&db); return rc; } /* Implementation of the is_greylisted predicate has no sense for traditional greylist databases, because greylisting interval is not known beforehand. FIXME: keep the reference below up to date. */ static int is_greylisted_traditional(eval_environ_t env, char *email) { @@ -629,150 +699,164 @@ is_greylisted_traditional(eval_environ_t env, char *email) "4.12.1.23", "Greylisting functions"); return 0; } /* New greylist implementation (by Con Tassios): the database keeps the time the greylisting period is set to expire (`interval' seconds from now) */ static int do_greylist_ct(eval_environ_t env, char *email, long interval) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; - int readonly; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; + int readonly = 0; time_t now; - rc = mf_dbm_open(greylist_format->dbname, &db, MU_STREAM_RDWR, 0600, - &readonly); + rc = _mf_dbm_open(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600); + if (rc) { + rc = _mf_dbm_open(&db, greylist_format->dbname, + MU_STREAM_READ, 0); + readonly = 1; + } MF_ASSERT(rc == 0, mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), - greylist_format->dbname, mf_dbm_strerror()); + greylist_format->dbname, mu_strerror(rc)); memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(key) = email; - MF_DATUM_SIZE(key) = strlen(email)+1; + key.mu_dptr = email; + key.mu_dsize = strlen(email) + 1; time(&now); - if (mf_dbm_fetch(&db, key, &contents) == 0) { + rc = mu_dbm_fetch(db, &key, &contents); + if (rc == 0) { time_t timestamp; - MF_ASSERT(MF_DATUM_SIZE(contents) == sizeof timestamp, + MF_ASSERT(contents.mu_dsize == sizeof timestamp, mfe_dbfailure, _("greylist database %s has wrong data size"), greylist_format->dbname); - timestamp = *(time_t*) MF_DATUM_PTR(contents); + timestamp = *(time_t*) contents.mu_dptr; if (now < timestamp) { time_t diff = timestamp - now; MF_VAR_REF(greylist_seconds_left, diff); MF_DEBUG(MU_DEBUG_TRACE6, ("%s still greylisted (for %lu sec.)", email, (unsigned long) diff)); rc = 1; } else if (now - timestamp > greylist_format->expire_interval) { MF_DEBUG(MU_DEBUG_TRACE6, ("greylist record for %s expired", email)); MF_VAR_REF(greylist_seconds_left, interval); if (!readonly) { now += interval; - memcpy(MF_DATUM_PTR(contents), - &now, sizeof now); - if (mf_dbm_insert(&db, key, contents, 1)) + memcpy(contents.mu_dptr, &now, sizeof now); + rc = mu_dbm_store(db, &key, &contents, 1); + if (rc) mu_error(_("Cannot insert datum " "`%-.*s' in greylist " "database %s: %s"), - MF_DATUM_SIZE(key), - (char*)MF_DATUM_PTR(key), + key.mu_dsize, + (char*)key.mu_dptr, greylist_format->dbname, - mf_dbm_strerror()); + rc == MU_ERR_FAILURE ? + mu_dbm_strerror(db) : + mu_strerror(rc)); } else MF_DEBUG(MU_DEBUG_TRACE6, ("database opened in readonly mode: " "not updating")); rc = 1; } else { MF_DEBUG(MU_DEBUG_TRACE6, ("%s finished greylisting period", email)); rc = 0; } - mf_dbm_datum_free(&contents); + mu_dbm_datum_free(&contents); } else if (!readonly) { MF_DEBUG(MU_DEBUG_TRACE6, ("greylisting %s", email)); MF_VAR_REF(greylist_seconds_left, interval); now += interval; - MF_DATUM_PTR(contents) = (void*)&now; - MF_DATUM_SIZE(contents) = sizeof now; - if (mf_dbm_insert(&db, key, contents, 1)) + contents.mu_dptr = (void*)&now; + contents.mu_dsize = sizeof now; + rc = mu_dbm_store(db, &key, &contents, 1); + if (rc) mu_error(_("Cannot insert datum `%-.*s' in greylist " "database %s: %s"), - MF_DATUM_SIZE(key), (char*)MF_DATUM_PTR(key), + key.mu_dsize, (char*)key.mu_dptr, greylist_format->dbname, - mf_dbm_strerror()); + rc == MU_ERR_FAILURE ? + mu_dbm_strerror(db) : mu_strerror(rc)); rc = 1; } else rc = 0; - mf_dbm_close(&db); + mu_dbm_destroy(&db); return rc; } /* The `is_greylisted' predicate for new databases */ static int is_greylisted_ct(eval_environ_t env, char *email) { int rc; - MF_DBM_FILE db; - MF_DBM_DATUM key; - MF_DBM_DATUM contents; - int readonly; + mu_dbm_file_t db; + struct mu_dbm_datum key; + struct mu_dbm_datum contents; + int readonly = 0; time_t now; - rc = mf_dbm_open(greylist_format->dbname, &db, MU_STREAM_RDWR, 0600, - &readonly); + rc = _mf_dbm_open(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600); + if (rc) { + rc = _mf_dbm_open(&db, greylist_format->dbname, + MU_STREAM_READ, 0); + readonly = 1; + } MF_ASSERT(rc == 0, mfe_dbfailure, _("mf_dbm_open(%s) failed: %s"), - greylist_format->dbname, mf_dbm_strerror()); + greylist_format->dbname, mu_strerror(rc)); memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); - MF_DATUM_PTR(key) = email; - MF_DATUM_SIZE(key) = strlen(email) + 1; + key.mu_dptr = email; + key.mu_dsize = strlen(email) + 1; time(&now); - if (mf_dbm_fetch(&db, key, &contents) == 0) { + rc = mu_dbm_fetch(db, &key, &contents); + if (rc == 0) { time_t timestamp; - MF_ASSERT(MF_DATUM_SIZE(contents) == sizeof timestamp, + MF_ASSERT(contents.mu_dsize == sizeof timestamp, mfe_dbfailure, _("greylist database %s has wrong data size"), greylist_format->dbname); - timestamp = *(time_t*) MF_DATUM_PTR(contents); + timestamp = *(time_t*) contents.mu_dptr; rc = timestamp > now; if (rc) MF_VAR_REF(greylist_seconds_left, timestamp - now); - mf_dbm_datum_free(&contents); + mu_dbm_datum_free(&contents); } else rc = 0; - mf_dbm_close(&db); + mu_dbm_destroy(&db); return rc; } struct greylist_class { int (*gl_fun)(eval_environ_t, char *, long); int (*gl_pred)(eval_environ_t, char *); }; struct greylist_class greylist_class[] = { { do_greylist_traditional, is_greylisted_traditional }, { do_greylist_ct, is_greylisted_ct } diff --git a/src/calloutd.c b/src/calloutd.c index cd054125..c3753593 100644 --- a/src/calloutd.c +++ b/src/calloutd.c @@ -30,25 +30,24 @@ #include <sysexits.h> #include <mailutils/mailutils.h> #include <mailutils/libcfg.h> #include <mailutils/libargp.h> #include <mailutils/daemon.h> #include "libmf.h" #include "callout.h" #include "srvman.h" #include "srvcfg.h" #include "mfdb.h" -#include "mf-dbm.h" void xalloc_die() { mu_error(_("not enough memory")); abort(); } static void version(FILE *stream, struct argp_state *state) { @@ -116,25 +115,24 @@ main(int argc, char **argv) mf_init_nls(); mf_proctitle_init(argc, argv, environ); if (!program_invocation_short_name) program_invocation_short_name = argv[0]; argp_program_version_hook = version; /* Set default logging */ mu_log_facility = DEFAULT_LOG_FACILITY; mu_stdstream_setup(MU_STDSTREAM_RESET_NONE); mf_srvcfg_log_setup(stderr_closed_p() ? "syslog" : "stderr"); libcallout_init(); - libdbm_init(); db_format_setup(); mf_server_save_cmdline(argc, argv); dnsbase_init(); database_cfg_init(); mu_acl_cfg_init(); srvman_init(); mf_srvcfg_init(argv[0], NULL); mu_argp_init(program_version, "<" PACKAGE_BUGREPORT ">"); mu_site_rcfile = SYSCONFDIR "/calloutd.conf"; rc = mu_app_init(&argp, capa, callout_cfg_param, argc, argv, @@ -28,32 +28,32 @@ #include <signal.h> #include <pwd.h> #include <grp.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <mailutils/mailutils.h> #include <mailutils/server.h> #include <mailutils/syslog.h> #include <mailutils/libargp.h> +#include <mailutils/dbm.h> #include "mailfromd.h" #include "callout.h" #include "srvman.h" #include "inttostr.h" #include "srvcfg.h" #include "filenames.h" -#include "mf-dbm.h" #include "builtin.h" #include "prog.h" /* Configurable options */ int mode = MAILFROMD_DAEMON; /* Default operation mode */ enum smtp_state test_state = smtp_state_envfrom; /* State for --test mode */ int need_script = 1; /* Set if the current mode requires reading the script file */ char *script_file = DEFAULT_SCRIPT_FILE; int script_check; /* Check config file syntax and exit */ @@ -909,29 +909,28 @@ struct mu_cfg_param mf_cfg_param[] = { N_("Trace executed actions.") }, { "trace-program", mu_cfg_callback, NULL, 0, cb_trace_program, N_("Enable filter program tracing."), N_("modules: list") }, { "relayed-domain-file", mu_cfg_callback, NULL, 0, cb_relayed_domain_file, N_("Read relayed domain names from the file"), N_("file: string") }, { "database", mu_cfg_section, NULL }, - { "lock-retry-count", mu_cfg_size, &lock_retry_count_option, 0, NULL, - N_("Retry acquiring DBM file lock this number of times.") }, - { "lock-retry-timeout", mu_cfg_callback, &lock_retry_timeout_option, 0, - config_cb_time_t, - N_("Set the time span between the two DBM locking attempts."), + { "lock-retry-count", mu_cfg_callback, 0, 0, config_cb_ignore, + N_("Ignored for backward compatibility.") }, + { "lock-retry-timeout", mu_cfg_callback, 0,0, config_cb_ignore, + N_("Ignored for backward compatibility."), N_("time") }, { "max-match-mx", mu_cfg_size, &max_match_mx, 0, NULL, N_("Maximum number of MXs used by MFL \"mx match\" operation.") }, { "runtime", mu_cfg_section, NULL }, { NULL } }; static struct mu_cfg_param *runtime_param; @@ -994,49 +993,73 @@ db_format_enumerator(struct db_format *fmt, void *data) printf("%s database: %s\n", fmt->name, fmt->dbname); if (strcmp(fmt->name, "cache") == 0) { printf("%s positive expiration: %lu\n", fmt->name, |