Back to index

opendkim  2.6.6
opendkim-db.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2008 Sendmail, Inc. and its suppliers.
00003 **     All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2012, The OpenDKIM Project.  All rights reserved.
00006 **
00007 **  $Id: opendkim-db.c,v 1.101.10.1 2010/10/27 21:43:09 cm-msk Exp $
00008 */
00009 
00010 #ifndef lint
00011 static char opendkim_db_c_id[] = "@(#)$Id: opendkim-db.c,v 1.101.10.1 2010/10/27 21:43:09 cm-msk Exp $";
00012 #endif /* !lint */
00013 
00014 #include "build-config.h"
00015 
00016 /* for Solaris */
00017 #ifndef _REENTRANT
00018 # define _REENTRANT
00019 #endif /* ! _REENTRANT */
00020 
00021 /* system includes */
00022 #include <sys/types.h>
00023 #include <sys/uio.h>
00024 #include <sys/stat.h>
00025 #include <sys/file.h>
00026 #ifdef HAVE_STDBOOL_H
00027 # include <stdbool.h>
00028 #endif /* HAVE_STDBOOL_H */
00029 #include <syslog.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <errno.h>
00033 #include <unistd.h>
00034 #include <fcntl.h>
00035 #include <assert.h>
00036 #include <ctype.h>
00037 #include <pthread.h>
00038 #include <stdio.h>
00039 #include <regex.h>
00040 
00041 /* libopendkim includes */
00042 #include <dkim.h>
00043 #include <dkim-strl.h>
00044 
00045 /* repute includes */
00046 #ifdef _FFR_REPUTATION
00047 # include <repute.h>
00048 #endif /* _FFR_REPUTATION */
00049 
00050 /* opendkim includes */
00051 #include "util.h"
00052 #ifdef OPENDKIM_DB_ONLY
00053 # undef USE_LDAP
00054 # undef USE_SASL
00055 # undef USE_ODBX
00056 # undef USE_LUA
00057 # undef _FFR_SOCKETDB
00058 #endif /* OPENDKIM_DB_ONLY */
00059 #include "opendkim-db.h"
00060 #ifdef USE_LUA
00061 # include "opendkim-lua.h"
00062 #endif /* USE_LUA */
00063 #include "opendkim.h"
00064 
00065 /* various DB library includes */
00066 #ifdef _FFR_SOCKETDB
00067 # include <sys/socket.h>
00068 # include <sys/un.h>
00069 # include <netinet/in.h>
00070 # include <arpa/inet.h>
00071 #endif /* _FFR_SOCKETDB */
00072 #ifdef USE_DB
00073 # include <db.h>
00074 #endif /* USE_DB */
00075 #ifdef USE_ODBX
00076 # include <odbx.h>
00077 #endif /* USE_ODBX */
00078 #ifdef USE_LDAP
00079 # include <ldap.h>
00080 #endif /* USE_LDAP */
00081 #ifdef USE_SASL
00082 # include <sasl/sasl.h>
00083 #endif /* USE_SASL */
00084 #ifdef USE_LUA
00085 # include <lua.h>
00086 #endif /* USE_LUA */
00087 #ifdef USE_LIBMEMCACHED
00088 # include <libmemcached/memcached.h>
00089 #endif /* USE_LIBMEMCACHED */
00090 #ifdef USE_MDB
00091 # include <mdb.h>
00092 #endif /* USE_MDB */
00093 #ifdef USE_ERLANG
00094 # include <sys/time.h>
00095 # include <erl_interface.h>
00096 # include <ei.h>
00097 #endif /* USE_ERLANG */
00098 
00099 /* macros */
00100 #define       BUFRSZ               1024
00101 #define       DEFARRAYSZ           16
00102 #ifdef _FFR_DB_HANDLE_POOLS
00103 # define DEFPOOLMAX         10
00104 #endif /* _FFR_DB_HANDLE_POOLS */
00105 #define DKIMF_DB_DEFASIZE   8
00106 #define DKIMF_DB_MODE              0644
00107 #define DKIMF_LDAP_MAXURIS  8
00108 #define DKIMF_LDAP_DEFTIMEOUT      5
00109 #ifdef _FFR_LDAP_CACHING
00110 # define DKIMF_LDAP_TTL            600
00111 #endif /* _FFR_LDAP_CACHING */
00112 #ifdef _FFR_SOCKETDB
00113 # define DKIMF_SOCKET_TIMEOUT      5
00114 #endif /* _FFR_SOCKETDB */
00115 
00116 #define       DKIMF_DB_IFLAG_FREEARRAY 0x01
00117 #define       DKIMF_DB_IFLAG_RECONNECT 0x02
00118 
00119 #ifndef FALSE
00120 # define FALSE                     0
00121 #endif /* ! FALSE */
00122 #ifndef TRUE
00123 # define TRUE               1
00124 #endif /* ! TRUE */
00125 
00126 #ifndef MAX
00127 # define MAX(x,y)    ((x) > (y) ? (x) : (y))
00128 #endif /* ! MAX */
00129 
00130 #define STRORNULL(x) ((x)[0] == '\0' ? NULL : (x))
00131 
00132 #ifdef USE_DB
00133 # ifndef DB_NOTFOUND
00134 #  define DB_NOTFOUND              1
00135 # endif /* ! DB_NOTFOUND */
00136 # ifndef DB_VERSION_MAJOR
00137 #  define DB_VERSION_MAJOR  1
00138 # endif /* ! DB_VERSION_MAJOR */
00139 
00140 # define DB_VERSION_CHECK(x,y,z) ((DB_VERSION_MAJOR == (x) && \
00141                                DB_VERSION_MINOR == (y) && \
00142                                DB_VERSION_PATCH >= (z)) || \
00143                               (DB_VERSION_MAJOR == (x) && \
00144                                DB_VERSION_MINOR > (y)) || \
00145                               DB_VERSION_MAJOR > (x))
00146 
00147 # if DB_VERSION_CHECK(3,0,0)
00148 #  define DB_STRERROR(x)    db_strerror(x)
00149 # else /* DB_VERSION_CHECK(3,0,0) */
00150 #  define DB_STRERROR(x)    strerror(errno)
00151 # endif /* DB_VERSION_CHECK(3,0,0) */
00152 
00153 # if DB_VERSION_MAJOR < 2
00154 #  define DKIMF_DBCLOSE(db) (db)->close((db))
00155 # else /* DB_VERSION_MAJOR < 2 */
00156 #  define DKIMF_DBCLOSE(db) (db)->close((db), 0)
00157 # endif /* DB_VERSION_MAJOR < 2 */
00158 #endif /* USE_DB */
00159 
00160 /* macros */
00161 #ifndef MIN
00162 # define MIN(x,y)       ((x) < (y) ? (x) : (y))
00163 #endif /* ! MIN */
00164 
00165 /* data types */
00166 struct dkimf_db
00167 {
00168        u_int                db_flags;
00169        u_int                db_iflags;
00170        u_int                db_type;
00171        int                  db_status;
00172        int                  db_nrecs;
00173        pthread_mutex_t *    db_lock;
00174        void *               db_handle;    /* handler handle */
00175        void *               db_data;      /* dkimf_db handle */
00176        void *               db_cursor;    /* cursor */
00177        void *               db_entry;     /* entry (context) */
00178        char **                     db_array;
00179 };
00180 
00181 struct dkimf_db_table
00182 {
00183        char *               name;
00184        int                  code;
00185 };
00186 
00187 struct dkimf_db_list
00188 {
00189        char *               db_list_key;
00190        char *               db_list_value;
00191        struct dkimf_db_list *      db_list_next;
00192 };
00193 
00194 struct dkimf_db_relist
00195 {
00196        regex_t                     db_relist_re;
00197        char *               db_relist_data;
00198        struct dkimf_db_relist * db_relist_next;
00199 };
00200 
00201 #ifdef USE_ODBX
00202 struct dkimf_db_dsn
00203 {
00204        char                 dsn_backend[BUFRSZ];
00205        char                 dsn_datacol[BUFRSZ];
00206        char                 dsn_dbase[BUFRSZ];
00207        char                 dsn_host[BUFRSZ];
00208        char                 dsn_keycol[BUFRSZ];
00209        char                 dsn_password[BUFRSZ];
00210        char                 dsn_port[BUFRSZ];
00211        char                 dsn_table[BUFRSZ];
00212        char                 dsn_user[BUFRSZ];
00213        const char *         dsn_filter;
00214 };
00215 #endif /* USE_ODBX */
00216 
00217 #ifdef USE_LDAP
00218 struct dkimf_db_ldap
00219 {
00220        int                  ldap_timeout;
00221        char                 ldap_urilist[BUFRSZ];
00222        LDAPURLDesc *        ldap_descr;
00223 # ifdef _FFR_LDAP_CACHING
00224 #  ifdef USE_DB
00225        DKIMF_DB             ldap_cache;
00226 #  endif /* USE_DB */
00227 # endif /* _FFR_LDAP_CACHING */
00228        pthread_mutex_t             ldap_lock;
00229 };
00230 
00231 # ifdef _FFR_LDAP_CACHING
00232 #  ifdef USE_DB
00233 #   define DKIMF_DB_CACHE_DATA            0
00234 #   define DKIMF_DB_CACHE_PENDING  1
00235 struct dkimf_db_ldap_cache
00236 {
00237        _Bool                ldc_absent;
00238        int                  ldc_state;
00239        int                  ldc_nresults;
00240        int                  ldc_waiters;
00241        int                  ldc_error;
00242        time_t               ldc_expire;
00243        void *               ldc_handle;
00244        char **                     ldc_results;
00245        pthread_cond_t              ldc_cond;
00246 };
00247 #  endif /* USE_DB */
00248 # endif /* _FFR_LDAP_CACHING */
00249 #endif /* USE_LDAP */
00250 
00251 #ifdef USE_LUA
00252 struct dkimf_db_lua
00253 {
00254        char *               lua_script;
00255        size_t               lua_scriptlen;
00256        char *               lua_error;
00257 };
00258 #endif /* USE_LUA */
00259 
00260 #ifdef _FFR_REPUTATION
00261 struct dkimf_db_repute
00262 {
00263        REPUTE               repute_handle;
00264 # ifdef _FFR_REPUTATION_CACHE
00265        DKIMF_DB             repute_cache;
00266 # endif /* _FFR_REPUTATION_CACHE */
00267 };
00268 
00269 # ifdef _FFR_REPUTATION_CACHE
00270 struct dkimf_db_repute_cache
00271 {
00272        float                repcache_rep;
00273        float                repcache_conf;
00274        unsigned long        repcache_samp;
00275        unsigned long        repcache_limit;
00276        time_t               repcache_when;
00277 };
00278 # endif /* _FFR_REPUTATION_CACHE */
00279 #endif /* _FFR_REPUTATION */
00280 
00281 #ifdef _FFR_SOCKETDB
00282 struct dkimf_db_socket
00283 {
00284        int                  sockdb_fd;
00285        struct dkimf_dstring *      sockdb_buf;
00286 };
00287 #endif /* _FFR_SOCKETDB */
00288 
00289 #ifdef USE_MDB
00290 struct dkimf_db_mdb
00291 {
00292        MDB_env *            mdb_env;
00293        MDB_txn *            mdb_txn;
00294        MDB_dbi                     mdb_dbi;
00295 };
00296 #endif /* USE_MDB */
00297 
00298 #ifdef USE_ERLANG
00299 struct dkimf_db_erlang
00300 {
00301        char *               erlang_nodes;
00302        char *               erlang_module;
00303        char *               erlang_function;
00304        char *               erlang_cookie;
00305 };
00306 #endif /* USE_ERLANG */
00307 
00308 /* globals */
00309 struct dkimf_db_table dbtypes[] =
00310 {
00311        { "csl",             DKIMF_DB_TYPE_CSL },
00312        { "file",            DKIMF_DB_TYPE_FILE },
00313        { "refile",          DKIMF_DB_TYPE_REFILE },
00314 #ifdef USE_DB
00315        { "db",                     DKIMF_DB_TYPE_BDB },
00316 #endif /* USE_DB */
00317 #ifdef USE_ODBX
00318        { "dsn",             DKIMF_DB_TYPE_DSN },
00319 #endif /* USE_ODBX */
00320 #ifdef USE_LDAP
00321        { "ldap",            DKIMF_DB_TYPE_LDAP },
00322        { "ldapi",           DKIMF_DB_TYPE_LDAP },
00323        { "ldaps",           DKIMF_DB_TYPE_LDAP },
00324 #endif /* USE_LDAP */
00325 #ifdef USE_LUA
00326        { "lua",             DKIMF_DB_TYPE_LUA },
00327 #endif /* USE_LUA */
00328 #ifdef USE_LIBMEMCACHED
00329        { "memcache",        DKIMF_DB_TYPE_MEMCACHE },
00330 #endif /* USE_LIBMEMCACHED */
00331 #ifdef _FFR_REPUTATION
00332        { "repute",          DKIMF_DB_TYPE_REPUTE },
00333 #endif /* _FFR_REPUTATION */
00334 #ifdef _FFR_SOCKETDB
00335        { "socket",          DKIMF_DB_TYPE_SOCKET },
00336 #endif /* _FFR_SOCKETDB */
00337 #ifdef USE_MDB
00338        { "mdb",             DKIMF_DB_TYPE_MDB },
00339 #endif /* USE_MDB */
00340 #ifdef USE_ERLANG
00341        { "erlang",          DKIMF_DB_TYPE_ERLANG },
00342 #endif /* USE_ERLANG */
00343        { NULL,                     DKIMF_DB_TYPE_UNKNOWN },
00344 };
00345 
00346 static char *dkimf_db_ldap_param[DKIMF_LDAP_PARAM_MAX + 1];
00347 
00348 #ifdef _FFR_DB_HANDLE_POOLS
00349 struct handle_pool
00350 {
00351        u_int         hp_dbtype;
00352        u_int         hp_max;
00353        u_int         hp_alloc;
00354        u_int         hp_asize;
00355        u_int         hp_count;
00356        void *        hp_hdata;
00357        void **              hp_handles;
00358        pthread_mutex_t      hp_lock;
00359        pthread_cond_t       hp_signal;
00360 };
00361 #endif /* _FFR_DB_HANDLE_POOLS */
00362 
00363 #ifdef _FFR_DB_HANDLE_POOLS
00364 /*
00365 **  DKIMF_DB_HP_NEW -- create a handle pool
00366 **
00367 **  Parameters:
00368 **     type -- DB type
00369 **     max -- maximum pool size
00370 **     hdata -- data needed to make new handles
00371 **
00372 **  Return value:
00373 **     Pointer to a newly-allocated handle pool, or NULL on error.
00374 */
00375 
00376 static struct handle_pool *
00377 dkimf_db_hp_new(u_int type, u_int max, void *hdata)
00378 {
00379        struct handle_pool *new;
00380 
00381        new = (struct handle_pool *) malloc(sizeof *new);
00382        if (new != NULL)
00383        {
00384               new->hp_alloc = 0;
00385               new->hp_asize = 0;
00386               new->hp_count = 0;
00387               new->hp_dbtype = type;
00388               new->hp_handles = NULL;
00389               new->hp_hdata = hdata;
00390               new->hp_max = max;
00391               pthread_mutex_init(&new->hp_lock, NULL);
00392               pthread_cond_init(&new->hp_signal, NULL);
00393        }
00394 
00395        return new;
00396 }
00397 
00398 /*
00399 **  DKIMF_DB_HP_FREE -- free a handle pool
00400 **
00401 **  Parameters:
00402 **     pool -- bool to free up
00403 **
00404 **  Return value:
00405 **     None.
00406 */
00407 
00408 static void
00409 dkimf_db_hp_free(struct handle_pool *pool)
00410 {
00411        u_int c;
00412 
00413        assert(pool != NULL);
00414 
00415        for (c = 0; c < pool->hp_count; c++)
00416        {
00417               switch (pool->hp_dbtype)
00418               {
00419 #ifdef USE_ODBX
00420                 case DKIMF_DB_TYPE_DSN:
00421                 {
00422                      odbx_t *odbx;
00423 
00424                      odbx = (odbx_t *) pool->hp_handles[c];
00425 
00426                      (void) odbx_unbind(odbx);
00427                      (void) odbx_finish(odbx);
00428                      free(odbx);
00429 
00430                      break;
00431                 }
00432 #endif /* USE_ODBX */
00433 
00434                 default:
00435                      break;
00436               }
00437        }
00438 
00439        pthread_mutex_destroy(&pool->hp_lock);
00440        pthread_cond_destroy(&pool->hp_signal);
00441        free(pool->hp_handles);
00442        free(pool);
00443 }
00444 
00445 /*
00446 **  DKIMF_DB_HP_GET -- get a handle from a handle pool
00447 **
00448 **  Parameters:
00449 **     pool -- pool from which to get a handle
00450 **     err -- error code (returned)
00451 **
00452 **  Return value:
00453 **     A handle appropriate to the associated DB type that is not currently
00454 **     in use by another thread, or NULL on error.
00455 */
00456 
00457 static void *
00458 dkimf_db_hp_get(struct handle_pool *pool, int *err)
00459 {
00460        void *ret;
00461 
00462        assert(pool != NULL);
00463 
00464        pthread_mutex_lock(&pool->hp_lock);
00465 
00466        for (;;)
00467        {
00468               /* if one is available, return it */
00469               if (pool->hp_count > 0)
00470               {
00471                      ret = pool->hp_handles[0];
00472 
00473                      if (pool->hp_count > 1)
00474                      {
00475                             memmove(&pool->hp_handles[0],
00476                                     &pool->hp_handles[1],
00477                                     sizeof(void *) * (pool->hp_count - 1));
00478                      }
00479 
00480                      pool->hp_count--;
00481 
00482                      pthread_mutex_unlock(&pool->hp_lock);
00483 
00484                      return ret;
00485               }
00486 
00487               /* if we can allocate one, do so */
00488               if (pool->hp_alloc <= pool->hp_max)
00489               {
00490                      switch (pool->hp_dbtype)
00491                      {
00492 #ifdef USE_ODBX
00493                        case DKIMF_DB_TYPE_DSN:
00494                        {
00495                             int dberr;
00496                             odbx_t *odbx;
00497                             struct dkimf_db_dsn *dsn;
00498 
00499                             dsn = (struct dkimf_db_dsn *) pool->hp_hdata;
00500 
00501                             dberr = odbx_init(&odbx,
00502                                               STRORNULL(dsn->dsn_backend),
00503                                               STRORNULL(dsn->dsn_host),
00504                                               STRORNULL(dsn->dsn_port));
00505 
00506                             if (dberr < 0)
00507                             {
00508                                    if (err != NULL)
00509                                           *err = dberr;
00510 
00511                                    (void) odbx_finish(odbx);
00512                                    pthread_mutex_unlock(&pool->hp_lock);
00513 
00514                                    return NULL;
00515                             }
00516 
00517                             dberr = odbx_bind(odbx,
00518                                                     STRORNULL(dsn->dsn_dbase),
00519                                                     STRORNULL(dsn->dsn_user),
00520                                                     STRORNULL(dsn->dsn_password),
00521                                                     ODBX_BIND_SIMPLE);
00522                             if (dberr < 0)
00523                             {
00524                                    if (err != NULL)
00525                                           *err = dberr;
00526 
00527                                    (void) odbx_finish(odbx);
00528                                    pthread_mutex_unlock(&pool->hp_lock);
00529 
00530                                    return NULL;
00531                             }
00532 
00533                             ret = odbx;
00534 
00535                             break;
00536                        }
00537 #endif /* USE_ODBX */
00538 
00539                        default:
00540                             assert(0);
00541                             break;
00542                      }
00543 
00544                      pool->hp_alloc++;
00545 
00546                      pthread_mutex_unlock(&pool->hp_lock);
00547 
00548                      return ret;
00549               }
00550 
00551               /* already full; wait for one */
00552               pthread_cond_wait(&pool->hp_signal, &pool->hp_lock);
00553        }
00554 }
00555 
00556 /*
00557 **  DKIMF_DB_HP_DEAD -- report that a handle found in the pool was dead
00558 **
00559 **  Parameters:
00560 **     pool -- handle pool to be updated
00561 **
00562 **  Return value:
00563 **     None.
00564 **
00565 **  Notes:
00566 **     The caller is expected to identify a dead handle and deallocate it.
00567 */
00568 
00569 static void
00570 dkimf_db_hp_dead(struct handle_pool *pool)
00571 {
00572        assert(pool != NULL);
00573 
00574        pthread_mutex_lock(&pool->hp_lock);
00575        pool->hp_alloc--;
00576        pthread_cond_signal(&pool->hp_signal);
00577        pthread_mutex_unlock(&pool->hp_lock);
00578 }
00579 
00580 /*
00581 **  DKIMF_DB_HP_PUT -- put a handle back into a handle pool after use
00582 **
00583 **  Parameters:
00584 **     pool -- pool from which to get a handle
00585 **     handle -- handle being returned
00586 **
00587 **  Return value:
00588 **     None.
00589 */
00590 
00591 static void
00592 dkimf_db_hp_put(struct handle_pool *pool, void *handle)
00593 {
00594        assert(pool != NULL);
00595        assert(handle != NULL);
00596 
00597        pthread_mutex_lock(&pool->hp_lock);
00598 
00599        /* need to grow the array? */
00600        if (pool->hp_asize == pool->hp_count)
00601        {
00602               u_int newasz;
00603 
00604               if (pool->hp_asize == 0)
00605               {
00606                      newasz = DKIMF_DB_DEFASIZE;
00607                      pool->hp_handles = (void **) malloc(newasz * sizeof(void *));
00608                      assert(pool->hp_handles != NULL);
00609               }
00610               else
00611               {
00612                      void **newa;
00613 
00614                      newasz = pool->hp_asize * 2;
00615                      newa = (void **) realloc(pool->hp_handles,
00616                                               newasz * sizeof(void *));
00617                      assert(newa != NULL);
00618                      pool->hp_handles = newa;
00619               }
00620 
00621               pool->hp_asize = newasz;
00622        }
00623 
00624        /* append it */
00625        pool->hp_handles[pool->hp_count] = handle;
00626 
00627        /* increment the count */
00628        pool->hp_count++;
00629 
00630        /* signal any waiters */
00631        pthread_cond_signal(&pool->hp_signal);
00632 
00633        /* all done */
00634        pthread_mutex_unlock(&pool->hp_lock);
00635 }
00636 
00637 #endif /* _FFR_DB_HANDLE_POOLS */
00638 
00639 #if (USE_SASL && USE_LDAP)
00640 /*
00641 **  DKIMF_DB_SASLINTERACT -- SASL binding interaction callback
00642 **
00643 **  Parameters:
00644 **     ld -- LDAP handle (see below)
00645 **     flags -- LDAP handling flags
00646 **     defaults -- defaults pointer (see below)
00647 **     interact -- SASL interaction object
00648 **
00649 **  Return value:
00650 **     LDAP_SUCCESS (for now)
00651 **
00652 **  Notes:
00653 **     If SASL requires additional parameters that OpenLDAP didn't provide
00654 **     in its call, it uses a callback we have to provide to try to get them.
00655 **     The layering here can get quite confusing.  "defaults" is an
00656 **     application-specific handle that can point to a bunch of defaults
00657 **     set elsewhere, but we don't need it here so it's ignored.  Similarly,
00658 **     "ld" is not actually needed.
00659 */
00660 
00661 static int
00662 dkimf_db_saslinteract(LDAP *ld, unsigned int flags, void *defaults,
00663                       void *sasl_interact)
00664 {
00665        sasl_interact_t *interact;
00666 
00667        assert(sasl_interact != NULL);
00668 
00669        interact = sasl_interact;
00670 
00671        switch (interact->id)
00672        {
00673          case SASL_CB_PASS:
00674               interact->result = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_BINDPW];
00675               interact->len = strlen(interact->result);
00676               break;
00677 
00678          case SASL_CB_GETREALM:
00679               interact->result = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_AUTHREALM];
00680               interact->len = strlen(interact->result);
00681               break;
00682 
00683          case SASL_CB_AUTHNAME:
00684               interact->result = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_AUTHNAME];
00685               interact->len = strlen(interact->result);
00686               break;
00687 
00688          case SASL_CB_USER:
00689               interact->result = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_AUTHUSER];
00690               if (interact->result == NULL)
00691                      interact->len = 0;
00692               else
00693                      interact->len = strlen(interact->result);
00694               break;
00695 
00696          default:
00697               interact->result = "";
00698               interact->len = 0;
00699               break;
00700        }
00701 
00702        return SASL_OK;
00703 }
00704 #endif /* (USE_SASL && USE_LDAP) */
00705 
00706 /*
00707 **  DKIMF_DB_HEXDIGIT -- convert a hex digit to decimal value
00708 **
00709 **  Parameters:
00710 **     c -- input character
00711 **
00712 **  Return value:
00713 **     Converted value, or 0 on error.
00714 */
00715 
00716 static int
00717 dkimf_db_hexdigit(int c)
00718 {
00719        if (c >= '0' && c <= '9')
00720               return c - '0';
00721        else if (c >= 'A' && c <= 'F')
00722               return c - 'A' + 10;
00723        else if (c >= 'a' && c <= 'f')
00724               return c - 'f' + 10;
00725        else
00726               return 0;
00727 }
00728 
00729 /*
00730 **  DKIMF_DB_DATASPLIT -- split a database value or set of values into a
00731 **                        request array
00732 **
00733 **  Parameters:
00734 **     buf -- data buffer
00735 **     buflen -- buffer length
00736 **     req -- request array
00737 **     reqnum -- length of request array
00738 **
00739 **  Return value:
00740 **     0 -- successful data split
00741 **     -1 -- not enough elements present to fulfill the request
00742 */
00743 
00744 static int
00745 dkimf_db_datasplit(char *buf, size_t buflen,
00746                    DKIMF_DBDATA req, unsigned int reqnum)
00747 {
00748        int ridx;
00749        int ret = 0;
00750        size_t clen;
00751        size_t remain;
00752        char *p;
00753 
00754        assert(buf != NULL);
00755 
00756        if (req == NULL || reqnum == 0)
00757               return 0;
00758 
00759        p = buf;
00760        remain = buflen;
00761 
00762        for (ridx = 0; ridx < reqnum; ridx++)
00763        {
00764               if (remain <= 0)
00765                      break;
00766 
00767               if ((req[ridx].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
00768               {
00769                      clen = MIN(remain, req[ridx].dbdata_buflen);
00770                      memcpy(req[ridx].dbdata_buffer, p, clen);
00771                      req[ridx].dbdata_buflen = remain;
00772                      remain = 0;
00773               }
00774               else if (ridx == reqnum - 1)
00775               {
00776                      clen = MIN(remain, req[ridx].dbdata_buflen);
00777                      memcpy(req[ridx].dbdata_buffer, p, clen);
00778                      req[ridx].dbdata_buflen = remain;
00779               }
00780               else
00781               {
00782                      char *q;
00783 
00784                      q = strchr(p, ':');
00785                      if (q != NULL)
00786                      {
00787                             clen = q - p;
00788                             memcpy(req[ridx].dbdata_buffer, p,
00789                                    MIN(clen, req[ridx].dbdata_buflen));
00790                             req[ridx].dbdata_buflen = clen;
00791                             p += clen + 1;
00792                             remain -= (clen + 1);
00793                      }
00794                      else
00795                      {
00796                             clen = remain;
00797                             memcpy(req[ridx].dbdata_buffer, p,
00798                                    MIN(clen, req[ridx].dbdata_buflen));
00799                             req[ridx].dbdata_buflen = clen;
00800                             remain = 0;
00801                      }
00802               }
00803        }
00804 
00805        /* mark the ones that got no data */
00806        if (ridx < reqnum)
00807        {
00808               int c;
00809 
00810               for (c = ridx; c < reqnum; c++)
00811               {
00812                      if ((req[c].dbdata_flags & DKIMF_DB_DATA_OPTIONAL) == 0)
00813                             ret = -1;
00814                      req[c].dbdata_buflen = (size_t) -1;
00815               }
00816        }
00817 
00818         return ret;
00819 }
00820 
00821 #ifdef USE_LDAP
00822 # define ISRFC2254CHR(q)    ((q) == 0x2a ||      \
00823                              (q) == 0x28 || \
00824                              (q) == 0x29 || \
00825                              (q) == 0x5c || \
00826                              (q) == 0x00)
00827 
00828 # define ADDRFC2254CHR(x, y, z)    { \
00829                                    *(x)++ = '\\'; \
00830                                    if ((y) > (x)) \
00831                                    { \
00832                                           (x) += snprintf((x), \
00833                                                           (y) - (x), \
00834                                                           "%02x", \
00835                                                           (z)); \
00836                                    } \
00837                             }
00838 
00839 /*
00840 **  DKIMF_DB_MKLDAPQUERY -- generate an LDAP query
00841 **
00842 **  Parameters:
00843 **     buf -- parameter (the actual query)
00844 **     buflen -- length of data in "buf"
00845 **     query -- query string (a domain name?)
00846 **     out -- outbut buffer
00847 **     outlen -- size of "out"
00848 **
00849 **  Return value:
00850 **     None.
00851 **
00852 **  Notes:
00853 **     Expands "$d" and "$D" as defined in opendkim.conf(5).
00854 ** 
00855 **     Should report overflows.
00856 */
00857 
00858 static void
00859 dkimf_db_mkldapquery(char *buf, char *query, char *out, size_t outlen)
00860 {
00861        char last = '\0';
00862        char *p;
00863        char *o;
00864        char *q;
00865        char *pend;
00866        char *oend;
00867        char *qend;
00868 
00869        assert(buf != NULL);
00870        assert(query != NULL);
00871        assert(out != NULL);
00872 
00873        p = buf;
00874        pend = p + strlen(p) - 1;
00875 
00876        q = query;
00877        qend = query + strlen(query) - 1;
00878 
00879        o = out;
00880        oend = out + outlen - 1;
00881 
00882        while (p <= pend && o <= oend)
00883        {
00884               if (last == '$')
00885               {
00886                      if (*p == 'd')
00887                      {
00888                             for (q = query; o <= oend && q <= qend; q++)
00889                             {
00890                                    if (ISRFC2254CHR(*q))
00891                                    {
00892                                           ADDRFC2254CHR(o, oend, *q);
00893                                    }
00894                                    else
00895                                    {
00896                                           *o++ = *q;
00897                                    }
00898                             }
00899                      }
00900                      else if (*p == 'D')
00901                      {
00902                             for (q = query; o <= oend && q <= qend; q++)
00903                             {
00904                                    if (q == query)
00905                                    {
00906                                           o += strlcpy(o, "dc=",
00907                                                        oend - o);
00908                                    }
00909 
00910                                    if (*q == '.')
00911                                    {
00912                                           o += strlcpy(o, ",dc=",
00913                                                        oend - o);
00914                                    }
00915                                    else if (ISRFC2254CHR(*q))
00916                                    {
00917                                           ADDRFC2254CHR(o, oend, *q);
00918                                    }
00919                                    else
00920                                    {
00921                                           *o++ = *q;
00922                                    }
00923                             }
00924                      }
00925                      else
00926                      {
00927                             *q++ = *p;
00928                      }
00929               }
00930               else if (*p != '$')
00931               {
00932                      *o++ = *p;
00933               }
00934 
00935               last = *p;
00936               p++;
00937        }
00938 }
00939 #endif /* USE_LDAP */
00940 
00941 /*
00942 **  DKIMF_DB_NEXTPUNCT -- find next punctuation
00943 **
00944 **  Parameters:
00945 **     str -- start of the search
00946 **
00947 **  Return value:
00948 **     Pointer to the next punctuation found, or NULL if none.
00949 */
00950 
00951 static char *
00952 dkimf_db_nextpunct(char *str)
00953 {
00954        char *p;
00955 
00956        assert(str != NULL);
00957 
00958        for (p = str; *p != '\0'; p++)
00959        {
00960               if (*p == ':' ||
00961                   *p == '/' ||
00962                   *p == '@' ||
00963                   *p == '+' ||
00964                   *p == '=' ||
00965                   *p == '?')
00966                      return p;
00967        }
00968 
00969        return NULL;
00970 }
00971 
00972 /*
00973 **  DKIMF_DB_LIST_FREE -- destroy a linked list
00974 **
00975 **  Parameters:
00976 **     list -- list handle
00977 **
00978 **  Return value:
00979 **     None.
00980 */
00981 
00982 static void
00983 dkimf_db_list_free(struct dkimf_db_list *list)
00984 {
00985        struct dkimf_db_list *next;
00986 
00987        assert(list != NULL);
00988 
00989        while (list != NULL)
00990        {
00991               free(list->db_list_key);
00992               if (list->db_list_value != NULL)
00993                      free(list->db_list_value);
00994               next = list->db_list_next;
00995               free(list);
00996               list = next;
00997        }
00998 }
00999               
01000 /*
01001 **  DKIMF_DB_RELIST_FREE -- destroy a linked regex list
01002 **
01003 **  Parameters:
01004 **     list -- list handle
01005 **
01006 **  Return value:
01007 **     None.
01008 */
01009 
01010 static void
01011 dkimf_db_relist_free(struct dkimf_db_relist *list)
01012 {
01013        struct dkimf_db_relist *next;
01014 
01015        assert(list != NULL);
01016 
01017        while (list != NULL)
01018        {
01019               regfree(&list->db_relist_re);
01020               if (list->db_relist_data != NULL)
01021                      free(list->db_relist_data);
01022               next = list->db_relist_next;
01023               free(list);
01024               list = next;
01025        }
01026 }
01027 
01028 #ifdef USE_LDAP
01029 /*
01030 **  DKIMF_DB_OPEN_LDAP -- attempt to contact an LDAP server
01031 **
01032 **  Parameters:
01033 **     ld -- LDAP handle (updated on success)
01034 **     ldap -- local LDAP data
01035 **
01036 **  Return value:
01037 **     An LDAP_* constant.
01038 */
01039 
01040 int
01041 dkimf_db_open_ldap(LDAP **ld, struct dkimf_db_ldap *ldap, char **err)
01042 {
01043        int v = LDAP_VERSION3;
01044        int n;
01045        int lderr;
01046        char *q;
01047        char *r;
01048        char *u;
01049        struct timeval timeout;
01050 
01051        assert(ld != NULL);
01052        assert(ldap != NULL);
01053 
01054        /* create LDAP handle */
01055        lderr = ldap_initialize(ld, ldap->ldap_urilist);
01056        if (lderr != LDAP_SUCCESS)
01057        {
01058               if (err != NULL)
01059                      *err = ldap_err2string(lderr);
01060               return lderr;
01061        }
01062 
01063        /* set LDAP version */
01064        lderr = ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION, &v);
01065        if (lderr != LDAP_OPT_SUCCESS)
01066        {
01067               if (err != NULL)
01068                      *err = ldap_err2string(lderr);
01069               ldap_unbind_ext(*ld, NULL, NULL);
01070               *ld = NULL;
01071               return lderr;
01072        }
01073 
01074        /* enable auto-restarts */
01075        lderr = ldap_set_option(*ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
01076        if (lderr != LDAP_OPT_SUCCESS)
01077        {
01078               if (err != NULL)
01079                      *err = ldap_err2string(lderr);
01080               ldap_unbind_ext(*ld, NULL, NULL);
01081               *ld = NULL;
01082               return lderr;
01083        }
01084 
01085        /* request timeouts */
01086        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_TIMEOUT];
01087        timeout.tv_sec = DKIMF_LDAP_DEFTIMEOUT;
01088        timeout.tv_usec = 0;
01089        if (q != NULL)
01090        {
01091               errno = 0;
01092               timeout.tv_sec = strtoul(q, &r, 10);
01093               if (errno == ERANGE)
01094                      timeout.tv_sec = DKIMF_LDAP_DEFTIMEOUT;
01095        }
01096 
01097        lderr = ldap_set_option(*ld, LDAP_OPT_TIMEOUT, &timeout);
01098        if (lderr != LDAP_OPT_SUCCESS)
01099        {
01100               if (err != NULL)
01101                      *err = ldap_err2string(lderr);
01102               ldap_unbind_ext(*ld, NULL, NULL);
01103               *ld = NULL;
01104               return lderr;
01105        }
01106 
01107        /* request keepalive */
01108        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_KA_IDLE];
01109        if (q != NULL)
01110        {
01111               errno = 0;
01112               n = strtoul(q, &r, 10);
01113               if (errno != ERANGE)
01114               {
01115                      lderr = ldap_set_option(*ld, LDAP_OPT_X_KEEPALIVE_IDLE,
01116                                              &n);
01117                      if (lderr != LDAP_OPT_SUCCESS)
01118                      {
01119                             if (err != NULL)
01120                                    *err = ldap_err2string(lderr);
01121                             ldap_unbind_ext(*ld, NULL, NULL);
01122                             *ld = NULL;
01123                             return lderr;
01124                      }
01125               }
01126        }
01127 
01128        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_KA_PROBES];
01129        if (q != NULL)
01130        {
01131               errno = 0;
01132               n = strtoul(q, &r, 10);
01133               if (errno != ERANGE)
01134               {
01135                      lderr = ldap_set_option(*ld,
01136                                              LDAP_OPT_X_KEEPALIVE_PROBES,
01137                                              &n);
01138                      if (lderr != LDAP_OPT_SUCCESS)
01139                      {
01140                             if (err != NULL)
01141                                    *err = ldap_err2string(lderr);
01142                             ldap_unbind_ext(*ld, NULL, NULL);
01143                             *ld = NULL;
01144                             return lderr;
01145                      }
01146               }
01147        }
01148 
01149        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_KA_INTERVAL];
01150        if (q != NULL)
01151        {
01152               errno = 0;
01153               n = strtoul(q, &r, 10);
01154               if (errno != ERANGE)
01155               {
01156                      lderr = ldap_set_option(*ld,
01157                                              LDAP_OPT_X_KEEPALIVE_INTERVAL,
01158                                              &n);
01159                      if (lderr != LDAP_OPT_SUCCESS)
01160                      {
01161                             if (err != NULL)
01162                                    *err = ldap_err2string(lderr);
01163                             ldap_unbind_ext(*ld, NULL, NULL);
01164                             *ld = NULL;
01165                             return lderr;
01166                      }
01167               }
01168        }
01169 
01170        /* attempt TLS if requested, except for ldaps */
01171        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_USETLS];
01172        if (q != NULL && (*q == 'y' || *q == 'Y') &&
01173            strcasecmp(ldap->ldap_descr->lud_scheme, "ldaps") != 0)
01174        {
01175               lderr = ldap_start_tls_s(*ld, NULL, NULL);
01176               if (lderr != LDAP_SUCCESS)
01177               {
01178                      if (err != NULL)
01179                             *err = ldap_err2string(lderr);
01180                      ldap_unbind_ext(*ld, NULL, NULL);
01181                      *ld = NULL;
01182                      return lderr;
01183               }
01184        }
01185 
01186        /* attempt binding */
01187        q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_AUTHMECH];
01188        u = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_BINDUSER];
01189        if (q == NULL || strcasecmp(q, "none") == 0 ||
01190            strcasecmp(q, "simple") == 0)
01191        {
01192               struct berval passwd;
01193 
01194               r = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_BINDPW];
01195               if (r != NULL)
01196               {
01197                      passwd.bv_val = r;
01198                      passwd.bv_len = strlen(r);
01199               }
01200               else
01201               {
01202                      passwd.bv_val = NULL;
01203                      passwd.bv_len = 0;
01204               }
01205 
01206               lderr = ldap_sasl_bind_s(*ld, u, q, &passwd,
01207                                        NULL, NULL, NULL);
01208               if (lderr != LDAP_SUCCESS)
01209               {
01210                      if (err != NULL)
01211                             *err = ldap_err2string(lderr);
01212                      ldap_unbind_ext(*ld, NULL, NULL);
01213                      *ld = NULL;
01214                      return lderr;
01215               }
01216        }
01217        else
01218        {
01219 # ifdef USE_SASL
01220               lderr = ldap_sasl_interactive_bind_s(*ld,
01221                                                    u,   /* bind user */
01222                                                    q,   /* SASL mech */
01223                                                    NULL, /* controls */
01224                                                    NULL, /* controls */
01225                                                    LDAP_SASL_QUIET, /* flags */
01226                                                    dkimf_db_saslinteract, /* callback */
01227                                                    NULL);
01228               if (lderr != LDAP_SUCCESS)
01229               {
01230                      if (err != NULL)
01231                             *err = ldap_err2string(lderr);
01232                      ldap_unbind_ext(*ld, NULL, NULL);
01233                      *ld = NULL;
01234                      return lderr;
01235               }
01236 
01237 # else /* USE_SASL */
01238 
01239               /* unknown auth mechanism */
01240               if (err != NULL)
01241                      *err = "Unknown auth mechanism";
01242               ldap_unbind_ext(*ld, NULL, NULL);
01243               *ld = NULL;
01244               return LDAP_AUTH_METHOD_NOT_SUPPORTED;
01245 
01246 # endif /* USE_SASL */
01247        }
01248 
01249        return LDAP_SUCCESS;
01250 }
01251 #endif /* USE_LDAP */
01252 
01253 /*
01254 **  DKIMF_DB_TYPE -- return database type
01255 **
01256 **  Parameters:
01257 **     db -- DKIMF_DB handle
01258 ** 
01259 **  Return value:
01260 **     A DKIMF_DB_TYPE_* constant.
01261 */
01262 
01263 int
01264 dkimf_db_type(DKIMF_DB db)
01265 {
01266        assert(db != NULL);
01267 
01268        return db->db_type;
01269 }
01270 
01271 #ifdef USE_ERLANG
01272 /*
01273 **  DKIMF_DB_ERL_CONNECT -- connect to a distributed Erlang node
01274 **
01275 **  Parameters:
01276 **     db -- DKIMF_DB handle
01277 **     ecp -- Pointer to ei_cnode
01278 **
01279 **  Return value:
01280 **     File descriptor or -1 on error.
01281 */
01282 
01283 static int
01284 dkimf_db_erl_connect(DKIMF_DB db, ei_cnode *ecp)
01285 {
01286        int fd;
01287        int ret;
01288        int instance;
01289        unsigned int seed;
01290        char node_name[12];
01291        struct timeval tv;
01292        char *q;
01293        char *last;
01294        struct dkimf_db_erlang *e;
01295 
01296        gettimeofday(&tv, NULL);
01297        seed = tv.tv_sec * tv.tv_usec;
01298        instance = rand_r(&seed) % 999;
01299 
01300        e = (struct dkimf_db_erlang *) db->db_data;
01301 
01302        snprintf(node_name, sizeof node_name, "opendkim%d", instance);
01303 
01304        ret = ei_connect_init(ecp, node_name, e->erlang_cookie, instance);
01305        if (ret != 0)
01306               return -1;
01307 
01308        fd = -1;
01309        for (q = strtok_r(e->erlang_nodes, ",", &last);
01310             q != NULL;
01311             q = strtok_r(NULL, ",", &last))
01312        {
01313               fd = ei_connect(ecp, q);
01314               if (fd >= 0)
01315                      break;
01316        }
01317        if (fd < 0)
01318               return -1;
01319 
01320        return fd;
01321 }
01322 
01323 /*
01324 **  DKIMF_DB_ERL_FREE -- free allocated memory for Erlang configuration
01325 **
01326 **  Parameters:
01327 **     ep -- Pointer to struct dkimf_db_erlang
01328 **
01329 **  Return value:
01330 **     None.
01331 */
01332 
01333 static void
01334 dkimf_db_erl_free(struct dkimf_db_erlang *ep)
01335 {
01336        if (ep == NULL)
01337               return;
01338        if (ep->erlang_nodes != NULL)
01339               free(ep->erlang_nodes);
01340        if (ep->erlang_module != NULL)
01341               free(ep->erlang_module);
01342        if (ep->erlang_function != NULL)
01343               free(ep->erlang_function);
01344        if (ep->erlang_cookie != NULL)
01345               free(ep->erlang_cookie);
01346        free(ep);
01347 }
01348 
01349 /*
01350 **  DKIMF_DB_ERL_ALLOC_BUFFER -- allocate memory for a char* buffer
01351 **                               depending on erlang response size
01352 **
01353 **  Parameters:
01354 **     eip -- pointer to response ei_x_buff
01355 **     index -- pointer to current response index
01356 **     sizep -- size of response (returned)
01357 **
01358 ** Return value:
01359 **     Pointer to allocated buffer or NULL on error.
01360 */
01361 
01362 static char *
01363 dkimf_db_erl_alloc_buffer(ei_x_buff *eip, int *index, int *sizep)
01364 {
01365        int err;
01366        int type, size;
01367 
01368        err = ei_get_type(eip->buff, index, &type, &size);
01369        if (err < 0)
01370               return NULL;
01371        *sizep = size + 1;
01372        return malloc(*sizep);
01373 }
01374 
01375 /*
01376 **  DKIMF_DB_ERL_DECODE_ATOM -- decode an Erlang atom and check it
01377 **                              against its desired value
01378 **
01379 **  Parameters:
01380 **     eip -- pointer to response ei_x_buff
01381 **     index -- pointer to current response index
01382 **     cmp -- desired atom value
01383 **
01384 **  Return value:
01385 **     0 if the atom value matches de desired value, != 0 otherwise.
01386 */
01387 
01388 static int
01389 dkimf_db_erl_decode_atom(ei_x_buff *eip, int *index, const char *cmp)
01390 {
01391        int err;
01392        int size;
01393        int ret;
01394        char *buf;
01395 
01396        buf = dkimf_db_erl_alloc_buffer(eip, index, &size);
01397        err = ei_decode_atom(eip->buff, index, buf);
01398        if (err != 0)
01399               return err;
01400        buf[size - 1] = '\0';
01401 
01402        ret = strcmp(buf, cmp);
01403 
01404        free(buf);
01405        return ret;
01406 }
01407 
01408 /*
01409 **  DKIMF_DB_ERL_DECODE_TUPLE -- decode an Erlang tuple, optionally
01410 **                               checking its arity
01411 **
01412 **  Parameters:
01413 **     eip -- pointer to response ei_x_buff
01414 **     index -- pointer to current response index
01415 **     num_elements -- pointer desired tuple arity (returned)
01416 **
01417 **  Return value:
01418 **     0 -- success
01419 **     -1 -- error.
01420 **
01421 **  Notes:
01422 **     If num_elements points to a positive number, the decoded tuple
01423 **     arity is checked against it, and if the values differ, the function
01424 **      will return an error.  Otherwise, num_elements is set to the decoded
01425 **      tuple arity.
01426 */
01427 
01428 static int
01429 dkimf_db_erl_decode_tuple(ei_x_buff *eip, int *index, int *num_elements)
01430 {
01431        int err;
01432        int arity;
01433 
01434        err = ei_decode_tuple_header(eip->buff, index, &arity);
01435        if (err < 0)
01436               return err;
01437        if (*num_elements > 0 && *num_elements != arity)
01438               return -1;
01439        *num_elements = arity;
01440        return 0;
01441 }
01442 
01443 /*
01444 **  DKIMF_DB_ERL_DECODE_BITSTRING -- decode an Erlang bitstring
01445 **
01446 **  Parameters:
01447 **     eip -- pointer to response ei_x_buff
01448 **     index -- pointer to current response index
01449 **
01450 **  Return value:
01451 **     Pointer to allocated buffer used to store the bitstring value
01452 **      or NULL on error.
01453 **
01454 **  Notes:
01455 **     The caller is responsible for freeing the buffer.
01456 */
01457 
01458 static char *
01459 dkimf_db_erl_decode_bitstring(ei_x_buff *eip, int *index)
01460 {
01461        int err;
01462        int size;
01463        long len;
01464        char *buf;
01465 
01466        buf = dkimf_db_erl_alloc_buffer(eip, index, &size);
01467        err = ei_decode_binary(eip->buff, index, buf, &len);
01468        if (err < 0)
01469               return NULL;
01470        buf[size - 1] = '\0';
01471        return buf;
01472 }
01473 
01474 /*
01475 **  DKIMF_DB_ERL_DECODE_INTEGER -- decode an Erlang integer
01476 **
01477 **  Parameters:
01478 **     eip -- pointer to response ei_x_buff
01479 **     index -- pointer to current response index
01480 **      val -- pointer to decoded integer (returned)
01481 **
01482 **  Return value:
01483 **     0: success
01484 **      < 0: error
01485 */
01486 
01487 static int
01488 dkimf_db_erl_decode_int(ei_x_buff *eip, int *index, long *val)
01489 {
01490        int err;
01491 
01492        err = ei_decode_long(eip->buff, index, val);
01493        if (err < 0)
01494               return err;
01495        return 0;
01496 }
01497 
01498 /*
01499 **  DKIMF_DB_ERL_DECODE_RESPONSE -- decode an Erlang RPC response
01500 **
01501 **  Parameters:
01502 **     resp -- pointer to response ei_x_buff
01503 **      notfound -- string containing the atom to be returned in case
01504 **                  of a record not found
01505 **     req -- list of data requests
01506 **     reqnum -- number of data requests
01507 **     key -- buffer to receive the key (may be NULL)
01508 **     keylen -- bytes available at "key" (updated)
01509 **
01510 **  Return value:
01511 **     -1: error
01512 **      1: record not found
01513 **     0: success
01514 **
01515 **  Notes:
01516 **     Assumes keys returned from Erlang are either integers or
01517 **      bitstrings.
01518 */
01519 
01520 static int
01521 dkimf_db_erl_decode_response(ei_x_buff *resp, const char *notfound,
01522                              DKIMF_DBDATA req, unsigned int reqnum,
01523                              char *key, size_t *keylen)
01524 {
01525        int ret;
01526        int res_index, res_type, res_size;
01527 
01528        res_index = 0;
01529        ret = ei_get_type(resp->buff, &res_index, &res_type, &res_size);
01530        if (ret != 0)
01531               return -1;
01532 
01533        switch (res_type)
01534        {
01535          case ERL_ATOM_EXT:
01536          {
01537               /*
01538               **  If we got an atom then it must signal record not found or
01539               **  no more records in the table.
01540               */
01541 
01542               ret = dkimf_db_erl_decode_atom(resp, &res_index, notfound);
01543               if (ret != 0)
01544                      return -1;
01545               return 1;
01546          }
01547 
01548          case ERL_SMALL_TUPLE_EXT:
01549          case ERL_LARGE_TUPLE_EXT:
01550          {
01551               /* got a tuple {ok, something} */
01552               int nres;
01553               int arity;
01554 
01555               arity = 2;
01556               ret = dkimf_db_erl_decode_tuple(resp, &res_index, &arity);
01557               if (ret == -1)
01558                      return -1;
01559               ret = dkimf_db_erl_decode_atom(resp, &res_index, "ok");
01560               if (ret != 0)
01561                      return -1;
01562 
01563               ret = ei_get_type(resp->buff, &res_index, &res_type,
01564                                 &res_size);
01565               if (ret < 0)
01566                      return -1;
01567 
01568               switch (res_type)
01569               {
01570                 case ERL_SMALL_INTEGER_EXT:
01571                 case ERL_INTEGER_EXT:
01572                 {
01573                      /*
01574                      **  The tuple is {ok, IntegerDomainId}
01575                      **  (we were called from SigningTable)
01576                      */
01577 
01578                      int c;
01579                      int n;
01580                      long val;
01581 
01582                      if (reqnum == 0)
01583                             return 0;
01584                      ret = dkimf_db_erl_decode_int(resp, &res_index, &val);
01585                      if (ret != 0)
01586                             return -1;
01587                      n = snprintf(req[0].dbdata_buffer,
01588                                   req[0].dbdata_buflen, "%ld", val);
01589                      req[0].dbdata_buflen = n + 1;
01590                      for (c = 1; c < reqnum; c++)
01591                             req[c].dbdata_buflen = 0;
01592                      return 0;
01593                 }
01594 
01595                 case ERL_BINARY_EXT:
01596                 {
01597                      /*
01598                      **  The tuple is {ok, BitstringDomainId}
01599                      **  (we were called from SigningTable)
01600                      */
01601 
01602                      int c;
01603                      char *val;
01604 
01605                      if (reqnum == 0)
01606                             return 0;
01607                      val = dkimf_db_erl_decode_bitstring(resp, &res_index);
01608                      if (val == NULL)
01609                             return -1;
01610                      req[0].dbdata_buflen = strlcpy(req[0].dbdata_buffer,
01611                                                     val,
01612                                                     req[0].dbdata_buflen);
01613                      free(val);
01614                      for (c = 1; c < reqnum; c++)
01615                             req[c].dbdata_buflen = 0;
01616                      return 0;
01617                 }
01618 
01619                 case ERL_SMALL_TUPLE_EXT:
01620                 case ERL_LARGE_TUPLE_EXT:
01621                 {
01622                      /*
01623                      **  The tuple is either
01624                      **   {ok, {Cursor, Domain, Selector, PrivKey}}
01625                      **  (we were called from dkimf_db_walk()); or
01626                      **   {ok, {Domain, Selector, PrivKey}
01627                      **  (we were called from dkimf_db_get()).
01628                      */
01629 
01630                      int c;
01631                      arity = 0;
01632 
01633                      ret = dkimf_db_erl_decode_tuple(resp, &res_index,
01634                                                      &arity);
01635                      if (ret == -1)
01636                             return -1;
01637 
01638                      if (key != NULL && keylen != NULL)
01639                      {
01640                             ret = ei_get_type(resp->buff, &res_index,
01641                                               &res_type, &res_size);
01642                             if (ret != 0)
01643                                    return -1;
01644 
01645                             switch (res_type)
01646                             {
01647                               case ERL_SMALL_INTEGER_EXT:
01648                               case ERL_INTEGER_EXT:
01649                               {
01650                                    int n;
01651                                    long val;
01652                                    ret = dkimf_db_erl_decode_int(resp,
01653                                                                  &res_index,
01654                                                                  &val);
01655                                    if (ret != 0)
01656                                           return -1;
01657                                    n = snprintf(key, *keylen, "%ld", val);
01658                                    *keylen = n + 1;
01659                                    break;
01660                               }
01661 
01662                               case ERL_BINARY_EXT:
01663                               {
01664                                    char *val;
01665                                    val = dkimf_db_erl_decode_bitstring(resp,
01666                                                                        &res_index);
01667                                    if (val == NULL)
01668                                           return -1;
01669 
01670                                    *keylen = dkim_strlcpy(key, val,
01671                                                           *keylen);
01672                                    free(val);
01673                                    break;
01674                               }
01675 
01676                               default:
01677                                    return -1;
01678                             }
01679                      }
01680 
01681                      if (reqnum == 0)
01682                             return 0;
01683 
01684                      ret = ei_get_type(resp->buff, &res_index, &res_type,
01685                                        &res_size);
01686                      if (ret != 0)
01687                             return -1;
01688 
01689                      nres = (key != NULL && keylen != NULL) ? arity - 1
01690                                                             : arity;
01691                      for (c = 0; c < reqnum; c++)
01692                      {
01693                             if (c >= nres)
01694                             {
01695                                    req[c].dbdata_buflen = 0;
01696                             }
01697                             else
01698                             {
01699                                    char *val;
01700                                    val = dkimf_db_erl_decode_bitstring(resp,
01701                                                                        &res_index);
01702                                    if (val == NULL)
01703                                           return -1;
01704                                    req[c].dbdata_buflen = dkim_strlcpy(req[c].dbdata_buffer,
01705                                                           val,
01706                                                           req[c].dbdata_buflen);
01707                                    free(val);
01708                             }
01709                      }
01710 
01711                      return 0;
01712                 }
01713 
01714                 default:
01715                        return -1;
01716               }
01717          }
01718 
01719          default:
01720               return -1;
01721        }
01722 }
01723 #endif /* USE_ERLANG */
01724 
01725 /*
01726 **  DKIMF_DB_OPEN -- open a database
01727 **
01728 **  Parameters:
01729 **     db -- DKIMF_DB handle (returned)
01730 **     name -- name of DB to open
01731 **     flags -- operational flags
01732 **     lock -- lock to use during operations
01733 **     err -- error string from underlying library (returned; may be NULL)
01734 **
01735 **  Return value:
01736 **     3 -- other open error
01737 **     2 -- illegal request (e.g. writable flat file)
01738 **     1 -- unknown database type
01739 **     0 -- success
01740 **     -1 -- failure; check errno
01741 **
01742 **  Notes:
01743 **     The type of the database is implied by a leading "type:" string
01744 **     as part of "name".  The list of valid types is listed in the
01745 **     "dbtypes" table above.  Without such a prefix, a name that starts
01746 **     with "/" implies "file", otherwise "csl" is used.
01747 **
01748 **     Currently defined types:
01749 **     csl -- "name" contains a comma-separated list
01750 **     file -- a flat file; may be simply a list of names if only a
01751 **             memership test is needed, or it can be "key value" lines
01752 **             in which case dkimf_db_get() can be used to extract the
01753 **             value of a named key
01754 **     refile -- a flat file containing patterns (i.e. strings with the
01755 **               wildcard "*"); only membership tests are allowed
01756 **     db -- a Sleepycat hash or b-tree database file, which can be used
01757 **           for membership tests or key-value pairs
01758 **     dsn -- a data store name, meaning SQL or ODBC in the backend,
01759 **            with interface provided by OpenDBX
01760 **     ldap -- an LDAP server, interace provide by OpenLDAP
01761 **     lua -- a Lua script; the returned value is the result
01762 **     erlang -- an erlang function to be called in a distributed erlang node
01763 */
01764 
01765 int
01766 dkimf_db_open(DKIMF_DB *db, char *name, u_int flags, pthread_mutex_t *lock,
01767               char **err)
01768 {
01769        DKIMF_DB new;
01770        char *comma;
01771        char *p;
01772 
01773        assert(db != NULL);
01774        assert(name != NULL);
01775 
01776        new = (DKIMF_DB) malloc(sizeof(struct dkimf_db));
01777        if (new == NULL)
01778        {
01779               if (err != NULL)
01780                      *err = strerror(errno);
01781               return -1;
01782        }
01783 
01784        memset(new, '\0', sizeof(struct dkimf_db));
01785 
01786        new->db_flags = flags;
01787        new->db_type = DKIMF_DB_TYPE_UNKNOWN;
01788 
01789        p = strchr(name, ':');
01790        comma = strchr(name, ',');
01791 
01792        /* catch a CSL that contains colons not in the first entry */
01793        if (comma != NULL && p != NULL && comma < p)
01794               p = NULL;
01795 
01796        if (p == NULL)
01797        {
01798 # ifdef USE_DB
01799               char *q;
01800 
01801               q = NULL;
01802               for (p = strstr(name, ".db");
01803                    p != NULL;
01804                    p = strstr(p + 1, ".db"))
01805                      q = p;
01806               if (q != NULL && *(q + 3) == '\0')
01807                      new->db_type = DKIMF_DB_TYPE_BDB;
01808               else
01809 # endif /* USE_DB */
01810               if (name[0] == '/')
01811                      new->db_type = DKIMF_DB_TYPE_FILE;
01812               else
01813                      new->db_type = DKIMF_DB_TYPE_CSL;
01814               p = name;
01815        }
01816        else
01817        {
01818               int c;
01819               size_t clen;
01820               char dbtype[BUFRSZ + 1];
01821 
01822               memset(dbtype, '\0', sizeof dbtype);
01823               clen = MIN(sizeof(dbtype) - 1, p - name);
01824               strncpy(dbtype, name, clen);
01825 
01826               for (c = 0; ; c++)
01827               {
01828                      if (dbtypes[c].name == NULL)
01829                             break;
01830 
01831                      if (strcasecmp(dbtypes[c].name, dbtype) == 0)
01832                             new->db_type = dbtypes[c].code;
01833               }
01834 
01835               if (new->db_type == DKIMF_DB_TYPE_UNKNOWN)
01836               {
01837                      free(new);
01838                      if (err != NULL)
01839                             *err = "Unknown database type";
01840                      return 1;
01841               }
01842 
01843               p++;
01844        }
01845 
01846        /* force DB accesses to be mutex-protected */
01847        if (new->db_type == DKIMF_DB_TYPE_DSN ||
01848            new->db_type == DKIMF_DB_TYPE_SOCKET)
01849               new->db_flags |= DKIMF_DB_FLAG_MAKELOCK;
01850 
01851        /* use provided lock, or create a new one if needed */
01852        if (lock != NULL)
01853        {
01854               new->db_lock = lock;
01855               new->db_flags &= ~DKIMF_DB_FLAG_MAKELOCK;
01856        }
01857        else if ((new->db_flags & DKIMF_DB_FLAG_MAKELOCK) != 0)
01858        {
01859               new->db_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
01860               if (new->db_lock == NULL)
01861               {
01862                      if (err != NULL)
01863                             *err = strerror(errno);
01864                      free(new);
01865                      return -1;
01866               }
01867 
01868               pthread_mutex_init(new->db_lock, NULL);
01869        }
01870 
01871        switch (new->db_type)
01872        {
01873          case DKIMF_DB_TYPE_CSL:
01874          {
01875               int n = 0;
01876               char *tmp;
01877               char *eq;
01878               char *ctx;
01879               struct dkimf_db_list *list = NULL;
01880               struct dkimf_db_list *next = NULL;
01881               struct dkimf_db_list *newl;
01882 
01883               if ((flags & DKIMF_DB_FLAG_READONLY) == 0)
01884               {
01885                      free(new);
01886                      errno = EINVAL;
01887                      if (err != NULL)
01888                             *err = strerror(errno);
01889                      return 2;
01890               }
01891 
01892               tmp = strdup(p);
01893               if (tmp == NULL)
01894               {
01895                      if (err != NULL)
01896                             *err = strerror(errno);
01897                      free(new);
01898                      return -1;
01899               }
01900 
01901               for (p = strtok_r(tmp, ",", &ctx);
01902                    p != NULL;
01903                    p = strtok_r(NULL, ",", &ctx))
01904               {
01905                      eq = strchr(p, '=');
01906                      if (eq != NULL)
01907                             *eq = '\0';
01908 
01909                      if (eq != NULL &&
01910                          (new->db_flags & DKIMF_DB_FLAG_VALLIST) != 0)
01911                      {
01912                             char *q;
01913                             char *ctx2;
01914 
01915                             for (q = strtok_r(eq + 1, "|", &ctx2);
01916                                  q != NULL;
01917                                  q = strtok_r(NULL, "|", &ctx2))
01918                             {
01919                                    newl = (struct dkimf_db_list *) malloc(sizeof(struct dkimf_db_list));
01920                                    if (newl == NULL)
01921                                    {
01922                                           if (err != NULL)
01923                                                  *err = strerror(errno);
01924                                           if (list != NULL)
01925                                                  dkimf_db_list_free(list);
01926                                           free(tmp);
01927                                           free(new);
01928                                           return -1;
01929                                    }
01930 
01931                                    newl->db_list_key = strdup(p);
01932                                    if (newl->db_list_key == NULL)
01933                                    {
01934                                           if (err != NULL)
01935                                                  *err = strerror(errno);
01936                                           free(newl);
01937                                           if (list != NULL)
01938                                                  dkimf_db_list_free(list);
01939                                           free(new);
01940                                           free(tmp);
01941                                           return -1;
01942                                    }
01943                                    dkimf_trimspaces(newl->db_list_key);
01944 
01945                                    newl->db_list_value = strdup(q);
01946                                    if (newl->db_list_value == NULL)
01947                                    {
01948                                           if (err != NULL)
01949                                                  *err = strerror(errno);
01950                                           free(newl->db_list_key);
01951                                           free(newl);
01952                                           if (list != NULL)
01953                                                  dkimf_db_list_free(list);
01954                                           free(tmp);
01955                                           free(new);
01956                                           return -1;
01957                                    }
01958                                    dkimf_trimspaces(newl->db_list_value);
01959 
01960                                    newl->db_list_next = NULL;
01961 
01962                                    if (list == NULL)
01963                                           list = newl;
01964                                    else
01965                                           next->db_list_next = newl;
01966 
01967                                    next = newl;
01968                                    n++;
01969                             }
01970                      }
01971                      else
01972                      {
01973                             newl = (struct dkimf_db_list *) malloc(sizeof(struct dkimf_db_list));
01974                             if (newl == NULL)
01975                             {
01976                                    if (err != NULL)
01977                                           *err = strerror(errno);
01978                                    if (list != NULL)
01979                                           dkimf_db_list_free(list);
01980                                    free(tmp);
01981                                    free(new);
01982                                    return -1;
01983                             }
01984 
01985                             newl->db_list_key = strdup(p);
01986                             if (newl->db_list_key == NULL)
01987                             {
01988                                    if (err != NULL)
01989                                           *err = strerror(errno);
01990                                    free(newl);
01991                                    if (list != NULL)
01992                                           dkimf_db_list_free(list);
01993                                    free(tmp);
01994                                    free(new);
01995                                    return -1;
01996                             }
01997                             dkimf_trimspaces(newl->db_list_key);
01998 
01999                             if (eq != NULL)
02000                             {
02001                                    newl->db_list_value = strdup(eq + 1);
02002                                    if (newl->db_list_value == NULL)
02003                                    {
02004                                           if (err != NULL)
02005                                                  *err = strerror(errno);
02006                                           free(newl->db_list_key);
02007                                           free(newl);
02008                                           free(tmp);
02009                                           if (list != NULL)
02010                                                  dkimf_db_list_free(list);
02011                                           free(new);
02012                                           return -1;
02013                                    }
02014                                    dkimf_trimspaces(newl->db_list_value);
02015                             }
02016                             else
02017                             {
02018                                    newl->db_list_value = NULL;
02019                             }
02020 
02021                             newl->db_list_next = NULL;
02022 
02023                             if (list == NULL)
02024                                    list = newl;
02025                             else
02026                                    next->db_list_next = newl;
02027 
02028                             next = newl;
02029                             n++;
02030                      }
02031               }
02032 
02033               free(tmp);
02034 
02035               new->db_handle = list;
02036               new->db_nrecs = n;
02037 
02038               break;
02039          }
02040 
02041          case DKIMF_DB_TYPE_FILE:
02042          {
02043               _Bool gapfound;
02044               int n = 0;
02045               FILE *f;
02046               char *key;
02047               char *value;
02048               struct dkimf_db_list *list = NULL;
02049               struct dkimf_db_list *next = NULL;
02050               struct dkimf_db_list *newl;
02051               char line[BUFRSZ + 1];
02052 
02053               if ((flags & DKIMF_DB_FLAG_READONLY) == 0)
02054               {
02055                      if (err != NULL)
02056                             *err = strerror(EINVAL);
02057                      free(new);
02058                      errno = EINVAL;
02059                      return 2;
02060               }
02061 
02062               f = fopen(p, "r");
02063               if (f == NULL)
02064               {
02065                      if (err != NULL)
02066                             *err = strerror(errno);
02067                      free(new);
02068                      return -1;
02069               }
02070 
02071               memset(line, '\0', sizeof line);
02072               while (fgets(line, BUFRSZ, f) != NULL)
02073               {
02074                      for (p = line; *p != '\0'; p++)
02075                      {
02076                             if (*p == '\n' || *p == '#')
02077                             {
02078                                    *p = '\0';
02079                                    break;
02080                             }
02081                      }
02082 
02083                      dkimf_trimspaces((u_char *) line);
02084                      if (strlen(line) == 0)
02085                             continue;
02086 
02087                      newl = (struct dkimf_db_list *) malloc(sizeof(struct dkimf_db_list));
02088                      if (newl == NULL)
02089                      {
02090                             if (err != NULL)
02091                                    *err = strerror(errno);
02092                             if (list != NULL)
02093                                    dkimf_db_list_free(list);
02094                             fclose(f);
02095                             free(new);
02096                             return -1;
02097                      }
02098 
02099                      key = NULL;
02100                      value = NULL;
02101                      gapfound = FALSE;
02102 
02103                      for (p = line; *p != '\0'; p++)
02104                      {
02105                             if (!isascii(*p) || !isspace(*p))
02106                             {
02107                                    if (key == NULL)
02108                                           key = p;
02109                                    else if (value == NULL && gapfound)
02110                                           value = p;
02111                             }
02112                             else if (key != NULL && value == NULL)
02113                             {
02114                                    *p = '\0';
02115                                    gapfound = TRUE;
02116                             }
02117                      }
02118 
02119                      assert(key != NULL);
02120                      
02121                      if (value != NULL &&
02122                          (new->db_flags & DKIMF_DB_FLAG_VALLIST) != 0)
02123                      {
02124                             char *q;
02125                             char *ctx;
02126 
02127                             for (q = strtok_r(value, "|", &ctx);
02128                                  q != NULL;
02129                                  q = strtok_r(NULL, "|", &ctx))
02130                             {
02131                                    newl = (struct dkimf_db_list *) malloc(sizeof(struct dkimf_db_list));
02132                                    if (newl == NULL)
02133                                    {
02134                                           if (err != NULL)
02135                                                  *err = strerror(errno);
02136                                           if (list != NULL)
02137                                                  dkimf_db_list_free(list);
02138                                           free(new);
02139 
02140                                           return -1;
02141                                    }
02142 
02143                                    newl->db_list_key = strdup(p);
02144                                    if (newl->db_list_key == NULL)
02145                                    {
02146                                           if (err != NULL)
02147                                                  *err = strerror(errno);
02148                                           free(newl);
02149                                           if (list != NULL)
02150                                                  dkimf_db_list_free(list);
02151                                           free(new);
02152 
02153                                           return -1;
02154                                    }
02155                                    dkimf_trimspaces(newl->db_list_key);
02156 
02157                                    newl->db_list_value = strdup(q);
02158                                    if (newl->db_list_value == NULL)
02159                                    {
02160                                           if (err != NULL)
02161                                                  *err = strerror(errno);
02162                                           free(newl->db_list_key);
02163                                           free(newl);
02164                                           if (list != NULL)
02165                                                  dkimf_db_list_free(list);
02166                                           return -1;
02167                                    }
02168                                    dkimf_trimspaces(newl->db_list_value);
02169 
02170                                    newl->db_list_next = NULL;
02171 
02172                                    if (list == NULL)
02173                                           list = newl;
02174                                    else
02175                                           next->db_list_next = newl;
02176        
02177                                    next = newl;
02178                                    n++;
02179                             }
02180                      }
02181                      else
02182                      {
02183                             newl->db_list_key = strdup(key);
02184                             if (newl->db_list_key == NULL)
02185                             {
02186                                    if (err != NULL)
02187                                           *err = strerror(errno);
02188                                    free(newl);
02189                                    if (list != NULL)
02190                                           dkimf_db_list_free(list);
02191                                    fclose(f);
02192                                    free(new);
02193                                    return -1;
02194                             }
02195                             dkimf_trimspaces(newl->db_list_key);
02196 
02197                             if (value != NULL)
02198                             {
02199                                    newl->db_list_value = strdup(value);
02200                                    if (newl->db_list_value == NULL)
02201                                    {
02202                                           if (err != NULL)
02203                                                  *err = strerror(errno);
02204                                           free(newl->db_list_key);
02205                                           free(newl);
02206                                           if (list != NULL)
02207                                                  dkimf_db_list_free(list);
02208                                           fclose(f);
02209                                           free(new);
02210                                           return -1;
02211                                    }
02212                                    dkimf_trimspaces(newl->db_list_value);
02213                             }
02214                             else
02215                             {
02216                                    newl->db_list_value = NULL;
02217                             }
02218 
02219                             newl->db_list_next = NULL;
02220 
02221                             if (list == NULL)
02222                                    list = newl;
02223                             else
02224                                    next->db_list_next = newl;
02225 
02226                             next = newl;
02227                             n++;
02228                      }
02229               }
02230 
02231               fclose(f);
02232 
02233               new->db_handle = list;
02234               new->db_nrecs = n;
02235 
02236               break;
02237          }
02238 
02239          case DKIMF_DB_TYPE_REFILE:
02240          {
02241               int status;
02242               int reflags;
02243               FILE *f;
02244               char *end;
02245               char *data;
02246               struct dkimf_db_relist *head = NULL;
02247               struct dkimf_db_relist *tail = NULL;
02248               struct dkimf_db_relist *newl;
02249               char line[BUFRSZ + 1];
02250               char patbuf[BUFRSZ + 1];
02251 
02252               if ((flags & DKIMF_DB_FLAG_READONLY) == 0)
02253               {
02254                      if (err != NULL)
02255                             *err = strerror(EINVAL);
02256                      free(new);
02257                      errno = EINVAL;
02258                      return 2;
02259               }
02260 
02261               f = fopen(p, "r");
02262               if (f == NULL)
02263               {
02264                      if (err != NULL)
02265                             *err = strerror(errno);
02266                      free(new);
02267                      return -1;
02268               }
02269 
02270               reflags = REG_EXTENDED;
02271               if ((new->db_flags & DKIMF_DB_FLAG_ICASE) != 0)
02272                      reflags |= REG_ICASE;
02273 
02274               memset(line, '\0', sizeof line);
02275               while (fgets(line, BUFRSZ, f) != NULL)
02276               {
02277                      end = NULL;
02278                      data = NULL;
02279 
02280                      for (p = line; *p != '\0'; p++)
02281                      {
02282                             if (*p == '\n' || *p == '#')
02283                             {
02284                                    *p = '\0';
02285                                    break;
02286                             }
02287                             else if (isascii(*p) && isspace(*p))
02288                             {
02289                                    end = p;
02290                             }
02291                      }
02292 
02293                      if (end != NULL)
02294                      {
02295                             *end = '\0';
02296                             for (data = end + 1; *data != '\0'; data++)
02297                             {
02298                                    if (!isascii(*data) || !isspace(*data))
02299                                           break;
02300                             }
02301                      }
02302 
02303                      dkimf_trimspaces((u_char *) line);
02304                      if (strlen(line) == 0)
02305                             continue;
02306 
02307                      newl = (struct dkimf_db_relist *) malloc(sizeof(struct dkimf_db_relist));
02308                      if (newl == NULL)
02309                      {
02310                             if (err != NULL)
02311                                    *err = strerror(errno);
02312                             if (head != NULL)
02313                                    dkimf_db_relist_free(head);
02314                             fclose(f);
02315                             free(new);
02316                             free(newl);
02317                             return -1;
02318                      }
02319 
02320                      memset(patbuf, '\0', sizeof patbuf);
02321 
02322                      if (!dkimf_mkregexp(line, patbuf, sizeof patbuf))
02323                      {
02324                             if (err != NULL)
02325                                    *err = "Error constructing regular expression";
02326                             if (head != NULL)
02327                                    dkimf_db_relist_free(head);
02328                             fclose(f);
02329                             free(new);
02330                             free(newl);
02331                             return -1;
02332                      }
02333 
02334                      status = regcomp(&newl->db_relist_re, patbuf, reflags);
02335                      if (status != 0)
02336                      {
02337                             if (err != NULL)
02338                                    *err = "Error compiling regular expression";
02339                             if (head != NULL)
02340                                    dkimf_db_relist_free(head);
02341                             fclose(f);
02342                             free(new);
02343                             free(newl);
02344                             return -1;
02345                      }
02346 
02347                      if (data != NULL)
02348                      {
02349                             newl->db_relist_data = strdup(data);
02350                             if (newl->db_relist_data == NULL)
02351                             {
02352                                    if (err != NULL)
02353                                           *err = strerror(errno);
02354                                    if (head != NULL)
02355                                           dkimf_db_relist_free(head);
02356                                    fclose(f);
02357                                    free(new);
02358                                    free(newl);
02359                                    return -1;
02360                             }
02361                             dkimf_trimspaces(newl->db_relist_data);
02362                      }
02363                      else
02364                      {
02365                             newl->db_relist_data = NULL;
02366                      }
02367 
02368                      newl->db_relist_next = NULL;
02369 
02370                      if (head == NULL)
02371                             head = newl;
02372                      else
02373                             tail->db_relist_next = newl;
02374 
02375                      tail = newl;
02376               }
02377 
02378               fclose(f);
02379 
02380               new->db_handle = head;
02381 
02382               break;
02383          }
02384 
02385 #ifdef USE_DB
02386          case DKIMF_DB_TYPE_BDB:
02387          {
02388 # if DB_VERSION_CHECK(2,0,0)
02389               int dbflags = 0;
02390 # endif /* DB_VERSION_CHECK(2,0,0) */
02391               int status = 0;
02392               DBTYPE bdbtype;
02393               DB *newdb;
02394 
02395 # if DB_VERSION_CHECK(2,0,0)
02396               if (flags & DKIMF_DB_FLAG_READONLY)
02397               {
02398                      dbflags |= DB_RDONLY;
02399                      bdbtype = DB_UNKNOWN;
02400               }
02401               else
02402               {
02403                      dbflags |= DB_CREATE;
02404                      bdbtype = DB_HASH;
02405               }
02406 # else /* DB_VERSION_CHECK(2,0,0) */
02407               bdbtype = DB_HASH;
02408 # endif /* DB_VERSION_CHECK(2,0,0) */
02409 
02410               if (*p == '\0')
02411               {
02412                      new->db_flags |= DKIMF_DB_FLAG_NOFDLOCK;
02413                      flags = new->db_flags;
02414                      p = NULL;
02415               }
02416 
02417 # if DB_VERSION_CHECK(3,0,0)
02418               status = db_create(&newdb, NULL, 0);
02419               if (status == 0)
02420               {
02421 #  if DB_VERSION_CHECK(4,1,25)
02422                      status = newdb->open(newdb, NULL, p, NULL,
02423                                             bdbtype, dbflags, 0);
02424 #  else /* DB_VERSION_CHECK(4,1,25) */
02425                      status = newdb->open(newdb, p, NULL, bdbtype,
02426                                           dbflags, 0);
02427 #  endif /* DB_VERSION_CHECK(4,1,25) */
02428               }
02429 # elif DB_VERSION_CHECK(2,0,0)
02430               status = db_open(p, bdbtype, dbflags, DKIMF_DB_MODE,
02431                                NULL, NULL, &newdb);
02432 # else /* DB_VERSION_CHECK(2,0,0) */
02433               newdb = dbopen(p,
02434                              (flags & DKIMF_DB_FLAG_READONLY ? O_RDONLY
02435                                                               : (O_CREAT|O_RDWR)),
02436                              DKIMF_DB_MODE, bdbtype, NULL);
02437               if (newdb == NULL)
02438                      status = errno;
02439 # endif /* DB_VERSION_CHECK */
02440 
02441               if (status != 0)
02442               {
02443                      if (err != NULL)
02444                             *err = DB_STRERROR(status);
02445                      free(new);
02446                      return 3;
02447               }
02448 
02449               new->db_handle = newdb;
02450 
02451               break;
02452          }
02453 #endif /* USE_DB */
02454 
02455 #ifdef USE_ODBX
02456          case DKIMF_DB_TYPE_DSN:
02457          {
02458               _Bool found;
02459               int dberr;
02460               struct dkimf_db_dsn *dsn;
02461               char *q;
02462               char *r;
02463               char *eq;
02464               char *tmp;
02465               odbx_t *odbx;
02466 
02467               dsn = (struct dkimf_db_dsn *) malloc(sizeof(struct dkimf_db_dsn));
02468               if (dsn == NULL)
02469               {
02470                      if (err != NULL)
02471                             *err = strerror(errno);
02472                      free(new);
02473                      return -1;
02474               }
02475 
02476               memset(dsn, '\0', sizeof *dsn);
02477 
02478               /*
02479               **  General format of a DSN:
02480               **  <backend>://[user[:pwd]@][port+]host/dbase[/key=val[?...]]
02481               **  
02482               **  "table", "keycol" and "datacol" will be set in one of the
02483               **  key-value pairs.  "filter" is optional.
02484               */
02485 
02486               tmp = strdup(p);
02487               if (tmp == NULL)
02488               {
02489                      if (err != NULL)
02490                             *err = strerror(errno);
02491                      free(dsn);
02492                      free(new);
02493                      return -1;
02494               }
02495 
02496               q = strchr(tmp, ':');
02497               if (q == NULL)
02498               {
02499                      if (err != NULL)
02500                             *err = strerror(EINVAL);
02501                      free(dsn);
02502                      free(tmp);
02503                      free(new);
02504                      return -1;
02505               }
02506 
02507               *q = '\0';
02508               strlcpy(dsn->dsn_backend, tmp, sizeof dsn->dsn_backend);
02509 
02510               q++;
02511               if (*q != '/' || *(q + 1) != '/')
02512               {
02513                      if (err != NULL)
02514                             *err = strerror(EINVAL);
02515                      free(dsn);
02516                      free(tmp);
02517                      return -1;
02518               }
02519 
02520               q += 2;
02521               found = FALSE;
02522               for (p = dkimf_db_nextpunct(q);
02523                    !found && p != NULL;
02524                    p = dkimf_db_nextpunct(q))
02525               {
02526                      switch (*p)
02527                      {
02528                        case ':':
02529                             *p = '\0';
02530 
02531                             if (dsn->dsn_user[0] != '\0')
02532                             {
02533                                    if (err != NULL)
02534                                           *err = strerror(EINVAL);
02535                                    free(dsn);
02536                                    free(tmp);
02537                                    free(new);
02538                                    return -1;
02539                             }
02540 
02541                             strlcpy(dsn->dsn_user, q,
02542                                     sizeof dsn->dsn_user);
02543                             q = p + 1;
02544                             break;
02545 
02546                        case '@':
02547                             *p = '\0';
02548 
02549                             if (dsn->dsn_user[0] == '\0')
02550                             {
02551                                    strlcpy(dsn->dsn_user, q,
02552                                            sizeof dsn->dsn_user);
02553                             }
02554                             else
02555                             {
02556                                    strlcpy(dsn->dsn_password, q,
02557                                            sizeof dsn->dsn_password);
02558                             }
02559 
02560                             q = p + 1;
02561                             break;
02562 
02563                        case '+':
02564                             *p = '\0';
02565 
02566                             strlcpy(dsn->dsn_port, q,
02567                                     sizeof dsn->dsn_port);
02568 
02569                             q = p + 1;
02570                             break;
02571 
02572                        case '/':
02573                             *p = '\0';
02574                             if (dsn->dsn_host[0] == '\0')
02575                             {
02576                                    strlcpy(dsn->dsn_host, q,
02577                                            sizeof dsn->dsn_host);
02578                             }
02579                             else
02580                             {
02581                                    found = TRUE;
02582                                    strlcpy(dsn->dsn_dbase, q,
02583                                            sizeof dsn->dsn_dbase);
02584                             }
02585                             q = p + 1;
02586                             break;
02587 
02588                        default:
02589                             if (err != NULL)
02590                                    *err = strerror(EINVAL);
02591                             free(dsn);
02592                             free(tmp);
02593                             free(new);
02594                             return -1;
02595                      }
02596               }
02597 
02598               if (dsn->dsn_host[0] == '\0')
02599               {
02600                      if (err != NULL)
02601                             *err = "SQL host not defined";
02602                      free(dsn);
02603                      free(tmp);
02604                      free(new);
02605                      return -1;
02606               }
02607 
02608               for (p = strtok_r(q, "?", &r);
02609                    p != NULL;
02610                    p = strtok_r(NULL, "?", &r))
02611               {
02612                      eq = strchr(p, '=');
02613                      if (eq == NULL)
02614                             continue;
02615 
02616                      *eq = '\0';
02617                      if (strcasecmp(p, "table") == 0)
02618                      {
02619                             strlcpy(dsn->dsn_table, eq + 1,
02620                                     sizeof dsn->dsn_table);
02621                      }
02622                      else if (strcasecmp(p, "keycol") == 0)
02623                      {
02624                             strlcpy(dsn->dsn_keycol, eq + 1,
02625                                     sizeof dsn->dsn_keycol);
02626                      }
02627                      else if (strcasecmp(p, "datacol") == 0)
02628                      {
02629                             strlcpy(dsn->dsn_datacol, eq + 1,
02630                                     sizeof dsn->dsn_datacol);
02631                      }
02632                      else if (strcasecmp(p, "filter") == 0)
02633                      {
02634                             size_t len;
02635 
02636                             len = strlen(eq + 1) + 1;
02637 
02638                             dsn->dsn_filter = malloc(len);
02639                             if (dsn->dsn_filter != NULL)
02640                             {
02641                                    int c;
02642                                    char *q;
02643                                    char *r;
02644 
02645                                    memset((void *) dsn->dsn_filter,
02646                                           '\0', len);
02647 
02648                                    r = (char *) dsn->dsn_filter;
02649 
02650                                    for (q = eq + 1;
02651                                         q < eq + len;
02652                                         q++)
02653                                    {
02654                                           if (*q == '=' &&
02655                                               isxdigit(*(q + 1)) &&
02656                                               isxdigit(*(q + 2)))
02657                                           {
02658                                                  c = 16 * dkimf_db_hexdigit(*(q + 1));
02659                                                  c += dkimf_db_hexdigit(*(q + 2));
02660                                                  *r++ = c;
02661                                                  q += 2;
02662                                           }
02663                                           else
02664                                           {
02665                                                  *r++ = *q;
02666                                           }
02667                                    }
02668                             }
02669                      }
02670               }
02671 
02672               /* error out if one of the required parameters was absent */
02673               if (dsn->dsn_table[0] == '\0' ||
02674                   dsn->dsn_keycol[0] == '\0' ||
02675                   dsn->dsn_datacol[0] == '\0')
02676               {
02677                      if (err != NULL)
02678                             *err = strerror(EINVAL);
02679                      free(dsn);
02680                      free(tmp);
02681                      free(new);
02682                      return -1;
02683               }
02684 
02685 # ifdef _FFR_DB_HANDLE_POOLS
02686               new->db_handle = dkimf_db_hp_new(new->db_type,
02687                                                DEFPOOLMAX, dsn);
02688               if (new == NULL)
02689               {
02690                      if (err != NULL)
02691                             *err = strerror(errno);
02692                      free(dsn);
02693                      free(tmp);
02694                      free(new);
02695                      return -1;
02696               }
02697 # else /* _FFR_DB_HANDLE_POOLS */
02698               /* create odbx handle */
02699               dberr = odbx_init(&odbx,
02700                                 STRORNULL(dsn->dsn_backend),
02701                                 STRORNULL(dsn->dsn_host),
02702                                 STRORNULL(dsn->dsn_port));
02703               if (dberr < 0)
02704               {
02705                      if (err != NULL)
02706                             *err = (char *) odbx_error(NULL, dberr);
02707                      free(dsn);
02708                      free(tmp);
02709                      return -1;
02710               }
02711 
02712               /* create bindings */
02713               dberr = odbx_bind(odbx, STRORNULL(dsn->dsn_dbase),
02714                                       STRORNULL(dsn->dsn_user),
02715                                       STRORNULL(dsn->dsn_password),
02716                                       ODBX_BIND_SIMPLE);
02717               if (dberr < 0)
02718               {
02719                      if (err != NULL)
02720                             *err = (char *) odbx_error(odbx, dberr);
02721                      (void) odbx_finish(odbx);
02722                      free(dsn);
02723                      free(tmp);
02724                      free(new);
02725                      return -1;
02726               }
02727 
02728               /* store handle */
02729               new->db_handle = (void *) odbx;
02730 # endif /* _FFR_DB_HANDLE_POOLS */
02731 
02732               new->db_data = (void *) dsn;
02733 
02734               /* clean up */
02735               free(tmp);
02736 
02737               break;
02738          }
02739 #endif /* USE_ODBX */
02740 
02741 #ifdef USE_LDAP
02742          case DKIMF_DB_TYPE_LDAP:
02743          {
02744               _Bool found;
02745               _Bool usetls = FALSE;
02746               int c;
02747               int lderr;
02748               int v = LDAP_VERSION3;
02749               size_t rem;
02750               size_t plen;
02751               struct dkimf_db_ldap *ldap;
02752               LDAP *ld;
02753               char *q;
02754               char *r;
02755               char *u;
02756               LDAPURLDesc *descr;
02757 #ifdef _FFR_LDAP_CACHING
02758 # ifdef USE_DB
02759               DB *newdb;
02760 # endif /* USE_DB */
02761 #endif /* _FFR_LDAP_CACHING */
02762               char *uris[DKIMF_LDAP_MAXURIS];
02763 
02764               memset(uris, '\0', sizeof uris);
02765 
02766               p = strdup(name);
02767               if (p == NULL)
02768               {
02769                      if (err != NULL)
02770                             *err = strerror(errno);
02771                      free(new);
02772                      return -1;
02773               }
02774 
02775               /* make sure they're all valid LDAP URIs */
02776               for (q = strtok_r(p, " \t", &r), c = 0;
02777                    q != NULL;
02778                    q = strtok_r(NULL, " \t", &r), c++)
02779               {
02780                      if (ldap_is_ldap_url(q) == 0)
02781                      {
02782                             if (err != NULL)
02783                                    *err = strerror(EINVAL);
02784                             free(p);
02785                             free(new);
02786                             return -1;
02787                      }
02788 
02789                      /* store the first N of them */
02790                      if (c < DKIMF_LDAP_MAXURIS)
02791                             uris[c] = q;
02792               }
02793 
02794               ldap = (struct dkimf_db_ldap *) malloc(sizeof(struct dkimf_db_ldap));
02795               if (ldap == NULL)
02796               {
02797                      if (err != NULL)
02798                             *err = strerror(errno);
02799                      free(p);
02800                      free(new);
02801                      return -1;
02802               }
02803 
02804               memset(ldap, '\0', sizeof *ldap);
02805               q = dkimf_db_ldap_param[DKIMF_LDAP_PARAM_TIMEOUT];
02806               if (q == NULL)
02807               {
02808                      ldap->ldap_timeout = DKIMF_LDAP_DEFTIMEOUT;
02809               }
02810               else
02811               {
02812                      errno = 0;
02813                      ldap->ldap_timeout = strtoul(q, &r, 10);
02814                      if (errno == ERANGE)
02815                             ldap->ldap_timeout = DKIMF_LDAP_DEFTIMEOUT;
02816               }
02817 
02818               /*
02819               **  General format of an LDAP specification:
02820               **  scheme://host[:port][/dn[?attrs[?scope[?filter[?exts]]]]]
02821               **  (see RFC4516)
02822               **  
02823               **  "bindpass", "authmech" and "usetls" will be set in
02824               **  other config values.
02825               **  
02826               **  Take the descriptive values (e.g. attributes) from the
02827               **  first one.
02828               */
02829 
02830               lderr = ldap_url_parse(uris[0], &ldap->ldap_descr);
02831               if (lderr != 0)
02832               {
02833                      if (err != NULL)
02834                             *err = ldap_err2string(lderr);
02835                      free(ldap);
02836                      free(p);
02837                      free(new);
02838                      return -1;
02839               }
02840 
02841               /* construct the URI list for this handle */
02842               rem = sizeof ldap->ldap_urilist;
02843               q = ldap->ldap_urilist;
02844               for (c = 0; c < DKIMF_LDAP_MAXURIS; c++)
02845               {
02846                      if (uris[c] == NULL)
02847                             break;
02848 
02849                      (void) ldap_url_parse(uris[c], &descr);
02850 
02851                      if (c != 0)
02852                      {
02853                             *q = ' ';
02854                             q++;
02855                             rem--;
02856                      }
02857 
02858                      plen = snprintf(q, rem, "%s://%s:%d",
02859                                      descr->lud_scheme,
02860                                      descr->lud_host,
02861                                      descr->lud_port);
02862 
02863                      if (plen >= rem)
02864                      {
02865                             if (err != NULL)
02866                                    *err = "LDAP URI too large";
02867                             free(ldap);
02868                             free(p);
02869                             free(new);
02870                             return -1;
02871                      }
02872 
02873                      q += plen;
02874                      rem -= plen;
02875 
02876                      ldap_free_urldesc(descr);
02877               }
02878 
02879               lderr = dkimf_db_open_ldap(&ld, ldap, err);
02880               if (lderr != LDAP_SUCCESS &&
02881                   (flags & DKIMF_DB_FLAG_SOFTSTART) == 0)
02882               {
02883                      if (err != NULL)
02884                             *err = ldap_err2string(lderr);
02885                      free(ldap);
02886                      free(p);
02887                      free(new);
02888                      return -1;
02889               }
02890               else
02891               {
02892                      ld = NULL;
02893               }
02894 
02895               pthread_mutex_init(&ldap->ldap_lock, NULL);
02896 
02897 # ifdef _FFR_LDAP_CACHING
02898 #  ifdef USE_DB
02899               /* establish LDAP cache DB */
02900               lderr = 0;
02901 
02902 #   if DB_VERSION_CHECK(3,0,0)
02903               lderr = db_create(&newdb, NULL, 0);
02904               if (lderr == 0)
02905               {
02906 #    if DB_VERSION_CHECK(4,1,25)
02907                      lderr = newdb->open(newdb, NULL, NULL, NULL,
02908                                          DB_HASH, DB_CREATE, 0);
02909 #    else /* DB_VERSION_CHECK(4,1,25) */
02910                      lderr = newdb->open(newdb, NULL, NULL, DB_HASH,
02911                                          DB_CREATE, 0);
02912 #    endif /* DB_VERSION_CHECK(4,1,25) */
02913               }
02914 #   elif DB_VERSION_CHECK(2,0,0)
02915               lderr = db_open(NULL, DB_HASH, 0, DKIMF_DB_MODE,
02916                               NULL, NULL, &newdb);
02917 #   else /* DB_VERSION_CHECK(2,0,0) */
02918               newdb = dbopen(NULL, (O_CREAT|O_RDWR),
02919                              DKIMF_DB_MODE, DB_HASH, NULL);
02920               if (newdb == NULL)
02921                      lderr = errno;
02922 #   endif /* DB_VERSION_CHECK */
02923 
02924               if (lderr == 0)
02925               {
02926                      DKIMF_DB cachedb;
02927 
02928                      cachedb = malloc(sizeof *cachedb);
02929                      if (cachedb != NULL)
02930                      {
02931                             memset(cachedb, '\0', sizeof *cachedb);
02932 
02933                             cachedb->db_type = DKIMF_DB_TYPE_BDB;
02934                             cachedb->db_handle = newdb;
02935 
02936                             ldap->ldap_cache = cachedb;
02937                      }
02938                      else
02939                      {
02940                             DKIMF_DBCLOSE(newdb);
02941                      }
02942               }
02943 #  endif /* USE_DB */
02944 # endif /* _FFR_LDAP_CACHING */
02945 
02946               /* store handle */
02947               new->db_handle = (void *) ld;
02948               new->db_data = (void *) ldap;
02949 
02950               /* clean up */
02951               free(p);
02952               break;
02953          }
02954 #endif /* USE_LDAP */
02955 
02956 #ifdef USE_LUA
02957          case DKIMF_DB_TYPE_LUA:
02958          {
02959               int fd;
02960               ssize_t rlen;
02961               char *tmp;
02962               struct stat s;
02963               struct dkimf_lua_script_result lres;
02964               struct dkimf_db_lua *lua;
02965 
02966               fd = open(p, O_RDONLY);
02967               if (fd < 0)
02968               {
02969                      if (err != NULL)
02970                             *err = strerror(errno);
02971                      return -1;
02972               }
02973 
02974               if (fstat(fd, &s) == -1)
02975               {
02976                      if (err != NULL)
02977                             *err = strerror(errno);
02978                      close(fd);
02979                      return -1;
02980               }
02981 
02982               lua = (struct dkimf_db_lua *) malloc(sizeof *lua);
02983               if (lua == NULL)
02984               {
02985                      if (err != NULL)
02986                             *err = strerror(errno);
02987                      return -1;
02988               }
02989               memset(lua, '\0', sizeof *lua);
02990               new->db_data = (void *) lua;
02991 
02992               tmp = (void *) malloc(s.st_size + 1);
02993               if (tmp == NULL)
02994               {
02995                      if (err != NULL)
02996                             *err = strerror(errno);
02997                      free(new->db_data);
02998                      close(fd);
02999                      return -1;
03000               }
03001               memset(tmp, '\0', s.st_size + 1);
03002 
03003               rlen = read(fd, tmp, s.st_size);
03004               if (rlen < s.st_size)
03005               {
03006                      if (err != NULL)
03007                      {
03008                             if (rlen == -1)
03009                                    *err = strerror(errno);
03010                             else
03011                                    *err = "Read truncated";
03012                      }
03013                      free(tmp);
03014                      free(new->db_data);
03015                      close(fd);
03016                      return -1;
03017               }
03018 
03019               close(fd);
03020 
03021               /* try to compile it */
03022               if (dkimf_lua_db_hook(tmp, 0, NULL, &lres, 
03023                                     (void *) &lua->lua_script,
03024                                     &lua->lua_scriptlen) != 0)
03025               {
03026                      if (err != NULL)
03027                             *err = "Lua compilation error";
03028                      free(tmp);
03029                      free(new->db_data);
03030                      return -1;
03031               }
03032 
03033               free(tmp);
03034               break;
03035          }
03036 #endif /* USE_LUA */
03037 
03038 #ifdef USE_LIBMEMCACHED
03039          case DKIMF_DB_TYPE_MEMCACHE:
03040          {
03041               int ns = 0;
03042               in_port_t port;
03043               char *colon;
03044               char *q;
03045               char *key;
03046               char *last;
03047               char *tmp;
03048               memcached_st *mcs = NULL;
03049 
03050               tmp = strdup(p);
03051               if (tmp == NULL)
03052                      return -1;
03053 
03054               q = strchr(tmp, '/');
03055               if (q == NULL)
03056               {
03057                      free(tmp);
03058                      return -1;
03059               }
03060               *q = '\0';
03061 
03062               key = strdup(q + 1);
03063               if (key == NULL)
03064               {
03065                      free(tmp);
03066                      return -1;
03067               }
03068 
03069               mcs = memcached_create(NULL);
03070               if (mcs == NULL)
03071               {
03072                      free(tmp);
03073                      free(key);
03074                      return -1;
03075               }
03076 
03077               for (q = strtok_r(tmp, ",", &last);
03078                    q != NULL;
03079                    q = strtok_r(NULL, ",", &last))
03080               {
03081                      colon = strchr(q, ':');
03082                      if (colon != NULL)
03083                             *colon = '\0';
03084 
03085                      if (colon == NULL)
03086                             port = MEMCACHED_DEFAULT_PORT;
03087                      else
03088                             port = atoi(colon + 1);
03089 
03090                      if (memcached_server_add(mcs,
03091                                               q, port) != MEMCACHED_SUCCESS)
03092                      {
03093                             free(tmp);
03094                             free(key);
03095                             memcached_free(mcs);
03096                             return -1;
03097                      }
03098               }
03099 
03100               new->db_handle = mcs;
03101               new->db_data = key;
03102 
03103               free(tmp);
03104               break;
03105          }
03106 #endif /* USE_LIBMEMCACHED */
03107 
03108 #ifdef _FFR_REPUTATION
03109          case DKIMF_DB_TYPE_REPUTE:
03110          {
03111               unsigned int reporter = 0;
03112               char *q;
03113               REPUTE r;
03114               struct dkimf_db_repute *dbr;
03115               char useragent[BUFRSZ + 1];
03116 
03117               q = strchr(p, ':');
03118               if (q != NULL)
03119               {
03120                      char *s;
03121 
03122                      *q = '\0';
03123                      reporter = (unsigned int) strtoul(q + 1, &s, 10);
03124                      if (*s != '\0')
03125                             return -1;
03126               }
03127 
03128               r = repute_new(p, reporter);
03129               if (r == NULL)
03130                      return -1;
03131 
03132               q = (char *) repute_curlversion(r);
03133               snprintf(useragent, sizeof useragent, "%s/%s %s%s%s",
03134                        DKIMF_PRODUCTNS, VERSION,
03135                        "libcurl",
03136                        q == NULL ? "" : "/",
03137                        q == NULL ? "" : q);
03138               repute_useragent(r, useragent);
03139 
03140               dbr = (struct dkimf_db_repute *) malloc(sizeof *dbr);
03141               if (dbr == NULL)
03142               {
03143                      repute_close(r);
03144                      return -1;
03145               }
03146 
03147               dbr->repute_handle = r;
03148 # ifdef _FFR_REPUTATION_CACHE
03149               dbr->repute_cache = NULL;
03150 # endif /* _FFR_REPUTATION_CACHE */
03151 
03152               new->db_data = (void *) dbr;
03153 
03154               break;
03155          }
03156 #endif /* _FFR_REPUTATION */
03157 
03158 #ifdef _FFR_SOCKETDB
03159          case DKIMF_DB_TYPE_SOCKET:
03160          {
03161               int fd;
03162               int status;
03163               char *colon;
03164               struct dkimf_db_socket *sdb;
03165 
03166               sdb = (struct dkimf_db_socket *) malloc(sizeof *sdb);
03167               if (sdb == NULL)
03168               {
03169                      if (err != NULL)
03170                             *err = strerror(errno);
03171                      free(new);
03172                      return 2;
03173               }
03174 
03175               if ((flags & DKIMF_DB_FLAG_READONLY) == 0)
03176               {
03177                      if (err != NULL)
03178                             *err = strerror(EINVAL);
03179                      free(new);
03180                      errno = EINVAL;
03181                      return 2;
03182               }
03183 
03184               if (*p == '/')
03185               {                                  /* UNIX domain */
03186                      struct sockaddr_un sun;
03187 
03188                      fd = socket(AF_UNIX, SOCK_STREAM, 0);
03189                      if (fd < 0)
03190                      {
03191                             if (err != NULL)
03192                                    *err = strerror(errno);
03193                             free(new);
03194                             return 2;
03195                      }
03196 
03197                      memset(&sun, '\0', sizeof sun);
03198                      sun.sun_family = AF_UNIX;
03199                      sun.sun_len = sizeof(sun);
03200                      dkim_strlcpy(sun.sun_path, p, sizeof(sun.sun_path));
03201 
03202                      status = connect(fd, (struct sockaddr *) &sun,
03203                                       sizeof sun);
03204                      if (status < 0)
03205                      {
03206                             if (err != NULL)
03207                                    *err = strerror(errno);
03208                             free(new);
03209                             return 2;
03210                      }
03211               }
03212               else
03213               {                                  /* port@host */
03214                      int af;
03215                      char *at;
03216                      char *q;
03217                      uint16_t port;
03218                      struct sockaddr_storage ss;
03219                      struct in_addr ip4;
03220 # ifdef AF_INET6
03221                      struct in6_addr ip6;
03222 # endif /* AF_INET6 */
03223 
03224                      at = strchr(p, '@');
03225                      if (at == NULL)
03226                      {
03227                             if (err != NULL)
03228                                    *err = strerror(EINVAL);
03229                             free(new);
03230                             errno = EINVAL;
03231                             return 2;
03232                      }
03233 
03234                      *at = '\0';
03235 
03236                      port = (uint16_t) strtoul(p, &q, 10);
03237                      if (*q != '\0')
03238                      {
03239                             struct servent *srv;
03240 
03241                             srv = getservbyname(p, "tcp");
03242                             if (srv == NULL)
03243                             {
03244                                    if (err != NULL)
03245                                           *err = strerror(EINVAL);
03246                                    free(new);
03247                                    errno = EINVAL;
03248                                    return 2;
03249                             }
03250 
03251                             port = srv->s_port;
03252                      }
03253                      else
03254                      {
03255                             port = htons(port);
03256                      }
03257 
03258                      fd = -1;
03259 
03260                      if (inet_pton(AF_INET, at + 1, &ip4) == 1)
03261                      {
03262                             af = AF_INET;
03263                      }
03264 # ifdef AF_INET6
03265                      else if (inet_pton(AF_INET6, at + 1, &ip6) == 1)
03266                      {
03267                             af = AF_INET6;
03268                      }
03269 # endif /* AF_INET6 */
03270                      else
03271                      {
03272 # ifdef HAVE_GETADDRINFO
03273                             int save_errno;
03274                             struct addrinfo hint;
03275                             struct addrinfo *aitop;
03276                             struct addrinfo *aicur;
03277                             struct protoent *proto;
03278 
03279                             proto = getprotobyname("tcp");
03280                             if (proto == NULL)
03281                             {
03282                                    if (err != NULL)
03283                                           *err = strerror(EPROTONOSUPPORT);
03284                                    free(new);
03285                                    errno = EPROTONOSUPPORT;
03286                                    return 2;
03287                             }
03288 
03289                             memset(&hint, '\0', sizeof hint);
03290                             hint.ai_protocol = proto->p_proto;
03291 
03292                             status = getaddrinfo(at + 1, p, &hint, &aitop);
03293                             if (status != 0)
03294                             {
03295                                    if (err != NULL)
03296                                           *err = (char *) gai_strerror(status);
03297                                    free(new);
03298                                    errno = EINVAL;
03299                                    return 2;
03300                             }
03301 
03302                             for (aicur = aitop;
03303                                  aicur != NULL;
03304                                  aicur = aicur->ai_next)
03305                             {
03306                                    fd = socket(aicur->ai_family,
03307                                                aicur->ai_socktype,
03308                                                aicur->ai_protocol);
03309                                    if (fd == -1)
03310                                    {
03311                                           save_errno = errno;
03312                                           continue;
03313                                    }
03314 
03315                                    status = connect(fd, aicur->ai_addr,
03316                                                     aicur->ai_addrlen);
03317                                    if (status == 0)
03318                                           break;
03319 
03320                                    save_errno = errno;
03321                                    close(fd);
03322                                    fd = -1;
03323                             }
03324 
03325                             freeaddrinfo(aitop);
03326 
03327                             if (fd == -1)
03328                             {
03329                                    if (err != NULL)
03330                                           *err = strerror(save_errno);
03331                                    free(new);
03332                                    errno = save_errno;
03333                                    return 2;
03334                             }
03335 # else /* HAVE_GETADDRINFO */
03336                             struct hostent *h;
03337                             struct sockaddr_in sin4;
03338 #  ifdef HAVE_GETHOSTBYNAME2
03339                             struct sockaddr_in6 sin6;
03340 
03341                             h = gethostbyname2(at + 1, AF_INET6);
03342                             if (h != NULL)
03343                             {
03344                                    af = AF_INET6;
03345 
03346                                    fd = socket(AF_INET6, SOCK_STREAM, 0);
03347                                    if (fd < 0)
03348                                    {
03349                                           if (err != NULL)
03350                                                  *err = strerror(errno);
03351                                           free(new);
03352                                           return 2;
03353                                    }
03354 
03355                                    for (c = 0;
03356                                         h->h_addr_list[c] != NULL;
03357                                         c++)
03358                                    {
03359                                           memset(&sin6, '\0',
03360                                                  sizeof sin6);
03361 
03362                                           sin6.sin6_family = AF_INET6;
03363                                           sin6.sin6_port = port;
03364                                           memcpy(&sin6.sin6_addr,
03365                                                  h->h_addr_list[c],
03366                                                  sizeof sin6.sin6_addr);
03367 
03368                                           status = connect(fd,
03369                                                            (struct sockaddr *) &sin6,
03370                                                            sizeof sin6);
03371                                           if (status == 0)
03372                                                  break;
03373 
03374                                           save_errno = errno;
03375                                    }
03376 
03377                                    close(fd);
03378                                    fd = -1;
03379                             }
03380 #  endif /* HAVE_GETHOSTBYNAME2 */
03381 
03382                             h = gethostbyname(at + 1);
03383                             if (h != NULL)
03384                             {
03385                                    af = AF_INET;
03386 
03387                                    fd = socket(AF_INET, SOCK_STREAM, 0);
03388                                    if (fd < 0)
03389                                    {
03390                                           if (err != NULL)
03391                                                  *err = strerror(errno);
03392                                           free(new);
03393                                           return 2;
03394                                    }
03395 
03396                                    for (c = 0;
03397                                         h->h_addr_list[c] != NULL;
03398                                         c++)
03399                                    {
03400                                           memset(&sin4, '\0',
03401                                                  sizeof sin4);
03402 
03403                                           sin.sin_family = AF_INET;
03404                                           sin.sin_port = port;
03405                                           memcpy(&sin.sin_addr,
03406                                                  h->h_addr_list[c],
03407                                                  sizeof sin.sin_addr);
03408 
03409                                           status = connect(fd,
03410                                                            (struct sockaddr *) &sin4,
03411                                                            sizeof sin4);
03412                                           if (status == 0)
03413                                                  break;
03414 
03415                                           save_errno = errno;
03416                                    }
03417 
03418                                    close(fd);
03419                                    fd = -1;
03420                             }
03421 
03422                             if (fd == -1)
03423                             {
03424                                    if (err != NULL)
03425                                           *err = strerror(save_errno);
03426                                    free(new);
03427                                    errno = save_errno;
03428                                    return 2;
03429                             }
03430 # endif /* HAVE_GETADDRINFO */
03431                      }
03432 
03433                      if (fd == -1)
03434                      {
03435                             int save_errno;
03436 
03437                             fd = socket(af, SOCK_STREAM, 0);
03438                             if (fd < 0)
03439                             {
03440                                    if (err != NULL)
03441                                           *err = strerror(errno);
03442                                    free(new);
03443                                    return 2;
03444                             }
03445 
03446 # ifdef AF_INET6
03447                             if (af == AF_INET6)
03448                             {
03449                                    struct sockaddr_in6 sin6;
03450 
03451                                    memset(&sin6, '\0', sizeof sin6);
03452 
03453                                    sin6.sin6_family = AF_INET6;
03454                                    sin6.sin6_port = port;
03455                                    memcpy(&sin6.sin6_addr, &ip6,
03456                                           sizeof sin6.sin6_addr);
03457 
03458                                    status = connect(fd,
03459                                                     (struct sockaddr *) &sin6,
03460                                                     sizeof sin6);
03461 
03462                                    if (status != 0)
03463                                    {
03464                                           save_errno = errno;
03465                                           close(fd);
03466                                           if (err != NULL)
03467                                                  *err = strerror(save_errno);
03468                                           free(new);
03469                                           return 2;
03470                                    }
03471                             }
03472 # endif /* AF_INET6 */
03473 
03474                             if (af == AF_INET)
03475                             {
03476                                    struct sockaddr_in sin4;
03477 
03478                                    memset(&sin4, '\0', sizeof sin4);
03479 
03480                                    sin4.sin_family = AF_INET;
03481                                    sin4.sin_port = port;
03482                                    memcpy(&sin4.sin_addr, &ip4,
03483                                           sizeof sin4.sin_addr);
03484 
03485                                    status = connect(fd,
03486                                                     (struct sockaddr *) &sin4,
03487                                                     sizeof sin4);
03488 
03489                                    if (status != 0)
03490                                    {
03491                                           save_errno = errno;
03492                                           close(fd);
03493                                           if (err != NULL)
03494                                                  *err = strerror(save_errno);
03495                                           free(new);
03496                                           return 2;
03497                                    }
03498                             }
03499                      }
03500               }
03501 
03502               sdb->sockdb_fd = fd;
03503               sdb->sockdb_buf = dkimf_dstring_new(BUFRSZ, 0);
03504 
03505               new->db_handle = sdb;
03506 
03507               break;
03508          }
03509 #endif /* _FFR_SOCKETDB */
03510 
03511 #ifdef USE_MDB
03512          case DKIMF_DB_TYPE_MDB:
03513          {
03514               int status;
03515               struct dkimf_db_mdb *mdb;
03516 
03517               mdb = (struct dkimf_db_mdb *) malloc(sizeof *mdb);
03518               if (mdb == NULL)
03519                      return -1;
03520 
03521               status = mdb_env_create(&mdb->mdb_env);
03522               if (status != 0)
03523               {
03524                      if (err != NULL)
03525                             *err = mdb_strerror(status);
03526                      free(mdb);
03527                      return -1;
03528               }
03529 
03530               status = mdb_env_open(mdb->mdb_env, p, 0, 0);
03531               if (status != 0)
03532               {
03533                      if (err != NULL)
03534                             *err = mdb_strerror(status);
03535                      mdb_env_close(mdb->mdb_env);
03536                      free(mdb);
03537                      return -1;
03538               }
03539 
03540               status = mdb_txn_begin(mdb->mdb_env, NULL, 0, &mdb->mdb_txn);
03541               if (status != 0)
03542               {
03543                      if (err != NULL)
03544                             *err = mdb_strerror(status);
03545                      mdb_env_close(mdb->mdb_env);
03546                      free(mdb);
03547                      return -1;
03548               }
03549 
03550               status = mdb_open(mdb->mdb_txn, NULL, 0, &mdb->mdb_dbi);
03551               if (status != 0)
03552               {
03553                      if (err != NULL)
03554                             *err = mdb_strerror(status);
03555                      mdb_txn_abort(mdb->mdb_txn);
03556                      mdb_env_close(mdb->mdb_env);
03557                      free(mdb);
03558                      return -1;
03559               }
03560 
03561               new->db_data = (void *) mdb;
03562 
03563               break;
03564          }
03565 #endif /* USE_MDB */
03566 
03567 #ifdef USE_ERLANG
03568          case DKIMF_DB_TYPE_ERLANG:
03569          {
03570               _Bool err = FALSE;
03571               int c;
03572               char *q;
03573               char *last;
03574               char *r;
03575               char *tmp;
03576               struct dkimf_db_erlang *e;
03577 
03578               /*
03579               **  Erlang dataset configuration format:
03580               **   erlang:node1,node2,...:cookie:module:function
03581               */
03582 
03583               tmp = strdup(p);
03584               if (tmp == NULL)
03585                      return -1;
03586 
03587               e = calloc(1, sizeof *e);
03588               if (e == NULL)
03589               {
03590                      free(tmp);
03591                      return -1;
03592               }
03593 
03594               c = 0;
03595 
03596               for (q = strtok_r(tmp, ":", &last);
03597                    !err && q != NULL;
03598                    q = strtok_r(NULL, ":", &last))
03599               {
03600                      switch (c)
03601                      {
03602                        case 0:
03603                             e->erlang_nodes = strdup(q);
03604                             if (e->erlang_nodes == NULL)
03605                                    err = TRUE;
03606                             break;
03607 
03608                        case 1:
03609                             e->erlang_cookie = strdup(q);
03610                             if (e->erlang_cookie == NULL)
03611                                    err = TRUE;
03612                             break;
03613 
03614                        case 2:
03615                             e->erlang_module = strdup(q);
03616                             if (e->erlang_module == NULL)
03617                                    err = TRUE;
03618                             break;
03619 
03620                        case 3:
03621                             e->erlang_function = strdup(q);
03622                             if (e->erlang_function == NULL)
03623                                    err = TRUE;
03624                             break;
03625 
03626                        case 4:
03627                             err = TRUE;
03628                             break;
03629                      }
03630 
03631                      c++;
03632               }
03633 
03634               if (err || c < 3)
03635               {
03636                      free(tmp);
03637                      dkimf_db_erl_free(e);
03638                      return -1;
03639               }
03640 
03641               new->db_data = e;
03642               free(tmp);
03643               break;
03644          }
03645 #endif /* USE_ERLANG */
03646        }
03647 
03648        *db = new;
03649        return 0;
03650 }
03651 
03652 /*
03653 **  DKIMF_DB_DELETE -- delete a key/data pair from an open database
03654 **
03655 **  Parameters:
03656 **     db -- DB handle to use for searching
03657 **     buf -- pointer to record to be deleted
03658 **     buflen -- size of record at "buf"; if 0, use strlen()
03659 **
03660 **  Return value:
03661 **     0 -- operation successful
03662 **     !0 -- error occurred; error code returned
03663 */
03664 
03665 int
03666 dkimf_db_delete(DKIMF_DB db, void *buf, size_t buflen)
03667 {
03668        int ret = EINVAL;
03669 #ifdef USE_DB
03670        DBT q;
03671        int fd;
03672        int status;
03673        DB *bdb;
03674 #endif /* USE_DB */
03675 
03676        assert(db != NULL);
03677        assert(buf != NULL);
03678 
03679        if (db->db_type == DKIMF_DB_TYPE_FILE ||
03680            db->db_type == DKIMF_DB_TYPE_CSL || 
03681            db->db_type == DKIMF_DB_TYPE_DSN || 
03682            db->db_type == DKIMF_DB_TYPE_LDAP || 
03683            db->db_type == DKIMF_DB_TYPE_LUA || 
03684            db->db_type == DKIMF_DB_TYPE_MEMCACHE || 
03685            db->db_type == DKIMF_DB_TYPE_REPUTE || 
03686            db->db_type == DKIMF_DB_TYPE_REFILE ||
03687            db->db_type == DKIMF_DB_TYPE_ERLANG)
03688               return EINVAL;
03689 
03690 #ifdef USE_DB
03691        bdb = (DB *) db->db_handle;
03692 
03693        memset(&q, 0, sizeof q);
03694        q.data = (char *) buf;
03695        q.size = (buflen == 0 ? strlen(q.data) : buflen);
03696 
03697        ret = 0;
03698 
03699        /* establish write-lock */
03700        fd = -1;
03701        status = 0;
03702        if ((db->db_flags & DKIMF_DB_FLAG_NOFDLOCK) == 0)
03703        {
03704 # if DB_VERSION_CHECK(2,0,0)
03705               status = bdb->fd(bdb, &fd);
03706 # else /* DB_VERSION_CHECK(2,0,0) */
03707               fd = bdb->fd(bdb);
03708 # endif /* DB_VERSION_CHECK(2,0,0) */
03709        }
03710 
03711        if (db->db_lock != NULL)
03712               (void) pthread_mutex_lock(db->db_lock);
03713 
03714        if (status == 0 && fd != -1)
03715        {
03716 # ifdef LOCK_EX
03717               status = flock(fd, LOCK_EX);
03718               if (status != 0)
03719               {
03720                      db->db_status = status;
03721                      if (db->db_lock != NULL)
03722                             (void) pthread_mutex_unlock(db->db_lock);
03723                      return -1;
03724               }
03725 # else /* LOCK_EX */
03726               struct flock l;
03727 
03728               l.l_start = 0;
03729               l.l_len = 0;
03730               l.l_type = F_WRLCK;
03731               l.l_whence = SEEK_SET;
03732 
03733               status = fcntl(fd, F_SETLKW, &l);
03734               if (status != 0)
03735               {
03736                      db->db_status = status;
03737                      if (db->db_lock != NULL)
03738                             (void) pthread_mutex_unlock(db->db_lock);
03739                      return -1;
03740               }
03741 # endif /* LOCK_EX */
03742        }
03743 
03744 # if DB_VERSION_CHECK(2,0,0)
03745        status = bdb->del(bdb, NULL, &q, 0);
03746        if (status == 0)
03747               ret = 0;
03748        else
03749               ret = status;
03750 # else /* DB_VERSION_CHECK(2,0,0) */
03751        status = bdb->del(bdb, &q, 0);
03752        if (status == 1)
03753               ret = -1;
03754        else if (status == 0)
03755               ret = 0;
03756        else
03757               ret = errno;
03758 # endif /* DB_VERSION_CHECK(2,0,0) */
03759 
03760        /* surrender write-lock */
03761        if (fd != -1)
03762        {
03763 # ifdef LOCK_UN
03764               status = flock(fd, LOCK_UN);
03765               if (status != 0)
03766               {
03767                      db->db_status = status;
03768                      if (db->db_lock != NULL)
03769                             (void) pthread_mutex_unlock(db->db_lock);
03770                      return -1;
03771               }
03772 # else /* LOCK_UN */
03773               struct flock l;
03774 
03775               l.l_start = 0;
03776               l.l_len = 0;
03777               l.l_type = F_UNLCK;
03778               l.l_whence = SEEK_SET;
03779 
03780               status = fcntl(fd, F_SETLKW, &l);
03781               if (status != 0)
03782               {
03783                      db->db_status = status;
03784                      if (db->db_lock != NULL)
03785                             (void) pthread_mutex_unlock(db->db_lock);
03786                      return -1;
03787               }
03788 # endif /* LOCK_UN */
03789        }
03790 
03791        if (db->db_lock != NULL)
03792               (void) pthread_mutex_unlock(db->db_lock);
03793 #endif /* USE_DB */
03794 
03795        return ret;
03796 }
03797 
03798 /*
03799 **  DKIMF_DB_PUT -- store a key/data pair in an open database
03800 **
03801 **  Parameters:
03802 **     db -- DB handle to use for searching
03803 **     buf -- pointer to key record
03804 **     buflen -- size of key (use strlen() if 0)
03805 **     outbuf -- data buffer
03806 **     outbuflen -- number of bytes at outbuf to use as data
03807 **
03808 **  Return value:
03809 **     0 -- operation successful
03810 **     !0 -- error occurred; error code returned
03811 */
03812 
03813 int
03814 dkimf_db_put(DKIMF_DB db, void *buf, size_t buflen,
03815              void *outbuf, size_t outbuflen)
03816 {
03817        int ret = EINVAL;
03818 #ifdef USE_DB
03819        DBT d;
03820        DBT q;
03821        int fd;
03822        int status;
03823        DB *bdb;
03824 #endif /* USE_DB */
03825 #ifdef USE_MDB
03826        MDB_val key;
03827        MDB_val data;
03828        MDB_dbi dbi;
03829        MDB_txn *txn;
03830        struct dkimf_db_mdb *mdb;
03831 #endif /* USE_MDB */
03832 
03833        assert(db != NULL);
03834        assert(buf != NULL);
03835        assert(outbuf != NULL);
03836 
03837        if (db->db_type == DKIMF_DB_TYPE_FILE ||
03838            db->db_type == DKIMF_DB_TYPE_CSL || 
03839            db->db_type == DKIMF_DB_TYPE_DSN || 
03840            db->db_type == DKIMF_DB_TYPE_LDAP || 
03841            db->db_type == DKIMF_DB_TYPE_LUA || 
03842            db->db_type == DKIMF_DB_TYPE_REPUTE || 
03843            db->db_type == DKIMF_DB_TYPE_REFILE)
03844               return EINVAL;
03845 
03846 #ifdef USE_DB
03847        bdb = (DB *) db->db_handle;
03848 
03849        memset(&d, 0, sizeof d);
03850        memset(&q, 0, sizeof q);
03851 
03852        d.data = outbuf;
03853        d.size = outbuflen;
03854 # if DB_VERSION_CHECK(2,0,0)
03855        d.ulen = d.size;
03856        d.flags = DB_DBT_USERMEM;
03857 # endif /* DB_VERSION_CHECK(2,0,0) */
03858 
03859        q.data = (char *) buf;
03860        q.size = (buflen == 0 ? strlen(q.data) : buflen);
03861 # if DB_VERSION_CHECK(2,0,0)
03862        q.ulen = q.size;
03863        q.flags = DB_DBT_USERMEM;
03864 # endif /* DB_VERSION_CHECK(2,0,0) */
03865 
03866        ret = 0;
03867 
03868        /* establish write-lock */
03869        fd = -1;
03870        status = 0;
03871        if ((db->db_flags & DKIMF_DB_FLAG_NOFDLOCK) == 0)
03872        {
03873 # if DB_VERSION_CHECK(2,0,0)
03874               status = bdb->fd(bdb, &fd);
03875               if (status != 0)
03876               {
03877                      db->db_status = status;
03878                      return status;
03879               }
03880 # else /* DB_VERSION_CHECK(2,0,0) */
03881               fd = bdb->fd(bdb);
03882 # endif /* DB_VERSION_CHECK(2,0,0) */
03883        }
03884 
03885        if (db->db_lock != NULL)
03886               (void) pthread_mutex_lock(db->db_lock);
03887 
03888        if (status == 0 && fd != -1)
03889        {
03890 # ifdef LOCK_EX
03891               status = flock(fd, LOCK_EX);
03892               if (status != 0)
03893               {
03894                      db->db_status = status;
03895                      if (db->db_lock != NULL)
03896                             (void) pthread_mutex_unlock(db->db_lock);
03897                      return -1;
03898               }
03899 # else /* LOCK_EX */
03900               struct flock l;
03901 
03902               l.l_start = 0;
03903               l.l_len = 0;
03904               l.l_type = F_WRLCK;
03905               l.l_whence = SEEK_SET;
03906 
03907               status = fcntl(fd, F_SETLKW, &l);
03908               if (status != 0)
03909               {
03910                      db->db_status = status;
03911                      if (db->db_lock != NULL)
03912                             (void) pthread_mutex_unlock(db->db_lock);
03913                      return -1;
03914               }
03915 # endif /* LOCK_EX */
03916        }
03917 
03918 # if DB_VERSION_CHECK(2,0,0)
03919        status = bdb->put(bdb, NULL, &q, &d, 0);
03920        if (status == 0)
03921        {
03922               ret = 0;
03923        }
03924        else
03925        {
03926               db->db_status = status;
03927               ret = status;
03928        }
03929 # else /* DB_VERSION_CHECK(2,0,0) */
03930        status = bdb->put(bdb, &q, &d, 0);
03931        if (status == 1)
03932        {
03933               ret = -1;
03934        }
03935        else if (status == 0)
03936        {
03937               ret = 0;
03938        }
03939        else
03940        {
03941               db->db_status = status;
03942               ret = errno;
03943        }
03944 # endif /* DB_VERSION_CHECK(2,0,0) */
03945 
03946        /* surrender write-lock */
03947        if (fd != -1)
03948        {
03949 # ifdef LOCK_UN
03950               status = flock(fd, LOCK_UN);
03951               if (status != 0)
03952               {
03953                      db->db_status = status;
03954                      if (db->db_lock != NULL)
03955                             (void) pthread_mutex_unlock(db->db_lock);
03956                      return -1;
03957               }
03958 # else /* LOCK_UN */
03959               struct flock l;
03960 
03961               l.l_start = 0;
03962               l.l_len = 0;
03963               l.l_type = F_UNLCK;
03964               l.l_whence = SEEK_SET;
03965 
03966               status = fcntl(fd, F_SETLKW, &l);
03967               if (status != 0)
03968               {
03969                      db->db_status = status;
03970                      if (db->db_lock != NULL)
03971                             (void) pthread_mutex_unlock(db->db_lock);
03972                      return -1;
03973               }
03974 # endif /* LOCK_UN */
03975        }
03976 
03977        if (db->db_lock != NULL)
03978               (void) pthread_mutex_unlock(db->db_lock);
03979 #endif /* USE_DB */
03980 
03981 #ifdef USE_MDB
03982        mdb = db->db_data;
03983 
03984        if (db->db_lock != NULL)
03985               (void) pthread_mutex_lock(db->db_lock);
03986 
03987        key.mv_data = outbuf;
03988        key.mv_size = outbuflen;
03989        data.mv_data = (char *) buf;
03990        data.mv_size = (buflen == 0 ? strlen(buf) : buflen);
03991 
03992        if (mdb_txn_begin(mdb->mdb_env, NULL, 0, &txn) == 0 &&
03993            mdb_open(txn, NULL, 0, &dbi) == 0 &&
03994            mdb_put(txn, dbi, &key, &data, 0) == 0)
03995               ret = 0;
03996        else
03997               ret = -1;
03998 
03999        if (txn != NULL)
04000        {
04001               if (ret == 0)
04002                      mdb_txn_commit(txn);
04003               else
04004                      mdb_txn_abort(txn);
04005        }
04006 
04007        if (db->db_lock != NULL)
04008               (void) pthread_mutex_unlock(db->db_lock);
04009 #endif /* USE_MDB */
04010 
04011        return ret;
04012 }
04013 
04014 /*
04015 **  DKIMF_DB_GET -- retrieve data from an open database
04016 **
04017 **  Parameters:
04018 **     db -- DB handle to use for searching
04019 **     buf -- pointer to the key
04020 **     buflen -- length of key (use strlen() if 0)
04021 **     req -- list of data requests
04022 **     reqnum -- number of data requests
04023 **     exists -- pointer to a "_Bool" updated to be TRUE if the record
04024 **               was found, FALSE otherwise (may be NULL)
04025 **
04026 **  Return value:
04027 **     0 -- operation successful
04028 **     !0 -- error occurred; error code returned
04029 **
04030 **  Notes:
04031 **     "req" references a caller-provided array of DKIMF_DBDATA
04032 **     structures that describe the name of the attribute wanted,
04033 **     the location to which to write the data, and how big that buffer is.
04034 **     On completion, any found attributes will have their lengths
04035 **     set to the number of bytes retrieved and the data will be copied
04036 **     up to the limit (if more data was retrieved than the space available,
04037 **     the available space will be filled but the returned length will be
04038 **     longer); any not-found attributes will leave the buffers unchanged
04039 **     and the lengths will be set to (unsigned int) -1.
04040 **
04041 **     For LDAP queries, the attribute name is used as the LDAP attribute
04042 **     name in the request.
04043 **
04044 **     For SQL queries, the attribute name is not used; columns are specified
04045 **     in the DSN (see dkimf_db_open() above), and are copied into the
04046 **     request in order.
04047 **
04048 **     For backward compatibility, text values in the other databases
04049 **     that are colon-delimited will be parsed as such, and the requested
04050 **     values will be filled in in order (so for "aaa:bbb", "aaa" will be
04051 **     copied into the first attribute, "bbb" will be copied to the second,
04052 **     and all others will receive no data.
04053 */
04054 
04055 int
04056 dkimf_db_get(DKIMF_DB db, void *buf, size_t buflen,
04057              DKIMF_DBDATA req, unsigned int reqnum, _Bool *exists)
04058 {
04059        _Bool matched;
04060 
04061        assert(db != NULL);
04062        assert(buf != NULL);
04063        assert(req != NULL || reqnum == 0);
04064 
04065        /*
04066        **  Indicate "not found" if we require ASCII-only and there was
04067        **  non-ASCII in the query.
04068        */
04069 
04070        if ((db->db_flags & DKIMF_DB_FLAG_ASCIIONLY) != 0)
04071        {
04072               char *p;
04073               char *end;
04074 
04075               end = (char *) buf + buflen;
04076 
04077               for (p = (char *) buf; p <= end; p++)
04078               {
04079                      if (!isascii(*p))
04080                      {
04081                             if (*exists)
04082                                    *exists = FALSE;
04083 
04084                             return 0;
04085                      }
04086               }
04087        }
04088 
04089        switch (db->db_type)
04090        {
04091          case DKIMF_DB_TYPE_FILE:
04092          case DKIMF_DB_TYPE_CSL:
04093          {
04094               struct dkimf_db_list *list;
04095 
04096               for (list = (struct dkimf_db_list *) db->db_handle;
04097                    list != NULL;
04098                    list = list->db_list_next)
04099               {
04100                      matched = FALSE;
04101 
04102                      if ((db->db_flags & DKIMF_DB_FLAG_ICASE) == 0)
04103                      {
04104                             if (strcmp(buf, list->db_list_key) == 0)
04105                                    matched = TRUE;
04106                      }
04107                      else
04108                      {
04109                             if (strcasecmp(buf, list->db_list_key) == 0)
04110                                    matched = TRUE;
04111                      }
04112 
04113                      if (!matched)
04114                             continue;
04115 
04116                      if ((db->db_flags & DKIMF_DB_FLAG_MATCHBOTH) == 0 ||
04117                          reqnum == 0 || list->db_list_value == NULL)
04118                             break;
04119 
04120                      matched = FALSE;
04121                      assert(list->db_list_value != NULL);
04122 
04123                      if ((db->db_flags & DKIMF_DB_FLAG_ICASE) == 0)
04124                      {
04125                             if (strncmp(req[0].dbdata_buffer,
04126                                         list->db_list_value,
04127                                         req[0].dbdata_buflen) == 0)
04128                                    matched = TRUE;
04129                      }
04130                      else
04131                      {
04132                             if (strncasecmp(req[0].dbdata_buffer,
04133                                             list->db_list_value,
04134                                             req[0].dbdata_buflen) == 0)
04135                                    matched = TRUE;
04136                      }
04137 
04138                      if (matched)
04139                             break;
04140               }
04141 
04142               if (list == NULL)
04143               {
04144                      if (exists != NULL)
04145                             *exists = FALSE;
04146               }
04147               else
04148               {
04149                      if (exists != NULL)
04150                             *exists = TRUE;
04151                      if (list->db_list_value != NULL && reqnum != 0)
04152                      {
04153                             if (dkimf_db_datasplit(list->db_list_value,
04154                                                    strlen(list->db_list_value),
04155                                                    req, reqnum) != 0)
04156                                    return -1;
04157                      }
04158               }
04159 
04160               return 0;
04161          }
04162 
04163          case DKIMF_DB_TYPE_REFILE:
04164          {
04165               struct dkimf_db_relist *list;
04166 
04167               list = (struct dkimf_db_relist *) db->db_handle;
04168 
04169               while (list != NULL)
04170               {
04171                      if (regexec(&list->db_relist_re, buf, 0, NULL, 0) == 0)
04172                      {
04173                             if (exists != NULL)
04174                                    *exists = TRUE;
04175 
04176                             if (reqnum != 0 &&
04177                                 list->db_relist_data != NULL)
04178                             {
04179                                    if (dkimf_db_datasplit(list->db_relist_data,
04180                                                           strlen(list->db_relist_data),
04181                                                           req,
04182                                                           reqnum) != 0)
04183                                           return -1;
04184                             }
04185 
04186                             return 0;
04187                      }
04188 
04189                      list = list->db_relist_next;
04190               }
04191 
04192               if (exists != NULL)
04193                      *exists = FALSE;
04194 
04195               return 0;
04196          }
04197 
04198 #ifdef USE_DB
04199          case DKIMF_DB_TYPE_BDB:
04200          {
04201               int ret;
04202               int status;
04203               int fd;
04204               DB *bdb;
04205               DBT d;
04206               DBT q;
04207               char databuf[BUFRSZ + 1];
04208 
04209               bdb = (DB *) db->db_handle;
04210 
04211               memset(&d, 0, sizeof d);
04212               memset(&q, 0, sizeof q);
04213               q.data = (char *) buf;
04214               q.size = (buflen == 0 ? strlen(q.data) : buflen);
04215 
04216               ret = 0;
04217 
04218 # if DB_VERSION_CHECK(2,0,0)
04219               d.flags = DB_DBT_USERMEM;
04220               d.ulen = BUFRSZ;
04221 # endif /* DB_VERSION_CHECK(2,0,0) */
04222               d.data = databuf;
04223               d.size = BUFRSZ;
04224 
04225               memset(databuf, '\0', sizeof databuf);
04226 
04227               /* establish read-lock */
04228               fd = -1;
04229               status = 0;
04230               if ((db->db_flags & DKIMF_DB_FLAG_NOFDLOCK) == 0)
04231               {
04232 # if DB_VERSION_CHECK(2,0,0)
04233                      status = bdb->fd(bdb, &fd);
04234 # else /* DB_VERSION_CHECK(2,0,0) */
04235                      fd = bdb->fd(bdb);
04236 # endif /* DB_VERSION_CHECK(2,0,0) */
04237               }
04238 
04239               /* single-thread readers since we can only lock the DB once */
04240               if (db->db_lock != NULL)
04241                      (void) pthread_mutex_lock(db->db_lock);
04242 
04243               if (status == 0 && fd != -1)
04244               {
04245 # ifdef LOCK_SH
04246                      status = flock(fd, LOCK_SH);
04247                      if (status != 0)
04248                      {
04249                             db->db_status = status;
04250                             if (db->db_lock != NULL)
04251                                    (void) pthread_mutex_unlock(db->db_lock);
04252                             return -1;
04253                      }
04254 # else /* LOCK_SH */
04255                      struct flock l;
04256 
04257                      l.l_start = 0;
04258                      l.l_len = 0;
04259                      l.l_type = F_RDLCK;
04260                      l.l_whence = SEEK_SET;
04261 
04262                      status = fcntl(fd, F_SETLKW, &l);
04263                      if (status != 0)
04264                      {
04265                             db->db_status = status;
04266                             if (db->db_lock != NULL)
04267                                    (void) pthread_mutex_unlock(db->db_lock);
04268                             return -1;
04269                      }
04270 # endif /* LOCK_SH */
04271               }
04272 
04273 # if DB_VERSION_CHECK(2,0,0)
04274               status = bdb->get(bdb, NULL, &q, &d, 0);
04275               if (status == 0)
04276               {
04277                      if (exists != NULL)
04278                             *exists = TRUE;
04279 
04280                      ret = 0;
04281                      if (reqnum != 0)
04282                      {
04283                             ret = dkimf_db_datasplit(databuf, d.size,
04284                                                      req, reqnum);
04285                      }
04286 
04287               }
04288               else if (status == DB_NOTFOUND)
04289               {
04290                      if (exists != NULL)
04291                             *exists = FALSE;
04292                      ret = 0;
04293               }
04294               else
04295               {
04296                      db->db_status = status;
04297                      ret = status;
04298               }
04299 # else /* DB_VERSION_CHECK(2,0,0) */
04300               status = bdb->get(bdb, &q, &d, 0);
04301               if (status == 1)
04302               {
04303                      if (exists != NULL)
04304                             *exists = FALSE;
04305                      ret = 0;
04306               }
04307               else if (status == 0)
04308               {
04309                      size_t clen;
04310 
04311                      if (exists != NULL)
04312                             *exists = TRUE;
04313 
04314                      clen = MIN(sizeof databuf - 1, d.size);
04315                      memset(databuf, '\0', sizeof databuf);
04316                      memcpy(databuf, d.data, clen);
04317 
04318                      ret = 0;
04319                      if (reqnum != 0)
04320                      {
04321                             ret = dkimf_db_datasplit(databuf, clen,
04322                                                      req, reqnum);
04323                      }
04324               }
04325               else
04326               {
04327                      db->db_status = errno;
04328                      ret = errno;
04329               }
04330 # endif /* DB_VERSION_CHECK(2,0,0) */
04331 
04332               /* surrender read-lock */
04333               if (fd != -1)
04334               {
04335 # ifdef LOCK_SH
04336                      status = flock(fd, LOCK_UN);
04337                      if (status != 0)
04338                      {
04339                             db->db_status = status;
04340                             if (db->db_lock != NULL)
04341                                    (void) pthread_mutex_unlock(db->db_lock);
04342                             return -1;
04343                      }
04344 # else /* LOCK_SH */
04345                      struct flock l;
04346 
04347                      l.l_start = 0;
04348                      l.l_len = 0;
04349                      l.l_type = F_UNLCK;
04350                      l.l_whence = SEEK_SET;
04351 
04352                      status = fcntl(fd, F_SETLKW, &l);
04353                      if (status != 0)
04354                      {
04355                             db->db_status = status;
04356                             if (db->db_lock != NULL)
04357                                    (void) pthread_mutex_unlock(db->db_lock);
04358                             return -1;
04359                      }
04360 # endif /* LOCK_SH */
04361               }
04362 
04363               if (db->db_lock != NULL)
04364                      (void) pthread_mutex_unlock(db->db_lock);
04365 
04366               return ret;
04367          }
04368 #endif /* USE_DB */
04369 
04370 #ifdef USE_ODBX
04371          case DKIMF_DB_TYPE_DSN:
04372          {
04373               _Bool reconnected = FALSE;
04374               int err;
04375               int fields;
04376               int rescnt = 0;
04377               int rowcnt = 0;
04378               u_long elen;
04379               odbx_result_t *result;
04380               odbx_t *odbx = NULL;
04381               struct dkimf_db_dsn *dsn;
04382               char query[BUFRSZ];
04383               char escaped[BUFRSZ];
04384 
04385               dsn = (struct dkimf_db_dsn *) db->db_data;
04386 
04387 # ifdef _FFR_DB_HANDLE_POOLS
04388               odbx = dkimf_db_hp_get((struct handle_pool *) db->db_handle,
04389                                      &err);
04390               if (odbx == NULL)
04391               {
04392                      db->db_status = err;
04393                      return -1;
04394               }
04395 # else /* _FFR_DB_HANDLE_POOLS */
04396               if (db->db_lock != NULL)
04397                      (void) pthread_mutex_lock(db->db_lock);
04398 
04399               /* see if we need to reopen */
04400               if ((db->db_iflags & DKIMF_DB_IFLAG_RECONNECT) != 0)
04401               {
04402                      err = odbx_init((odbx_t **) &db->db_handle,
04403                                      STRORNULL(dsn->dsn_backend),
04404                                      STRORNULL(dsn->dsn_host),
04405                                      STRORNULL(dsn->dsn_port));
04406                      if (err < 0)
04407                      {
04408                             db->db_status = err;
04409                             return -1;
04410                      }
04411 
04412                      err = odbx_bind((odbx_t *) db->db_handle,
04413                                      STRORNULL(dsn->dsn_dbase),
04414                                       STRORNULL(dsn->dsn_user),
04415                                       STRORNULL(dsn->dsn_password),
04416                                       ODBX_BIND_SIMPLE);
04417                      if (err < 0)
04418                      {
04419                             (void) odbx_finish((odbx_t *) db->db_handle);
04420                             db->db_status = err;
04421                             return -1;
04422                      }
04423 
04424                      reconnected = TRUE;
04425                      db->db_iflags &= ~DKIMF_DB_IFLAG_RECONNECT;
04426               }
04427 
04428               odbx = (odbx_t *) db->db_handle;
04429 
04430 # endif /* _FFR_DB_HANDLE_POOLS */
04431 
04432               memset(escaped, '\0', sizeof escaped);
04433               elen = sizeof escaped - 1;
04434               err = odbx_escape(odbx, buf,
04435                                 (buflen == 0 ? strlen(buf) : buflen),
04436                                 escaped, &elen);
04437               if (err < 0)
04438               {
04439                      db->db_status = err;
04440                      if (db->db_lock != NULL)
04441                             (void) pthread_mutex_unlock(db->db_lock);
04442 
04443 # ifdef _FFR_DB_HANDLE_POOLS
04444                      dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04445                                      (void *) odbx);
04446 # endif /* _FFR_DB_HANDLE_POOLS */
04447 
04448                      return err;
04449               }
04450 
04451               snprintf(query, sizeof query,
04452                        "SELECT %s FROM %s WHERE %s = '%s'%s%s",
04453                        dsn->dsn_datacol,
04454                        dsn->dsn_table,
04455                        dsn->dsn_keycol, escaped,
04456                        dsn->dsn_filter == NULL ? "" : " AND ",
04457                        dsn->dsn_filter == NULL ? "" : dsn->dsn_filter);
04458 
04459               err = odbx_query(odbx, query, 0);
04460               if (err < 0)
04461               {
04462                      int status;
04463 
04464                      db->db_status = err;
04465 
04466                      if (reconnected)
04467                      {
04468                             if (db->db_lock != NULL)
04469                                    (void) pthread_mutex_unlock(db->db_lock);
04470 # ifdef _FFR_DB_HANDLE_POOLS
04471                             dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04472                                             (void *) odbx);
04473 # endif /* _FFR_DB_HANDLE_POOLS */
04474 
04475                             return err;
04476                      }
04477 
04478                      status = odbx_error_type(odbx, err);
04479 
04480 #ifdef _FFR_POSTGRESQL_RECONNECT_HACK
04481                      if (status >= 0)
04482                      {
04483                             const char *estr;
04484 
04485                             estr = odbx_error(odbx, db->db_status);
04486 
04487                             if (estr != NULL &&
04488                                 strncmp(estr, "FATAL:", 6) == 0)
04489                                    status = -1;
04490                      }
04491 #endif /* _FFR_POSTGRESQL_RECONNECT_HACK */
04492 
04493                      if (status < 0)
04494                      {
04495                             (void) odbx_unbind(odbx);
04496                             (void) odbx_finish(odbx);
04497 
04498 # ifdef _FFR_DB_HANDLE_POOLS
04499                             dkimf_db_hp_dead((struct handle_pool *) db->db_handle);
04500 # else /* _FFR_DB_HANDLE_POOLS */
04501                             db->db_iflags |= DKIMF_DB_IFLAG_RECONNECT;
04502 # endif /* _FFR_DB_HANDLE_POOLS */
04503 
04504                             if (db->db_lock != NULL)
04505                                    (void) pthread_mutex_unlock(db->db_lock);
04506 
04507                             return dkimf_db_get(db, buf, buflen, req,
04508                                                 reqnum, exists);
04509                      }
04510                      else
04511                      {
04512                             if (db->db_lock != NULL)
04513                                    (void) pthread_mutex_unlock(db->db_lock);
04514                             return err;
04515                      }
04516               }
04517 
04518               for (rescnt = 0; ; rescnt++)
04519               {
04520                      err = odbx_result(odbx, &result, NULL, 0);
04521                      if (err < 0)
04522                      {
04523                             int status;
04524                             db->db_status = err;
04525 
04526                             if (reconnected)
04527                             {
04528                                    if (db->db_lock != NULL)
04529                                           (void) pthread_mutex_unlock(db->db_lock);
04530 # ifdef _FFR_DB_HANDLE_POOLS
04531                                    dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04532                                                    (void *) odbx);
04533 # endif /* _FFR_DB_HANDLE_POOLS */
04534                                    return err;
04535                             }
04536 
04537                             status = odbx_error_type(odbx, err);
04538 
04539 #ifdef _FFR_POSTGRESQL_RECONNECT_HACK
04540                             if (status >= 0)
04541                             {
04542                                    const char *estr;
04543 
04544                                    estr = odbx_error(odbx, db->db_status);
04545 
04546                                    if (estr != NULL &&
04547                                        strncmp(estr, "FATAL:", 6) == 0)
04548                                           status = -1;
04549                             }
04550 #endif /* _FFR_POSTGRESQL_RECONNECT_HACK */
04551 
04552                             if (result != NULL)
04553                                    (void) odbx_result_finish(result);
04554 
04555                             if (status < 0)
04556                             {
04557                                    (void) odbx_unbind(odbx);
04558                                    (void) odbx_finish(odbx);
04559 
04560 # ifdef _FFR_DB_HANDLE_POOLS
04561                                    dkimf_db_hp_dead((struct handle_pool *) db->db_handle);
04562 # else /* _FFR_DB_HANDLE_POOLS */
04563                                    db->db_iflags |= DKIMF_DB_IFLAG_RECONNECT;
04564 # endif /* _FFR_DB_HANDLE_POOLS */
04565 
04566                                    if (db->db_lock != NULL)
04567                                           (void) pthread_mutex_unlock(db->db_lock);
04568 
04569                                    return dkimf_db_get(db, buf, buflen,
04570                                                        req, reqnum,
04571                                                        exists);
04572                             }
04573 
04574                             if (db->db_lock != NULL)
04575                                    (void) pthread_mutex_unlock(db->db_lock);
04576 # ifdef _FFR_DB_HANDLE_POOLS
04577                             dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04578                                             (void *) odbx);
04579 # endif /* _FFR_DB_HANDLE_POOLS */
04580 
04581                             return err;
04582                      }
04583                      else if (err == ODBX_RES_DONE)
04584                      {
04585                             if (exists != NULL && rescnt == 0)
04586                                    *exists = FALSE;
04587                             err = odbx_result_finish(result);
04588                             if (db->db_lock != NULL)
04589                                    (void) pthread_mutex_unlock(db->db_lock);
04590 # ifdef _FFR_DB_HANDLE_POOLS
04591                             dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04592                                             (void *) odbx);
04593 # endif /* _FFR_DB_HANDLE_POOLS */
04594 
04595                             return 0;
04596                      }
04597 
04598                      for (rowcnt = 0; ; rowcnt++)
04599                      {
04600                             err = odbx_row_fetch(result);
04601                             if (err < 0)
04602                             {
04603                                    db->db_status = err;
04604                                    err = odbx_result_finish(result);
04605                                    if (db->db_lock != NULL)
04606                                           (void) pthread_mutex_unlock(db->db_lock);
04607 # ifdef _FFR_DB_HANDLE_POOLS
04608                                    dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04609                                                    (void *) odbx);
04610 # endif /* _FFR_DB_HANDLE_POOLS */
04611                                    return db->db_status;
04612                             }
04613                             else if (err == ODBX_RES_DONE)
04614                             {
04615                                    if (exists != NULL && rescnt == 0 &&
04616                                        rowcnt == 0)
04617                                           *exists = FALSE;
04618                                    break;
04619                             }
04620 
04621                             /* only copy out the first hit */
04622                             if (rescnt == 0 && rowcnt == 0)
04623                             {
04624                                    fields = odbx_column_count(result);
04625                                    if (fields == 0)
04626                                           continue;
04627 
04628                                    if (exists != NULL)
04629                                           *exists = TRUE;
04630 
04631                                    if (reqnum != 0)
04632                                    {
04633                                           int c;
04634 
04635                                           for (c = 0; c < reqnum; c++)
04636                                           {
04637                                                  if (c >= fields)
04638                                                  {
04639                                                         req[c].dbdata_buflen = 0;
04640                                                  }
04641                                                  else
04642                                                  {
04643                                                         char *val;
04644 
04645                                                         val = (char *) odbx_field_value(result,
04646                                                                                         c);
04647 
04648                                                         if (val == NULL)
04649                                                         {
04650                                                                req[c].dbdata_buflen = 0;
04651                                                         }
04652                                                         else
04653                                                         {
04654                                                                req[c].dbdata_buflen = strlcpy(req[c].dbdata_buffer,
04655                                                                                               val,
04656                                                                                               req[c].dbdata_buflen);
04657                                                         }
04658                                                  }
04659                                           }
04660                                    }
04661                             }
04662                      }
04663 
04664                      err = odbx_result_finish(result);
04665               }
04666 
04667               if (db->db_lock != NULL)
04668                      (void) pthread_mutex_unlock(db->db_lock);
04669 
04670 # ifdef _FFR_DB_HANDLE_POOLS
04671               dkimf_db_hp_put((struct handle_pool *) db->db_handle,
04672                               (void *) odbx);
04673 # endif /* _FFR_DB_HANDLE_POOLS */
04674 
04675               return 0;
04676          }
04677 #endif /* USE_ODBX */
04678 
04679 #ifdef USE_LDAP
04680          case DKIMF_DB_TYPE_LDAP:
04681          {
04682               int c;
04683               int status;
04684               LDAP *ld;
04685               LDAPMessage *result;
04686               LDAPMessage *e;
04687               struct dkimf_db_ldap *ldap;
04688 #ifdef _FFR_LDAP_CACHING
04689 # ifdef USE_DB
04690               struct dkimf_db_ldap_cache *ldc = NULL;
04691 # endif /* USE_DB */
04692 #endif /* _FFR_LDAP_CACHING */
04693               struct berval **vals;
04694               char query[BUFRSZ];
04695               char filter[BUFRSZ];
04696               struct timeval timeout;
04697 
04698               ld = (LDAP *) db->db_handle;
04699               ldap = (struct dkimf_db_ldap *) db->db_data;
04700 
04701               pthread_mutex_lock(&ldap->ldap_lock);
04702 
04703               if (ld == NULL)
04704               {
04705                      int lderr;
04706 
04707                      lderr = dkimf_db_open_ldap(&ld, ldap, NULL);
04708                      if (lderr == LDAP_SUCCESS)
04709                      {
04710                             db->db_handle = ld;
04711                      }
04712                      else
04713                      {
04714                             db->db_status = lderr;
04715                             pthread_mutex_unlock(&ldap->ldap_lock);
04716                             return lderr;
04717                      }
04718               }
04719 
04720 #ifdef _FFR_LDAP_CACHING
04721 # ifdef USE_DB
04722               if (ldap->ldap_cache != NULL)
04723               {
04724                      _Bool cex = FALSE;
04725                      struct dkimf_db_data dbd;
04726 
04727                      dbd.dbdata_buffer = (char *) &ldc;
04728                      dbd.dbdata_buflen = sizeof ldc;
04729                      dbd.dbdata_flags = DKIMF_DB_DATA_BINARY;
04730 
04731                      status = dkimf_db_get(ldap->ldap_cache, buf, buflen,
04732                                            &dbd, 1, &cex);
04733 
04734                      if (cex)
04735                      {
04736                             struct timeval now;
04737                             struct dkimf_db_ldap_cache_result *r;
04738 
04739                             (void) gettimeofday(&now, NULL);
04740 
04741                             if (ldc->ldc_state == DKIMF_DB_CACHE_DATA &&
04742                                 ldc->ldc_absent)
04743                             {
04744                                    if (exists != NULL)
04745                                           *exists = FALSE;
04746 
04747                                    pthread_mutex_unlock(&ldap->ldap_lock);
04748                                    return 0;
04749                             }
04750                             else if (ldc->ldc_state == DKIMF_DB_CACHE_DATA &&
04751                                      ldc->ldc_expire <= now.tv_sec)
04752                             {
04753                                    ldc->ldc_state = DKIMF_DB_CACHE_PENDING;
04754                             }
04755                             else if (ldc->ldc_state == DKIMF_DB_CACHE_DATA &&
04756                                      ldc->ldc_error != 0)
04757                             {
04758                                    pthread_mutex_unlock(&ldap->ldap_lock);
04759                                    return ldc->ldc_error;
04760                             }
04761                             else if (ldc->ldc_state == DKIMF_DB_CACHE_DATA &&
04762                                      ldc->ldc_expire > now.tv_sec)
04763                             {
04764                                    if (exists != NULL)
04765                                           *exists = TRUE;
04766 
04767                                    for (c = 0;
04768                                         c < reqnum && c < ldc->ldc_nresults;
04769                                         c++)
04770                                    {
04771                                           req[c].dbdata_buflen = strlcpy(req[c].dbdata_buffer,
04772                                                                          ldc->ldc_results[c],
04773                                                                          req[c].dbdata_buflen);
04774                                    }
04775 
04776                                    while (c < reqnum)
04777                                           req[c++].dbdata_buflen = 0;
04778 
04779                                    pthread_mutex_unlock(&ldap->ldap_lock);
04780 
04781                                    return 0;
04782                             }
04783                             else if (ldc->ldc_state == DKIMF_DB_CACHE_PENDING)
04784                             {
04785                                    struct timespec timeout;
04786 
04787                                    timeout.tv_sec = now.tv_sec + ldap->ldap_timeout;
04788                                    timeout.tv_nsec = now.tv_usec * 1000;
04789 
04790                                    ldc->ldc_waiters++;
04791 
04792                                    while (ldc->ldc_state == DKIMF_DB_CACHE_PENDING)
04793                                    {
04794                                           status = pthread_cond_timedwait(&ldc->ldc_cond,
04795                                                                           &ldap->ldap_lock,
04796                                                                           &timeout);
04797                                           if (status != 0)
04798                                           {
04799                                                  pthread_mutex_unlock(&ldap->ldap_lock);
04800                                                  return status;
04801                                           }
04802                                    }
04803 
04804                                    if (ldc->ldc_error != 0)
04805                                    {
04806                                           pthread_mutex_unlock(&ldap->ldap_lock);
04807                                           return ldc->ldc_error;
04808                                    }
04809 
04810                                    if (ldc->ldc_absent)
04811                                    {
04812                                           if (exists != NULL)
04813                                                  *exists = FALSE;
04814 
04815                                           pthread_mutex_unlock(&ldap->ldap_lock);
04816                                           return 0;
04817                                    }
04818 
04819                                    for (c = 0;
04820                                         c < reqnum && c < ldc->ldc_nresults;
04821                                         c++)
04822                                    {
04823                                           req[c].dbdata_buflen = strlcpy(req[c].dbdata_buffer,
04824                                                                          ldc->ldc_results[c],
04825                                                                          req[c].dbdata_buflen);
04826                                    }
04827 
04828                                    while (c < reqnum)
04829                                           req[c++].dbdata_buflen = 0;
04830 
04831                                    ldc->ldc_waiters--;
04832 
04833                                    pthread_cond_signal(&ldc->ldc_cond);
04834 
04835                                    pthread_mutex_unlock(&ldap->ldap_lock);
04836 
04837                                    return 0;
04838                             }
04839                      }
04840 
04841                      /* add pending info to cache */
04842                      if (ldc == NULL)
04843                      {
04844                             ldc = malloc(sizeof *ldc);
04845                             if (ldc == NULL)
04846                             {
04847                                    pthread_mutex_unlock(&ldap->ldap_lock);
04848                                    return errno;
04849                             }
04850 
04851                             memset(ldc, '\0', sizeof *ldc);
04852 
04853                             pthread_cond_init(&ldc->ldc_cond, NULL);
04854                             ldc->ldc_state = DKIMF_DB_CACHE_PENDING;
04855 
04856                             status = dkimf_db_put(ldap->ldap_cache,
04857                                                   buf, buflen,
04858                                                   &ldc, sizeof ldc);
04859                             if (status != 0)
04860                             {
04861                                    pthread_mutex_unlock(&ldap->ldap_lock);
04862                                    return status;
04863                             }
04864                      }
04865 
04866                      /* unlock so others can try */
04867                      pthread_mutex_unlock(&ldap->ldap_lock);
04868 
04869                      ldc->ldc_error = 0;
04870               }
04871 # endif /* USE_DB */
04872 #endif /* _FFR_LDAP_CACHING */
04873 
04874               memset(query, '\0', sizeof query);
04875               memset(filter, '\0', sizeof filter);
04876 
04877               dkimf_db_mkldapquery(ldap->ldap_descr->lud_dn, buf, query,
04878                                    sizeof query);
04879               if (ldap->ldap_descr->lud_filter != NULL)
04880               {
04881                      dkimf_db_mkldapquery(ldap->ldap_descr->lud_filter, buf,
04882                                           filter, sizeof filter);
04883               }
04884 
04885               timeout.tv_sec = ldap->ldap_timeout;
04886               timeout.tv_usec = 0;
04887 
04888               status = ldap_search_ext_s(ld, query,
04889                                          ldap->ldap_descr->lud_scope,
04890                                          filter,
04891                                          ldap->ldap_descr->lud_attrs,
04892                                          0, NULL, NULL,
04893                                          &timeout, 0, &result);
04894               if (LDAP_NAME_ERROR(status))
04895               {
04896                      if (exists != NULL)
04897                             *exists = FALSE;
04898 #ifdef _FFR_LDAP_CACHING
04899 # ifdef USE_DB
04900                      ldc->ldc_absent = TRUE;
04901                      ldc->ldc_state = DKIMF_DB_CACHE_DATA;
04902                      pthread_cond_broadcast(&ldc->ldc_cond);
04903 # endif /* USE_DB */
04904 #endif /* _FFR_LDAP_CACHING */
04905                      pthread_mutex_unlock(&ldap->ldap_lock);
04906                      return 0;
04907               }
04908               else if (status == LDAP_SERVER_DOWN ||
04909                        status == LDAP_TIMEOUT)
04910               {
04911                      ldap_unbind_ext(ld, NULL, NULL);
04912                      db->db_handle = NULL;
04913                      if ((db->db_iflags & DKIMF_DB_IFLAG_RECONNECT) != 0)
04914                      {
04915                             db->db_status = status;
04916                             pthread_mutex_unlock(&ldap->ldap_lock);
04917                             return -1;
04918                      }
04919 
04920                      db->db_iflags |= DKIMF_DB_IFLAG_RECONNECT;
04921 
04922                      pthread_mutex_unlock(&ldap->ldap_lock);
04923 
04924                      status = dkimf_db_get(db, buf, buflen, req, reqnum,
04925                                            exists);
04926 
04927                      db->db_iflags &= ~DKIMF_DB_IFLAG_RECONNECT;
04928 
04929                      return status;
04930               }
04931               else if (status != LDAP_SUCCESS)
04932               {
04933                      db->db_status = status;
04934 #ifdef _FFR_LDAP_CACHING
04935 # ifdef USE_DB
04936                      ldc->ldc_error = status;
04937                      ldc->ldc_expire = time(NULL) + DKIMF_LDAP_TTL;
04938                      ldc->ldc_state = DKIMF_DB_CACHE_DATA;
04939                      pthread_cond_broadcast(&ldc->ldc_cond);
04940 # endif /* USE_DB */
04941 #endif /* _FFR_LDAP_CACHING */
04942                      pthread_mutex_unlock(&ldap->ldap_lock);
04943                      return status;
04944               }
04945 
04946               e = NULL;
04947               if (result != NULL)
04948                      e = ldap_first_entry(ld, result);
04949               if (e == NULL)
04950               {
04951                      if (exists != NULL)
04952                             *exists = FALSE;
04953 #ifdef _FFR_LDAP_CACHING
04954 # ifdef USE_DB
04955                      ldc->ldc_absent = TRUE;
04956                      ldc->ldc_state = DKIMF_DB_CACHE_DATA;
04957                      pthread_cond_broadcast(&ldc->ldc_cond);
04958 # endif /* USE_DB */
04959 #endif /* _FFR_LDAP_CACHING */
04960                      pthread_mutex_unlock(&ldap->ldap_lock);
04961                      return 0;
04962               }
04963 
04964               if (exists != NULL)
04965                      *exists = TRUE;
04966 
04967               for (c = 0; c < reqnum; c++)
04968               {
04969                      /* bail if we're out of attributes */
04970                      if (ldap->ldap_descr->lud_attrs[c] == NULL)
04971                             break;
04972 
04973                      vals = ldap_get_values_len(ld, e,
04974                                                 ldap->ldap_descr->lud_attrs[c]);
04975                      if (vals != NULL && vals[0] != NULL)
04976                      {
04977                             size_t clen;
04978 
04979                             clen = MIN(req[c].dbdata_buflen,
04980                                        vals[0]->bv_len);
04981                             memcpy(req[c].dbdata_buffer, vals[0]->bv_val,
04982                                    clen);
04983                             clen = MAX(req[c].dbdata_buflen,
04984                                        vals[0]->bv_len);
04985                             req[c].dbdata_buflen = clen;
04986                             ldap_value_free_len(vals);
04987                      }
04988               }
04989 
04990               /* tag requests that weren't fulfilled */
04991               while (c < reqnum)
04992                      req[c++].dbdata_buflen = 0;
04993 
04994               ldap_msgfree(result);
04995 # ifdef _FFR_LDAP_CACHING
04996 #  ifdef USE_DB
04997               pthread_mutex_lock(&ldap->ldap_lock);
04998 
04999               /* flush anything already cached */
05000               if (ldc->ldc_nresults != 0)
05001               {
05002                      for (c = 0; c < ldc->ldc_nresults; c++)
05003                             free(ldc->ldc_results[c]);
05004                      free(ldc->ldc_results);
05005               }
05006 
05007               /* cache results */
05008               ldc->ldc_results = malloc(sizeof(char *) * reqnum);
05009               if (ldc->ldc_results == NULL)
05010               {
05011                      ldc->ldc_error = errno;
05012                      ldc->ldc_expire = time(NULL) + DKIMF_LDAP_TTL;
05013                      ldc->ldc_state = DKIMF_DB_CACHE_DATA;
05014                      pthread_mutex_unlock(&ldap->ldap_lock);
05015                      return errno;
05016               }
05017               ldc->ldc_nresults = reqnum;
05018 
05019               for (c = 0; c < reqnum; c++)
05020               {
05021                      ldc->ldc_results[c] = strdup(req[c].dbdata_buffer);
05022                      if (ldc->ldc_results[c] == NULL)
05023                      {
05024                             ldc->ldc_error = errno;
05025                             pthread_mutex_unlock(&ldap->ldap_lock);
05026                             return errno;
05027                      }
05028               }
05029 
05030               ldc->ldc_state = DKIMF_DB_CACHE_DATA;
05031               ldc->ldc_expire = time(NULL) + DKIMF_LDAP_TTL;
05032 
05033               /* notify waiters */
05034               pthread_cond_broadcast(&ldc->ldc_cond);
05035 #  endif /* USE_DB */
05036 # endif /* _FFR_LDAP_CACHING */
05037               pthread_mutex_unlock(&ldap->ldap_lock);
05038               return 0;
05039          }
05040 #endif /* USE_LDAP */
05041 
05042 #ifdef USE_LUA
05043          case DKIMF_DB_TYPE_LUA:
05044          {
05045               int c;
05046               int status;
05047               struct dkimf_db_lua *lua;
05048               struct dkimf_lua_script_result lres;
05049 
05050               memset(&lres, '\0', sizeof lres);
05051 
05052               lua = (struct dkimf_db_lua *) db->db_data;
05053 
05054               status = dkimf_lua_db_hook((const char *) lua->lua_script,
05055                                          lua->lua_scriptlen,
05056                                          (const char *) buf, &lres,
05057                                          NULL, NULL);
05058               if (status != 0)
05059                      return -1;
05060 
05061               if (exists != NULL)
05062                      *exists = (lres.lrs_rcount != 0);
05063 
05064               /* copy results */
05065               for (c = 0; c < reqnum && c < lres.lrs_rcount; c++)
05066               {
05067                      req[c].dbdata_buflen = strlcpy(req[c].dbdata_buffer,
05068                                                     lres.lrs_results[c],
05069                                                     req[c].dbdata_buflen);
05070               }
05071 
05072               /* tag requests that weren't fulfilled */
05073               while (c < reqnum)
05074                      req[c++].dbdata_buflen = 0;
05075 
05076               /* clean up */
05077               for (c = 0; c < lres.lrs_rcount; c++)
05078                      free(lres.lrs_results[c]);
05079               if (lres.lrs_results != NULL)
05080                      free(lres.lrs_results);
05081 
05082               return 0;
05083          }
05084 #endif /* USE_LUA */
05085 
05086 #ifdef USE_LIBMEMCACHED
05087          case DKIMF_DB_TYPE_MEMCACHE:
05088          {
05089               memcached_st *mcs;
05090               memcached_return_t ret;
05091               char *out;
05092               char *key;
05093               size_t vlen;
05094               uint32_t flags;
05095               char query[BUFRSZ + 1];
05096 
05097               mcs = (memcached_st *) db->db_handle;
05098               key = (char *) db->db_data;
05099 
05100               snprintf(query, sizeof query, "%s:%s", key, buf);
05101               
05102               out = memcached_get(mcs, query, strlen(query), &vlen,
05103                                   &flags, &ret);
05104 
05105               if (out != NULL)
05106               {
05107                      if (exists != NULL)
05108                             *exists = TRUE;
05109 
05110                      if (dkimf_db_datasplit(out, vlen, req, reqnum) != 0)
05111                      {
05112                             free(out);
05113                             return -1;
05114                      }
05115 
05116                      free(out);
05117                      return 0;
05118               }
05119               else if (ret == MEMCACHED_NOTFOUND)
05120               {
05121                      if (exists != NULL)
05122                             *exists = FALSE;
05123 
05124                      return 0;
05125               }
05126               else
05127               {
05128                      db->db_status = (int) ret;
05129                      return -1;
05130               }
05131          }
05132 #endif /* USE_LIBMEMCACHED */
05133 
05134 #ifdef _FFR_REPUTATION
05135          case DKIMF_DB_TYPE_REPUTE:
05136          {
05137               _Bool found = FALSE;
05138               int c;
05139               float rep;
05140               float conf;
05141               unsigned long samp;
05142               unsigned long limit;
05143               time_t when;
05144               REPUTE_STAT rstat;
05145               REPUTE r;
05146               struct dkimf_db_repute *dbr;
05147 
05148               dbr = (struct dkimf_db_repute *) db->db_data;
05149               r = dbr->repute_handle;
05150 
05151 # ifdef _FFR_REPUTATION_CACHE
05152               if (dbr->repute_cache != NULL)
05153               {
05154                      int status;
05155                      time_t now;
05156                      struct dkimf_db_repute_cache rc;
05157                      struct dkimf_db_data req;
05158 
05159                      memset(&rc, '\0', sizeof rc);
05160 
05161                      req.dbdata_buffer = (void *) &rc;
05162                      req.dbdata_buflen = sizeof rc;
05163                      req.dbdata_flags = DKIMF_DB_DATA_BINARY;
05164 
05165                      status = dkimf_db_get(dbr->repute_cache, buf, buflen,
05166                                            &req, 1, &found);
05167 
05168                      (void) time(&now);
05169 
05170                      if (status == 0 && found)
05171                      {
05172                             if (rc.repcache_when + REPUTE_CACHE < now)
05173                             {
05174                                    found = FALSE;
05175                             }
05176                             else
05177                             {
05178                                    rep = rc.repcache_rep;
05179                                    conf = rc.repcache_conf;
05180                                    samp = rc.repcache_samp;
05181                                    limit = rc.repcache_limit;
05182                                    when = rc.repcache_when;
05183 
05184                                    if (exists != NULL)
05185                                           *exists = TRUE;
05186                             }
05187                      }
05188               }
05189 # endif /* _FFR_REPUTATION_CACHE */
05190 
05191               if (!found)
05192               {
05193                      rstat = repute_query(r, (char *) buf, &rep, &conf,
05194                                           &samp, &limit, &when);
05195 
05196                      if (rstat == REPUTE_STAT_PARSE)
05197                             return 0;
05198                      else if (rstat != REPUTE_STAT_OK)
05199                             return -1;
05200 
05201                      if (exists != NULL)
05202                      {
05203                             *exists = TRUE;
05204 
05205 # ifdef _FFR_REPUTATION_CACHE
05206                             if (dbr->repute_cache == NULL)
05207                             {
05208                                    (void) dkimf_db_open(&dbr->repute_cache,
05209                                                         "db:",
05210                                                         DKIMF_DB_FLAG_MAKELOCK,
05211                                                         NULL,
05212                                                         NULL);
05213                             }
05214 
05215                             if (dbr->repute_cache != NULL)
05216                             {
05217                                    struct dkimf_db_repute_cache rc;
05218 
05219                                    rc.repcache_rep = rep;
05220                                    rc.repcache_conf = conf;
05221                                    rc.repcache_samp = samp;
05222                                    rc.repcache_limit = limit;
05223                                    rc.repcache_when = when;
05224 
05225                                    (void) dkimf_db_put(dbr->repute_cache,
05226                                                        buf, buflen,
05227                                                        &rc, sizeof rc);
05228                             }
05229 # endif /* _FFR_REPUTATION_CACHE */
05230                      }
05231               }
05232 
05233               if (reqnum >= 1 && req[0].dbdata_buffer != NULL &&
05234                   req[0].dbdata_buflen != 0)
05235               {
05236                      if ((req[0].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
05237                      {
05238                             if (req[0].dbdata_buflen != sizeof rep)
05239                                    return -1;
05240                             memcpy(req[0].dbdata_buffer, &rep, sizeof rep);
05241                      }
05242                      else
05243                      {
05244                             req[0].dbdata_buflen = snprintf(req[0].dbdata_buffer,
05245                                                             req[0].dbdata_buflen,
05246                                                             "%f", rep);
05247                      }
05248               }
05249 
05250               if (reqnum >= 2 && req[1].dbdata_buffer != NULL &&
05251                   req[1].dbdata_buflen != 0)
05252               {
05253                      if ((req[1].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
05254                      {
05255                             if (req[1].dbdata_buflen != sizeof conf)
05256                                    return -1;
05257                             memcpy(req[1].dbdata_buffer, &conf,
05258                                    sizeof conf);
05259                      }
05260                      else
05261                      {
05262                             req[1].dbdata_buflen = snprintf(req[1].dbdata_buffer,
05263                                                             req[1].dbdata_buflen,
05264                                                             "%f", conf);
05265                      }
05266               }
05267 
05268               if (reqnum >= 3 && req[2].dbdata_buffer != NULL &&
05269                   req[2].dbdata_buflen != 0)
05270               {
05271                      if ((req[2].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
05272                      {
05273                             if (req[2].dbdata_buflen != sizeof samp)
05274                                    return -1;
05275                             memcpy(req[2].dbdata_buffer, &samp,
05276                                    sizeof samp);
05277                      }
05278                      else
05279                      {
05280                             req[2].dbdata_buflen = snprintf(req[2].dbdata_buffer,
05281                                                             req[2].dbdata_buflen,
05282                                                             "%lu", samp);
05283                      }
05284               }
05285 
05286               if (reqnum >= 4 && req[3].dbdata_buffer != NULL &&
05287                   req[3].dbdata_buflen != 0)
05288               {
05289                      if ((req[3].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
05290                      {
05291                             if (req[3].dbdata_buflen != sizeof when)
05292                                    return -1;
05293                             memcpy(req[3].dbdata_buffer, &when,
05294                                    sizeof when);
05295                      }
05296                      else
05297                      {
05298                             req[3].dbdata_buflen = snprintf(req[3].dbdata_buffer,
05299                                                             req[3].dbdata_buflen,
05300                                                             "%lu", when);
05301                      }
05302               }
05303 
05304               if (reqnum >= 5 && req[4].dbdata_buffer != NULL &&
05305                   req[4].dbdata_buflen != 0)
05306               {
05307                      if ((req[4].dbdata_flags & DKIMF_DB_DATA_BINARY) != 0)
05308                      {
05309                             if (req[4].dbdata_buflen != sizeof limit)
05310                                    return -1;
05311                             memcpy(req[4].dbdata_buffer, &limit,
05312                                    sizeof limit);
05313                      }
05314                      else
05315                      {
05316                             req[4].dbdata_buflen = snprintf(req[4].dbdata_buffer,
05317                                                             req[4].dbdata_buflen,
05318                                                             "%lu", limit);
05319                      }
05320               }
05321 
05322               /* tag requests that weren't fulfilled */
05323               for (c = 5; c < reqnum; c++)
05324                      req[c].dbdata_buflen = 0;
05325 
05326               return 0;
05327          }
05328 #endif /* _FFR_REPUTATION */
05329 
05330 #ifdef _FFR_SOCKETDB
05331          case DKIMF_DB_TYPE_SOCKET:
05332          {
05333               int status;
05334               size_t len;
05335               size_t wlen;
05336               fd_set rfds;
05337               struct timeval timeout;
05338               struct iovec iov[2];
05339               struct dkimf_db_socket *sdb;
05340               char *tmp;
05341               char inbuf[BUFRSZ];
05342 
05343               sdb = (struct dkimf_db_socket *) db->db_handle;
05344 
05345               timeout.tv_sec = DKIMF_SOCKET_TIMEOUT;
05346               timeout.tv_usec = 0;
05347 
05348               iov[0].iov_base = buf;
05349               iov[0].iov_len = buflen;
05350 
05351               iov[1].iov_base = "\n";
05352               iov[1].iov_len = 1;
05353 
05354               /* single-thread readers */
05355               if (db->db_lock != NULL)
05356                      (void) pthread_mutex_lock(db->db_lock);
05357 
05358               wlen = writev(sdb->sockdb_fd, iov, 2);
05359               if (wlen < buflen + 1)
05360               {
05361                      db->db_status = errno;
05362                      if (db->db_lock != NULL)
05363                             (void) pthread_mutex_unlock(db->db_lock);
05364                      return -1;
05365               }
05366 
05367               FD_ZERO(&rfds);
05368               FD_SET(sdb->sockdb_fd, &rfds);
05369 
05370               dkimf_dstring_blank(sdb->sockdb_buf);
05371 
05372               for (;;)
05373               {
05374                      status = select(sdb->sockdb_fd + 1, &rfds, NULL, NULL,
05375                                      &timeout);
05376                      if (status != 1)
05377                      {
05378                             db->db_status = errno;
05379                             if (db->db_lock != NULL)
05380                                    (void) pthread_mutex_unlock(db->db_lock);
05381                             return -1;
05382                      }
05383 
05384                      wlen = read(sdb->sockdb_fd, inbuf, sizeof inbuf);
05385                      if (wlen == (size_t) -1)
05386                      {
05387                             db->db_status = errno;
05388                             if (db->db_lock != NULL)
05389                                    (void) pthread_mutex_unlock(db->db_lock);
05390                             return -1;
05391                      }
05392 
05393                      if (wlen == 0)
05394                             break;
05395 
05396                      dkimf_dstring_catn(sdb->sockdb_buf, inbuf, wlen);
05397 
05398                      tmp = dkimf_dstring_get(sdb->sockdb_buf);
05399                      len = dkimf_dstring_len(sdb->sockdb_buf);
05400 
05401                      if (tmp[len - 1] == '\n')
05402                             break;
05403               }
05404 
05405               if (len > 0 && exists != NULL)
05406                      *exists = TRUE;
05407 
05408               if (dkimf_db_datasplit(tmp, len - 1, req, reqnum) != 0)
05409               {
05410                      if (db->db_lock != NULL)
05411                             (void) pthread_mutex_unlock(db->db_lock);
05412                      return -1;
05413               }
05414               else
05415               {
05416                      if (db->db_lock != NULL)
05417                             (void) pthread_mutex_unlock(db->db_lock);
05418                      return 0;
05419               }
05420          }
05421 #endif /* _FFR_SOCKETDB */
05422 
05423 #ifdef USE_MDB
05424          case DKIMF_DB_TYPE_MDB:
05425          {
05426               int status;
05427               struct dkimf_db_mdb *mdb;
05428               MDB_val key;
05429               MDB_val data;
05430 
05431               mdb = (struct dkimf_db_mdb *) db->db_handle;
05432 
05433               key.mv_size = buflen;
05434               key.mv_data = buf;
05435 
05436               status = mdb_get(mdb->mdb_txn, mdb->mdb_dbi, &key, &data);
05437               if (status == MDB_NOTFOUND)
05438               {
05439                      if (exists != NULL)
05440                             *exists = FALSE;
05441               }
05442               else if (status == 0)
05443               {
05444                      if (exists != NULL)
05445                             *exists = TRUE;
05446 
05447                      if (dkimf_db_datasplit(data.mv_data, data.mv_size,
05448                                             req, reqnum) != 0)
05449                             return -1;
05450               }
05451               else
05452               {
05453                      db->db_status = status;
05454                      return -1;
05455               }
05456 
05457               return 0;
05458          }
05459 #endif /* USE_MDB */
05460 
05461 #ifdef USE_ERLANG
05462          case DKIMF_DB_TYPE_ERLANG:
05463          {
05464               int fd;
05465               int ret;
05466               int res_size;
05467               int res_index;
05468               int res_type;
05469               struct dkimf_db_erlang *e;
05470               ei_cnode ec;
05471               ei_x_buff args;
05472               ei_x_buff resp;
05473 
05474               e = (struct dkimf_db_erlang *) db->db_data;
05475 
05476               ei_x_new(&args);
05477               ei_x_new(&resp);
05478 
05479               ei_x_encode_list_header(&args, 1);
05480               ei_x_encode_binary(&args, buf, strlen(buf));
05481               ei_x_encode_empty_list(&args);
05482 
05483               fd = dkimf_db_erl_connect(db, &ec);
05484               if (fd < 0)
05485               {
05486                      db->db_status = erl_errno;
05487                      ei_x_free(&args);
05488                      ei_x_free(&resp);
05489                      return -1;
05490               }
05491 
05492               ret = ei_rpc(&ec, fd, e->erlang_module, e->erlang_function,
05493                           args.buff, args.index, &resp);
05494               close(fd);
05495               if (ret == -1)
05496               {
05497                      db->db_status = erl_errno;
05498                      ei_x_free(&args);
05499                      ei_x_free(&resp);
05500                      return ret;
05501               }
05502 
05503               ret = dkimf_db_erl_decode_response(&resp, "not_found", req,
05504                                                  reqnum, NULL, NULL);
05505 
05506               if (exists != NULL)
05507               {
05508                      if (ret == 1)
05509                             *exists = FALSE;
05510                      else if (ret == 0)
05511                             *exists = TRUE;
05512               }
05513 
05514               ei_x_free(&args);
05515               ei_x_free(&resp);
05516 
05517               if (ret == -1)
05518                      db->db_status = erl_errno;
05519 
05520               return 0;
05521          }
05522 #endif /* USE_ERLANG */
05523 
05524          default:
05525               assert(0);
05526               return 0;            /* to silence the compiler */
05527        }
05528 
05529        /* NOTREACHED */
05530 }
05531 
05532 /*
05533 **  DKIMF_DB_CLOSE -- close a DB handle
05534 **
05535 **  Parameters:
05536 **     db -- DB handle to shut down
05537 **
05538 **  Return value:
05539 **     0 on success, something else on failure
05540 **
05541 **  Notes:
05542 **     On failure, db has not been freed.  It's not clear what to do in
05543 **     that case other than get very upset because we probably have a
05544 **     descriptor that can't be closed.  The subsystem involved should
05545 **     probably disable itself or otherwise attract attention.
05546 */
05547 
05548 int
05549 dkimf_db_close(DKIMF_DB db)
05550 {
05551        assert(db != NULL);
05552 
05553        if (db->db_array != NULL)
05554        {
05555               int c;
05556 
05557               if ((db->db_iflags & DKIMF_DB_IFLAG_FREEARRAY) != 0)
05558               {
05559                      for (c = 0; db->db_array[c] != NULL; c++)
05560                             free(db->db_array[c]);
05561               }
05562               free(db->db_array);
05563               db->db_array = NULL;
05564        }
05565 
05566        if (db->db_lock != NULL &&
05567            (db->db_flags & DKIMF_DB_FLAG_MAKELOCK) != 0)
05568        {
05569               pthread_mutex_destroy(db->db_lock);
05570               free(db->db_lock);
05571        }
05572 
05573        switch (db->db_type)
05574        {
05575          case DKIMF_DB_TYPE_FILE:
05576          case DKIMF_DB_TYPE_CSL:
05577               if (db->db_handle != NULL)
05578                      dkimf_db_list_free(db->db_handle);
05579               free(db);
05580               return 0;
05581 
05582          case DKIMF_DB_TYPE_REFILE:
05583               if (db->db_handle != NULL)
05584                      dkimf_db_relist_free(db->db_handle);
05585               free(db);
05586               return 0;
05587 
05588 #ifdef USE_DB
05589          case DKIMF_DB_TYPE_BDB:
05590          {
05591               int status;
05592 
05593 # if DB_VERSION_CHECK(2,0,0)
05594               if (db->db_cursor != NULL)
05595                      ((DBC *) (db->db_cursor))->c_close((DBC *) db->db_cursor);
05596 # endif /* DB_VERSION_CHECK(2,0,0) */
05597               status = DKIMF_DBCLOSE((DB *) (db->db_handle));
05598               if (status != 0)
05599                      db->db_status = status;
05600               else
05601                      free(db);
05602 
05603               return status;
05604          }
05605 #endif /* USE_DB */
05606 
05607 #ifdef USE_ODBX
05608          case DKIMF_DB_TYPE_DSN:
05609 # ifdef _FFR_DB_HANDLE_POOLS
05610               dkimf_db_hp_free((struct handle_pool *) db->db_handle);
05611 # else /* _FFR_DB_HANDLE_POOLS */
05612               (void) odbx_finish((odbx_t *) db->db_handle);
05613 # endif /* _FFR_DB_HANDLE_POOLS */
05614               free(db->db_data);
05615               free(db);
05616               return 0;
05617 #endif /* USE_ODBX */
05618 
05619 #ifdef USE_LDAP
05620          case DKIMF_DB_TYPE_LDAP:
05621          {
05622               struct dkimf_db_ldap *ldap;
05623 
05624               ldap = (struct dkimf_db_ldap *) db->db_data;
05625 
05626               ldap_unbind_ext((LDAP *) db->db_handle, NULL, NULL);
05627               pthread_mutex_destroy(&ldap->ldap_lock);
05628 # ifdef _FFR_LDAP_CACHING
05629 #  ifdef USE_DB
05630               if (ldap->ldap_cache != NULL)
05631               {
05632                      _Bool first = TRUE;
05633                      int c;
05634                      int status;
05635                      struct dkimf_db_ldap_cache *ldc;
05636                      struct dkimf_db_data dbd;
05637 
05638                      dbd.dbdata_buffer = (char *) &ldc;
05639                      dbd.dbdata_buflen = sizeof ldc;
05640                      dbd.dbdata_flags = DKIMF_DB_DATA_BINARY;
05641 
05642                      for (;;)
05643                      {
05644                             status = dkimf_db_walk(ldap->ldap_cache, first,
05645                                                    NULL, NULL, &dbd, 1);
05646 
05647                             if (status != 0)
05648                                    break;
05649 
05650                             for (c = 0; c < ldc->ldc_nresults; c++)
05651                                    free(ldc->ldc_results[c]);
05652                             free(ldc->ldc_results);
05653                             free(ldc);
05654 
05655                             first = FALSE;
05656                      }
05657                      
05658                      (void) dkimf_db_close(ldap->ldap_cache);
05659               }
05660 #  endif /* USE_DB */
05661 # endif /* _FFR_LDAP_CACHING */
05662               (void) ldap_free_urldesc(ldap->ldap_descr);
05663               free(db->db_data);
05664               free(db);
05665               return 0;
05666          }
05667 #endif /* USE_LDAP */
05668 
05669 #ifdef USE_LUA
05670          case DKIMF_DB_TYPE_LUA:
05671          {
05672               struct dkimf_db_lua *lua;
05673 
05674               lua = (struct dkimf_db_lua *) db->db_data;
05675 
05676               free(lua->lua_script);
05677               free(db->db_data);
05678               free(db);
05679               return 0;
05680          }
05681 #endif /* USE_LUA */
05682 
05683 #ifdef USE_LIBMEMCACHED
05684          case DKIMF_DB_TYPE_MEMCACHE:
05685          {
05686               memcached_st *mcs;
05687 
05688               mcs = (memcached_st *) db->db_handle;
05689 
05690               memcached_free(mcs);
05691               free(db->db_data);
05692               return 0;
05693          }
05694 #endif /* USE_LIBMEMCACHED */
05695 
05696 #ifdef _FFR_REPUTATION
05697          case DKIMF_DB_TYPE_REPUTE:
05698          {
05699               struct dkimf_db_repute *dbr;
05700 
05701               dbr = db->db_data;
05702               repute_close(dbr->repute_handle);
05703 # ifdef _FFR_REPUTATION_CACHE
05704               if (dbr->repute_cache != NULL)
05705                      dkimf_db_close(dbr->repute_cache);
05706 # endif /* _FFR_REPUTATION_CACHE */
05707               free(db->db_data);
05708               free(db);
05709               return 0;
05710          }
05711 #endif /* _FFR_REPUTATION */
05712 
05713 #ifdef _FFR_SOCKETDB
05714          case DKIMF_DB_TYPE_SOCKET:
05715               if (db->db_handle != NULL)
05716               {
05717                      struct dkimf_db_socket *sdb;
05718 
05719                      sdb = (struct dkimf_db_socket *) db->db_handle;
05720                      close(sdb->sockdb_fd);
05721               }
05722               free(db);
05723               return 0;
05724 #endif /* _FFR_SOCKETDB */
05725 
05726 #ifdef USE_MDB
05727          case DKIMF_DB_TYPE_MDB:
05728          {
05729               struct dkimf_db_mdb *mdb;
05730 
05731               mdb = db->db_data;
05732 
05733               if (db->db_cursor != NULL)
05734                      mdb_cursor_close(db->db_cursor);
05735 
05736               mdb_txn_abort(mdb->mdb_txn);
05737               mdb_env_close(mdb->mdb_env);
05738               free(db->db_data);
05739               free(db);
05740               return 0;
05741          }
05742 #endif /* USE_MDB */
05743 
05744 #ifdef USE_ERLANG
05745          case DKIMF_DB_TYPE_ERLANG:
05746          {
05747               struct dkimf_db_erlang *e;
05748 
05749               e = (struct dkimf_db_erlang *) db->db_data;
05750               dkimf_db_erl_free(e);
05751               return 0;
05752          }
05753 #endif /* USE_ERLANG */
05754 
05755          default:
05756               assert(0);
05757               return -1;
05758        }
05759 }
05760 
05761 /*
05762 **  DKIMF_DB_STRERROR -- obtain an error string
05763 **
05764 **  Parameters:
05765 **     db -- DKIMF_DB handle of interest
05766 **     err -- error buffer
05767 **     errlen -- bytes available at "err"
05768 **
05769 **  Return value:
05770 **     Bytes written to "err".
05771 */
05772 
05773 int
05774 dkimf_db_strerror(DKIMF_DB db, char *err, size_t errlen)
05775 {
05776        assert(db != NULL);
05777        assert(err != NULL);
05778 
05779        switch (db->db_type)
05780        {
05781          case DKIMF_DB_TYPE_FILE:
05782          case DKIMF_DB_TYPE_CSL:
05783          case DKIMF_DB_TYPE_SOCKET:
05784               return strlcpy(err, strerror(db->db_status), errlen);
05785 
05786          case DKIMF_DB_TYPE_REFILE:
05787               return regerror(db->db_status, db->db_data, err, errlen);
05788 
05789 #ifdef USE_DB
05790          case DKIMF_DB_TYPE_BDB:
05791               return strlcpy(err, DB_STRERROR(db->db_status), errlen);
05792 #endif /* USE_DB */
05793 
05794 #ifdef USE_ODBX
05795          case DKIMF_DB_TYPE_DSN:
05796          {
05797               char *p;
05798 
05799               strlcpy(err, odbx_error((odbx_t *) db->db_handle,
05800                                       db->db_status), errlen);
05801               for (p = err + strlen(err) - 1; p >= err; p--)
05802               {
05803                      if (*p == '\n')
05804                             *p = '\0';
05805                      else
05806                             break;
05807               }
05808          }
05809 
05810 #endif /* USE_ODBX */
05811 
05812 #ifdef USE_LDAP
05813          case DKIMF_DB_TYPE_LDAP:
05814               return strlcpy(err, ldap_err2string(db->db_status), errlen);
05815 #endif /* USE_LDAP */
05816 
05817 #ifdef USE_LUA
05818          case DKIMF_DB_TYPE_LUA:
05819          {
05820               struct dkimf_db_lua *lua;
05821 
05822               lua = (struct dkimf_db_lua *) db->db_data;
05823               if (lua->lua_error != NULL)
05824                      return strlcpy(err, lua->lua_error, errlen);
05825               else
05826                      return 0;
05827          }
05828 #endif /* USE_LUA */
05829 
05830 #ifdef USE_LIBMEMCACHED
05831          case DKIMF_DB_TYPE_MEMCACHE:
05832               return strlcpy(err,
05833                              memcached_strerror((memcached_st *) db->db_handle,
05834                                                 db->db_status), errlen);
05835 #endif /* USE_LIBMEMCACHED */
05836 
05837 #ifdef _FFR_REPUTATION
05838          case DKIMF_DB_TYPE_REPUTE:
05839          {
05840               struct dkimf_db_repute *dbr;
05841               REPUTE rep;
05842 
05843               dbr = (struct dkimf_db_repute *) db->db_data;
05844               rep = dbr->repute_handle;
05845               return strlcpy(err, repute_error(rep), errlen);
05846          }
05847 #endif /* _FFR_REPUTATION */
05848 
05849 #ifdef USE_MDB
05850          case DKIMF_DB_TYPE_MDB:
05851               return strlcpy(err, mdb_strerror(db->db_status), errlen);
05852 #endif /* USE_MDB */
05853 
05854 #ifdef USE_ERLANG
05855          case DKIMF_DB_TYPE_ERLANG:
05856               return strlcpy(err, strerror(db->db_status), errlen);
05857 #endif /* USE_ERLANG */
05858 
05859          default:
05860               assert(0);
05861               return -1;           /* to silence the compiler */
05862        }
05863 
05864        /* NOTREACHED */
05865 }
05866 
05867 /*
05868 **  DKIMF_DB_WALK -- walk a database
05869 **
05870 **  Parameters:
05871 **     db -- database
05872 **     first -- get first record?
05873 **     key -- buffer to receive the key
05874 **     keylen -- bytes available at "key" (updated)
05875 **     req -- buffers to receive the data ("requests")
05876 **     reqnum -- number of requests
05877 **
05878 **  Return value:
05879 **     0 -- record returned
05880 **     1 -- no more records
05881 **     -1 -- error
05882 */
05883 
05884 int
05885 dkimf_db_walk(DKIMF_DB db, _Bool first, void *key, size_t *keylen,
05886               DKIMF_DBDATA req, unsigned int reqnum)
05887 {
05888        assert(db != NULL);
05889 
05890        if ((key != NULL && keylen == NULL) ||
05891            (key == NULL && keylen != NULL))
05892               return -1;
05893 
05894        if (db->db_type == DKIMF_DB_TYPE_REFILE ||
05895            db->db_type == DKIMF_DB_TYPE_SOCKET ||
05896            db->db_type == DKIMF_DB_TYPE_LUA)
05897               return -1;
05898 
05899        switch (db->db_type)
05900        {
05901          case DKIMF_DB_TYPE_CSL:
05902          case DKIMF_DB_TYPE_FILE:
05903          {
05904               struct dkimf_db_list *list;
05905 
05906               if (first)
05907                      list = (struct dkimf_db_list *) db->db_handle;
05908               else
05909                      list = (struct dkimf_db_list *) db->db_cursor;
05910 
05911               if (list == NULL)
05912                      return 1;
05913 
05914               if (key != NULL)
05915                      *keylen = strlcpy(key, list->db_list_key, *keylen);
05916 
05917               if (reqnum != 0)
05918               {
05919                      if (list->db_list_value != NULL)
05920                      {
05921                             if (dkimf_db_datasplit(list->db_list_value,
05922                                                    strlen(list->db_list_value),
05923                                                    req, reqnum) != 0)
05924                                         return -1;
05925                      }
05926               }
05927 
05928               list = list->db_list_next;
05929               db->db_cursor = list;
05930 
05931               return 0;
05932          }
05933 
05934 #ifdef USE_DB
05935          case DKIMF_DB_TYPE_BDB:
05936          {
05937               int status = 0;
05938               DB *bdb;
05939               DBT k;
05940               DBT d;
05941 # if DB_VERSION_CHECK(2,0,0)
05942               DBC *dbc;
05943 # endif /* DB_VERSION_CHECK(2,0,0) */
05944               char databuf[BUFRSZ + 1];
05945 
05946               bdb = (DB *) db->db_handle;
05947 
05948 # if DB_VERSION_CHECK(2,0,0)
05949               /* establish a cursor if needed */
05950               dbc = db->db_cursor;
05951               if (dbc == NULL)
05952               {
05953                      status = bdb->cursor(bdb, NULL, &dbc, 0);
05954                      if (status != 0)
05955                      {
05956                             db->db_status = status;
05957                             return -1;
05958                      }
05959 
05960                      db->db_cursor = dbc;
05961               }
05962 # endif /* DB_VERSION_CHECK(2,0,0) */
05963 
05964               memset(&k, '\0', sizeof k);
05965               memset(&d, '\0', sizeof d);
05966 
05967 # if DB_VERSION_CHECK(2,0,0)
05968               k.data = (void *) key;
05969               k.flags = DB_DBT_USERMEM;
05970               k.ulen = (keylen != NULL ? *keylen : 0);
05971 # endif /* DB_VERSION_CHECK(2,0,0) */
05972 
05973 # if DB_VERSION_CHECK(2,0,0)
05974               d.data = databuf;
05975               d.flags = DB_DBT_USERMEM;
05976               d.ulen = sizeof databuf;
05977 # endif /* DB_VERSION_CHECK(2,0,0) */
05978 
05979 # if DB_VERSION_CHECK(2,0,0)
05980               status = dbc->c_get(dbc, &k, &d, first ? DB_FIRST : DB_NEXT);
05981 # else /* DB_VERSION_CHECK(2,0,0) */
05982               status = bdb->seq(bdb, &k, &d, first ? R_FIRST : R_NEXT);
05983 # endif /* DB_VERSION_CHECK(2,0,0) */
05984               if (status == DB_NOTFOUND)
05985               {
05986                      return 1;
05987               }
05988               else if (status != 0)
05989               {
05990                      db->db_status = status;
05991                      return -1;
05992               }
05993               else
05994               {
05995 # if !DB_VERSION_CHECK(2,0,0)
05996                      if (key != NULL)
05997                      {
05998                             memcpy(key, k.data, MIN(k.size, *keylen));
05999                             *keylen = MIN(k.size, *keylen);
06000                      }
06001 
06002                      if (reqnum != 0)
06003                      {
06004                             if (dkimf_db_datasplit(d.data, d.size,
06005                                                    req, reqnum) != 0)
06006                                         return -1;
06007                      }
06008 # else /* DB_VERSION_CHECK(2,0,0) */
06009                      if (reqnum != 0)
06010                      {
06011                             if (dkimf_db_datasplit(databuf, sizeof databuf,
06012                                                    req, reqnum) != 0)
06013                                         return -1;
06014                      }
06015 
06016                      if (keylen != NULL)
06017                             *keylen = k.size;
06018 # endif /* DB_VERSION_CHECK(2,0,0) */
06019 
06020                      return 0;
06021               }
06022          }
06023 #endif /* USE_DB */
06024 
06025 #ifdef USE_ODBX
06026          case DKIMF_DB_TYPE_DSN:
06027          {
06028               int err;
06029               int fields;
06030               odbx_result_t *result;
06031               struct dkimf_db_dsn *dsn;
06032 
06033               dsn = (struct dkimf_db_dsn *) db->db_data;
06034               result = (odbx_result_t *) db->db_cursor;
06035 
06036               /* purge old results cursor if known */
06037               if (result != NULL && first)
06038               {
06039                      (void) odbx_result_finish(result);
06040                      result = NULL;
06041               }
06042               
06043               /* run a query and start results cursor if needed */
06044               if (result == NULL)
06045               {
06046                      char query[BUFRSZ];
06047 
06048                      snprintf(query, sizeof query, "SELECT %s,%s FROM %s",
06049                               dsn->dsn_keycol, dsn->dsn_datacol,
06050                               dsn->dsn_table);
06051 
06052                      err = odbx_query((odbx_t *) db->db_handle, query, 0);
06053                      if (err < 0)
06054                      {
06055                             db->db_status = err;
06056                             return -1;
06057                      }
06058 
06059                      err = odbx_result((odbx_t *) db->db_handle,
06060                                        &result, NULL, 0);
06061                      if (err < 0)
06062                      {
06063                             (void) odbx_result_finish(result);
06064                             db->db_status = err;
06065                             return -1;
06066                      }
06067 
06068                      db->db_cursor = result;
06069               }
06070 
06071               err = odbx_row_fetch(result);
06072               if (err < 0)
06073               {
06074                      (void) odbx_result_finish(result);
06075                      db->db_cursor = NULL;
06076                      db->db_status = err;
06077                      return -1;
06078               }
06079 
06080               if (err == ODBX_RES_DONE)
06081                      return 1;
06082 
06083               fields = odbx_column_count(result);
06084               if (fields == 0)
06085               {
06086                      /* query returned no columns somehow */
06087                      (void) odbx_result_finish(result);
06088                      db->db_cursor = NULL;
06089                      return -1;
06090               }
06091 
06092               if (key != NULL && keylen != NULL)
06093               {
06094                      *keylen = strlcpy(key,
06095                                        (char *) odbx_field_value(result, 0),
06096                                         *keylen);
06097               }
06098 
06099               if (reqnum != 0)
06100               {
06101                      int c;
06102 
06103                      for (c = 0; c < reqnum; c++)
06104                      {
06105                             if (c >= fields)
06106                             {
06107                                    req[c].dbdata_buflen = 0;
06108                             }
06109                             else
06110                             {
06111                                    char *val;
06112 
06113                                    val = (char *) odbx_field_value(result,
06114                                                                    c + 1);
06115 
06116                                    req[c].dbdata_buflen = strlcpy(req[c].dbdata_buffer,
06117                                                                   val,
06118                                                                   req[c].dbdata_buflen);
06119                             }
06120                      }
06121               }
06122 
06123               return 0;
06124          }
06125 #endif /* USE_ODBX */
06126 
06127 #ifdef USE_LDAP
06128          case DKIMF_DB_TYPE_LDAP:
06129          {
06130               int c;
06131               int status;
06132               char *p;
06133               LDAP *ld;
06134               LDAPMessage *result;
06135               LDAPMessage *e;
06136               struct dkimf_db_ldap *ldap;
06137               struct berval **vals;
06138               char filter[BUFRSZ];
06139               char query[BUFRSZ];
06140               struct timeval timeout;
06141 
06142               ld = (LDAP *) db->db_handle;
06143               ldap = (struct dkimf_db_ldap *) db->db_data;
06144               result = (LDAPMessage *) db->db_cursor;
06145 
06146               pthread_mutex_lock(&ldap->ldap_lock);
06147 
06148               if (first)
06149               {
06150                      if (result != NULL)
06151                      {
06152                             ldap_msgfree(result);
06153                             db->db_cursor = NULL;
06154                             db->db_entry = NULL;
06155                      }
06156 
06157                      memset(query, '\0', sizeof query);
06158                      memset(filter, '\0', sizeof filter);
06159 
06160                      dkimf_db_mkldapquery(ldap->ldap_descr->lud_dn, "",
06161                                           query, sizeof query);
06162                      dkimf_db_mkldapquery(ldap->ldap_descr->lud_filter, "*",
06163                                           filter, sizeof filter);
06164 
06165                      timeout.tv_sec = ldap->ldap_timeout;
06166                      timeout.tv_usec = 0;
06167 
06168                      status = ldap_search_ext_s(ld, query,
06169                                                 ldap->ldap_descr->lud_scope,
06170                                                 filter,
06171                                                 ldap->ldap_descr->lud_attrs,
06172                                                 0, NULL, NULL,
06173                                                 &timeout, 0, &result);
06174 
06175                      if (status != LDAP_SUCCESS)
06176                      {
06177                             db->db_status = status;
06178                             pthread_mutex_unlock(&ldap->ldap_lock);
06179                             return -1;
06180                      }
06181 
06182                      db->db_cursor = (void *) result;
06183 
06184                      e = ldap_first_entry(ld, result);
06185                      if (e == NULL)
06186                      {
06187                             pthread_mutex_unlock(&ldap->ldap_lock);
06188                             return 1;
06189                      }
06190 
06191                      db->db_entry = (void *) e;
06192               }
06193               else
06194               {
06195                      e = ldap_next_entry(ld, (LDAPMessage *) db->db_entry);
06196                      if (e == NULL)
06197                      {
06198                             pthread_mutex_unlock(&ldap->ldap_lock);
06199                             return 1;
06200                      }
06201 
06202                      db->db_entry = (void *) e;
06203               }
06204 
06205               p = ldap_get_dn(ld, e);
06206               if (p != NULL)
06207               {
06208 #if LDAP_API_VERSION < 3001
06209                      LDAPDN *dn = NULL;
06210 #else /* LDAP_API_VERSION < 3001 */
06211                      LDAPDN dn = NULL;
06212 #endif /* LDAP_API_VERSION < 3001 */
06213                      LDAPRDN rdn = NULL;
06214                      LDAPAVA *ava = NULL;
06215 
06216                      if (ldap_str2dn(p, &dn, 0) != 0)
06217                      {
06218                             ldap_memfree(p);
06219                             pthread_mutex_unlock(&ldap->ldap_lock);
06220                             return 1;
06221                      }
06222 
06223                      if (dn != NULL)
06224                      {
06225 #if LDAP_API_VERSION < 3001
06226                             rdn = dn[0][0][0];
06227 #else /* LDAP_API_VERSION < 3001 */
06228                             rdn = dn[0];
06229 #endif /* LDAP_API_VERSION < 3001 */
06230                             ava = rdn[0];
06231                      }
06232 
06233                      if (key != NULL && keylen != NULL && dn != NULL &&
06234                          ava->la_value.bv_len != 0)
06235                      {
06236                             *keylen = strlcpy(key,
06237                                               ava->la_value.bv_val,
06238                                               *keylen);
06239                      }
06240                      else if (keylen != NULL)
06241                      {
06242                             *keylen = 0;
06243                      }
06244 
06245                      ldap_dnfree(dn);
06246                      ldap_memfree(p);
06247               }
06248 
06249               for (c = 0; c < reqnum; c++)
06250               {
06251                      vals = ldap_get_values_len(ld, e,
06252                                                 ldap->ldap_descr->lud_attrs[c]);
06253                      if (vals != NULL && vals[0]->bv_len != 0)
06254                      {
06255                             size_t clen;
06256 
06257                             clen = MIN(req[c].dbdata_buflen,
06258                                        vals[0]->bv_len);
06259                             memcpy(req[c].dbdata_buffer, vals[0]->bv_val,
06260                                    clen);
06261                             clen = MAX(req[c].dbdata_buflen,
06262                                        vals[0]->bv_len);
06263                             req[c].dbdata_buflen = clen;
06264                             ldap_value_free_len(vals);
06265                      }
06266                      else
06267                      {
06268                             req[c].dbdata_buflen = 0;
06269                      }
06270               }
06271 
06272               pthread_mutex_unlock(&ldap->ldap_lock);
06273 
06274               return 0;
06275          }
06276 #endif /* USE_LDAP */
06277 
06278 #ifdef USE_MDB
06279          case DKIMF_DB_TYPE_MDB:
06280          {
06281               int status = 0;
06282               MDB_val k;
06283               MDB_val d;
06284               MDB_cursor *dbc;
06285               struct dkimf_db_mdb *mdb;
06286               char databuf[BUFRSZ + 1];
06287 
06288               mdb = (struct dkimf_db_mdb *) db->db_handle;
06289 
06290               dbc = db->db_cursor;
06291               if (dbc == NULL)
06292               {
06293                      status = mdb_cursor_open(mdb->mdb_txn, mdb->mdb_dbi,
06294                                               &dbc);
06295                      if (status != 0)
06296                      {
06297                             db->db_status = status;
06298                             return -1;
06299                      }
06300 
06301                      db->db_cursor = dbc;
06302               }
06303 
06304               memset(&k, '\0', sizeof k);
06305               memset(&d, '\0', sizeof d);
06306 
06307               status = mdb_cursor_get(dbc, &k, &d,
06308                                       first ? MDB_FIRST : MDB_NEXT);
06309               if (status == MDB_NOTFOUND)
06310               {
06311                      return 1;
06312               }
06313               else if (status != 0)
06314               {
06315                      db->db_status = status;
06316                      return -1;
06317               }
06318               else
06319               {
06320                      memcpy(key, k.mv_data, MIN(k.mv_size, *keylen));
06321                      *keylen = MIN(k.mv_size, *keylen);
06322 
06323                      if (reqnum != 0)
06324                      {
06325                             if (dkimf_db_datasplit(d.mv_data, d.mv_size,
06326                                                    req, reqnum) != 0)
06327                                         return -1;
06328                      }
06329 
06330                      return 0;
06331               }
06332          }
06333 #endif /* USE_MDB */
06334 
06335 #ifdef USE_ERLANG
06336          case DKIMF_DB_TYPE_ERLANG:
06337          {
06338               int ret, fd;
06339               char *cursor;
06340               struct dkimf_db_erlang *e;
06341               ei_cnode ec;
06342               ei_x_buff args;
06343               ei_x_buff resp;
06344 
06345               e = (struct dkimf_db_erlang *) db->db_data;
06346               cursor = (char *) db->db_cursor;
06347 
06348               ei_x_new(&args);
06349               ei_x_new(&resp);
06350 
06351               if (!first && cursor == NULL)
06352                      assert(0);
06353 
06354               if (first && cursor != NULL)
06355               {
06356                      free(cursor);
06357                      cursor = NULL;
06358               }
06359 
06360               ei_x_encode_list_header(&args, 1);
06361               if (first)
06362               {
06363                      ei_x_encode_atom(&args, "first");
06364               }
06365               else
06366               {
06367                      ei_x_encode_tuple_header(&args, 2);
06368                      ei_x_encode_atom(&args, "next");
06369                      ei_x_encode_binary(&args, cursor, strlen(cursor));
06370               }
06371               ei_x_encode_empty_list(&args);
06372 
06373               fd = dkimf_db_erl_connect(db, &ec);
06374               if (fd < 0)
06375               {
06376                      ei_x_free(&args);
06377                      ei_x_free(&resp);
06378                      return -1;
06379               }
06380 
06381               ret = ei_rpc(&ec, fd, e->erlang_module, e->erlang_function,
06382                           args.buff, args.index, &resp);
06383               close(fd);
06384               if (ret == -1)
06385               {
06386                      ei_x_free(&args);
06387                      ei_x_free(&resp);
06388                      return -1;
06389               }
06390 
06391               ret = dkimf_db_erl_decode_response(&resp, "$end_of_table",
06392                                                  req, reqnum, key, keylen);
06393 
06394               ei_x_free(&args);
06395               ei_x_free(&resp);
06396 
06397               switch (ret)
06398               {
06399                 case -1:
06400                 {
06401                        if (cursor != NULL)
06402                               free(cursor);
06403                        return -1;
06404                 }
06405 
06406                 case 1:
06407                 {
06408                        free(cursor);
06409                        db->db_cursor = NULL;
06410                        return 1;
06411                 }
06412 
06413                 case 0:
06414                 {
06415                        if (key != NULL && keylen != NULL)
06416                        {
06417                               size_t cursize;
06418                               cursize = *keylen + 1;
06419                               cursor = malloc(cursize);
06420                               if (cursor == NULL)
06421                                      return -1;
06422                               strlcpy(cursor, key, cursize);
06423                               db->db_cursor = cursor;
06424                        }
06425 
06426                        return 0;
06427                 }
06428               }
06429 
06430               assert(cursor != NULL);
06431          }
06432 #endif /* USE_ERLANG */
06433 
06434          default:
06435               assert(0);
06436               return -1;           /* to silence compiler warnings */
06437        }
06438 }
06439 
06440 /*
06441 **  DKIMF_DB_MKARRAY_BASE -- make a (char *) array treating the DB as a
06442 **                           delta to a provided base
06443 **
06444 **  Parameters:
06445 **     db -- a DKIMF_DB handle
06446 **     a -- array (returned)
06447 **     base -- base array
06448 ** 
06449 **  Return value:
06450 **     Length of the created array, or -1 on error/empty.
06451 */
06452 
06453 static int
06454 dkimf_db_mkarray_base(DKIMF_DB db, char ***a, const char **base)
06455 {
06456        _Bool found;
06457        int c;
06458        int status;
06459        int nalloc = 0;
06460        int nout = 0;
06461        int nbase;
06462        size_t buflen;
06463        char **out = NULL;
06464        char buf[BUFRSZ + 1];
06465 
06466        assert(db != NULL);
06467        assert(a != NULL);
06468 
06469        /* count base elements */
06470        for (nbase = 0; base[nbase] != NULL; nbase++)
06471               continue;
06472 
06473        /* initialize output array */
06474        nalloc = MAX(nbase, 16);
06475        out = (char **) malloc(sizeof(char *) * nalloc);
06476        if (out == NULL)
06477               return -1;
06478        out[0] = NULL;
06479 
06480        /* copy the base array modulo removals in the DB */
06481        for (c = 0; c < nbase; c++)
06482        {
06483               memset(buf, '\0', sizeof buf);
06484 
06485               snprintf(buf, sizeof buf, "-%s", base[c]);
06486 
06487               found = FALSE;
06488               status = dkimf_db_get(db, buf, 0, NULL, 0, &found);
06489               if (status != 0)
06490               {
06491                      for (c = 0; c < nout; c++)
06492                             free(out[c]);
06493                      free(out);
06494                      return -1;
06495               }
06496 
06497               if (!found)
06498               {
06499                      if (nout == nalloc - 1)
06500                      {
06501                             char **new;
06502 
06503                             new = (char **) realloc(out,
06504                                                     sizeof(char *) * (nalloc * 2));
06505                             if (new == NULL)
06506                             {
06507                                    for (c = 0; c < nout; c++)
06508                                           free(out[c]);
06509                                    free(out);
06510                                    return -1;
06511                             }
06512 
06513                             out = new;
06514                             nalloc *= 2;
06515                      }
06516 
06517                      out[nout] = strdup(base[c]);
06518                      if (out[nout] == NULL)
06519                      {
06520                             for (c = 0; c < nout; c++)
06521                                    free(out[c]);
06522                             free(out);
06523                             return -1;
06524                      }
06525 
06526                      nout++;
06527                      out[nout] = NULL;
06528               }
06529        }
06530 
06531        /* now add any in the DB that aren't in the array */
06532        for (c = 0; ; c++)
06533        {
06534               buflen = sizeof buf - 1;
06535               memset(buf, '\0', sizeof buf);
06536 
06537               status = dkimf_db_walk(db, (c == 0), buf, &buflen, NULL, 0);
06538               if (status == -1)
06539               {
06540                      for (c = 0; c < nout; c++)
06541                             free(out[c]);
06542                      free(out);
06543                      return -1;
06544               }
06545               else if (status == 1)
06546               {
06547                      break;
06548               }
06549               else if (buf[0] != '+')
06550               {
06551                      continue;
06552               }
06553 
06554               if (nout == nalloc - 1)
06555               {
06556                      char **new;
06557 
06558                      new = (char **) realloc(out,
06559                                              sizeof(char *) * (nalloc * 2));
06560                      if (new == NULL)
06561                      {
06562                             for (c = 0; c < nout; c++)
06563                                    free(out[c]);
06564                             free(out);
06565                             return -1;
06566                      }
06567 
06568                      out = new;
06569                      nalloc *= 2;
06570               }
06571 
06572               out[nout] = strdup(&buf[1]);
06573               if (out[nout] == NULL)
06574               {
06575                      for (c = 0; c < nout; c++)
06576                             free(out[c]);
06577                      free(out);
06578                      return -1;
06579               }
06580 
06581               nout++;
06582               out[nout] = NULL;
06583        }
06584 
06585        *a = out;
06586        return nout;
06587 }
06588 
06589 /*
06590 **  DKIMF_DB_MKARRAY -- make a (char *) array of DB contents
06591 **
06592 **  Parameters:
06593 **     db -- a DKIMF_DB handle
06594 **     a -- array (returned)
06595 **     base -- base array (may be NULL)
06596 **
06597 **  Return value:
06598 **     Length of the created array, or -1 on error/empty.
06599 */
06600 
06601 int
06602 dkimf_db_mkarray(DKIMF_DB db, char ***a, const char **base)
06603 {
06604        _Bool found;
06605        int status;
06606        char **out;
06607 
06608        assert(db != NULL);
06609        assert(a != NULL);
06610 
06611        if (db->db_type == DKIMF_DB_TYPE_REFILE ||
06612            db->db_type == DKIMF_DB_TYPE_SOCKET ||
06613            db->db_type == DKIMF_DB_TYPE_LUA)
06614               return -1;
06615 
06616 #ifdef USE_DB
06617        if (db->db_type != DKIMF_DB_TYPE_BDB && db->db_nrecs == 0)
06618               return 0;
06619 #endif /* USE_DB */
06620 
06621        if ((db->db_type == DKIMF_DB_TYPE_FILE ||
06622             db->db_type == DKIMF_DB_TYPE_CSL) &&
06623            db->db_array != NULL)
06624        {
06625               *a = db->db_array;
06626               return db->db_nrecs;
06627        }
06628 
06629        found = FALSE;
06630        status = dkimf_db_get(db, "*", 0, NULL, 0, &found);
06631        if (status != 0)
06632               return -1;
06633        if (found && base != NULL)
06634               return dkimf_db_mkarray_base(db, a, base);
06635 
06636        switch (db->db_type)
06637        {
06638          case DKIMF_DB_TYPE_FILE:
06639          case DKIMF_DB_TYPE_CSL:
06640          {
06641               int c = 0;
06642               struct dkimf_db_list *cur;
06643 
06644               out = (char **) malloc(sizeof(char *) * (db->db_nrecs + 1));
06645               if (out != NULL)
06646               {
06647                      cur = db->db_handle;
06648                      for (c = 0; c < db->db_nrecs; c++)
06649                      {
06650                             out[c] = cur->db_list_key;
06651                             cur = cur->db_list_next;
06652                      }
06653 
06654                      out[c] = NULL;
06655               }
06656 
06657               db->db_array = out;
06658 
06659               *a = out;
06660 
06661               return c;
06662          }
06663 
06664 #ifdef USE_DB
06665          case DKIMF_DB_TYPE_BDB:
06666 #endif /* USE_DB */
06667 #ifdef USE_ODBX
06668          case DKIMF_DB_TYPE_DSN:
06669 #endif /* USE_ODBX */
06670 #if defined(USE_DB) || defined(USE_ODBX)
06671          {
06672               int c;
06673               int nr = 0;
06674               int na = 0;
06675               int status;
06676               size_t keylen;
06677               char keybuf[BUFRSZ + 1];
06678 
06679               if (db->db_array != NULL)
06680               {
06681                      for (c = 0; db->db_array[c] != NULL; c++)
06682                             free(db->db_array[c]);
06683                      free(db->db_array);
06684                      db->db_array = NULL;
06685               }
06686 
06687               status = 0;
06688               while (status == 0)
06689               {
06690                      memset(keybuf, '\0', sizeof keybuf);
06691 
06692                      keylen = sizeof keybuf - 1;
06693                      status = dkimf_db_walk(db, (nr == 0),
06694                                             keybuf, &keylen, NULL, 0);
06695 
06696                      if (nr == 0)
06697                      {
06698                             out = (char **) malloc(sizeof(char *) * DEFARRAYSZ);
06699                             if (out == NULL)
06700                                    return -1;
06701 
06702                             out[0] = strdup(keybuf);
06703                             if (out[0] == NULL)
06704                             {
06705                                    free(out);
06706                                    return -1;
06707                             }
06708 
06709                             na = DEFARRAYSZ;
06710                             nr = 1;
06711                             out[nr] = NULL;
06712                      }
06713                      else
06714                      {
06715                             if (nr + 1 == na)
06716                             {
06717                                    int newsz;
06718                                    char **newout;
06719 
06720                                    newsz = na * 2;
06721 
06722                                    newout = (char **) realloc(out, sizeof (char *) * newsz);
06723                                    if (newout == NULL)
06724                                    {
06725                                           for (c = 0; c < nr; c++)
06726                                                  free(out[c]);
06727                                           free(out);
06728                                           return -1;
06729                                    }
06730 
06731                                    na = newsz;
06732                             }
06733 
06734                             out[nr] = strdup(keybuf);
06735                             if (out[nr] == NULL)
06736                             {
06737                                    for (c = 0; c < nr; c++)
06738                                           free(out[c]);
06739                                    free(out);
06740                                    return -1;
06741                             }
06742 
06743                             nr++;
06744                             out[nr] = NULL;
06745                      }
06746               }
06747 
06748               if (status == -1)
06749               {
06750                      for (c = 0; c < nr; c++)
06751                             free(out[c]);
06752                      free(out);
06753                      return -1;
06754               }
06755 
06756               db->db_array = out;
06757               db->db_iflags |= DKIMF_DB_IFLAG_FREEARRAY;
06758               *a = out;
06759               return nr;
06760          }
06761 #endif /* defined(USE_DB) || defined(USE_ODBX) */
06762 
06763          default:
06764               return -1;
06765        }
06766 }
06767 
06768 /*
06769 **  DKIMF_DB_REWALK -- walk a regular expression DB looking for matches
06770 **
06771 **  Parameters:
06772 **     db -- database of interest
06773 **     str -- string to match
06774 **     req -- list of data requests
06775 **     reqnum -- number of data requests
06776 **     ctx -- context pointer (updated) (may be NULL)
06777 **
06778 **  Return value:
06779 **     -1 -- error
06780 **     0 -- match found
06781 **     1 -- no match found
06782 */
06783 
06784 int
06785 dkimf_db_rewalk(DKIMF_DB db, char *str, DKIMF_DBDATA req, unsigned int reqnum,
06786                 void **ctx)
06787 {
06788        int status;
06789        struct dkimf_db_relist *re;
06790 
06791        assert(db != NULL);
06792        assert(str != NULL);
06793 
06794        if (db->db_type != DKIMF_DB_TYPE_REFILE)
06795               return -1;
06796 
06797        if (ctx != NULL && *ctx != NULL)
06798        {
06799               re = (struct dkimf_db_relist *) *ctx;
06800               if (re->db_relist_next == NULL)
06801                      return 1;
06802               else
06803                      re = re->db_relist_next;
06804        }
06805        else
06806        {
06807               re = (struct dkimf_db_relist *) db->db_handle;
06808        }
06809 
06810        while (re != NULL)
06811        {
06812               status = regexec(&re->db_relist_re, str, 0, NULL, 0);
06813 
06814               if (status == 0)
06815               {
06816                      if (ctx != NULL)
06817                             *ctx = re;
06818 
06819                      if (dkimf_db_datasplit(re->db_relist_data,
06820                                            strlen(re->db_relist_data),
06821                                            req, reqnum) != 0)
06822                      {
06823                                 return -1;
06824                      }
06825                      else
06826                      {
06827                             return 0;
06828                      }
06829               }
06830               else if (status != REG_NOMATCH)
06831               {
06832                      return -1;
06833               }
06834 
06835               re = re->db_relist_next;
06836        }
06837 
06838        return 1;
06839 }
06840 
06841 /*
06842 **  DKIMF_DB_SET_LDAP_PARAM -- set an LDAP parameter
06843 **
06844 **  Parameters:
06845 **     param -- parameter code to set
06846 **     str -- new string pointer value
06847 **
06848 **  Return value:
06849 **     None.
06850 */
06851 
06852 void
06853 dkimf_db_set_ldap_param(int param, char *str)
06854 {
06855        assert(param >= 0 && param <= DKIMF_LDAP_PARAM_MAX);
06856 
06857        dkimf_db_ldap_param[param] = str;
06858 }
06859 
06860 /*
06861 **  DKIMF_DB_CHOWN -- set ownership and permissions on a DB
06862 **
06863 **  Parameters:
06864 **     db -- DKIMF_DB handle
06865 **     uid -- target uid
06866 **
06867 **  Return value:
06868 **     1 -- success
06869 **     0 -- not a DB that can be chowned
06870 **     -1 -- fchown() failed
06871 */
06872 
06873 int
06874 dkimf_db_chown(DKIMF_DB db, uid_t uid)
06875 {
06876        int fd = -1;
06877        int status;
06878 #ifdef USE_DB
06879        DB *bdb;
06880 #endif /* USE_DB */
06881 
06882        assert(db != NULL);
06883        assert(uid >= 0);
06884 
06885        if (dkimf_db_type(db) != DKIMF_DB_TYPE_BDB ||
06886            (db->db_flags & DKIMF_DB_FLAG_READONLY) != 0 ||
06887            (db->db_flags & DKIMF_DB_FLAG_NOFDLOCK) != 0)
06888               return 0;
06889 
06890 #ifdef USE_DB
06891        bdb = (DB *) db->db_handle;
06892 
06893 # if DB_VERSION_CHECK(2,0,0)
06894        status = bdb->fd(bdb, &fd);
06895 # else /* DB_VERSION_CHECK(2,0,0) */
06896        fd = bdb->fd(bdb);
06897 # endif /* DB_VERSION_CHECK(2,0,0) */
06898 
06899        if (fd == -1)
06900               return 0;
06901 
06902        if (fchown(fd, uid, -1) != 0)
06903               return -1;
06904        else
06905               return 1;
06906 
06907 #else /* USE_DB */
06908 
06909        return 0;
06910 
06911 #endif /* USE_DB */
06912 }