Back to index

opendkim  2.6.2
Classes | Defines | Typedefs | Functions | Variables
opendkim.c File Reference
#include "build-config.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <sysexits.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <math.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <pthread.h>
#include <netdb.h>
#include <signal.h>
#include <regex.h>
#include <openssl/sha.h>
#include <openssl/err.h>
#include "libmilter/mfapi.h"
#include "dkim.h"
#include "dkim-strl.h"
#include "config.h"
#include "opendkim-db.h"
#include "opendkim-config.h"
#include "opendkim-crypto.h"
#include "opendkim.h"
#include "opendkim-ar.h"
#include "opendkim-arf.h"
#include "opendkim-dns.h"
#include "util.h"
#include "test.h"

Go to the source code of this file.

Classes

struct  addrlist
struct  handling
struct  dkimf_config
struct  msgctx
struct  connctx
struct  lookup

Defines

#define _POSIX_PTHREAD_SEMANTICS
#define _PATH_DEVNULL   "/dev/null"
#define CMDLINEOPTS   "Ab:c:d:De:fF:k:lL:no:p:P:qQrs:S:t:T:u:vVWx:?"
#define MIN(x, y)   ((x) < (y) ? (x) : (y))
#define DKIMF_MILTER_ACCEPT   0
#define DKIMF_MILTER_REJECT   1
#define DKIMF_MILTER_TEMPFAIL   2
#define DKIMF_MILTER_DISCARD   3
#define DKIMF_MILTER_QUARANTINE   4
#define HNDL_DEFAULT   0
#define HNDL_NOSIGNATURE   1
#define HNDL_BADSIGNATURE   2
#define HNDL_DNSERROR   3
#define HNDL_INTERNAL   4
#define HNDL_SECURITY   5
#define HNDL_NOKEY   6
#define HNDL_POLICYERROR   7
#define HNDL_REPERROR   8
#define DKIMF_MODE_SIGNER   0x01
#define DKIMF_MODE_VERIFIER   0x02
#define DKIMF_MODE_DEFAULT   (DKIMF_MODE_SIGNER|DKIMF_MODE_VERIFIER)
#define DKIMF_STATUS_GOOD   0
#define DKIMF_STATUS_BAD   1
#define DKIMF_STATUS_NOKEY   2
#define DKIMF_STATUS_REVOKED   3
#define DKIMF_STATUS_NOSIGNATURE   4
#define DKIMF_STATUS_BADFORMAT   5
#define DKIMF_STATUS_PARTIAL   6
#define DKIMF_STATUS_VERIFYERR   7
#define DKIMF_STATUS_UNKNOWN   8
#define SIGMIN_BYTES   0
#define SIGMIN_PERCENT   1
#define SIGMIN_MAXADD   2
#define ADSPDENYSMTP   "550"
#define ADSPDENYESC   "5.7.1"
#define ADSPDENYTEXT   "rejected due to DKIM ADSP evaluation"
#define ADSPNXDOMAINSMTP   "550"
#define ADSPNXDOMAINESC   "5.7.1"
#define ADSPNXDOMAINTEXT   "sender domain does not exist"
#define DELIMITER   "\001"
#define CRLF   "\r\n" /* CRLF */
#define JOBID(x)   ((x) == NULL ? JOBIDUNKNOWN : (char *) (x))
#define TRYFREE(x)
#define DKIMF_EOHMACROS   "i {daemon_name} {auth_type}"

Typedefs

typedef struct msgctxmsgctx
typedef struct connctxconnctx

Functions

sfsistat mlfi_abort __P ((SMFICTX *))
sfsistat mlfi_body __P ((SMFICTX *, u_char *, size_t))
sfsistat mlfi_connect __P ((SMFICTX *, char *, _SOCK_ADDR *))
sfsistat mlfi_envfrom __P ((SMFICTX *, char **))
sfsistat mlfi_header __P ((SMFICTX *, char *, char *))
sfsistat mlfi_negotiate __P ((SMFICTX *, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long *, unsigned long *, unsigned long *, unsigned long *))
static int dkimf_add_signrequest __P ((struct msgctx *, DKIMF_DB, char *, char *, ssize_t))
sfsistat dkimf_addrcpt __P ((SMFICTX *, char *))
sfsistat dkimf_chgheader __P ((SMFICTX *, char *, int, char *))
static void dkimf_config_reload __P ((void))
static Header dkimf_findheader __P ((msgctx, char *, int))
sfsistat dkimf_insheader __P ((SMFICTX *, int, char *, char *))
static void dkimf_policyreport __P ((connctx, struct dkimf_config *, char *))
void dkimf_sendprogress __P ((const void *))
sfsistat dkimf_setpriv __P ((SMFICTX *, void *))
sfsistat dkimf_setreply __P ((SMFICTX *, char *, char *, char *))
sfsistat smfi_insheader (SMFICTX *ctx, int idx, char *hname, char *hvalue)
void * dkimf_getpriv (SMFICTX *ctx)
sfsistat dkimf_setpriv (SMFICTX *ctx, void *ptr)
sfsistat dkimf_insheader (SMFICTX *ctx, int idx, char *hname, char *hvalue)
sfsistat dkimf_chgheader (SMFICTX *ctx, char *hname, int idx, char *hvalue)
sfsistat dkimf_quarantine (SMFICTX *ctx, char *reason)
sfsistat dkimf_addheader (SMFICTX *ctx, char *hname, char *hvalue)
sfsistat dkimf_addrcpt (SMFICTX *ctx, char *addr)
sfsistat dkimf_delrcpt (SMFICTX *ctx, char *addr)
sfsistat dkimf_setreply (SMFICTX *ctx, char *rcode, char *xcode, char *replytxt)
char * dkimf_getsymval (SMFICTX *ctx, char *sym)
static void dkimf_add_ar_fields (struct msgctx *dfc, struct dkimf_config *conf, SMFICTX *ctx)
static void dkimf_db_error (DKIMF_DB db, const char *key)
static void dkimf_init_syslog (char *facility)
static _Bool dkimf_restart_check (int n, time_t t)
size_t dkimf_reptoken (u_char *out, size_t outlen, u_char *in, u_char *sub)
_Bool dkimf_insecure (mode_t mode, gid_t grp)
static _Bool dkimf_loadkey (char *buf, size_t *buflen, _Bool *insecure, char **error)
static int dkimf_add_signrequest (struct msgctx *dfc, DKIMF_DB keytable, char *keyname, char *signer, ssize_t signlen)
static DKIM_STAT dkimf_msr_header (struct signreq *sr, DKIM **last, u_char *header, size_t headerlen)
static DKIM_STAT dkimf_msr_eoh (struct signreq *sr, DKIM **last)
static DKIM_STAT dkimf_msr_body (struct signreq *sr, DKIM **last, u_char *body, size_t bodylen)
static int dkimf_msr_minbody (struct signreq *sr)
static DKIM_STAT dkimf_msr_eom (struct signreq *sr, DKIM **last)
static DKIM_CBSTAT dkimf_prescreen (DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs)
static int dkimf_arftype (msgctx dfc)
static int dkimf_arfdkim (msgctx dfc)
static void dkimf_reportaddr (struct dkimf_config *conf)
static int dkimf_configlookup (char *opt, struct lookup *table)
static int dkimf_local_adsp (struct dkimf_config *conf, char *domain, dkim_policy_t *pcode)
DKIM * dkimf_getdkim (void *vp)
struct signreqdkimf_getsrlist (void *vp)
static void dkimf_sighandler (int sig)
static void * dkimf_reloader (void *vp)
static void dkimf_killchild (pid_t pid, int sig, _Bool dolog)
static void dkimf_zapkey (struct dkimf_config *conf)
static _Bool dkimf_authorsigok (msgctx msg)
static struct dkimf_configdkimf_config_new (void)
static void dkimf_config_free (struct dkimf_config *conf)
static void dkimf_parsehandler (struct config *cfg, char *name, struct handling *hndl)
static int dkimf_config_load (struct config *data, struct dkimf_config *conf, char *err, size_t errlen)
static _Bool dkimf_config_setlib (struct dkimf_config *conf, char **err)
static void dkimf_config_reload (void)
static _Bool dkimf_checkbldb (DKIMF_DB db, char *to, char *jobid)
static void dkimf_stdio (void)
void dkimf_sendprogress (const void *ctx)
static msgctx dkimf_initcontext (struct dkimf_config *conf)
static void dkimf_log_ssl_errors (char *jobid, char *selector, char *domain)
static void dkimf_cleanup (SMFICTX *ctx)
sfsistat dkimf_miltercode (SMFICTX *ctx, int dmc, char *str)
static sfsistat dkimf_libstatus (SMFICTX *ctx, DKIM *dkim, char *where, int status)
static Header dkimf_findheader (msgctx dfc, char *hname, int instance)
static int dkimf_apply_signtable (struct msgctx *dfc, DKIMF_DB keydb, DKIMF_DB signdb, unsigned char *user, unsigned char *domain, char *errkey, size_t errlen, _Bool multisig)
static void dkimf_sigreport (connctx cc, struct dkimf_config *conf, char *hostname)
static void dkimf_policyreport (connctx cc, struct dkimf_config *conf, char *hostname)
void dkimf_ar_all_sigs (char *hdr, size_t hdrlen, DKIM *dkim, struct dkimf_config *conf, int *status)
sfsistat mlfi_connect (SMFICTX *ctx, char *host, _SOCK_ADDR *ip)
sfsistat mlfi_envfrom (SMFICTX *ctx, char **envfrom)
sfsistat mlfi_envrcpt (SMFICTX *ctx, char **envrcpt)
sfsistat mlfi_header (SMFICTX *ctx, char *headerf, char *headerv)
sfsistat mlfi_eoh (SMFICTX *ctx)
sfsistat mlfi_body (SMFICTX *ctx, u_char *bodyp, size_t bodylen)
sfsistat mlfi_eom (SMFICTX *ctx)
sfsistat mlfi_abort (SMFICTX *ctx)
sfsistat mlfi_close (SMFICTX *ctx)
static int usage (void)
int main (int argc, char **argv)

Variables

static char opendkim_c_id [] = "@(#)$Id: opendkim.c,v 1.230 2010/10/28 06:10:07 cm-msk Exp $"
_Bool dolog
_Bool reload
_Bool no_i_whine
_Bool quarantine
_Bool testmode
_Bool die
int diesig
int thread_count
char * progname
char * sock
char * conffile
struct dkimf_configcurconf
char reportcmd [BUFRSZ+1]
char reportaddr [MAXADDRESS+1]
char myhostname [DKIM_MAXHOSTNAMELEN+1]
pthread_mutex_t conf_lock

Class Documentation

struct addrlist

Definition at line 148 of file opendkim.c.

Collaboration diagram for addrlist:
Class Members
char * a_addr
struct addrlist * a_next
struct handling

Definition at line 158 of file opendkim.c.

Class Members
int hndl_badsig
int hndl_dnserr
int hndl_internal
int hndl_nokey
int hndl_nosig
int hndl_policyerr
int hndl_security
struct dkimf_config

Definition at line 204 of file opendkim.c.

Collaboration diagram for dkimf_config:
Class Members
_Bool conf_acceptdk
_Bool conf_addxhdr
int conf_adspaction
_Bool conf_adspnxdomain
_Bool conf_allowsha1only
_Bool conf_allsigs
_Bool conf_alwaysaddar
char ** conf_alwayshdrs
DKIMF_DB conf_alwayshdrsdb
char * conf_authservid
_Bool conf_authservidwithjobid
DKIMF_DB conf_bldb
_Bool conf_blen
dkim_canon_t conf_bodycanon
char * conf_canonstr
_Bool conf_capture
char * conf_chroot
int conf_clockdrift
struct config * conf_data
char * conf_diagdir
_Bool conf_dnsconnect
unsigned int conf_dnstimeout
_Bool conf_dolog
_Bool conf_dolog_success
DKIMF_DB conf_domainsdb
char * conf_domlist
DKIMF_DB conf_dontsigntodb
_Bool conf_enablecores
DKIMF_DB conf_exemptdb
char * conf_exemptfile
DKIMF_DB conf_exignore
char * conf_externalfile
_Bool conf_fixcrlf
dkim_canon_t conf_hdrcanon
DKIMF_DB conf_internal
char * conf_internalfile
_Bool conf_keepar
_Bool conf_keeptmpfiles
char * conf_keyfile
size_t conf_keylen
char * conf_keytable
DKIMF_DB conf_keytabledb
DKIM_LIB * conf_libopendkim
DKIMF_DB conf_localadsp_db
char * conf_localadsp_file
_Bool conf_logresults
_Bool conf_logwhy
char ** conf_macros
DKIMF_DB conf_macrosdb
unsigned int conf_maxhdrsz
unsigned int conf_maxverify
char ** conf_mbs
DKIMF_DB conf_mbsdb
_Bool conf_milterv2
unsigned int conf_mode
char * conf_modestr
char * conf_mtacommand
char ** conf_mtas
DKIMF_DB conf_mtasdb
_Bool conf_multisig
_Bool conf_noadsp
_Bool conf_noheaderb
regex_t ** conf_nosignpats
DKIMF_DB conf_omithdrdb
char ** conf_omithdrs
char * conf_omitlist
DKIMF_DB conf_peerdb
char * conf_peerfile
unsigned int conf_refcnt
char ** conf_remar
_Bool conf_remarall
DKIMF_DB conf_remardb
_Bool conf_remsigs
char * conf_reportaddr
char * conf_reportaddrbcc
_Bool conf_reqhdrs
_Bool conf_reqreports
_Bool conf_restrace
_Bool conf_safekeys
dkim_sigkey_t conf_seckey
char * conf_selectcanonhdr
u_char * conf_selector
_Bool conf_sendadspreports
char ** conf_senderhdrs
DKIMF_DB conf_senderhdrsdb
_Bool conf_sendreports
char * conf_siglimit
size_t conf_sigmin
int conf_sigmintype
dkim_alg_t conf_signalg
char * conf_signalgstr
ssize_t conf_signbytes
char ** conf_signhdrs
DKIMF_DB conf_signhdrsdb
char * conf_signtable
DKIMF_DB conf_signtabledb
unsigned long conf_sigttl
_Bool conf_singleauthres
_Bool conf_stricthdrs
_Bool conf_subdomains
char * conf_testdnsdata
DKIMF_DB conf_testdnsdb
DKIMF_DB conf_thirdpartydb
char * conf_tmpdir
_Bool conf_weaksyntax
_Bool conf_ztags
struct msgctx

Definition at line 469 of file opendkim.c.

Collaboration diagram for msgctx:
Class Members
_Bool mctx_addheader
_Bool mctx_bldbdone
dkim_canon_t mctx_bodycanon
_Bool mctx_capture
unsigned char mctx_dkimar
DKIM * mctx_dkimv
unsigned char mctx_domain
unsigned char mctx_envfrom
_Bool mctx_eom
int mctx_hdrbytes
dkim_canon_t mctx_hdrcanon
_Bool mctx_headeronly
struct Header * mctx_hqhead
struct Header * mctx_hqtail
u_char * mctx_jobid
u_char * mctx_laddr
_Bool mctx_ltag
dkim_policy_t mctx_pcode
unsigned int mctx_pflags
int mctx_presult
DKIM_PSTATE * mctx_pstate
int mctx_queryalg
struct addrlist * mctx_rcptlist
dkim_alg_t mctx_signalg
struct signreq * mctx_srhead
struct signreq * mctx_srtail
int mctx_status
_Bool mctx_susp
struct dkimf_dstring * mctx_tmpstr
struct connctx

Definition at line 543 of file opendkim.c.

Collaboration diagram for connctx:
Class Members
struct dkimf_config * cctx_config
char cctx_host
_Bool cctx_milterv2
struct msgctx * cctx_msg
_Bool cctx_noleadspc
struct lookup

Definition at line 44 of file opendkim-ar.c.

Class Members
int code
char * str

Define Documentation

#define _PATH_DEVNULL   "/dev/null"

Definition at line 74 of file opendkim.c.

Definition at line 17 of file opendkim.c.

#define ADSPDENYESC   "5.7.1"

Definition at line 593 of file opendkim.c.

#define ADSPDENYSMTP   "550"

Definition at line 592 of file opendkim.c.

#define ADSPDENYTEXT   "rejected due to DKIM ADSP evaluation"

Definition at line 594 of file opendkim.c.

#define ADSPNXDOMAINESC   "5.7.1"

Definition at line 597 of file opendkim.c.

#define ADSPNXDOMAINSMTP   "550"

Definition at line 596 of file opendkim.c.

#define ADSPNXDOMAINTEXT   "sender domain does not exist"

Definition at line 598 of file opendkim.c.

#define CMDLINEOPTS   "Ab:c:d:De:fF:k:lL:no:p:P:qQrs:S:t:T:u:vVWx:?"

Definition at line 132 of file opendkim.c.

#define CRLF   "\r\n" /* CRLF */

Definition at line 814 of file opendkim.c.

#define DELIMITER   "\001"

Definition at line 612 of file opendkim.c.

#define DKIMF_EOHMACROS   "i {daemon_name} {auth_type}"

Definition at line 825 of file opendkim.c.

#define DKIMF_MILTER_ACCEPT   0

Definition at line 138 of file opendkim.c.

#define DKIMF_MILTER_DISCARD   3

Definition at line 141 of file opendkim.c.

#define DKIMF_MILTER_QUARANTINE   4

Definition at line 142 of file opendkim.c.

#define DKIMF_MILTER_REJECT   1

Definition at line 139 of file opendkim.c.

#define DKIMF_MILTER_TEMPFAIL   2

Definition at line 140 of file opendkim.c.

Definition at line 576 of file opendkim.c.

#define DKIMF_MODE_SIGNER   0x01

Definition at line 574 of file opendkim.c.

#define DKIMF_MODE_VERIFIER   0x02

Definition at line 575 of file opendkim.c.

#define DKIMF_STATUS_BAD   1

Definition at line 579 of file opendkim.c.

#define DKIMF_STATUS_BADFORMAT   5

Definition at line 583 of file opendkim.c.

#define DKIMF_STATUS_GOOD   0

Definition at line 578 of file opendkim.c.

#define DKIMF_STATUS_NOKEY   2

Definition at line 580 of file opendkim.c.

#define DKIMF_STATUS_NOSIGNATURE   4

Definition at line 582 of file opendkim.c.

#define DKIMF_STATUS_PARTIAL   6

Definition at line 584 of file opendkim.c.

#define DKIMF_STATUS_REVOKED   3

Definition at line 581 of file opendkim.c.

#define DKIMF_STATUS_UNKNOWN   8

Definition at line 586 of file opendkim.c.

#define DKIMF_STATUS_VERIFYERR   7

Definition at line 585 of file opendkim.c.

#define HNDL_BADSIGNATURE   2

Definition at line 566 of file opendkim.c.

#define HNDL_DEFAULT   0

Definition at line 564 of file opendkim.c.

#define HNDL_DNSERROR   3

Definition at line 567 of file opendkim.c.

#define HNDL_INTERNAL   4

Definition at line 568 of file opendkim.c.

#define HNDL_NOKEY   6

Definition at line 570 of file opendkim.c.

#define HNDL_NOSIGNATURE   1

Definition at line 565 of file opendkim.c.

#define HNDL_POLICYERROR   7

Definition at line 571 of file opendkim.c.

#define HNDL_REPERROR   8

Definition at line 572 of file opendkim.c.

#define HNDL_SECURITY   5

Definition at line 569 of file opendkim.c.

#define JOBID (   x)    ((x) == NULL ? JOBIDUNKNOWN : (char *) (x))

Definition at line 817 of file opendkim.c.

#define MIN (   x,
 
)    ((x) < (y) ? (x) : (y))

Definition at line 135 of file opendkim.c.

#define SIGMIN_BYTES   0

Definition at line 588 of file opendkim.c.

#define SIGMIN_MAXADD   2

Definition at line 590 of file opendkim.c.

#define SIGMIN_PERCENT   1

Definition at line 589 of file opendkim.c.

#define TRYFREE (   x)
Value:
do { \
                            if ((x) != NULL) \
                            { \
                                   free(x); \
                                   (x) = NULL; \
                            } \
                     } while (0)

Definition at line 818 of file opendkim.c.


Typedef Documentation

typedef struct connctx* connctx

Definition at line 542 of file opendkim.c.

typedef struct msgctx* msgctx

Definition at line 468 of file opendkim.c.


Function Documentation

void *dkimf_getpriv __P ( (SMFICTX *)  )
sfsistat mlfi_body __P ( (SMFICTX *, u_char *, size_t)  )
sfsistat mlfi_connect __P ( (SMFICTX *, char *, _SOCK_ADDR *)  )
sfsistat mlfi_envrcpt __P ( (SMFICTX *, char **)  )
sfsistat dkimf_addheader __P ( (SMFICTX *, char *, char *)  )
sfsistat mlfi_negotiate __P ( (SMFICTX *, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long *, unsigned long *, unsigned long *, unsigned long *)  )
static int dkimf_add_signrequest __P ( (struct msgctx *, DKIMF_DB, char *, char *, ssize_t)  ) [static]
sfsistat dkimf_quarantine __P ( (SMFICTX *, char *)  )
sfsistat dkimf_chgheader __P ( (SMFICTX *, char *, int, char *)  )
static void dkimf_config_reload __P ( (void)  ) [static]
static Header dkimf_findheader __P ( (msgctx, char *, int)  ) [static]
sfsistat dkimf_insheader __P ( (SMFICTX *, int, char *, char *)  )
static void dkimf_sigreport __P ( (connctx, struct dkimf_config *, char *)  ) [static]
void dkimf_sendprogress __P ( (const void *)  )
sfsistat dkimf_setpriv __P ( (SMFICTX *, void *)  )
sfsistat dkimf_setreply __P ( (SMFICTX *, char *, char *, char *)  )
static void dkimf_add_ar_fields ( struct msgctx dfc,
struct dkimf_config conf,
SMFICTX *  ctx 
) [static]

Definition at line 4332 of file opendkim.c.

{
       assert(dfc != NULL);
       assert(conf != NULL);
       assert(ctx != NULL);

       if (dkimf_insheader(ctx, 1, AUTHRESULTSHDR,
                           (char *) dfc->mctx_dkimar) == MI_FAILURE)
       {
              if (conf->conf_dolog)
              {
                     syslog(LOG_ERR, "%s: %s header add failed",
                            dfc->mctx_jobid, AUTHRESULTSHDR);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_add_signrequest ( struct msgctx dfc,
DKIMF_DB  keytable,
char *  keyname,
char *  signer,
ssize_t  signlen 
) [static]

Definition at line 4663 of file opendkim.c.

{
       _Bool found = FALSE;
       size_t keydatasz;
       struct signreq *new;
       struct dkimf_db_data dbd[3];
       char keydata[MAXBUFRSZ + 1];
       char domain[DKIM_MAXHOSTNAMELEN + 1];
       char selector[BUFRSZ + 1];

       assert(dfc != NULL);

       /*
       **  Error out if we want the default key but the key or selector were
       **  not provided.
       */

       if (keyname == NULL)
       {
              if (curconf->conf_seckey == NULL ||
                  curconf->conf_selector == NULL)
                     return 1;
       }

       if (keytable != NULL)
       {
              _Bool insecure;
              char *errstr;

              assert(keyname != NULL);

              memset(domain, '\0', sizeof domain);
              memset(selector, '\0', sizeof selector);
              memset(keydata, '\0', sizeof keydata);

              dbd[0].dbdata_buffer = domain;
              dbd[0].dbdata_buflen = sizeof domain - 1;
              dbd[0].dbdata_flags = DKIMF_DB_DATA_OPTIONAL;
              dbd[1].dbdata_buffer = selector;
              dbd[1].dbdata_buflen = sizeof selector - 1;
              dbd[1].dbdata_flags = DKIMF_DB_DATA_OPTIONAL;
              dbd[2].dbdata_buffer = keydata;
              dbd[2].dbdata_buflen = sizeof keydata - 1;
              dbd[2].dbdata_flags = DKIMF_DB_DATA_OPTIONAL;

              if (dkimf_db_get(keytable, keyname, strlen(keyname),
                               dbd, 3, &found) != 0)
                     return -1;

              if (!found)
                     return 1;

              if (dbd[0].dbdata_buflen == 0 ||
                  dbd[0].dbdata_buflen == (size_t) -1 ||
                  dbd[1].dbdata_buflen == 0 ||
                  dbd[1].dbdata_buflen == (size_t) -1 ||
                  dbd[2].dbdata_buflen == 0 ||
                  dbd[2].dbdata_buflen == (size_t) -1)
              {
                     if (dolog)
                     {
                            syslog(LOG_ERR,
                                   "KeyTable entry for '%s' corrupt",
                                   keyname);
                     }

                     return 2;
              }

              if (domain[0] == '%' && domain[1] == '\0' &&
                  dfc->mctx_domain == NULL)
              {
                     if (dolog)
                     {
                            syslog(LOG_ERR,
                                   "KeyTable entry for '%s' cannot be resolved",
                                   keyname);
                     }

                     return 3;
              }

              if (keydata[0] == '/')
              {
                     char *d;
                     char tmpdata[MAXBUFRSZ + 1];

                     memset(tmpdata, '\0', sizeof tmpdata);

                     if (domain[0] == '%' && domain[1] == '\0')
                            d = dfc->mctx_domain;
                     else
                            d = domain;

                     dkimf_reptoken(tmpdata, sizeof tmpdata, keydata, d);

                     memcpy(keydata, tmpdata, sizeof keydata);
              }

              keydatasz = sizeof keydata - 1;
              insecure = FALSE;
              if (!dkimf_loadkey(dbd[2].dbdata_buffer, &keydatasz,
                                 &insecure, &errstr))
              {
                     if (dolog)
                     {
                            syslog(LOG_ERR, "can't load key from %s: %s",
                                   dbd[2].dbdata_buffer, errstr);
                     }

                     return 2;
              }

              if (insecure)
              {
                     if (dolog)
                     {
                            int sev;

                            sev = (curconf->conf_safekeys ? LOG_ERR
                                                          : LOG_WARNING);

                            syslog(sev, "%s: key data is not secure",
                                   keyname);
                     }

                     if (curconf->conf_safekeys)
                            return 2;
              }
       }

       new = malloc(sizeof *new);
       if (new == NULL)
              return -1;

       new->srq_next = NULL;
       new->srq_dkim = NULL;
       new->srq_domain = NULL;
       new->srq_selector = NULL;
       new->srq_keydata = NULL;
       new->srq_signlen = signlen;
       if (signer != NULL && signer[0] != '\0')
              new->srq_signer = (u_char *) strdup(signer);
       else
              new->srq_signer = NULL;

       if (keytable != NULL)
       {
              if (domain[0] == '%' && domain[1] == '\0')
                     new->srq_domain = (u_char *) strdup((char *) dfc->mctx_domain);
              else
                     new->srq_domain = (u_char *) strdup((char *) domain);

              new->srq_selector = (u_char *) strdup((char *) selector);
              new->srq_keydata = (void *) malloc(keydatasz + 1);
              if (new->srq_keydata == NULL)
              {
                     free(new);
                     return -1;
              }
              memset(new->srq_keydata, '\0', keydatasz + 1);
              memcpy(new->srq_keydata, dbd[2].dbdata_buffer, keydatasz);
       }

       if (dfc->mctx_srtail != NULL)
              dfc->mctx_srtail->srq_next = new;
       else
              dfc->mctx_srtail = new;

       if (dfc->mctx_srhead == NULL)
              dfc->mctx_srhead = new;

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_addheader ( SMFICTX *  ctx,
char *  hname,
char *  hvalue 
)

Definition at line 994 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(hname != NULL);
       assert(hvalue != NULL);

       if (testmode)
              return dkimf_test_addheader(ctx, hname, hvalue);
       else
              return smfi_addheader(ctx, hname, hvalue);
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_addrcpt ( SMFICTX *  ctx,
char *  addr 
)

Definition at line 1018 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(addr != NULL);

       if (testmode)
              return dkimf_test_addrcpt(ctx, addr);
       else
              return smfi_addrcpt(ctx, addr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_apply_signtable ( struct msgctx dfc,
DKIMF_DB  keydb,
DKIMF_DB  signdb,
unsigned char *  user,
unsigned char *  domain,
char *  errkey,
size_t  errlen,
_Bool  multisig 
) [static]

Definition at line 9448 of file opendkim.c.

{
       _Bool found;
       int nfound = 0;
       char keyname[BUFRSZ + 1];
       u_char tmp[BUFRSZ + 1];

       assert(dfc != NULL);
       assert(keydb != NULL);
       assert(signdb != NULL);
       assert(user != NULL);
       assert(domain != NULL);

       if (dkimf_db_type(signdb) == DKIMF_DB_TYPE_REFILE)
       {
              int status;
              void *ctx = NULL;
              struct dkimf_db_data dbd[2];
              char addr[MAXADDRESS + 1];
              u_char signer[MAXADDRESS + 1];

              snprintf(addr, sizeof addr, "%s@%s", user, domain);

              memset(&dbd, '\0', sizeof dbd);
              dbd[0].dbdata_buffer = keyname;
              dbd[1].dbdata_buffer = (char *) signer;
              dbd[1].dbdata_flags = DKIMF_DB_DATA_OPTIONAL;

              /* walk RE set, find match(es), make request(s) */
              for (;;)
              {
                     memset(keyname, '\0', sizeof keyname);
                     dbd[0].dbdata_buflen = sizeof keyname - 1;
                     memset(signer, '\0', sizeof signer);
                     dbd[1].dbdata_buflen = sizeof signer - 1;

                     status = dkimf_db_rewalk(signdb, addr, dbd, 2, &ctx);
                     if (status == -1)
                            return -1;
                     else if (status == 1)
                            break;

                     if (keyname[0] == '%' && keyname[1] == '\0')
                            dkim_strlcpy(keyname, domain, sizeof keyname);

                     dkimf_reptoken(tmp, sizeof tmp, signer, domain);
                     status = dkimf_add_signrequest(dfc, keydb, keyname,
                                                    (char *) tmp,
                                                    (ssize_t) -1);
                     if (status != 0 && errkey != NULL)
                            strlcpy(errkey, keyname, errlen);
                     if (status == 1)
                            return -2;
                     else if (status == 2 || status == 3 || status == -1)
                            return -3;

                     nfound++;

                     if (!multisig)
                            return nfound;
              }
       }
       else
       {
              int status;
              char *p;
              char tmpaddr[MAXADDRESS + 1];
              u_char signer[MAXADDRESS + 1];
              struct dkimf_db_data req[2];

              memset(&req, '\0', sizeof req);

              memset(keyname, '\0', sizeof keyname);
              memset(signer, '\0', sizeof signer);
              req[0].dbdata_buffer = keyname;
              req[0].dbdata_buflen = sizeof keyname - 1;
              req[1].dbdata_buffer = (char *) signer;
              req[1].dbdata_buflen = sizeof signer - 1;
              req[1].dbdata_flags = DKIMF_DB_DATA_OPTIONAL;

              /* first try full "user@host" */
              snprintf(tmpaddr, sizeof tmpaddr, "%s@%s", user, domain);

              found = FALSE;
              status = dkimf_db_get(signdb, tmpaddr, strlen(tmpaddr),
                                    req, 2, &found);
              if (status != 0 ||
                  (found && (req[0].dbdata_buflen == 0 ||
                             req[0].dbdata_buflen == (size_t) -1)))
              {
                     if (status != 0 && dolog)
                            dkimf_db_error(signdb, tmpaddr);
                     return -1;
              }
              else if (found)
              {
                     if (keyname[0] == '%' && keyname[1] == '\0')
                            dkim_strlcpy(keyname, domain, sizeof keyname);

                     dkimf_reptoken(tmp, sizeof tmp, signer, domain);

                     status = dkimf_add_signrequest(dfc, keydb, keyname,
                                                    (char *) tmp,
                                                    (ssize_t) -1);
                     if (status != 0 && errkey != NULL)
                            strlcpy(errkey, keyname, errlen);
                     if (status == 1)
                            return -2;
                     else if (status == 2 || status == 3 || status == -1)
                            return -3;

                     nfound++;

                     if (!multisig)
                            return nfound;
              }

              /* now just "host" */
              found = FALSE;
              req[0].dbdata_buflen = sizeof keyname - 1;
              req[1].dbdata_buflen = sizeof signer - 1;
              memset(keyname, '\0', sizeof keyname);
              memset(signer, '\0', sizeof signer);
              status = dkimf_db_get(signdb, domain, strlen((char *) domain),
                                    req, 2, &found);
              if (status != 0 ||
                  (found && (req[0].dbdata_buflen == 0 ||
                             req[0].dbdata_buflen == (size_t) -1)))
              {
                     if (status != 0 && dolog)
                            dkimf_db_error(signdb, (char *) domain);
                     return -1;
              }
              else if (found)
              {
                     if (keyname[0] == '%' && keyname[1] == '\0')
                            dkim_strlcpy(keyname, domain, sizeof keyname);

                     dkimf_reptoken(tmp, sizeof tmp, signer, domain);

                     status = dkimf_add_signrequest(dfc, keydb, keyname,
                                                    (char *) tmp,
                                                    (ssize_t) -1);
                     if (status != 0 && errkey != NULL)
                            strlcpy(errkey, keyname, errlen);
                     if (status == 1)
                            return -2;
                     else if (status == 2 || status == 3 || status == -1)
                            return -3;

                     nfound++;

                     if (!multisig)
                            return nfound;
              }

              /* next "user@.domain" and ".domain", degrading */
              for (p = strchr((char *) domain, '.');
                   p != NULL;
                   p = strchr(p + 1, '.'))
              {
                     snprintf(tmpaddr, sizeof tmpaddr, "%s@%s",
                              user, p);

                     found = FALSE;
                     req[0].dbdata_buflen = sizeof keyname - 1;
                     req[1].dbdata_buflen = sizeof signer - 1;
                     memset(keyname, '\0', sizeof keyname);
                     memset(signer, '\0', sizeof signer);
                     status = dkimf_db_get(signdb, tmpaddr, strlen(tmpaddr),
                                           req, 2, &found);
                     if (status != 0 ||
                         (found && (req[0].dbdata_buflen == 0 ||
                                    req[0].dbdata_buflen == (size_t) -1)))
                     {
                            if (status != 0 && dolog)
                                   dkimf_db_error(signdb, tmpaddr);
                            return -1;
                     }
                     else if (found)
                     {
                            if (keyname[0] == '%' && keyname[1] == '\0')
                            {
                                   dkim_strlcpy(keyname, domain,
                                                sizeof keyname);
                            }

                            dkimf_reptoken(tmp, sizeof tmp, signer,
                                           domain);

                            status = dkimf_add_signrequest(dfc, keydb,
                                                           keyname,
                                                           (char *) tmp,
                                                           (ssize_t) -1);
                            if (status != 0 && errkey != NULL)
                                   strlcpy(errkey, keyname, errlen);
                            if (status == 1)
                                   return -2;
                            else if (status == 2 || status == 3 ||
                                     status == -1)
                                   return -3;

                            nfound++;

                            if (!multisig)
                                   return nfound;
                     }

                     found = FALSE;
                     req[0].dbdata_buflen = sizeof keyname - 1;
                     req[1].dbdata_buflen = sizeof signer - 1;
                     memset(keyname, '\0', sizeof keyname);
                     memset(signer, '\0', sizeof signer);
                     status = dkimf_db_get(signdb, p, strlen(p),
                                           req, 2, &found);
                     if (status != 0 ||
                         (found && (req[0].dbdata_buflen == 0 ||
                                    req[0].dbdata_buflen == (size_t) -1)))
                     {
                            if (status != 0 && dolog)
                                   dkimf_db_error(signdb, p);
                            return -1;
                     }
                     else if (found)
                     {
                            if (keyname[0] == '%' && keyname[1] == '\0')
                            {
                                   dkim_strlcpy(keyname, domain,
                                                sizeof keyname);
                            }

                            dkimf_reptoken(tmp, sizeof tmp, signer,
                                           domain);

                            status = dkimf_add_signrequest(dfc, keydb,
                                                           keyname,
                                                           (char *) tmp,
                                                           (ssize_t) -1);
                            if (status != 0 && errkey != NULL)
                                   strlcpy(errkey, keyname, errlen);
                            if (status == 1)
                                   return -2;
                            else if (status == 2 || status == 3 ||
                                     status == -1)
                                   return -3;

                            nfound++;

                            if (!multisig)
                                   return nfound;
                     }
              }

              /* now "user@*" */
              snprintf(tmpaddr, sizeof tmpaddr, "%s@*", user);

              found = FALSE;
              req[0].dbdata_buflen = sizeof keyname - 1;
              req[1].dbdata_buflen = sizeof signer - 1;
              memset(keyname, '\0', sizeof keyname);
              memset(signer, '\0', sizeof signer);
              status = dkimf_db_get(signdb, tmpaddr, strlen(tmpaddr),
                                    req, 2, &found);
              if (status != 0 ||
                  (found && (req[0].dbdata_buflen == 0 ||
                             req[0].dbdata_buflen == (size_t) -1)))
              {
                     if (status != 0 && dolog)
                            dkimf_db_error(signdb, tmpaddr);
                     return -1;
              }
              else if (found)
              {
                     if (keyname[0] == '%' && keyname[1] == '\0')
                            dkim_strlcpy(keyname, domain, sizeof keyname);

                     dkimf_reptoken(tmp, sizeof tmp, signer, domain);

                     status = dkimf_add_signrequest(dfc, keydb, keyname,
                                                    (char *) tmp,
                                                    (ssize_t) -1);
                     if (status != 0 && errkey != NULL)
                            strlcpy(errkey, keyname, errlen);
                     if (status == 1)
                            return -2;
                     else if (status == 2 || status == 3 || status == -1)
                            return -3;

                     nfound++;

                     if (!multisig)
                            return nfound;
              }

              /* finally just "*" */
              found = FALSE;
              req[0].dbdata_buflen = sizeof keyname - 1;
              req[1].dbdata_buflen = sizeof signer - 1;
              memset(keyname, '\0', sizeof keyname);
              memset(signer, '\0', sizeof signer);
              status = dkimf_db_get(signdb, "*", 1, req, 2, &found);
              if (status != 0 ||
                  (found && (req[0].dbdata_buflen == 0 ||
                             req[0].dbdata_buflen == (size_t) -1)))
              {
                     if (status != 0 && dolog)
                            dkimf_db_error(signdb, "*");
                     return -1;
              }
              else if (found)
              {
                     if (keyname[0] == '%' && keyname[1] == '\0')
                            dkim_strlcpy(keyname, domain, sizeof keyname);

                     dkimf_reptoken(tmp, sizeof tmp, signer, domain);

                     status = dkimf_add_signrequest(dfc, keydb, keyname,
                                                    (char *) tmp,
                                                    (ssize_t) -1);
                     if (status != 0 && errkey != NULL)
                            strlcpy(errkey, keyname, errlen);
                     if (status == 1)
                            return -2;
                     else if (status == 2 || status == 3 || status == -1)
                            return -3;

                     nfound++;

                     if (!multisig)
                            return nfound;
              }
       }

       return nfound;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkimf_ar_all_sigs ( char *  hdr,
size_t  hdrlen,
DKIM *  dkim,
struct dkimf_config conf,
int *  status 
)

Definition at line 10407 of file opendkim.c.

{
       int nsigs;
       DKIM_STAT dstatus;
       DKIM_SIGINFO **sigs;

       assert(hdr != NULL);
       assert(dkim != NULL);
       assert(conf != NULL);
       assert(status != NULL);

       dstatus = dkim_getsiglist(dkim, &sigs, &nsigs);
       if (dstatus == DKIM_STAT_OK)
       {
              int c;
              int sigerror;
              int sec;
              DKIM_STAT ts;
              u_int keybits;
              size_t ssl;
              char *result;
              char *dnssec;
              char ss[BUFRSZ + 1];
              char tmp[BUFRSZ + 1];
              char val[MAXADDRESS + 1];
              char comment[BUFRSZ + 1];

              for (c = 0; c < nsigs; c++)
              {
                     dnssec = NULL;

                     memset(comment, '\0', sizeof comment);

                     sigerror = dkim_sig_geterror(sigs[c]);

                     if (dkim_sig_getkeysize(sigs[c],
                                             &keybits) != DKIM_STAT_OK)
                            keybits = 0;

                     ssl = sizeof ss - 1;
                     ts = dkim_get_sigsubstring(dkim, sigs[c], ss, &ssl);

                     if ((dkim_sig_getflags(sigs[c]) & DKIM_SIGFLAG_PASSED) != 0 &&
                         dkim_sig_getbh(sigs[c]) == DKIM_SIGBH_MATCH)
                     {
                            result = "pass";
                     }
                     else if (sigerror == DKIM_SIGERROR_MULTIREPLY ||
                              sigerror == DKIM_SIGERROR_KEYFAIL ||
                              sigerror == DKIM_SIGERROR_DNSSYNTAX)
                     {
                            result = "temperror";
                     }
                     else if ((dkim_sig_getflags(sigs[c]) & DKIM_SIGFLAG_PROCESSED) != 0 &&
                              ((dkim_sig_getflags(sigs[c]) & DKIM_SIGFLAG_PASSED) == 0 ||
                               dkim_sig_getbh(sigs[c]) != DKIM_SIGBH_MATCH))
                     {
                            const char *err;

                            result = "fail";

                            err = dkim_sig_geterrorstr(dkim_sig_geterror(sigs[c]));
                            if (err != NULL)
                            {
                                   snprintf(comment, sizeof comment,
                                            " reason=\"%s\"", err);
                            }
                     }
                     else if (sigerror != DKIM_SIGERROR_UNKNOWN &&
                              sigerror != DKIM_SIGERROR_OK)
                     {
                            result = "permerror";
                     }
                     else
                     {
                            result = "neutral";
                     }

                     dnssec = NULL;

#ifdef USE_UNBOUND
                     switch (dkim_sig_getdnssec(sigs[c]))
                     {
                       case DKIM_DNSSEC_UNKNOWN:
                            break;

                       case DKIM_DNSSEC_INSECURE:
                            dnssec = "insecure";
                            if (conf->conf_insecurekey == DKIMF_KEYACTIONS_FAIL)
                            {
                                   *status = DKIMF_STATUS_BAD;
                            }
                            else if (conf->conf_insecurekey == DKIMF_KEYACTIONS_NEUTRAL)
                            {
                                   *status = DKIMF_STATUS_VERIFYERR;
                                   result = "neutral";
                            }
                            break;

                       case DKIM_DNSSEC_BOGUS:
                            dnssec = "bogus";
                            if (conf->conf_boguskey == DKIMF_KEYACTIONS_FAIL)
                            {
                                   *status = DKIMF_STATUS_BAD;
                            }
                            else if (conf->conf_boguskey == DKIMF_KEYACTIONS_NEUTRAL)                    {
                                   *status = DKIMF_STATUS_VERIFYERR;
                                   result = "neutral";
                            }
                            break;

                       case DKIM_DNSSEC_SECURE:
                            dnssec = "secure";
                            break;
                     }
#endif /* USE_UNBOUND */

                     memset(val, '\0', sizeof val);

                     (void) dkim_sig_getidentity(dkim, sigs[c],
                                                 val, sizeof val - 1);

                     snprintf(tmp, sizeof tmp,
                              "%s%sdkim=%s%s (%u-bit key%s%s) header.i=%s%s%s",
                              c == 0 ? "" : ";",
                              DELIMITER, result, comment,
                              keybits,
                              dnssec == NULL ? "" : "; ",
                              dnssec == NULL ? "" : dnssec,
                              val,
                              ts == DKIM_STAT_OK ? " header.b=" : "",
                              ts == DKIM_STAT_OK ? ss : "");

                     strlcat(hdr, tmp, hdrlen);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_arfdkim ( msgctx  dfc) [static]
static int dkimf_arftype ( msgctx  dfc) [static]

Definition at line 5164 of file opendkim.c.

{
       assert(dfc != NULL);

       if (dfc->mctx_susp)
              return ARF_TYPE_FRAUD;
       else
              return ARF_TYPE_AUTHFAIL;
}

Here is the caller graph for this function:

static _Bool dkimf_authorsigok ( msgctx  msg) [static]

Definition at line 5567 of file opendkim.c.

{
       DKIM_STAT status;
       int c;
       int nsigs;
       DKIM_SIGINFO **sigs;

       assert(msg != NULL);

       status = dkim_getsiglist(msg->mctx_dkimv, &sigs, &nsigs);
       if (status != DKIM_STAT_OK)
              return FALSE;

       for (c = 0; c < nsigs; c++)
       {
              /* skip signatures with errors */
              if (dkim_sig_geterror(sigs[c]) != DKIM_SIGERROR_UNKNOWN &&
                  dkim_sig_geterror(sigs[c]) != DKIM_SIGERROR_OK)
                     continue;

              if (strcasecmp((char *) dkim_sig_getdomain(sigs[c]),
                             (char *) msg->mctx_domain) == 0 &&
                  (dkim_sig_getflags(sigs[c]) & DKIM_SIGFLAG_PASSED) != 0 &&
                  dkim_sig_getbh(sigs[c]) == DKIM_SIGBH_MATCH)
                     return TRUE;
       }

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkimf_checkbldb ( DKIMF_DB  db,
char *  to,
char *  jobid 
) [static]

Definition at line 8656 of file opendkim.c.

{
       int c;
       _Bool exists = FALSE;
       DKIM_STAT status;
       size_t out;
       char *domain;
       char *user;
       char *p;
       char addr[MAXADDRESS + 1];
       char dbaddr[MAXADDRESS + 1];

       strlcpy(addr, to, sizeof addr);
       status = dkim_mail_parse(addr, (u_char **) &user, (u_char **) &domain);
       if (status != 0 || user == NULL || domain == NULL)
       {
              if (dolog)
              {
                     syslog(LOG_INFO, "%s: can't parse %s: header",
                            jobid, to);
              }

              return FALSE;
       }

       for (p = domain; ; p = strchr(p + 1, '.'))
       {
              for (c = 0; c < 2; c++)
              {
                     if (c == 1 && p == NULL)
                     {
                            dbaddr[0] = '*';
                            dbaddr[1] = '\0';
                     }
                     else if (snprintf(dbaddr, sizeof dbaddr, "%s@%s",
                                       c == 0 ? user : "*",
                                       p == NULL ? "*" : p) >= (int) sizeof dbaddr)
                     {
                            if (dolog)
                            {
                                   syslog(LOG_ERR,
                                          "%s: overflow parsing \"%s\"",
                                          jobid, to);
                            }

                            return FALSE;
                     }

                     status = dkimf_db_get(db, dbaddr, 0, NULL, 0, &exists);
                     if (status == 0)
                     {
                            if (exists)
                                   return TRUE;
                     }
                     else if (dolog)
                     {
                            dkimf_db_error(db, dbaddr);
                     }
              }

              if (p == NULL)
                     break;
       }

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_chgheader ( SMFICTX *  ctx,
char *  hname,
int  idx,
char *  hvalue 
)

Definition at line 946 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(hname != NULL);

       if (testmode)
              return dkimf_test_chgheader(ctx, hname, idx, hvalue);
       else
              return smfi_chgheader(ctx, hname, idx, hvalue);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_cleanup ( SMFICTX *  ctx) [static]

Definition at line 8919 of file opendkim.c.

{
       msgctx dfc;
       connctx cc;

       assert(ctx != NULL);

       cc = (connctx) dkimf_getpriv(ctx);

       if (cc == NULL)
              return;

       dfc = cc->cctx_msg;

       /* release memory, reset state */
       if (dfc != NULL)
       {
              if (dfc->mctx_hqhead != NULL)
              {
                     Header hdr;
                     Header prev;

                     hdr = dfc->mctx_hqhead;
                     while (hdr != NULL)
                     {
                            TRYFREE(hdr->hdr_hdr);
                            TRYFREE(hdr->hdr_val);
                            prev = hdr;
                            hdr = hdr->hdr_next;
                            TRYFREE(prev);
                     }
              }

              if (dfc->mctx_rcptlist != NULL)
              {
                     struct addrlist *addr;
                     struct addrlist *next;

                     addr = dfc->mctx_rcptlist;
                     while (addr != NULL)
                     {
                            next = addr->a_next;

                            TRYFREE(addr->a_addr);
                            TRYFREE(addr);

                            addr = next;
                     }
              }

              if (dfc->mctx_srhead != NULL)
              {
                     struct signreq *sr;
                     struct signreq *next;

                     sr = dfc->mctx_srhead;
                     while (sr != NULL)
                     {
                            next = sr->srq_next;

                            if (sr->srq_dkim != NULL)
                                   dkim_free(sr->srq_dkim);
                            TRYFREE(sr->srq_keydata);
                            TRYFREE(sr->srq_domain);
                            TRYFREE(sr->srq_selector);
                            TRYFREE(sr->srq_signer);
                            TRYFREE(sr);

                            sr = next;
                     }
              }

#ifdef _FFR_ADSP_LISTS
              if (dfc->mctx_pstate != NULL)
                     dkim_policy_state_free(dfc->mctx_pstate);
#endif /* _FFR_ADSP_LISTS */

              if (dfc->mctx_dkimv != NULL)
                     dkim_free(dfc->mctx_dkimv);

#ifdef _FFR_VBR
              if (dfc->mctx_vbr != NULL)
                     vbr_close(dfc->mctx_vbr);

              TRYFREE(dfc->mctx_vbrinfo);
#endif /* _FFR_VBR */

              if (dfc->mctx_tmpstr != NULL)
                     dkimf_dstring_free(dfc->mctx_tmpstr);

#ifdef _FFR_STATSEXT
              if (dfc->mctx_statsext != NULL)
              {
                     struct statsext *cur;
                     struct statsext *next;

                     cur = dfc->mctx_statsext;
                     while (cur != NULL)
                     {
                            next = cur->se_next;
       
                            free(cur);

                            cur = next;
                     }
              }
#endif /* _FFR_STATSEXT */

#ifdef _FFR_LUA_GLOBALS
              if (dfc->mctx_luaglobalh != NULL)
              {
                     struct lua_global *cur;
                     struct lua_global *next;

                     cur = dfc->mctx_luaglobalh;
                     while (cur != NULL)
                     {
                            next = cur->lg_next;

                            if (cur->lg_type == LUA_TNUMBER ||
                                cur->lg_type == LUA_TSTRING)
                                   free(cur->lg_value);

                            free(cur);

                            cur = next;
                     }
              }
#endif /* _FFR_LUA_GLOBALS */

              free(dfc);
              cc->cctx_msg = NULL;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_config_free ( struct dkimf_config conf) [static]

Definition at line 5662 of file opendkim.c.

{
       assert(conf != NULL);
       assert(conf->conf_refcnt == 0);

       dkimf_zapkey(conf);

       if (conf->conf_libopendkim != NULL)
              dkim_close(conf->conf_libopendkim);

       if (conf->conf_testdnsdb != NULL)
              dkimf_db_close(conf->conf_testdnsdb);

       if (conf->conf_domainsdb != NULL)
              dkimf_db_close(conf->conf_domainsdb);

       if (conf->conf_bldb != NULL)
              dkimf_db_close(conf->conf_bldb);

       if (conf->conf_domlist != NULL)
              free(conf->conf_domlist);

       if (conf->conf_omithdrdb != NULL)
              dkimf_db_close(conf->conf_omithdrdb);

       if (conf->conf_thirdpartydb != NULL)
              dkimf_db_close(conf->conf_thirdpartydb);

       if (conf->conf_signhdrsdb != NULL)
              dkimf_db_close(conf->conf_signhdrsdb);

       if (conf->conf_alwayshdrsdb != NULL)
              dkimf_db_close(conf->conf_alwayshdrsdb);

       if (conf->conf_senderhdrsdb != NULL)
              dkimf_db_close(conf->conf_senderhdrsdb);

#ifdef _FFR_OVERSIGN
       if (conf->conf_oversigndb != NULL)
              dkimf_db_close(conf->conf_oversigndb);
#endif /* _FFR_OVERSIGN */

       if (conf->conf_mtasdb != NULL)
              dkimf_db_close(conf->conf_mtasdb);

       if (conf->conf_macrosdb != NULL)
              dkimf_db_close(conf->conf_macrosdb);

       if (conf->conf_mbsdb != NULL)
              dkimf_db_close(conf->conf_mbsdb);

       if (conf->conf_dontsigntodb != NULL)
              dkimf_db_close(conf->conf_dontsigntodb);

#ifdef _FFR_ATPS
       if (conf->conf_atpsdb != NULL)
              dkimf_db_close(conf->conf_atpsdb);
#endif /* _FFR_ATPS */

#ifdef _FFR_DKIM_REPUTATION
       if (conf->conf_reproot != NULL)
              free(conf->conf_reproot);
#endif /* _FFR_DKIM_REPUTATION */

       if (conf->conf_authservid != NULL)
              free(conf->conf_authservid);

       if (conf->conf_peerdb != NULL)
              dkimf_db_close(conf->conf_peerdb);

       if (conf->conf_internal != NULL)
              dkimf_db_close(conf->conf_internal);

       if (conf->conf_exignore != NULL)
              dkimf_db_close(conf->conf_exignore);

       if (conf->conf_exemptdb != NULL)
              dkimf_db_close(conf->conf_exemptdb);

#ifdef _FFR_REPLACE_RULES
       if (conf->conf_replist != NULL)
              dkimf_free_replist(conf->conf_replist);
       if (conf->conf_rephdrsdb != NULL)
              dkimf_db_close(conf->conf_rephdrsdb);
#endif /* _FFR_REPLACE_RULES */

#ifdef _FFR_VBR
       if (conf->conf_vbr_trusteddb != NULL)
              dkimf_db_close(conf->conf_vbr_trusteddb);
#endif /* _FFR_VBR */

       if (conf->conf_nosignpats != NULL)
       {
              int n;

              for (n = 0; conf->conf_nosignpats[n] != NULL; n++)
                     regfree(conf->conf_nosignpats[n]);

              free(conf->conf_nosignpats);
       }

       if (conf->conf_localadsp_db != NULL)
              dkimf_db_close(conf->conf_localadsp_db);

#ifdef _FFR_RESIGN
       if (conf->conf_resigndb != NULL)
              dkimf_db_close(conf->conf_resigndb);
#endif /* _FFR_RESIGN */

#ifdef _FFR_RATE_LIMIT
       if (conf->conf_ratelimitdb != NULL)
              dkimf_db_close(conf->conf_ratelimitdb);
       if (conf->conf_flowdatadb != NULL)
              dkimf_db_close(conf->conf_flowdatadb);
#endif /* _FFR_RATE_LIMIT */

#ifdef _FFR_REPUTATION
       if (conf->conf_repratiosdb != NULL)
              dkimf_db_close(conf->conf_repratiosdb);
       if (conf->conf_replimitsdb != NULL)
              dkimf_db_close(conf->conf_replimitsdb);
       if (conf->conf_replimitmodsdb != NULL)
              dkimf_db_close(conf->conf_replimitmodsdb);
       if (conf->conf_repspamcheck != NULL)
              regfree(&conf->conf_repspamre);
       if (conf->conf_rep != NULL)
              dkimf_rep_close(conf->conf_rep);
#endif /* _FFR_REPUTATION */

#ifdef USE_LUA
       if (conf->conf_setupscript != NULL)
              free(conf->conf_setupscript);
       if (conf->conf_setupfunc != NULL)
              free(conf->conf_setupfunc);
       if (conf->conf_screenscript != NULL)
              free(conf->conf_screenscript);
       if (conf->conf_screenfunc != NULL)
              free(conf->conf_screenfunc);
# ifdef _FFR_STATSEXT
       if (conf->conf_statsscript != NULL)
              free(conf->conf_statsscript);
       if (conf->conf_statsfunc != NULL)
              free(conf->conf_statsfunc);
# endif /* _FFR_STATSEXT */
       if (conf->conf_finalscript != NULL)
              free(conf->conf_finalscript);
       if (conf->conf_finalfunc != NULL)
              free(conf->conf_finalfunc);
#endif /* USE_LUA */

#ifdef USE_UNBOUND
       if (conf->conf_unbound != NULL)
              dkimf_unbound_close(conf->conf_unbound);
#endif /* USE_UNBOUND */

#ifdef USE_ARLIB
       if (conf->conf_arlib != NULL)
              ar_shutdown(conf->conf_arlib);
#endif /* USE_ARLIB */

       if (conf->conf_data != NULL)
              config_free(conf->conf_data);

       free(conf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_config_load ( struct config data,
struct dkimf_config conf,
char *  err,
size_t  errlen 
) [static]

Definition at line 5934 of file opendkim.c.

{
       int maxsign;
       int dbflags = 0;
       char *str;
       char confstr[BUFRSZ + 1];
       char basedir[MAXPATHLEN + 1];

       assert(conf != NULL);
       assert(err != NULL);

       memset(basedir, '\0', sizeof basedir);
       memset(confstr, '\0', sizeof confstr);

       if (data != NULL)
       {
#ifdef USE_LDAP
              (void) config_get(data, "LDAPSoftStart",
                                &conf->conf_softstart,
                                sizeof conf->conf_softstart);
#endif /* USE_LDAP */

              (void) config_get(data, "AddAllSignatureResults",
                                &conf->conf_allsigs,
                                sizeof conf->conf_allsigs);

              (void) config_get(data, "DNSConnect",
                                &conf->conf_dnsconnect,
                                sizeof conf->conf_dnsconnect);

              (void) config_get(data, "ResolverTracing",
                                &conf->conf_restrace,
                                sizeof conf->conf_restrace);

              (void) config_get(data, "AlwaysAddARHeader",
                                &conf->conf_alwaysaddar,
                                sizeof conf->conf_alwaysaddar);

              str = NULL;
              (void) config_get(data, "AuthservID", &str, sizeof str);
              if (str != NULL)
              {
                     if (strcmp(str, "HOSTNAME") == 0)
                            conf->conf_authservid = strdup(myhostname);
                     else   
                            conf->conf_authservid = strdup(str);
              }

              (void) config_get(data, "AuthservIDWithJobID",
                                &conf->conf_authservidwithjobid,
                                sizeof conf->conf_authservidwithjobid);

              str = NULL;
              (void) config_get(data, "BaseDirectory", &str, sizeof str);
              if (str != NULL)
                     strlcpy(basedir, str, sizeof basedir);

              if (conf->conf_canonstr == NULL)
              {
                     (void) config_get(data, "Canonicalization",
                                       &conf->conf_canonstr,
                                       sizeof conf->conf_canonstr);
              }

              (void) config_get(data, "ClockDrift", &conf->conf_clockdrift,
                                sizeof conf->conf_clockdrift);

#ifdef _FFR_DEFAULT_SENDER
              (void) config_get(data, "DefaultSender", &conf->conf_defsender,
                                sizeof conf->conf_defsender);
#endif /* _FFR_DEFAULT_SENDER */

              (void) config_get(data, "Diagnostics", &conf->conf_ztags,
                                sizeof conf->conf_ztags);

              (void) config_get(data, "DiagnosticDirectory",
                                &conf->conf_diagdir,
                                sizeof conf->conf_diagdir);

#ifdef _FFR_REDIRECT
              (void) config_get(data, "RedirectFailuresTo",
                                &conf->conf_redirect,
                                sizeof conf->conf_redirect);
#endif /* _FFR_REDIRECT */

#ifdef _FFR_RESIGN
              (void) config_get(data, "ResignMailTo",
                                &conf->conf_resign,
                                sizeof conf->conf_resign);
              (void) config_get(data, "ResignAll",
                                &conf->conf_resignall,
                                sizeof conf->conf_resignall);
#endif /* _FFR_RESIGN */

              if (conf->conf_dnstimeout == DEFTIMEOUT)
              {
                     (void) config_get(data, "DNSTimeout",
                                       &conf->conf_dnstimeout,
                                       sizeof conf->conf_dnstimeout);
              }

              (void) config_get(data, "EnableCoredumps",
                                &conf->conf_enablecores,
                                sizeof conf->conf_enablecores);

              (void) config_get(data, "RequestReports",
                                &conf->conf_reqreports,
                                sizeof conf->conf_reqreports);

              (void) config_get(data, "RequireSafeKeys",
                                &conf->conf_safekeys,
                                sizeof conf->conf_safekeys);

              (void) config_get(data, "TestDNSData",
                                &conf->conf_testdnsdata,
                                sizeof conf->conf_testdnsdata);

              (void) config_get(data, "NoHeaderB",
                                &conf->conf_noheaderb,
                                sizeof conf->conf_noheaderb);

              (void) config_get(data, "FixCRLF",
                                &conf->conf_fixcrlf,
                                sizeof conf->conf_fixcrlf);

              (void) config_get(data, "KeepTemporaryFiles",
                                &conf->conf_keeptmpfiles,
                                sizeof conf->conf_keeptmpfiles);

              (void) config_get(data, "StrictHeaders",
                                &conf->conf_stricthdrs,
                                sizeof conf->conf_stricthdrs);

              (void) config_get(data, "TemporaryDirectory",
                                &conf->conf_tmpdir,
                                sizeof conf->conf_tmpdir);

              (void) config_get(data, "MaximumHeaders", &conf->conf_maxhdrsz,
                                sizeof conf->conf_maxhdrsz);

              (void) config_get(data, "MaximumSignaturesToVerify",
                                &conf->conf_maxverify,
                                sizeof conf->conf_maxverify);

#ifdef _FFR_IDENTITY_HEADER
              (void) config_get(data, "IdentityHeader",
                              &conf->conf_identityhdr, 
                              sizeof conf->conf_identityhdr);

              (void) config_get(data, "IdentityHeaderRemove",
                                &conf->conf_rmidentityhdr,
                                sizeof conf->conf_rmidentityhdr);
#endif /* _FFR_IDENTITY_HEADER */
#ifdef _FFR_DKIM_REPUTATION
              (void) config_get(data, "DKIMReputationFail",
                                &conf->conf_repfail,
                                sizeof conf->conf_repfail);

              (void) config_get(data, "DKIMReputationPass",
                                &conf->conf_reppass,
                                sizeof conf->conf_reppass);

              (void) config_get(data, "DKIMReputationReject",
                                &conf->conf_repreject,
                                sizeof conf->conf_repreject);

              str = NULL;
              (void) config_get(data, "DKIMReputationRoot",
                                &str, sizeof str);
              if (str != NULL)
                     conf->conf_reproot = strdup(str);

              if (conf->conf_repfail < conf->conf_reppass)
              {
                     snprintf(err, errlen,
                              "invalid reputation thresholds (DKIMReputationFail < DKIMReputationPass)");
                     return -1;
              }

              if (conf->conf_repreject < conf->conf_repfail)
              {
                     snprintf(err, errlen,
                              "invalid reputation thresholds (DKIMReputationReject < DKIMReputationFail)");
                     return -1;
              }
#endif /* _FFR_DKIM_REPUTATION */

              if (conf->conf_siglimit == NULL)
              {
                     (void) config_get(data, "Minimum",
                                       &conf->conf_siglimit,
                                       sizeof conf->conf_siglimit);
              }

              if (conf->conf_modestr == NULL)
              {
                     (void) config_get(data, "Mode", &conf->conf_modestr,
                                       sizeof conf->conf_modestr);
              }

              dkimf_parsehandler(data, "On-Default", &conf->conf_handling);
              dkimf_parsehandler(data, "On-BadSignature",
                                 &conf->conf_handling);
              dkimf_parsehandler(data, "On-DNSError", &conf->conf_handling);
              dkimf_parsehandler(data, "On-KeyNotFound",
                                 &conf->conf_handling);
              dkimf_parsehandler(data, "On-InternalError",
                                 &conf->conf_handling);
              dkimf_parsehandler(data, "On-NoSignature",
                                 &conf->conf_handling);
              dkimf_parsehandler(data, "On-PolicyError",
                                 &conf->conf_handling);
#ifdef _FFR_REPUTATION
              dkimf_parsehandler(data, "On-ReptuationError",
                                 &conf->conf_handling);
#endif /* _FFR_REPUTATION */
              dkimf_parsehandler(data, "On-Security", &conf->conf_handling);

              (void) config_get(data, "RemoveARAll", &conf->conf_remarall,
                                sizeof conf->conf_remarall);

              (void) config_get(data, "KeepAuthResults", &conf->conf_keepar,
                                sizeof conf->conf_keepar);

              (void) config_get(data, "RemoveOldSignatures",
                                &conf->conf_remsigs,
                                sizeof conf->conf_remsigs);

              if (!conf->conf_reqhdrs)
              {
                     (void) config_get(data, "RequiredHeaders",
                                       &conf->conf_reqhdrs,
                                       sizeof conf->conf_reqhdrs);
              }

              if (conf->conf_selector == NULL)
              {
                     (void) config_get(data, "Selector",
                                       &conf->conf_selector,
                                       sizeof conf->conf_selector);
              }

#ifdef _FFR_SENDER_MACRO
              if (conf->conf_sendermacro == NULL)
              {
                     (void) config_get(data, "SenderMacro",
                                       &conf->conf_sendermacro,
                                       sizeof conf->conf_sendermacro);
              }
#endif /* _FFR_SENDER_MACRO */

              if (!conf->conf_sendreports)
              {
                     (void) config_get(data, "SendReports",
                                       &conf->conf_sendreports,
                                       sizeof conf->conf_sendreports);
              }
              (void) config_get(data, "MTACommand",
                                &conf->conf_mtacommand,
                                sizeof conf->conf_mtacommand);

              (void) config_get(data, "SendADSPReports",
                                &conf->conf_sendadspreports,
                                sizeof conf->conf_sendadspreports);

              (void) config_get(data, "ReportAddress",
                                &conf->conf_reportaddr,
                                sizeof conf->conf_reportaddr);

              (void) config_get(data, "ReportBccAddress",
                                &conf->conf_reportaddrbcc,
                                sizeof conf->conf_reportaddrbcc);

              if (conf->conf_signalgstr == NULL)
              {
                     (void) config_get(data, "SignatureAlgorithm",
                                       &conf->conf_signalgstr,
                                       sizeof conf->conf_signalgstr);
              }

              (void) config_get(data, "SignatureTTL", &conf->conf_sigttl,
                                sizeof conf->conf_sigttl);

#ifdef _FFR_STATS
              (void) config_get(data, "Statistics", &conf->conf_statspath,
                                sizeof conf->conf_statspath);

              (void) config_get(data, "StatisticsPrefix",
                                &conf->conf_reportprefix,
                                sizeof conf->conf_reportprefix);

              str = NULL;
              (void) config_get(data, "StatisticsName", &str, sizeof str);
              if (str != NULL)
                     conf->conf_reporthost = str;
#endif /* _FFR_STATS */

              if (!conf->conf_subdomains)
              {
                     (void) config_get(data, "SubDomains",
                                       &conf->conf_subdomains,
                                       sizeof conf->conf_subdomains);
              }

              if (!conf->conf_dolog)
              {
                     (void) config_get(data, "Syslog", &conf->conf_dolog,
                                       sizeof conf->conf_dolog);
              }

              if (!conf->conf_logwhy)
              {
                     (void) config_get(data, "LogWhy", &conf->conf_logwhy,
                                       sizeof conf->conf_logwhy);
              }

              (void) config_get(data, "LogResults", &conf->conf_logresults,
                                sizeof conf->conf_logresults);

              (void) config_get(data, "MultipleSignatures",
                                &conf->conf_multisig,
                                sizeof conf->conf_multisig);

              (void) config_get(data, "SyslogSuccess",
                                &conf->conf_dolog_success,
                                sizeof conf->conf_dolog_success);

              (void) config_get(data, "WeakSyntaxChecks",
                                &conf->conf_weaksyntax,
                                sizeof conf->conf_weaksyntax);

              (void) config_get(data, "ADSPNoSuchDomain",
                                &conf->conf_adspnxdomain,
                                sizeof conf->conf_adspnxdomain);

              (void) config_get(data, "DisableADSP",
                                &conf->conf_noadsp,
                                sizeof conf->conf_noadsp);

              str = NULL;
              (void) config_get(data, "ADSPAction", &str, sizeof str);
              if (str != NULL)
              {
                     int c;

                     c = dkimf_configlookup(str, dkimf_adspactions);
                     if (c == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown ADSP action '%s'", str);
                            return -1;
                     }

                     conf->conf_adspaction = c;
              }

              if (!conf->conf_addxhdr)
              {
                     (void) config_get(data, "X-Header",
                                       &conf->conf_addxhdr,
                                       sizeof conf->conf_addxhdr);
              }

              (void) config_get(data, "DomainKeysCompat",
                                &conf->conf_acceptdk,
                                sizeof conf->conf_acceptdk);

              (void) config_get(data, "CaptureUnknownErrors",
                                &conf->conf_capture,
                                sizeof conf->conf_capture);

              (void) config_get(data, "AllowSHA1Only",
                                &conf->conf_allowsha1only,
                                sizeof conf->conf_allowsha1only);

#ifdef USE_LDAP
              (void) config_get(data, "LDAPUseTLS",
                                &conf->conf_ldap_usetls,
                                sizeof conf->conf_ldap_usetls);

              if (conf->conf_ldap_usetls)
                     dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_USETLS, "y");
              else
                     dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_USETLS, "n");

              (void) config_get(data, "LDAPTimeout",
                                &conf->conf_ldap_timeout,
                                sizeof conf->conf_ldap_timeout);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_TIMEOUT,
                                      conf->conf_ldap_timeout);

              (void) config_get(data, "LDAPKeepaliveIdle",
                                &conf->conf_ldap_kaidle,
                                sizeof conf->conf_ldap_kaidle);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_KA_IDLE,
                                      conf->conf_ldap_kaidle);

              (void) config_get(data, "LDAPKeepaliveProbes",
                                &conf->conf_ldap_kaprobes,
                                sizeof conf->conf_ldap_kaprobes);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_KA_PROBES,
                                      conf->conf_ldap_kaprobes);

              (void) config_get(data, "LDAPKeepaliveInterval",
                                &conf->conf_ldap_kainterval,
                                sizeof conf->conf_ldap_kainterval);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_KA_INTERVAL,
                                      conf->conf_ldap_kainterval);

              (void) config_get(data, "LDAPAuthMechanism",
                                &conf->conf_ldap_authmech,
                                sizeof conf->conf_ldap_authmech);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHMECH,
                                      conf->conf_ldap_authmech);

# ifdef USE_SASL
              (void) config_get(data, "LDAPAuthName",
                                &conf->conf_ldap_authname,
                                sizeof conf->conf_ldap_authname);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHNAME,
                                      conf->conf_ldap_authname);

              (void) config_get(data, "LDAPAuthRealm",
                                &conf->conf_ldap_authrealm,
                                sizeof conf->conf_ldap_authrealm);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHREALM,
                                      conf->conf_ldap_authrealm);

              (void) config_get(data, "LDAPAuthUser",
                                &conf->conf_ldap_authuser,
                                sizeof conf->conf_ldap_authuser);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHUSER,
                                      conf->conf_ldap_authuser);
# endif /* USE_SASL */

              (void) config_get(data, "LDAPBindPassword",
                                &conf->conf_ldap_bindpw,
                                sizeof conf->conf_ldap_bindpw);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_BINDPW,
                                      conf->conf_ldap_bindpw);

              (void) config_get(data, "LDAPBindUser",
                                &conf->conf_ldap_binduser,
                                sizeof conf->conf_ldap_binduser);

              dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_BINDUSER,
                                      conf->conf_ldap_binduser);
#endif /* USE_LDAP */

#ifdef USE_UNBOUND
              (void) config_get(data, "TrustAnchorFile",
                                &conf->conf_trustanchorpath,
                                sizeof conf->conf_trustanchorpath);

              if (conf->conf_trustanchorpath != NULL &&
                  access(conf->conf_trustanchorpath, R_OK) != 0)
              {
                     snprintf(err, errlen, "%s: %s",
                              conf->conf_trustanchorpath, strerror(errno));
                     return -1;
              }

              (void) config_get(data, "UnboundConfigFile",
                                &conf->conf_unboundconfig,
                                sizeof conf->conf_unboundconfig);

              if (conf->conf_unboundconfig != NULL &&
                  access(conf->conf_unboundconfig, R_OK) != 0)
              {
                     snprintf(err, errlen, "%s: %s",
                              conf->conf_unboundconfig, strerror(errno));
                     return -1;
              }

              str = NULL;
              (void) config_get(data, "BogusKey", &str, sizeof str);
              if (str != NULL)
              {
                     int c;

                     c = dkimf_configlookup(str, dkimf_keyactions);
                     if (c == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown key action '%s'", str);
                            return -1;
                     }

                     conf->conf_boguskey = c;
              }
              else
              {
                     conf->conf_boguskey = DKIMF_KEYACTIONS_FAIL;
              }

              str = NULL;
              (void) config_get(data, "InsecureKey", &str, sizeof str);
              if (str != NULL)
              {
                     int c;

                     c = dkimf_configlookup(str, dkimf_keyactions);
                     if (c == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown key action '%s'", str);
                            return -1;
                     }

                     conf->conf_insecurekey = c;
              }
              else
              {
                     conf->conf_boguskey = DKIMF_KEYACTIONS_NONE;
              }

              str = NULL;
              (void) config_get(data, "BogusPolicy", &str, sizeof str);
              if (str != NULL)
              {
                     int c;

                     c = dkimf_configlookup(str, dkimf_policyactions);
                     if (c == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown policy action '%s'", str);
                            return -1;
                     }

                     conf->conf_boguspolicy = c;
              }
              else
              {
                     conf->conf_boguspolicy = DKIM_POLICYACTIONS_IGNORE;
              }

              str = NULL;
              (void) config_get(data, "InsecurePolicy", &str, sizeof str);
              if (str != NULL)
              {
                     int c;

                     c = dkimf_configlookup(str, dkimf_policyactions);
                     if (c == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown policy action '%s'", str);
                            return -1;
                     }

                     conf->conf_insecurepolicy = c;
              }
              else
              {
                     conf->conf_insecurepolicy = DKIM_POLICYACTIONS_APPLY;
              }
#endif /* USE_UNBOUND */

#ifdef USE_LUA
              str = NULL;
              (void) config_get(data, "SetupPolicyScript", &str, sizeof str);
              if (str != NULL)
              {
                     int fd;
                     ssize_t rlen;
                     struct stat s;
                     struct dkimf_lua_script_result lres;

                     fd = open(str, O_RDONLY, 0);
                     if (fd < 0)
                     {
                            snprintf(err, errlen, "%s: open(): %s", str,
                                     strerror(errno));
                            return -1;
                     }

                     if (fstat(fd, &s) == -1)
                     {
                            snprintf(err, errlen, "%s: fstat(): %s", str,
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     conf->conf_setupscript = malloc(s.st_size + 1);
                     if (conf->conf_setupscript == NULL)
                     {
                            snprintf(err, errlen, "malloc(): %s",
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     memset(conf->conf_setupscript, '\0', s.st_size + 1);
                     rlen = read(fd, conf->conf_setupscript, s.st_size);
                     if (rlen == -1)
                     {
                            snprintf(err, errlen, "%s: read(): %s",
                                     str, strerror(errno));
                            close(fd);
                            return -1;
                     }
                     else if (rlen < s.st_size)
                     {
                            snprintf(err, errlen, "%s: early EOF",
                                     str);
                            close(fd);
                            return -1;
                     }

                     close(fd);

                     memset(&lres, '\0', sizeof lres);
                     if (dkimf_lua_setup_hook(NULL, conf->conf_setupscript,
                                              0, str, &lres,
                                              &conf->conf_setupfunc,
                                              &conf->conf_setupfuncsz) != 0)
                     {
                            strlcpy(err, lres.lrs_error, errlen);
                            free(lres.lrs_error);
                            return -1;
                     }
              }

              str = NULL;
              (void) config_get(data, "ScreenPolicyScript",
                                &str, sizeof str);
              if (str != NULL)
              {
                     int fd;
                     ssize_t rlen;
                     struct stat s;
                     struct dkimf_lua_script_result lres;

                     fd = open(str, O_RDONLY, 0);
                     if (fd < 0)
                     {
                            snprintf(err, errlen, "%s: open(): %s", str,
                                     strerror(errno));
                            return -1;
                     }

                     if (fstat(fd, &s) == -1)
                     {
                            snprintf(err, errlen, "%s: fstat(): %s", str,
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     conf->conf_screenscript = malloc(s.st_size + 1);
                     if (conf->conf_screenscript == NULL)
                     {
                            snprintf(err, errlen, "malloc(): %s",
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     memset(conf->conf_screenscript, '\0', s.st_size + 1);
                     rlen = read(fd, conf->conf_screenscript, s.st_size);
                     if (rlen == -1)
                     {
                            snprintf(err, errlen, "%s: read(): %s",
                                     str, strerror(errno));
                            close(fd);
                            return -1;
                     }
                     else if (rlen < s.st_size)
                     {
                            snprintf(err, errlen, "%s: early EOF",
                                     str);
                            close(fd);
                            return -1;
                     }

                     close(fd);

                     memset(&lres, '\0', sizeof lres);
                     if (dkimf_lua_screen_hook(NULL,
                                               conf->conf_screenscript, 0,
                                               str, &lres,
                                               &conf->conf_screenfunc,
                                               &conf->conf_screenfuncsz) != 0)
                     {
                            strlcpy(err, lres.lrs_error, errlen);
                            free(lres.lrs_error);
                            return -1;
                     }
              }

# ifdef _FFR_STATSEXT
              str = NULL;
              (void) config_get(data, "StatisticsPolicyScript", &str,
                                sizeof str);
              if (str != NULL)
              {
                     int fd;
                     ssize_t rlen;
                     struct stat s;
                     struct dkimf_lua_script_result lres;

                     fd = open(str, O_RDONLY, 0);
                     if (fd < 0)
                     {
                            snprintf(err, errlen, "%s: open(): %s", str,
                                     strerror(errno));
                            return -1;
                     }

                     if (fstat(fd, &s) == -1)
                     {
                            snprintf(err, errlen, "%s: fstat(): %s", str,
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     conf->conf_statsscript = malloc(s.st_size + 1);
                     if (conf->conf_statsscript == NULL)
                     {
                            snprintf(err, errlen, "malloc(): %s",
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     memset(conf->conf_statsscript, '\0', s.st_size + 1);
                     rlen = read(fd, conf->conf_statsscript, s.st_size);
                     if (rlen == -1)
                     {
                            snprintf(err, errlen, "%s: read(): %s",
                                     str, strerror(errno));
                            close(fd);
                            return -1;
                     }
                     else if (rlen < s.st_size)
                     {
                            snprintf(err, errlen, "%s: early EOF",
                                     str);
                            close(fd);
                            return -1;
                     }

                     close(fd);

                     memset(&lres, '\0', sizeof lres);
                     if (dkimf_lua_stats_hook(NULL, conf->conf_statsscript,
                                              0, str, &lres,
                                              &conf->conf_statsfunc,
                                              &conf->conf_statsfuncsz) != 0)
                     {
                            strlcpy(err, lres.lrs_error, errlen);
                            free(lres.lrs_error);
                            return -1;
                     }
              }
# endif /* _FFR_STATSEXT */

              str = NULL;
              (void) config_get(data, "FinalPolicyScript", &str, sizeof str);
              if (str != NULL)
              {
                     int fd;
                     ssize_t rlen;
                     struct stat s;
                     struct dkimf_lua_script_result lres;

                     fd = open(str, O_RDONLY, 0);
                     if (fd < 0)
                     {
                            snprintf(err, errlen, "%s: open(): %s", str,
                                     strerror(errno));
                            return -1;
                     }

                     if (fstat(fd, &s) == -1)
                     {
                            snprintf(err, errlen, "%s: fstat(): %s", str,
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     conf->conf_finalscript = malloc(s.st_size + 1);
                     if (conf->conf_finalscript == NULL)
                     {
                            snprintf(err, errlen, "malloc(): %s",
                                     strerror(errno));
                            close(fd);
                            return -1;
                     }

                     memset(conf->conf_finalscript, '\0', s.st_size + 1);
                     rlen = read(fd, conf->conf_finalscript, s.st_size);
                     if (rlen == -1)
                     {
                            snprintf(err, errlen, "%s: read(): %s",
                                     str, strerror(errno));
                            close(fd);
                            return -1;
                     }
                     else if (rlen < s.st_size)
                     {
                            snprintf(err, errlen, "%s: early EOF",
                                     str);
                            close(fd);
                            return -1;
                     }

                     close(fd);

                     memset(&lres, '\0', sizeof lres);
                     if (dkimf_lua_final_hook(NULL, conf->conf_finalscript,
                                              0, str, &lres,
                                              &conf->conf_finalfunc,
                                              &conf->conf_finalfuncsz) != 0)
                     {
                            strlcpy(err, lres.lrs_error, errlen);
                            free(lres.lrs_error);
                            return -1;
                     }
              }
#endif /* USE_LUA */
       }

#ifdef USE_LDAP
       if (conf->conf_softstart)
              dbflags |= DKIMF_DB_FLAG_SOFTSTART;
#endif /* USE_LDAP */

       if (basedir[0] != '\0')
       {
              if (chdir(basedir) != 0)
              {
                     snprintf(err, errlen, "%s: chdir(): %s",
                              basedir, strerror(errno));
                     return -1;
              }
       }

       str = NULL;
       if (conf->conf_peerfile != NULL)
       {
              str = conf->conf_peerfile;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "PeerList", &str, sizeof str);
       }
       if (str != NULL && !testmode)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_peerdb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       if (conf->conf_testdnsdata != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_testdnsdb,
                                     conf->conf_testdnsdata,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       /* internal list */
       str = NULL;
       if (conf->conf_internalfile != NULL)
       {
              str = conf->conf_internalfile;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "InternalHosts", &str, sizeof str);
       }
       if (str != NULL && !testmode)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_internal, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }
       else
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_internal, DEFINTERNAL,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              DEFINTERNAL, dberr);
                     return -1;
              }
       }

       /* external ignore list */
       str = NULL;
       if (conf->conf_externalfile != NULL)
       {
              str = conf->conf_externalfile;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "ExternalIgnoreList", &str,
                                sizeof str);
       }
       if (str != NULL && !testmode)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_exignore, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       /* exempt domains list */
       str = NULL;
       if (conf->conf_exemptfile != NULL)
       {
              str = conf->conf_exemptfile;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "ExemptDomains", &str, sizeof str);
       }
       if (str != NULL && !testmode)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_exemptdb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       /* BodyLengthDB */
       str = NULL;
       if (data != NULL)
              (void) config_get(data, "BodyLengthDB", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_bldb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "SignHeaders", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_signhdrsdb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "RemoveARFrom", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_remardb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

#ifdef _FFR_ADSP_LISTS
       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "NoDiscardableMailTo", &str,
                                sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_nodiscardto, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }
#endif /* _FFR_ADSP_LISTS */

#ifdef _FFR_ATPS

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "ATPSHashAlgorithm",
                                &conf->conf_atpshash,
                                sizeof conf->conf_atpshash);
              (void) config_get(data, "ATPSDomains", &str, sizeof str);
       }

       if (dkimf_configlookup(conf->conf_atpshash, dkimf_atpshash) != 1)
       {
              snprintf(err, errlen, "unknown ATPS hash \"%s\"",
                       conf->conf_atpshash);
              return -1;
       }

       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_atpsdb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }
#endif /* _FFR_ATPS */

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "DontSignMailTo", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_dontsigntodb, str,
                                     (dbflags | 
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "MustBeSigned", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_mbsdb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (conf->conf_omitlist != NULL)
       {
              str = conf->conf_omitlist;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "OmitHeaders", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_omithdrdb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "MTA", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_mtasdb, str,
                                     (dbflags | DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }

              status = dkimf_db_mkarray(conf->conf_mtasdb, &conf->conf_mtas,
                                        NULL);
              if (status == -1)
                     return -1;
       }

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "AlwaysSignHeaders", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_alwayshdrsdb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

#ifdef _FFR_OVERSIGN
       str = NULL;
       if (data != NULL)
              (void) config_get(data, "OverSignHeaders", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_oversigndb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }
#endif /* _FFR_OVERSIGN */

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "SenderHeaders", &str, sizeof str);
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_senderhdrsdb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }

              status = dkimf_db_mkarray(conf->conf_senderhdrsdb,
                                        &conf->conf_senderhdrs,
                                        (const char **) dkim_default_senderhdrs);
              if (status == -1)
                     return -1;
       }
       else
       {
              conf->conf_senderhdrs = (char **) dkim_default_senderhdrs;
       }

#ifdef _FFR_VBR
       if (data != NULL)
       {
              (void) config_get(data, "VBR-Type", &conf->conf_vbr_deftype,
                                sizeof conf->conf_vbr_deftype);
              (void) config_get(data, "VBR-Certifiers",
                                &conf->conf_vbr_defcert,
                                sizeof conf->conf_vbr_defcert);
       }

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "VBR-TrustedCertifiers", &str,
                                sizeof str);
       }
       if (str != NULL)
       {
              char *dberr = NULL;
              int status;

              status = dkimf_db_open(&conf->conf_vbr_trusteddb, str,
                                     (dbflags |
                                      DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }

              (void) dkimf_db_mkarray(conf->conf_vbr_trusteddb,
                                      (char ***) &conf->conf_vbr_trusted,
                                      NULL);
       }

       if (data != NULL)
       {
              (void) config_get(data, "VBR-PurgeFields",
                                &conf->conf_vbr_purge,
                                sizeof conf->conf_vbr_purge);

              (void) config_get(data, "VBR-TrustedCertifiersOnly",
                                &conf->conf_vbr_trustedonly,
                                sizeof conf->conf_vbr_trustedonly);
       }
#endif /* _FFR_VBR */

       if (data != NULL)
       {
              (void) config_get(data, "SigningTable", &conf->conf_signtable,
                                sizeof conf->conf_signtable);

              if (conf->conf_signtable != NULL)
              {
                     int status;
                     char *dberr = NULL;

                     status = dkimf_db_open(&conf->conf_signtabledb,
                                            conf->conf_signtable,
                                            (dbflags |
                                             DKIMF_DB_FLAG_ICASE |
                                             DKIMF_DB_FLAG_ASCIIONLY |
                                             DKIMF_DB_FLAG_READONLY),
                                            NULL, &dberr);
                     if (status != 0)
                     {
                            snprintf(err, errlen,
                                     "%s: dkimf_db_open(): %s",
                                     conf->conf_signtable, dberr);
                            return -1;
                     }
              }
       }

       if (data != NULL)
       {
              (void) config_get(data, "KeyTable", &conf->conf_keytable,
                                sizeof conf->conf_keytable);

              if (conf->conf_keytable == NULL)
              {
                     (void) config_get(data, "KeyFile", &conf->conf_keyfile,
                                       sizeof conf->conf_keyfile);
              }
              else
              {
                     int status;
                     char *dberr = NULL;

                     status = dkimf_db_open(&conf->conf_keytabledb,
                                            conf->conf_keytable,
                                            (dbflags |
                                             DKIMF_DB_FLAG_READONLY), NULL,
                                            &dberr);
                     if (status != 0)
                     {
                            snprintf(err, errlen,
                                     "%s: dkimf_db_open(): %s",
                                     conf->conf_keytable, dberr);
                            return -1;
                     }

                     conf->conf_selector = NULL;
              }
       }

       if (conf->conf_signtabledb != NULL && conf->conf_keytabledb == NULL)
       {
              snprintf(err, errlen, "use of SigningTable requires KeyTable");
              return -1;
       }

       str = NULL;
       if (conf->conf_localadsp_file != NULL)
       {
              str = conf->conf_localadsp_file;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "LocalADSP", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_localadsp_db, str,
                                     (dbflags | DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "TrustSignaturesFrom", &str,
                                sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_thirdpartydb, str,
                                     (dbflags | DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

#ifdef _FFR_RESIGN
       str = NULL;
       if (conf->conf_resign != NULL)
       {
              str = conf->conf_resign;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "ResignMailTo", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_resigndb, str,
                                     (dbflags | DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }
#endif /* _FFR_RESIGN */

#ifdef _FFR_RATE_LIMIT
       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "RateLimits", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_ratelimitdb, str,
                                     (dbflags | DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "FlowData", &str, sizeof str);

              (void) config_get(data, "FlowDataTTL", &conf->conf_flowdatattl,
                                sizeof conf->conf_flowdatattl);

              (void) config_get(data, "FlowDataFactor",
                                &conf->conf_flowfactor,
                                sizeof conf->conf_flowfactor);
       }
       if (str != NULL)
       {
              int dbtype;
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_flowdatadb, str,
                                     (dbflags | DKIMF_DB_FLAG_ICASE |
                                      DKIMF_DB_FLAG_MAKELOCK),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }

              dbtype = dkimf_db_type(conf->conf_flowdatadb);
              if (dbtype != DKIMF_DB_TYPE_BDB)
              {
                     snprintf(err, errlen,
                              "%s: invalid data set type for FlowData",
                              str);
                     return -1;
              }
       }
#endif /* _FFR_RATE_LIMIT */

       str = NULL;
       if (conf->conf_domlist != NULL)
       {
              str = conf->conf_domlist;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "Domain", &str, sizeof str);
       }
       if (str != NULL && conf->conf_keytabledb == NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_domainsdb, str,
                                     (dbflags | DKIMF_DB_FLAG_READONLY |
                                      DKIMF_DB_FLAG_ICASE),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "MacroList", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              int dbtype;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_macrosdb, str,
                                     (dbflags | DKIMF_DB_FLAG_READONLY |
                                      DKIMF_DB_FLAG_VALLIST |
                                      DKIMF_DB_FLAG_MATCHBOTH), NULL,
                                     &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }

              dbtype = dkimf_db_type(conf->conf_macrosdb);
              if (dbtype != DKIMF_DB_TYPE_FILE &&
                  dbtype != DKIMF_DB_TYPE_CSL)
              {
                     snprintf(err, errlen,
                              "%s: invalid data set type for MacroList",
                              str);
                     return -1;
              }

              (void) dkimf_db_mkarray(conf->conf_macrosdb,
                                      &conf->conf_macros, NULL);
       }

       if (conf->conf_signalgstr != NULL)
       {
              conf->conf_signalg = dkimf_configlookup(conf->conf_signalgstr,
                                                      dkimf_sign);
              if (conf->conf_signalg == -1)
              {
                     snprintf(err, errlen,
                              "unknown signing algorithm \"%s\"",
                              conf->conf_signalgstr);
                     return -1;
              }
       }
       else
       {
              conf->conf_signalg = DKIM_SIGN_DEFAULT;
       }

       if (conf->conf_canonstr != NULL)
       {
              char *p;

              p = strchr(conf->conf_canonstr, '/');
              if (p == NULL)
              {
                     conf->conf_hdrcanon = dkimf_configlookup(conf->conf_canonstr,
                                                              dkimf_canon);
                     if (conf->conf_hdrcanon == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown canonicalization algorithm \"%s\"",
                                     conf->conf_canonstr);
                            return -1;
                     }

                     conf->conf_bodycanon = DKIM_CANON_DEFAULT;
              }
              else
              {
                     *p = '\0';

                     conf->conf_hdrcanon = dkimf_configlookup(conf->conf_canonstr,
                                                              dkimf_canon);
                     if (conf->conf_hdrcanon == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown canonicalization algorithm \"%s\"",
                                     conf->conf_canonstr);
                            return -1;
                     }

                     conf->conf_bodycanon = dkimf_configlookup(p + 1,
                                                               dkimf_canon);
                     if (conf->conf_bodycanon == -1)
                     {
                            snprintf(err, errlen,
                                     "unknown canonicalization algorithm \"%s\"",
                                     p + 1);
                            return -1;
                     }

                     *p = '/';
              }
       }

       str = NULL;
       if (conf->conf_siglimit != NULL)
       {
              str = conf->conf_siglimit;
       }
       else if (data != NULL)
       {
              (void) config_get(data, "Minimum", &str, sizeof str);
       }
       if (str != NULL)
       {
              unsigned long tmpl;
              char *p;

              errno = 0;

              if (str[0] == '-')
              {
                     tmpl = ULONG_MAX;
                     errno = ERANGE;
              }

              tmpl = strtoul(str, &p, 10);
              if (tmpl > UINT_MAX || errno != 0)
              {
                     snprintf(err, errlen, "illegal value for \"Minimum\"");
                     return -1;
              }

              conf->conf_sigmin = (unsigned int) tmpl;

              if (*p == '%')
              {
                     if (conf->conf_sigmin > 100)
                     {
                            snprintf(err, errlen,
                                     "illegal value for \"Minimum\"");
                            return -1;
                     }

                     conf->conf_sigmintype = SIGMIN_PERCENT;
              }
              else if (*p == '+')
              {
                     conf->conf_sigmintype = SIGMIN_MAXADD;
              }
              else if (*p != '\0')
              {
                     snprintf(err, errlen, "illegal value for \"Minimum\"");
                     return -1;
              }
       }

       maxsign = -1;
       if (data != NULL)
       {
              (void) config_get(data, "MaximumSignedBytes", &maxsign,
                                sizeof maxsign);
       }
       if (maxsign != -1)
       {
              conf->conf_signbytes = (long) maxsign;
              conf->conf_blen = TRUE;
       }

       if (conf->conf_modestr == NULL)
       {
              conf->conf_mode = (testmode ? DKIMF_MODE_VERIFIER
                                          : DKIMF_MODE_DEFAULT);
       }
       else
       {
              char *p;

              conf->conf_mode = 0;

              for (p = conf->conf_modestr; *p != '\0'; p++)
              {
                     switch (*p)
                     {
                       case 's':
                            conf->conf_mode |= DKIMF_MODE_SIGNER;
                            break;

                       case 'v':
                            conf->conf_mode |= DKIMF_MODE_VERIFIER;
                            break;

                       default:
                            snprintf(err, errlen, "unknown mode \"%c\"",
                                     *p);
                            return -1;
                     }
              }
       }

#ifdef _FFR_REPLACE_RULES
       /* replacement list */
       str = NULL;
       if (data != NULL)
       {
              (void) config_get(data, "ReplaceHeaders", &str, sizeof str);
       }
       if (str != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_rephdrsdb, str,
                                     (dbflags | DKIMF_DB_FLAG_READONLY |
                                      DKIMF_DB_FLAG_ICASE), NULL,
                                     &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              str, dberr);
                     return -1;
              }
       }

       str = NULL;
       if (data != NULL)
              (void) config_get(data, "ReplaceRules", &str, sizeof str);
       if (str != NULL)
       {
              FILE *f;

              f = fopen(str, "r");
              if (f == NULL)
              {
                     snprintf(err, errlen, "%s: fopen(): %s", str,
                              strerror(errno));
                     return -1;
              }

              if (!dkimf_load_replist(f, &conf->conf_replist))
              {
                     snprintf(err, errlen,
                              "failed to load ReplaceRules from %s", str);
                     fclose(f);
                     return -1;
              }

              fclose(f);
       }
#endif /* _FFR_REPLACE_RULES */

#ifdef _FFR_REPUTATION
       if (data != NULL)
       {
              (void) config_get(data, "ReputationVerbose",
                                &conf->conf_repverbose,
                                sizeof conf->conf_repverbose);

              (void) config_get(data, "ReputationLimits",
                                &conf->conf_replimits,
                                sizeof conf->conf_replimits);

              (void) config_get(data, "ReputationLimitModifiers",
                                &conf->conf_replimitmods,
                                sizeof conf->conf_replimitmods);

              (void) config_get(data, "ReputationCache",
                                &conf->conf_repcache,
                                sizeof conf->conf_repcache);

              (void) config_get(data, "ReputationCacheTTL",
                                &conf->conf_repcachettl,
                                sizeof conf->conf_repcachettl);

              (void) config_get(data, "ReputationDuplicates",
                                &conf->conf_repdups,
                                sizeof conf->conf_repdups);

              (void) config_get(data, "ReputationRatios",
                                &conf->conf_repratios,
                                sizeof conf->conf_repratios);

              (void) config_get(data, "ReputationLowTime",
                                &conf->conf_replowtime,
                                sizeof conf->conf_replowtime);

              (void) config_get(data, "ReputationTimeFactor",
                                &conf->conf_repfactor,
                                sizeof conf->conf_repfactor);

              (void) config_get(data, "ReputationSpamCheck",
                                &conf->conf_repspamcheck,
                                sizeof conf->conf_repspamcheck);

              (void) config_get(data, "ReputationMinimum",
                                &conf->conf_repminimum,
                                sizeof conf->conf_repminimum);
       }

       if (conf->conf_repspamcheck != NULL)
       {
              size_t tmplen;
              char tmpre[BUFRSZ + 1];

              tmplen = strlen(conf->conf_repspamcheck);
              if (tmplen < 3 ||
                  conf->conf_repspamcheck[0] != '/' ||
                  conf->conf_repspamcheck[tmplen - 1] != '/')
              {
                     snprintf(err, errlen,
                              "invalid value for ReputationSpamCheck");
                     return -1;
              }

              strlcpy(tmpre, conf->conf_repspamcheck + 1, sizeof tmpre);
              tmpre[tmplen - 2] = '\0';

              if (regcomp(&conf->conf_repspamre, tmpre, REG_EXTENDED) != 0)
              {
                     snprintf(err, errlen,
                              "unusable value for ReputationSpamCheck");
                     return -1;
              }
       }

       if (conf->conf_replowtime != NULL)
       {
              int status;
              char *dberr = NULL;

              status = dkimf_db_open(&conf->conf_replowtimedb,
                                     conf->conf_replowtime,
                                     (dbflags | DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              conf->conf_replowtime, dberr);
                     return -1;
              }
       }

       if (conf->conf_repratios != NULL)
       {
              int status;
              char *dberr = NULL;

              if (conf->conf_replimits != NULL)
              {
                     status = dkimf_db_open(&conf->conf_replimitsdb,
                                            conf->conf_replimits,
                                            (dbflags |
                                             DKIMF_DB_FLAG_READONLY), NULL,
                                            &dberr);
                     if (status != 0)
                     {
                            snprintf(err, errlen,
                                     "%s: dkimf_db_open(): %s",
                                     conf->conf_replimits, dberr);
                            return -1;
                     }
              }

              if (conf->conf_replimitmods != NULL)
              {
                     status = dkimf_db_open(&conf->conf_replimitmodsdb,
                                            conf->conf_replimitmods,
                                            (dbflags |
                                             DKIMF_DB_FLAG_READONLY), NULL,
                                            &dberr);
                     if (status != 0)
                     {
                            snprintf(err, errlen,
                                     "%s: dkimf_db_open(): %s",
                                     conf->conf_replimitmods, dberr);
                            return -1;
                     }
              }

              status = dkimf_db_open(&conf->conf_repratiosdb,
                                     conf->conf_repratios,
                                     (dbflags | DKIMF_DB_FLAG_READONLY),
                                     NULL, &dberr);
              if (status != 0)
              {
                     snprintf(err, errlen, "%s: dkimf_db_open(): %s",
                              conf->conf_repratios, dberr);
                     return -1;
              }

              if (dkimf_rep_init(&conf->conf_rep, conf->conf_repfactor,
                                  conf->conf_repminimum,
                                  conf->conf_repcachettl,
                                  conf->conf_repcache,
                                  conf->conf_repdups,
                                  conf->conf_replimitsdb,
                                  conf->conf_replimitmodsdb,
                                  conf->conf_repratiosdb,
                                 conf->conf_replowtimedb) != 0)
              {
                     snprintf(err, errlen,
                              "can't initialize reputation subsystem");
                     return -1;
              }
       }
#endif /* _FFR_REPUTATION */

       dkimf_reportaddr(conf);

       /* load the secret key, if one was specified */
       if (conf->conf_keyfile != NULL)
       {
              int status;
              int fd;
              ssize_t rlen;
              u_char *s33krit;
              struct stat s;

              status = stat(conf->conf_keyfile, &s);
              if (status != 0)
              {
                     if (conf->conf_dolog)
                     {
                            int saveerrno;

                            saveerrno = errno;

                            syslog(LOG_ERR, "%s: stat(): %s",
                                   conf->conf_keyfile,
                                   strerror(errno));

                            errno = saveerrno;
                     }

                     snprintf(err, errlen, "%s: stat(): %s",
                              conf->conf_keyfile, strerror(errno));
                     return -1;
              }

              if (dkimf_insecure(s.st_mode, s.st_gid))
              {
                     if (conf->conf_dolog)
                     {
                            int sev;

                            sev = (conf->conf_safekeys ? LOG_ERR
                                                       : LOG_WARNING);

                            syslog(sev, "%s: key data is not secure",
                                   conf->conf_keyfile);
                     }

                     if (conf->conf_safekeys)
                     {
                            snprintf(err, errlen,
                                     "%s: key data is not secure",
                                     conf->conf_keyfile);
                            return -1;
                     }
              }

              s33krit = malloc(s.st_size + 1);
              if (s33krit == NULL)
              {
                     if (conf->conf_dolog)
                     {
                            int saveerrno;

                            saveerrno = errno;

                            syslog(LOG_ERR, "malloc(): %s", 
                                   strerror(errno));

                            errno = saveerrno;
                     }

                     snprintf(err, errlen, "malloc(): %s", strerror(errno));
                     return -1;
              }
              conf->conf_keylen = s.st_size + 1;

              fd = open(conf->conf_keyfile, O_RDONLY, 0);
              if (fd < 0)
              {
                     if (conf->conf_dolog)
                     {
                            int saveerrno;

                            saveerrno = errno;

                            syslog(LOG_ERR, "%s: open(): %s",
                                   conf->conf_keyfile,
                                   strerror(errno));

                            errno = saveerrno;
                     }

                     snprintf(err, errlen, "%s: open(): %s",
                              conf->conf_keyfile, strerror(errno));
                     free(s33krit);
                     return -1;
              }
              else if (!S_ISREG(s.st_mode))
              {
                     snprintf(err, errlen, "%s: open(): Not a regular file",
                              conf->conf_keyfile);
                     close(fd);
                     free(s33krit);
                     return -1;
              }

              rlen = read(fd, s33krit, s.st_size + 1);
              if (rlen == (ssize_t) -1)
              {
                     if (conf->conf_dolog)
                     {
                            int saveerrno;

                            saveerrno = errno;

                            syslog(LOG_ERR, "%s: read(): %s",
                                   conf->conf_keyfile,
                                   strerror(errno));

                            errno = saveerrno;
                     }

                     snprintf(err, errlen, "%s: read(): %s",
                              conf->conf_keyfile, strerror(errno));
                     close(fd);
                     free(s33krit);
                     return -1;
              }
              else if (rlen != s.st_size)
              {
                     if (conf->conf_dolog)
                     {
                            syslog(LOG_ERR, "%s: read() wrong size (%lu)",
                                   conf->conf_keyfile, (u_long) rlen);
                     }

                     snprintf(err, errlen, "%s: read() wrong size (%lu)",
                              conf->conf_keyfile, (u_long) rlen);
                     close(fd);
                     free(s33krit);
                     return -1;
              }

              close(fd);
              s33krit[s.st_size] = '\0';
              conf->conf_seckey = s33krit;
       }

       /* confirm signing mode parameters */
       if ((conf->conf_mode & DKIMF_MODE_SIGNER) != 0)
       {
              if ((conf->conf_selector != NULL &&
                   conf->conf_keyfile == NULL) ||
                  (conf->conf_selector == NULL &&
                   conf->conf_keyfile != NULL))
              {
                     snprintf(err, errlen,
                              "KeyFile and Selector must both be defined or both be undefined");
                     return -1;
              }

              if (conf->conf_domainsdb != NULL &&
                  (conf->conf_selector == NULL ||
                   conf->conf_keyfile == NULL))
              {
                     snprintf(err, errlen,
                              "Domain requires KeyFile and Selector");
                     return -1;
              }

              if (conf->conf_signtable != NULL &&
                  conf->conf_keytable == NULL)
              {
                     snprintf(err, errlen,
                              "SigningTable requires KeyTable");
                     return -1;
              }

#ifdef USE_LUA
              if (conf->conf_keytable != NULL &&
                  conf->conf_signtable == NULL &&
                  conf->conf_setupscript == NULL)
              {
                     snprintf(err, errlen,
                              "KeyTable requires either SigningTable or SetupPolicyScript");
                     return -1;
              }
#else /* USE_LUA */
              if (conf->conf_keytable != NULL &&
                  conf->conf_signtable == NULL)
              {
                     snprintf(err, errlen,
                              "KeyTable requires SigningTable");
                     return -1;
              }
#endif /* USE_LUA */
       }

       /* activate logging if requested */
       if (conf->conf_dolog)
       {
              char *log_facility = NULL;

              if (data != NULL)
              {
                     (void) config_get(data, "SyslogFacility", &log_facility,
                                       sizeof log_facility);
              }

              dkimf_init_syslog(log_facility);
       }

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct dkimf_config* dkimf_config_new ( void  ) [static, read]

Definition at line 5608 of file opendkim.c.

{
       struct dkimf_config *new;

       new = (struct dkimf_config *) malloc(sizeof(struct dkimf_config));
       if (new == NULL)
              return NULL;

       memset(new, '\0', sizeof(struct dkimf_config));
       new->conf_hdrcanon = DKIM_CANON_DEFAULT;
       new->conf_bodycanon = DKIM_CANON_DEFAULT;
       new->conf_dnstimeout = DEFTIMEOUT;
       new->conf_maxverify = DEFMAXVERIFY;
       new->conf_maxhdrsz = DEFMAXHDRSZ;
       new->conf_signbytes = -1L;
       new->conf_sigmintype = SIGMIN_BYTES;
#ifdef _FFR_DKIM_REPUTATION
       new->conf_repreject = DKIM_REP_DEFREJECT;
#endif /* _FFR_DKIM_REPUTATION */
#ifdef _FFR_REPUTATION
       new->conf_repfactor = DKIMF_REP_DEFFACTOR;
       new->conf_repcachettl = DKIMF_REP_DEFCACHETTL;
#endif /* _FFR_REPUTATION */
       new->conf_safekeys = TRUE;
       new->conf_adspaction = SMFIS_CONTINUE;
#ifdef _FFR_STATS
       new->conf_reporthost = myhostname;
#endif /* _FFR_STATS */
#ifdef _FFR_RATE_LIMIT
       new->conf_flowdatattl = DEFFLOWDATATTL;
       new->conf_flowfactor = 1;
#endif /* _FFR_RATE_LIMIT */
       new->conf_mtacommand = SENDMAIL_PATH;
#ifdef _FFR_ATPS
       new->conf_atpshash = dkimf_atpshash[0].str;
#endif /* _FFR_ATPS */
       new->conf_selectcanonhdr = XSELECTCANONHDR;

       memcpy(&new->conf_handling, &defaults, sizeof new->conf_handling);

       return new;
}

Here is the caller graph for this function:

static void dkimf_config_reload ( void  ) [static]

Definition at line 8521 of file opendkim.c.

{
       struct dkimf_config *new;
       char errbuf[BUFRSZ + 1];

       pthread_mutex_lock(&conf_lock);

       if (!reload)
       {
              pthread_mutex_unlock(&conf_lock);
              return;
       }

       if (conffile == NULL)
       {
              if (curconf->conf_dolog)
                     syslog(LOG_ERR, "ignoring reload signal");

              reload = FALSE;

              pthread_mutex_unlock(&conf_lock);
              return;
       }

       new = dkimf_config_new();
       if (new == NULL)
       {
              if (curconf->conf_dolog)
                     syslog(LOG_ERR, "malloc(): %s", strerror(errno));
       }
       else
       {
              _Bool err = FALSE;
              u_int line;
              struct config *cfg;
              char *missing;
              char *errstr = NULL;
              char path[MAXPATHLEN + 1];

              strlcpy(path, conffile, sizeof path);

              cfg = config_load(conffile, dkimf_config, &line,
                                path, sizeof path);

              if (cfg == NULL)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR,
                                   "%s: configuration error at line %u: %s",
                                    path, line, config_error());
                     }
                     dkimf_config_free(new);
                     err = TRUE;
              }

              if (!err)
              {
                     missing = config_check(cfg, dkimf_config);
                     if (missing != NULL)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                           "%s: required parameter \"%s\" missing",
                                           conffile, missing);
                            }
                            config_free(cfg);
                            dkimf_config_free(new);
                            err = TRUE;
                     }
              }

              if (!err && dkimf_config_load(cfg, new, errbuf,
                                            sizeof errbuf) != 0)
              {
                     if (curconf->conf_dolog)
                            syslog(LOG_ERR, "%s: %s", conffile, errbuf);
                     config_free(cfg);
                     dkimf_config_free(new);
                     err = TRUE;
              }

              if (!err && !dkimf_config_setlib(new, &errstr))
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_WARNING,
                                   "can't configure DKIM library: %s; continuing",
                                   errstr);
                     }
                     config_free(cfg);
                     dkimf_config_free(new);
                     err = TRUE;
              }

              if (!err)
              {
                     if (curconf->conf_refcnt == 0)
                            dkimf_config_free(curconf);

                     dolog = new->conf_dolog;
                     curconf = new;
                     new->conf_data = cfg;

                     if (new->conf_dolog)
                     {
                            syslog(LOG_INFO,
                                   "configuration reloaded from %s",
                                   conffile);
                     }
              }
       }

       reload = FALSE;

       pthread_mutex_unlock(&conf_lock);

       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkimf_config_setlib ( struct dkimf_config conf,
char **  err 
) [static]

Definition at line 8141 of file opendkim.c.

{
       DKIM_STAT status;
       u_int opts;
       DKIM_LIB *lib;
       assert(conf != NULL);

       lib = conf->conf_libopendkim;
       if (lib == NULL)
       {
              lib = dkim_init(NULL, NULL);
              if (lib == NULL)
              {
                     if (err != NULL)
                            *err = "failed to initialize DKIM library";
                     return FALSE;
              }

              conf->conf_libopendkim = lib;
       }

       (void) dkim_options(lib, DKIM_OP_GETOPT, DKIM_OPTS_FLAGS,
                           &opts, sizeof opts);
       opts |= (DKIM_LIBFLAGS_ACCEPTV05 | DKIM_LIBFLAGS_DROPSIGNER);
       if (conf->conf_weaksyntax)
              opts |= DKIM_LIBFLAGS_BADSIGHANDLES;
#ifdef QUERY_CACHE
       if (querycache)
       {
              opts |= DKIM_LIBFLAGS_CACHE;
              (void) time(&cache_lastlog);
       }
#endif /* QUERY_CACHE */
       (void) dkim_options(lib, DKIM_OP_SETOPT, DKIM_OPTS_FLAGS,
                           &opts, sizeof opts);

       /* set the DNS callback */
       (void) dkim_set_dns_callback(lib, dkimf_sendprogress, CBINTERVAL);

       if (conf->conf_testdnsdb != NULL)
       {
              (void) dkimf_filedns_setup(lib, conf->conf_testdnsdb);
       }
       else
       {
#ifdef USE_ARLIB
              conf->conf_arlib = ar_init(NULL, NULL, NULL,
                                         (curconf->conf_restrace ? AR_FLAG_TRACELOGGING
                                                                 : 0) |
                                         (curconf->conf_dnsconnect ? AR_FLAG_USETCP
                                                                   : 0));
              if (conf->conf_arlib == NULL)
              {
                     if (err != NULL)
                            *err = "failed to initialize libar";

                     return FALSE;
              }

              (void) dkimf_arlib_setup(lib, conf->conf_arlib);
#endif /* USE_ARLIB */

#ifdef USE_UNBOUND
              if (dkimf_unbound_init(&conf->conf_unbound) != 0)
              {
                     if (err != NULL)
                            *err = "failed to initialize libunbound";

                     return FALSE;
              }

              if (conf->conf_trustanchorpath != NULL)
              {
                     if (access(conf->conf_trustanchorpath, R_OK) != 0)
                     {
                            if (err != NULL)
                                   *err = "can't access unbound trust anchor";
                            return FALSE;
                     }

                     status = dkimf_unbound_add_trustanchor(conf->conf_unbound,
                                                            conf->conf_trustanchorpath);
                     if (status != DKIM_STAT_OK)
                     {
                            if (err != NULL)
                                   *err = "failed to add unbound trust anchor";
                            return FALSE;
                     }
              }

              if (conf->conf_unboundconfig != NULL)
              {
                     if (access(conf->conf_unboundconfig, R_OK) != 0)
                     {
                            if (err != NULL)
                                   *err = "can't access unbound configuration file";
                            return FALSE;
                     }

                     status = dkimf_unbound_add_conffile(conf->conf_unbound,
                                                         conf->conf_unboundconfig);
                     if (status != DKIM_STAT_OK)
                     {
                            if (err != NULL)
                                   *err = "failed to add unbound configuration file";
              
                            return FALSE;
                     }
              }

              (void) dkimf_unbound_setup(lib, conf->conf_unbound);
#endif /* USE_UNBOUND */
       }

       (void) dkim_options(lib, DKIM_OP_SETOPT, DKIM_OPTS_TIMEOUT,
                           &conf->conf_dnstimeout,
                           sizeof conf->conf_dnstimeout);

       if (conf->conf_clockdrift != 0)
       {
              uint64_t drift = conf->conf_clockdrift;

              status = dkim_options(lib, DKIM_OP_SETOPT,
                                    DKIM_OPTS_CLOCKDRIFT, &drift,
                                    sizeof drift);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM clock drift limit";
                     return FALSE;
              }
       }

       if (conf->conf_sigttl != 0)
       {
              uint64_t sigtime = conf->conf_sigttl;

              status = dkim_options(lib, DKIM_OP_SETOPT,
                                    DKIM_OPTS_SIGNATURETTL, &sigtime,
                                    sizeof sigtime);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM signature TTL";
                     return FALSE;
              }
       }

       if (conf->conf_sendreports || conf->conf_keeptmpfiles ||
           conf->conf_stricthdrs || conf->conf_blen || conf->conf_ztags ||
           conf->conf_fixcrlf)
       {
              u_int opts;

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_GETOPT,
                                    DKIM_OPTS_FLAGS, &opts, sizeof opts);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to retrieve DKIM library options";
                     return FALSE;
              }

              if (conf->conf_sendreports || conf->conf_keeptmpfiles)
                     opts |= DKIM_LIBFLAGS_TMPFILES;
              if (conf->conf_keeptmpfiles)
                     opts |= DKIM_LIBFLAGS_KEEPFILES;
              if (conf->conf_blen)
                     opts |= DKIM_LIBFLAGS_SIGNLEN;
              if (conf->conf_ztags)
                     opts |= DKIM_LIBFLAGS_ZTAGS;
              if (conf->conf_fixcrlf)
                     opts |= DKIM_LIBFLAGS_FIXCRLF;
              if (conf->conf_acceptdk)
                     opts |= DKIM_LIBFLAGS_ACCEPTDK;
              if (conf->conf_stricthdrs)
                     opts |= DKIM_LIBFLAGS_STRICTHDRS;

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_FLAGS, &opts, sizeof opts);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }

       if (conf->conf_alwayshdrsdb != NULL)
       {
              status = dkimf_db_mkarray(conf->conf_alwayshdrsdb,
                                        &conf->conf_alwayshdrs, NULL);
              if (status == -1)
              {
                     if (err != NULL)
                            *err = "failed to generate DB array";
                     return FALSE;
              }

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_ALWAYSHDRS,
                                    conf->conf_alwayshdrs,
                                    sizeof conf->conf_alwayshdrs);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }

#ifdef _FFR_OVERSIGN
       if (conf->conf_oversigndb != NULL)
       {
              status = dkimf_db_mkarray(conf->conf_oversigndb,
                                        &conf->conf_oversignhdrs, NULL);
              if (status == -1)
              {
                     if (err != NULL)
                            *err = "failed to generate DB array";
                     return FALSE;
              }

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_OVERSIGNHDRS,
                                    conf->conf_oversignhdrs,
                                    sizeof conf->conf_oversignhdrs);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }
#endif /* _FFR_OVERSIGN */

       if (conf->conf_mbsdb != NULL)
       {
              status = dkimf_db_mkarray(conf->conf_mbsdb, &conf->conf_mbs,
                                        NULL);
              if (status == -1)
              {
                     if (err != NULL)
                            *err = "failed to generate DB array";
                     return FALSE;
              }

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_MUSTBESIGNED,
                                    conf->conf_mbs, sizeof conf->conf_mbs);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }

       if (conf->conf_omithdrdb != NULL)
       {
              status = dkimf_db_mkarray(conf->conf_omithdrdb,
                                        &conf->conf_omithdrs,
                                        (const char **) dkim_should_not_signhdrs);
              if (status == -1)
              {
                     if (err != NULL)
                            *err = "failed to generate DB array";
                     return FALSE;
              }

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_SKIPHDRS,
                                    conf->conf_omithdrs,
                                    sizeof conf->conf_omithdrs);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }
       else
       {
              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_SKIPHDRS,
                                    (void *) dkim_should_not_signhdrs,
                                    sizeof (u_char **));

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }

       if (conf->conf_signhdrsdb != NULL)
       {
              status = dkimf_db_mkarray(conf->conf_signhdrsdb,
                                        &conf->conf_signhdrs,
                                        (const char **) dkim_should_signhdrs);
              if (status == -1)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }

              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_SIGNHDRS, conf->conf_signhdrs,
                                    sizeof conf->conf_signhdrs);

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }
       else
       {
              status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                                    DKIM_OPTS_SIGNHDRS,
                                    (void *) dkim_should_signhdrs,
                                    sizeof (u_char **));

              if (status != DKIM_STAT_OK)
              {
                     if (err != NULL)
                            *err = "failed to set DKIM library options";
                     return FALSE;
              }
       }

       status = dkim_options(conf->conf_libopendkim, DKIM_OP_SETOPT,
                             DKIM_OPTS_TMPDIR,
                             (void *) conf->conf_tmpdir,
                             sizeof conf->conf_tmpdir);

       if (status != DKIM_STAT_OK)
       {
              if (err != NULL)
                     *err = "failed to set DKIM library options";
              return FALSE;
       }

       status = dkim_set_prescreen(conf->conf_libopendkim, dkimf_prescreen);
       if (status != DKIM_STAT_OK)
       {
              if (err != NULL)
                     *err = "failed to set DKIM prescreen function";
              return FALSE;
       }

       return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_configlookup ( char *  opt,
struct lookup table 
) [static]

Definition at line 5320 of file opendkim.c.

{
       int c;

       for (c = 0; ; c++)
       {
              if (table[c].str == NULL ||
                  strcasecmp(opt, table[c].str) == 0)
                     return table[c].code;
       }
}

Here is the caller graph for this function:

static void dkimf_db_error ( DKIMF_DB  db,
const char *  key 
) [static]

Definition at line 4362 of file opendkim.c.

{
       char errbuf[BUFRSZ];

       assert(db != NULL);
       assert(key != NULL);

       (void) dkimf_db_strerror(db, errbuf, sizeof errbuf);

       syslog(LOG_ERR, "error looking up \"%s\" in database: %s",
              key, errbuf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_delrcpt ( SMFICTX *  ctx,
char *  addr 
)

Definition at line 1041 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(addr != NULL);

       if (testmode)
              return dkimf_test_delrcpt(ctx, addr);
       else
              return smfi_delrcpt(ctx, addr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static Header dkimf_findheader ( msgctx  dfc,
char *  hname,
int  instance 
) [static]

Definition at line 9394 of file opendkim.c.

{
       Header hdr;

       assert(dfc != NULL);
       assert(hname != NULL);

       if (instance < 0)
              hdr = dfc->mctx_hqtail;
       else
              hdr = dfc->mctx_hqhead;

       while (hdr != NULL)
       {
              if (strcasecmp(hdr->hdr_hdr, hname) == 0)
              {
                     if (instance == 0 || instance == -1)
                            return hdr;
                     else if (instance > 0)
                            instance--;
                     else
                            instance++;
              }

              if (instance < 0)
                     hdr = hdr->hdr_prev;
              else
                     hdr = hdr->hdr_next;
       }

       return NULL;
}

Here is the caller graph for this function:

DKIM* dkimf_getdkim ( void *  vp)

Definition at line 5415 of file opendkim.c.

{
       struct connctx *cc;

       assert(vp != NULL);

       cc = vp;
       if (cc->cctx_msg != NULL)
              return cc->cctx_msg->mctx_dkimv;
       else
              return NULL;
}

Here is the caller graph for this function:

void* dkimf_getpriv ( SMFICTX *  ctx)

Definition at line 871 of file opendkim.c.

{
       assert(ctx != NULL);

       if (testmode)
              return dkimf_test_getpriv((void *) ctx);
       else
              return smfi_getpriv(ctx);
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct signreq* dkimf_getsrlist ( void *  vp) [read]

Definition at line 5439 of file opendkim.c.

{
       struct connctx *cc;

       assert(vp != NULL);

       cc = vp;
       if (cc->cctx_msg != NULL)
              return cc->cctx_msg->mctx_srhead;
       else
              return NULL;
}

Here is the caller graph for this function:

char* dkimf_getsymval ( SMFICTX *  ctx,
char *  sym 
)

Definition at line 1088 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(sym != NULL);

       if (testmode)
              return dkimf_test_getsymval(ctx, sym);
       else
              return smfi_getsymval(ctx, sym);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_init_syslog ( char *  facility) [static]

Definition at line 4388 of file opendkim.c.

{
#ifdef LOG_MAIL
       int code;
       struct lookup *p = NULL;

       closelog();

       code = LOG_MAIL;
       if (facility != NULL)
       {
              for (p = log_facilities; p != NULL; p++)
              {
                     if (strcasecmp(p->str, facility) == 0)
                     {
                            code = p->code;
                            break;
                     }
              }
       }

       openlog(progname, LOG_PID, code);
#else /* LOG_MAIL */
       closelog();

       openlog(progname, LOG_PID);
#endif /* LOG_MAIL */
}

Here is the caller graph for this function:

static msgctx dkimf_initcontext ( struct dkimf_config conf) [static]

Definition at line 8800 of file opendkim.c.

{
       msgctx ctx;

       assert(conf != NULL);

       ctx = (msgctx) malloc(sizeof(struct msgctx));
       if (ctx == NULL)
              return NULL;

       (void) memset(ctx, '\0', sizeof(struct msgctx));

       ctx->mctx_status = DKIMF_STATUS_UNKNOWN;
       ctx->mctx_hdrcanon = conf->conf_hdrcanon;
       ctx->mctx_bodycanon = conf->conf_bodycanon;
       ctx->mctx_signalg = DKIM_SIGN_DEFAULT;
       ctx->mctx_queryalg = DKIM_QUERY_DEFAULT;
#ifdef USE_UNBOUND
       ctx->mctx_dnssec_key = DKIM_DNSSEC_UNKNOWN;
       ctx->mctx_dnssec_policy = DKIM_DNSSEC_UNKNOWN;
#endif /* USE_UNBOUND */
       ctx->mctx_pcode = DKIM_POLICY_NONE;
       ctx->mctx_presult = DKIM_PRESULT_NONE;
#ifdef _FFR_ATPS
       ctx->mctx_atps = DKIM_ATPS_UNKNOWN;
#endif /* _FFR_ATPS */
#ifdef _FFR_REPUTATION
       SHA1_Init(&ctx->mctx_hash);
#endif /* _FFR_REPUTATION */

       return ctx;
}

Here is the caller graph for this function:

_Bool dkimf_insecure ( mode_t  mode,
gid_t  grp 
)

Definition at line 4541 of file opendkim.c.

{
       /* read/write by others is always bad */
       if ((mode & (S_IROTH|S_IWOTH)) != 0)
              return TRUE;

       /* read/write by group is bad if it's not a group we're in */
       if ((mode & (S_IRGRP|S_IWGRP)) != 0)
       {
              int c;
              int ngroups;
              gid_t gid;
              gid_t egid;
              gid_t gids[NGROUPS_MAX];

              gid = getgid();
              egid = getegid();
              ngroups = getgroups(NGROUPS_MAX, gids);

              if (grp == gid || grp == egid)
                     return FALSE;

              for (c = 0; c < ngroups; c++)
              {
                     if (grp == gids[c])
                            return FALSE;
              }

              return TRUE;
       }

       /* anything that gets here is safe */
       return FALSE;
}

Here is the caller graph for this function:

sfsistat dkimf_insheader ( SMFICTX *  ctx,
int  idx,
char *  hname,
char *  hvalue 
)

Definition at line 916 of file opendkim.c.

{
       assert(ctx != NULL);
       assert(hname != NULL);
       assert(hvalue != NULL);

       if (testmode)
              return dkimf_test_insheader(ctx, idx, hname, hvalue);
       else
#ifdef HAVE_SMFI_INSHEADER
              return smfi_insheader(ctx, idx, hname, hvalue);
#else /* HAVE_SMFI_INSHEADER */
              return smfi_addheader(ctx, hname, hvalue);
#endif /* HAVE_SMFI_INSHEADER */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_killchild ( pid_t  pid,
int  sig,
_Bool  dolog 
) [static]

Definition at line 5522 of file opendkim.c.

{
       if (kill(pid, sig) == -1 && dolog)
       {
              syslog(LOG_ERR, "kill(%d, %d): %s", pid, sig,
                     strerror(errno));
       }
}

Here is the caller graph for this function:

static sfsistat dkimf_libstatus ( SMFICTX *  ctx,
DKIM *  dkim,
char *  where,
int  status 
) [static]

Definition at line 9108 of file opendkim.c.

{
       int retcode = SMFIS_CONTINUE;
       msgctx dfc;
       connctx cc;
       DKIM_SIGINFO *sig;
       char *rcode = NULL;
       char *xcode = NULL;
       char *replytxt = NULL;
       struct dkimf_config *conf;
       u_char smtpprefix[BUFRSZ];

       assert(ctx != NULL);

       cc = dkimf_getpriv(ctx);
       assert(cc != NULL);
       dfc = cc->cctx_msg;
       assert(dfc != NULL);
       conf = cc->cctx_config;

       memset(smtpprefix, '\0', sizeof smtpprefix);

       switch (status)
       {
         case DKIM_STAT_OK:
              retcode = SMFIS_CONTINUE;
              break;

         case DKIM_STAT_INTERNAL:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_internal,
                                         NULL);
              if (conf->conf_capture)
                     dfc->mctx_capture = TRUE;
              if (conf->conf_dolog)
              {
                     const char *err = NULL;

                     if (dkim != NULL)
                            err = dkim_geterror(dkim);
                     if (err == NULL)
                            err = strerror(errno);

                     syslog(LOG_ERR,
                            "%s: %s%sinternal error from libopendkim: %s",
                            JOBID(dfc->mctx_jobid),
                            where == NULL ? "" : where,
                            where == NULL ? "" : ": ", err);
              }
              replytxt = "internal DKIM error";
              break;

         case DKIM_STAT_BADSIG:
              assert(dkim != NULL);
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_badsig,
                                         NULL);
              if (conf->conf_dolog)
              {
                     syslog(LOG_NOTICE, "%s: bad signature data",
                            JOBID(dfc->mctx_jobid));
              }
              replytxt = "bad DKIM signature data";

              memset(smtpprefix, '\0', sizeof smtpprefix);
              sig = dkim_getsignature(dkim);
              (void) dkim_sig_getreportinfo(dkim, sig,
                                            NULL, 0,
                                            NULL, 0,
                                            NULL, 0,
                                            smtpprefix, sizeof smtpprefix,
                                            NULL);

              break;

         case DKIM_STAT_NOSIG:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_nosig,
                                         NULL);
              if (conf->conf_dolog)
              {
                     if (conf->conf_logwhy ||
                         retcode != SMFIS_ACCEPT)
                     {
                            syslog(retcode == SMFIS_ACCEPT ? LOG_DEBUG
                                                           : LOG_NOTICE,
                                   "%s: no signature data",
                                   JOBID(dfc->mctx_jobid));
                     }
              }
              replytxt = "no DKIM signature data";
              break;

         case DKIM_STAT_NORESOURCE:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_internal,
                                         NULL);
              if (conf->conf_capture)
                     dfc->mctx_capture = TRUE;
              if (conf->conf_dolog)
              {
                     const char *err = NULL;

                     if (dkim != NULL)
                            err = dkim_geterror(dkim);
                     if (err == NULL)
                            err = strerror(errno);

                     syslog(LOG_ERR, "%s: %s%sresource unavailable: %s",
                            JOBID(dfc->mctx_jobid),
                            where == NULL ? "" : where,
                            where == NULL ? "" : ": ", err);
              }
              replytxt = "resource unavailable";
              break;

         case DKIM_STAT_CANTVRFY:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_badsig,
                                         NULL);
              if (conf->conf_dolog && dkim != NULL)
              {
                     const char *err = NULL;
                     err = dkim_geterror(dkim);
                     if (err == NULL)
                            err = "unknown cause";

                     syslog(LOG_ERR, "%s: signature processing failed: %s",
                            JOBID(dfc->mctx_jobid), err);
              }
              replytxt = "DKIM signature processing failed";
              break;

         case DKIM_STAT_REVOKED:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_badsig,
                                         NULL);
              if (conf->conf_dolog)
              {
                     u_char *selector = NULL;
                     u_char *domain = NULL;
                     DKIM_SIGINFO *sig;

                     sig = dkim_getsignature(dkim);
                     if (sig != NULL)
                     {
                            selector = dkim_sig_getselector(sig);
                            domain = dkim_sig_getdomain(sig);
                     }

                     if (selector != NULL && domain != NULL)
                     {
                            syslog(LOG_NOTICE,
                                   "%s: key revoked (s=%s, d=%s)",
                                   JOBID(dfc->mctx_jobid), selector,
                                   domain);
                     }
              }
              break;

         case DKIM_STAT_KEYFAIL:
         case DKIM_STAT_NOKEY:
              if (status == DKIM_STAT_KEYFAIL)
              {
                     retcode = dkimf_miltercode(ctx,
                                                conf->conf_handling.hndl_dnserr,
                                                NULL);
              }
              else
              {
                     retcode = dkimf_miltercode(ctx,
                                                conf->conf_handling.hndl_nokey,
                                                NULL);
              }

              if (conf->conf_dolog)
              {
                     const char *err = NULL;
                     u_char *selector = NULL;
                     u_char *domain = NULL;
                     DKIM_SIGINFO *sig;

                     err = dkim_geterror(dkim);

                     sig = dkim_getsignature(dkim);
                     if (sig != NULL)
                     {
                            selector = dkim_sig_getselector(sig);
                            domain = dkim_sig_getdomain(sig);
                     }

                     if (selector != NULL && domain != NULL)
                     {
                            syslog(LOG_ERR,
                                   "%s: key retrieval failed (s=%s, d=%s)%s%s",
                                   JOBID(dfc->mctx_jobid), selector,
                                   domain,
                                   err == NULL ? "" : ": ",
                                   err == NULL ? "" : err);
                     }
                     else
                     {
                            syslog(LOG_ERR, "%s: key retrieval failed%s%s",
                                   JOBID(dfc->mctx_jobid),
                                   err == NULL ? "" : ": ",
                                   err == NULL ? "" : err);
                     }
              }
              replytxt = "DKIM key retrieval failed";
              break;

         case DKIM_STAT_SYNTAX:
              retcode = dkimf_miltercode(ctx,
                                         conf->conf_handling.hndl_badsig,
                                         NULL);
              if (conf->conf_dolog)
              {
                     const char *err = NULL;

                     if (dkim != NULL)
                            err = dkim_geterror(dkim);
                     if (err == NULL)
                            err = "unspecified";

                     syslog(LOG_ERR, "%s: syntax error: %s",
                            JOBID(dfc->mctx_jobid), err);
              }
              replytxt = "DKIM signature syntax error";
              break;
       }

       switch (retcode)
       {
         case SMFIS_REJECT:
              rcode = "550";
              xcode = "5.7.0";
              break;

         case SMFIS_TEMPFAIL:
              rcode = "451";
              if (status == DKIM_STAT_KEYFAIL || status == DKIM_STAT_NOKEY)
                     xcode = "4.7.5";
              else
                     xcode = "4.7.0";
              break;

         default:
              break;
       }

       if (rcode != NULL && xcode != NULL && replytxt != NULL)
       {
              char replybuf[BUFRSZ];

              if (smtpprefix[0] == '\0')
              {
                     strlcpy(replybuf, replytxt, sizeof replybuf);
              }
              else
              {
                     snprintf(replybuf, sizeof replybuf, "%s: %s",
                              smtpprefix, replytxt);
              }

              (void) dkimf_setreply(ctx, rcode, xcode, replybuf);
       }

       return retcode;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkimf_loadkey ( char *  buf,
size_t *  buflen,
_Bool *  insecure,
char **  error 
) [static]

Definition at line 4590 of file opendkim.c.

{
       assert(buf != NULL);
       assert(buflen != NULL);

       if (buf[0] == '/' || (buf[0] == '.' && buf[1] == '/') ||
           (buf[0] == '.' && buf[1] == '.' && buf[2] == '/'))
       {
              int fd;
              int status;
              ssize_t rlen;
              struct stat s;

              fd = open(buf, O_RDONLY);
              if (fd < 0)
              {
                     if (error != NULL)
                            *error = strerror(errno);
                     return FALSE;
              }

              status = fstat(fd, &s);
              if (status != 0 || !S_ISREG(s.st_mode))
              {
                     if (error != NULL)
                     {
                            if (!S_ISREG(s.st_mode))
                                   *error = "Not a regular file";
                            else
                                   *error = strerror(errno);
                     }
                     close(fd);
                     return FALSE;
              }

              /*
              **  XXX -- really should check ancestor directories too,
              **  like sendmail's safefile()
              */

              if (insecure != NULL)
                     *insecure = dkimf_insecure(s.st_mode, s.st_gid);

              *buflen = MIN(s.st_size, *buflen);
              rlen = read(fd, buf, *buflen);
              close(fd);

              if (rlen < *buflen)
                     return FALSE;
       }

       return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_local_adsp ( struct dkimf_config conf,
char *  domain,
dkim_policy_t pcode 
) [static]

Definition at line 5346 of file opendkim.c.

{
       assert(conf != NULL);
       assert(domain != NULL);
       assert(pcode != NULL);

       if (conf->conf_localadsp_db != NULL)
       {
              _Bool found;
              size_t plen;
              char *p;
              char policy[BUFRSZ];
              struct dkimf_db_data dbd;

              memset(policy, '\0', sizeof policy);
              plen = sizeof policy;

              dbd.dbdata_buffer = policy;
              dbd.dbdata_buflen = plen;
              dbd.dbdata_flags = 0;

              if (dkimf_db_get(conf->conf_localadsp_db, domain, 0, 
                                    &dbd, 1, &found) != 0)
                     return 0;

              if (policy[0] == '\0')
                     found = FALSE;

              for (p = strchr(domain, '.');
                   p != NULL && !found;
                   p = strchr(p + 1, '.'))
              {
                     dbd.dbdata_buflen = plen;

                     if (dkimf_db_get(conf->conf_localadsp_db, p, 0,
                                           &dbd, 1, &found) != 0)
                            return 0;

                     if (policy[0] == '\0')
                            found = FALSE;
              }

              if (found)
              {
                     dkim_policy_t tmpp;

                     tmpp = dkimf_configlookup(policy, dkimf_policy);
                     if (tmpp != -1)
                     {
                            *pcode = tmpp;
                            return 1;
                     }
              }
       }

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_log_ssl_errors ( char *  jobid,
char *  selector,
char *  domain 
) [static]

Definition at line 8846 of file opendkim.c.

{
#ifdef USE_GNUTLS
       const char *errbuf;

       errbuf = dkimf_crypto_geterror();
       if (errbuf != NULL)
       {
              if (selector != NULL && domain != NULL)
              {
                     syslog(LOG_INFO, "%s: s=%s d=%s SSL %s", jobid,
                            selector, domain, errbuf);
              }
              else
              {
                     syslog(LOG_INFO, "%s: SSL %s", jobid, errbuf);
              }
       }
#else /* USE_GNUTLS */
       assert(jobid != NULL);

       /* log any queued SSL error messages */
       if (ERR_peek_error() != 0)
       {
              int n;
              int saveerr;
              u_long e;
              char errbuf[BUFRSZ + 1];
              char tmp[BUFRSZ + 1];

              saveerr = errno;

              memset(errbuf, '\0', sizeof errbuf);

              for (n = 0; ; n++)
              {
                     e = ERR_get_error();
                     if (e == 0)
                            break;

                     memset(tmp, '\0', sizeof tmp);
                     (void) ERR_error_string_n(e, tmp, sizeof tmp);
                     if (n != 0)
                            strlcat(errbuf, "; ", sizeof errbuf);
                     strlcat(errbuf, tmp, sizeof errbuf);
              }

              if (selector != NULL && domain != NULL)
              {
                     syslog(LOG_INFO, "%s: s=%s d=%s SSL %s", jobid,
                            selector, domain, errbuf);
              }
              else
              {
                     syslog(LOG_INFO, "%s: SSL %s", jobid, errbuf);
              }

              errno = saveerr;
       }
#endif /* USE_GNUTLS */
}
sfsistat dkimf_miltercode ( SMFICTX *  ctx,
int  dmc,
char *  str 
)

Definition at line 9067 of file opendkim.c.

{
       assert(ctx != NULL);

       switch (dmc)
       {
         case DKIMF_MILTER_ACCEPT:
              return SMFIS_ACCEPT;

         case DKIMF_MILTER_DISCARD:
              return SMFIS_DISCARD;

         case DKIMF_MILTER_QUARANTINE:
              (void) dkimf_quarantine(ctx, str == NULL ? progname : str);
              return SMFIS_ACCEPT;

         case DKIMF_MILTER_REJECT:
              return SMFIS_REJECT;

         case DKIMF_MILTER_TEMPFAIL:
              return SMFIS_TEMPFAIL;
       }

       /* NOTREACHED */
       return SMFIS_ACCEPT;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkimf_msr_body ( struct signreq sr,
DKIM **  last,
u_char *  body,
size_t  bodylen 
) [static]

Definition at line 4926 of file opendkim.c.

{
       DKIM_STAT status;

       assert(sr != NULL);
       assert(body != NULL);

       while (sr != NULL)
       {
              status = dkim_body(sr->srq_dkim, body, bodylen);
              if (status != DKIM_STAT_OK)
              {
                     if (last != NULL)
                            *last = sr->srq_dkim;
                     return status;
              }

              sr = sr->srq_next;
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkimf_msr_eoh ( struct signreq sr,
DKIM **  last 
) [static]

Definition at line 4890 of file opendkim.c.

{
       DKIM_STAT status;

       assert(sr != NULL);

       while (sr != NULL)
       {
              status = dkim_eoh(sr->srq_dkim);
              if (status != DKIM_STAT_OK)
              {
                     if (last != NULL)
                            *last = sr->srq_dkim;
                     return status;
              }
              sr = sr->srq_next;
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkimf_msr_eom ( struct signreq sr,
DKIM **  last 
) [static]

Definition at line 4992 of file opendkim.c.

{
       _Bool testkey;
       DKIM_STAT status;

       assert(sr != NULL);

       while (sr != NULL)
       {
              status = dkim_eom(sr->srq_dkim, &testkey);
              if (status != DKIM_STAT_OK)
              {
                     if (last != NULL)
                            *last = sr->srq_dkim;
                     return status;
              }
              sr = sr->srq_next;
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkimf_msr_header ( struct signreq sr,
DKIM **  last,
u_char *  header,
size_t  headerlen 
) [static]

Definition at line 4854 of file opendkim.c.

{
       DKIM_STAT status;

       assert(sr != NULL);
       assert(header != NULL);

       while (sr != NULL)
       {
              status = dkim_header(sr->srq_dkim, header, headerlen);
              if (status != DKIM_STAT_OK)
              {
                     if (last != NULL)
                            *last = sr->srq_dkim;
                     return status;
              }
              sr = sr->srq_next;
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dkimf_msr_minbody ( struct signreq sr) [static]

Definition at line 4961 of file opendkim.c.

{
       u_long mb = 0;
       u_long ret = 0;

       assert(sr != NULL);

       while (sr != NULL)
       {
              ret = dkim_minbody(sr->srq_dkim);
              if (ret > mb)
                     mb = ret;
              sr = sr->srq_next;
       }

       return mb;;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_parsehandler ( struct config cfg,
char *  name,
struct handling hndl 
) [static]

Definition at line 5841 of file opendkim.c.

{
       int action;
       char *val = NULL;

       assert(name != NULL);
       assert(strncasecmp(name, "on-", 3) == 0);
       assert(hndl != NULL);

       if (cfg == NULL)
              return;

       (void) config_get(cfg, name, &val, sizeof val);

       if (val != NULL)
       {
              action = dkimf_configlookup(val, dkimf_values);
              if (action != -1)
              {
                     switch (dkimf_configlookup(name + 3, dkimf_params))
                     {
                       case HNDL_DEFAULT:
                            hndl->hndl_nosig = action;
                            hndl->hndl_badsig = action;
                            hndl->hndl_dnserr = action;
                            hndl->hndl_internal = action;
                            hndl->hndl_security = action;
                            hndl->hndl_nokey = action;
                            hndl->hndl_policyerr = action;
#ifdef _FFR_REPUTATION
                            hndl->hndl_reperr = action;
#endif /* _FFR_REPUTATION */
                            break;

                       case HNDL_NOSIGNATURE:
                            hndl->hndl_nosig = action;
                            break;

                       case HNDL_BADSIGNATURE:
                            hndl->hndl_badsig = action;
                            break;

                       case HNDL_DNSERROR:
                            hndl->hndl_dnserr = action;
                            break;

                       case HNDL_INTERNAL:
                            hndl->hndl_internal = action;
                            break;

                       case HNDL_SECURITY:
                            hndl->hndl_security = action;
                            break;

                       case HNDL_NOKEY:
                            hndl->hndl_nokey = action;
                            break;

                       case HNDL_POLICYERROR:
                            hndl->hndl_policyerr = action;
                            break;

#ifdef _FFR_REPUTATION
                       case HNDL_REPERROR:
                            hndl->hndl_reperr = action;
                            break;
#endif /* _FFR_REPUTATION */

                       default:
                            break;
                     }
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_policyreport ( connctx  cc,
struct dkimf_config conf,
char *  hostname 
) [static]

Definition at line 10172 of file opendkim.c.

{
       _Bool sendreport = FALSE;
       int status;
       int arftype;
       int arfdkim;
       int nsigs = 0;
       u_int pct;
       time_t now;
       DKIM_STAT repstatus;
       char *p;
       char *last;
       FILE *out;
       msgctx dfc;
       DKIM_SIGINFO **sigs;
       struct Header *hdr;
       struct tm tm;
       char ipstr[DKIM_MAXHOSTNAMELEN + 1];
       char fmt[BUFRSZ];
       char opts[BUFRSZ];
       char addr[MAXADDRESS + 1];

       assert(cc != NULL);

       dfc = cc->cctx_msg;

       assert(dfc != NULL);
       assert(dfc->mctx_dkimv != NULL);
       assert(conf != NULL);
       assert(hostname != NULL);

       memset(addr, '\0', sizeof addr);
       memset(fmt, '\0', sizeof fmt);
       memset(opts, '\0', sizeof opts);

       if (dfc->mctx_dkimv != NULL)
              (void) dkim_getsiglist(dfc->mctx_dkimv, &sigs, &nsigs);

       /* if no report is possible, just skip it */
       repstatus = dkim_policy_getreportinfo(dfc->mctx_dkimv,
                                             (u_char *) addr, sizeof addr,
                                             (u_char *) opts, sizeof opts,
                                             NULL, 0, &pct);
       if (repstatus != DKIM_STAT_OK || addr[0] == '\0')
              return;

       /* ignore any domain name in "r=" */
       p = strchr(addr, '@');
       if (p != NULL)
              *p = '\0';

       /* ensure the event being reported was requested */
       if (opts[0] == '\0')
       {
              sendreport = TRUE;
       }
       else
       {
              for (p = strtok_r(opts, ":", &last);
                   p != NULL;
                   p = strtok_r(NULL, ":", &last))
              {
                     if (strcasecmp(p, ARF_OPTIONS_ADSP_ALL) == 0)
                     {
                            sendreport = TRUE;
                            break;
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_ADSP_SIGNED) == 0)
                     {
                            if (nsigs != 0)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_ADSP_UNSIGNED) == 0)
                     {
                            if (nsigs == 0)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
              }
       }

       if (!sendreport)
              return;

       out = popen(reportcmd, "w");
       if (out == NULL)
       {
              if (conf->conf_dolog)
              {
                     syslog(LOG_ERR, "%s: popen(): %s",
                            dfc->mctx_jobid, strerror(errno));
              }

              return;
       }

       /* determine the type of ARF failure and, if needed, a DKIM fail code */
       arftype = dkimf_arftype(dfc);
       if (arftype == ARF_TYPE_AUTHFAIL)
              arfdkim = dkimf_arfdkim(dfc);

       /* From: */
       fprintf(out, "From: %s\n", reportaddr);

       /* To: */
       fprintf(out, "To: %s@%s\n", addr, dfc->mctx_domain);

       /* Bcc: */
       if (conf->conf_reportaddrbcc != NULL)
              fprintf(out, "Bcc: %s\n", conf->conf_reportaddrbcc);

       /* Date: */
       memset(fmt, '\0', sizeof fmt);
       (void) time(&now);
       (void) localtime_r(&now, &tm);
       (void) strftime(fmt, sizeof fmt, "%a, %e %b %Y %H:%M:%S %z (%Z)", &tm);
       fprintf(out, "Date: %s\n", fmt);

       /* Subject: */
       fprintf(out, "Subject: ADSP failure report for %s\n",
               dfc->mctx_jobid);

       /* MIME stuff */
       fprintf(out, "MIME-Version: 1.0\n");
       fprintf(out,
               "Content-Type: multipart/report; report-type=feedback-report;\n\tboundary=\"dkimreport/%s/%s\"",
               hostname, dfc->mctx_jobid);

       /* ok, now then... */
       fprintf(out, "\n");

       /* first part: a text blob explaining what this is */
       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: text/plain\n");
       fprintf(out, "\n");
       fprintf(out, "DKIM failure report for job %s on %s\n\n",
               dfc->mctx_jobid, hostname);
       fprintf(out,
               "The failed message's header is attached.\n");
       fprintf(out, "\n");

       /* second part: formatted gunk */
       memset(ipstr, '\0', sizeof ipstr);

       switch (cc->cctx_ip.ss_family)
       {
         case AF_INET:
         {
              struct sockaddr_in sin4;

              memcpy(&sin4, &cc->cctx_ip, sizeof sin4);

              (void) inet_ntop(AF_INET, &sin4.sin_addr, ipstr, sizeof ipstr);

              break;
         }

#ifdef AF_INET6
         case AF_INET6:
         {
              struct sockaddr_in6 sin6;

              memcpy(&sin6, &cc->cctx_ip, sizeof sin6);

              (void) inet_ntop(AF_INET6, &sin6.sin6_addr, ipstr, sizeof ipstr);

              break;
         }
#endif /* AF_INET6 */
       }

       hdr = dkimf_findheader(dfc, (char *) "Message-ID", 0);

       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: message/feedback-report\n");
       fprintf(out, "\n");
       fprintf(out, "User-Agent: %s/%s\n", DKIMF_PRODUCTNS, VERSION);
       fprintf(out, "Version: %s\n", ARF_VERSION);
       fprintf(out, "Original-Envelope-Id: %s\n", dfc->mctx_jobid);
       fprintf(out, "Original-Mail-From: %s\n", dfc->mctx_envfrom);
       fprintf(out, "Reporting-MTA: %s\n", hostname);
       fprintf(out, "Source-IP: %s\n", ipstr);
       fprintf(out, "Message-ID:%s%s\n",
               cc->cctx_noleadspc ? "" : " ",
               hdr == NULL ? "(none)" : hdr->hdr_val);
       fprintf(out, "Arrival-Date: %s\n", fmt);
       fprintf(out, "Reported-Domain: %s\n", dkim_getdomain(dfc->mctx_dkimv));
       fprintf(out, "Delivery-Result: other\n");
       fprintf(out, "Feedback-Type: %s\n", arf_type_string(arftype));

       fprintf(out, "\n");

       /* third part: header block */
       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: text/rfc822-headers\n");
       fprintf(out, "\n");

       for (hdr = dfc->mctx_hqhead; hdr != NULL; hdr = hdr->hdr_next)
       {
              fprintf(out, "%s:%s%s\n", hdr->hdr_hdr,
                      cc->cctx_noleadspc ? "" : " ", hdr->hdr_val);
       }

       /* end */
       fprintf(out, "\n--dkimreport/%s/%s--\n", hostname, dfc->mctx_jobid);

       /* send it */
       status = pclose(out);
       if (status != 0 && conf->conf_dolog)
       {
              syslog(LOG_ERR, "%s: pclose(): returned status %d",
                     dfc->mctx_jobid, status);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_CBSTAT dkimf_prescreen ( DKIM *  dkim,
DKIM_SIGINFO **  sigs,
int  nsigs 
) [static]

Definition at line 5027 of file opendkim.c.

{
       int c;
       unsigned int ni = 0;
       u_char *domain;
       u_char *sdomain;
       SMFICTX *ctx;
       connctx cc;
       msgctx dfc;
       struct dkimf_config *conf;

       ctx = (SMFICTX *) dkim_get_user_context(dkim);
       cc = (connctx) dkimf_getpriv(ctx);
       conf = cc->cctx_config;
       dfc = cc->cctx_msg;
       domain = dkim_getdomain(dkim);

       if (conf->conf_maxverify > 0)
       {
              int n;
              _Bool *ig = NULL;

              ig = (_Bool *) malloc(sizeof(_Bool) * nsigs);
              if (ig == NULL)
                     return DKIM_CBSTAT_ERROR;

              /* mark everything to be ignored */
              for (c = 0; c < nsigs; c++)
                     ig[c] = TRUE;

              n = conf->conf_maxverify;

              if (conf->conf_thirdpartydb != NULL)
              {
                     _Bool found;

                     /* unmark sigs that are explicitly trusted */
                     for (c = 0; c < nsigs; c++)
                     {
                            sdomain = dkim_sig_getdomain(sigs[c]);

                            found = FALSE;

                            if (dkimf_db_get(conf->conf_thirdpartydb,
                                             (char *) sdomain, 0, NULL, 0,
                                             &found) != 0)
                            {
                                   free(ig);
                                   return DKIM_CBSTAT_ERROR;
                            }

                            if (found)
                            {
                                   ig[c] = FALSE;
                                   n--;
                            }
                     }
              }

              /* unmark from the top down any that don't exceed the limit */
              for (c = 0; c < nsigs && n > 0; c++)
              {
                     if (ig[c])
                     {
                            n--;
                            ig[c] = FALSE;
                     }
              }

              /* mark what's left to be ignored */
              for (c = 0; c < nsigs; c++)
              {
                     if (ig[c])
                     {
                            dkim_sig_ignore(sigs[c]);
                            ni++;
                     }
              }

              if (conf->conf_dolog && ni > 0)
              {
                     syslog(LOG_INFO, "%s: ignoring %u signature%s",
                            dkim_getid(dkim), ni, ni == 1 ? "" : "s");
              }

              free(ig);

              return DKIM_CBSTAT_CONTINUE;
       }

       /* ignore signatures which are neither first-party nor trusted */
       for (c = 0; c < nsigs; c++)
       {
              sdomain = dkim_sig_getdomain(sigs[c]);

              /* author domain */
              if (strcasecmp((char *) sdomain, (char *) domain) == 0)
                     continue;

              /* trusted third party domain */
              if (conf->conf_thirdpartydb != NULL)
              {
                     _Bool found = FALSE;

                     if (dkimf_db_get(conf->conf_thirdpartydb,
                                         (char *) sdomain, 0, NULL, 0,
                                         &found) != 0)
                            return DKIM_CBSTAT_ERROR;

                     if (found)
                            continue;
              }

              /* neither; arrange to ignore it */
              dkim_sig_ignore(sigs[c]);

              if (conf->conf_dolog)
              {
                     syslog(LOG_INFO, "%s: ignoring signature from %s",
                            dfc->mctx_jobid, sdomain);
              }
       }

       return DKIM_CBSTAT_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_quarantine ( SMFICTX *  ctx,
char *  reason 
)

Definition at line 969 of file opendkim.c.

{
       assert(ctx != NULL);

       if (testmode)
              return dkimf_test_quarantine(ctx, reason);
#ifdef SMFIF_QUARANTINE
       else
              return smfi_quarantine(ctx, reason);
#endif /* SMFIF_QUARANTINE */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void* dkimf_reloader ( void *  vp) [static]

Definition at line 5488 of file opendkim.c.

{
       int sig;
       sigset_t mask;

       (void) pthread_detach(pthread_self());

       sigemptyset(&mask);
       sigaddset(&mask, SIGUSR1);

       while (!die)
       {
              (void) sigwait(&mask, &sig);

              if (conffile != NULL)
                     reload = TRUE;
       }

       return NULL;
}

Here is the caller graph for this function:

static void dkimf_reportaddr ( struct dkimf_config conf) [static]

Definition at line 5252 of file opendkim.c.

{
       uid_t uid;
       struct passwd *pw;
       assert(conf != NULL);

       if (conf->conf_reportaddr != NULL)
       {
              int status;
              u_char *user;
              u_char *domain;
              u_char env[MAXADDRESS + 1]; /* reporting address */

              strlcpy(reportaddr, conf->conf_reportaddr, sizeof reportaddr);
              strlcpy((char *) env, conf->conf_reportaddr,
                      sizeof reportaddr);
              status = dkim_mail_parse(env, &user, &domain);
              if (status == 0 && user != NULL && domain != NULL)
              {
                     snprintf(reportcmd, sizeof reportcmd,
                              "%s -t -f%s@%s",
                              conf->conf_mtacommand, user, domain);

                     return;
              }
              else
              {
                     if (dolog)
                     {
                            syslog(LOG_ERR,
                                   "error parsing ReportAddress; using default");
                     }
              }
       }

       /* not successful case has already returned. Make up a value if not
        * set of an error occurs */

       uid = geteuid();
       pw = getpwuid(uid);

       if (pw == NULL)
       {
              snprintf(reportaddr, sizeof reportaddr,
                       "%u@%s", uid, myhostname);
       }
       else
       {
              snprintf(reportaddr, sizeof reportaddr,
                       "%s@%s", pw->pw_name, myhostname);
       }

       snprintf(reportcmd, sizeof reportcmd, "%s -t -f%s",
                conf->conf_mtacommand, reportaddr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t dkimf_reptoken ( u_char *  out,
size_t  outlen,
u_char *  in,
u_char *  sub 
)

Definition at line 4489 of file opendkim.c.

{
       size_t ret = 0;
       u_char *p;
       u_char *q;
       u_char *end;

       assert(out != NULL);
       assert(in != NULL);
       assert(sub != NULL);

       memset(out, '\0', outlen);

       q = out;
       end = q + outlen - 1;

       for (p = in; *p != '\0'; p++)
       {
              if (*p == '%')
              {
                     size_t c;

                     c = strlcpy((char *) q, (char *) sub, outlen - ret);
                     q += c;
                     ret += c;
              }
              else
              {
                     if (q < end)
                     {
                            *q = *p;
                            q++;
                            ret++;
                     }
              }
       }

       return ret;
}

Here is the caller graph for this function:

static _Bool dkimf_restart_check ( int  n,
time_t  t 
) [static]

Definition at line 4430 of file opendkim.c.

{
       static int idx;                           /* last filled slot */
       static int alen;                   /* allocated length */
       static time_t *list;

       if (t == 0)
       {
              alen = n * sizeof(time_t);

              list = (time_t *) malloc(alen);

              if (list == NULL)
                     return FALSE;

              memset(list, '\0', alen);

              idx = 0;
              alen = n;

              return TRUE;
       }
       else
       {
              int which;

              time_t now;

              (void) time(&now);

              which = (idx - 1) % alen;
              if (which == -1)
                     which = alen - 1;

              if (list[which] != 0 &&
                  list[which] + t > now)
                     return FALSE;

              list[which] = t;
              idx++;

              return TRUE;
       }
}

Here is the caller graph for this function:

void dkimf_sendprogress ( const void *  ctx)

Definition at line 8763 of file opendkim.c.

{
       if (ctx != NULL)
       {
              struct connctx *cc;
              struct msgctx *dfc;

              cc = (struct connctx *) dkimf_getpriv((SMFICTX *) ctx);
              dfc = cc->cctx_msg;

              if (dfc->mctx_eom)
              {
                     if (testmode)
                            (void) dkimf_test_progress((SMFICTX *) ctx);
#ifdef HAVE_SMFI_PROGRESS
                     else
                            (void) smfi_progress((SMFICTX *) ctx);
#endif /* HAVE_SMFI_PROGRESS */
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_setpriv ( SMFICTX *  ctx,
void *  ptr 
)

Definition at line 892 of file opendkim.c.

{
       assert(ctx != NULL);

       if (testmode)
              return dkimf_test_setpriv((void *) ctx, ptr);
       else
              return smfi_setpriv(ctx, ptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat dkimf_setreply ( SMFICTX *  ctx,
char *  rcode,
char *  xcode,
char *  replytxt 
)

Definition at line 1066 of file opendkim.c.

{
       assert(ctx != NULL);

       if (testmode)
              return dkimf_test_setreply(ctx, rcode, xcode, replytxt);
       else
              return smfi_setreply(ctx, rcode, xcode, replytxt);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_sighandler ( int  sig) [static]

Definition at line 5463 of file opendkim.c.

{
       if (sig == SIGINT || sig == SIGTERM || sig == SIGHUP)
       {
              diesig = sig;
              die = TRUE;
       }
       else if (sig == SIGUSR1)
       {
              if (conffile != NULL)
                     reload = TRUE;
       }
}

Here is the caller graph for this function:

static void dkimf_sigreport ( connctx  cc,
struct dkimf_config conf,
char *  hostname 
) [static]

Definition at line 9799 of file opendkim.c.

{
       _Bool sendreport = FALSE;
       int bfd = -1;
       int hfd = -1;
       int status;
       int arftype = ARF_TYPE_UNKNOWN;
       int arfdkim = ARF_DKIMF_UNKNOWN;
       u_int pct = 100;
       u_int rn;
       time_t now;
       DKIM_STAT repstatus;
       char *p;
       char *last;
       FILE *out;
       msgctx dfc;
       DKIM_SIGINFO *sig;
       struct Header *hdr;
       struct tm tm;
       char ipstr[DKIM_MAXHOSTNAMELEN + 1];
       char opts[BUFRSZ];
       char fmt[BUFRSZ];
       u_char addr[MAXADDRESS + 1];

       assert(cc != NULL);

       dfc = cc->cctx_msg;

       assert(dfc->mctx_dkimv != NULL);
       assert(conf != NULL);
       assert(hostname != NULL);

       memset(addr, '\0', sizeof addr);
       memset(opts, '\0', sizeof opts);

       sig = dkim_getsignature(dfc->mctx_dkimv);

       /* if no report is possible, just skip it */
       repstatus = dkim_sig_getreportinfo(dfc->mctx_dkimv, sig,
                                          &hfd, &bfd,
                                          (u_char *) addr, sizeof addr,
                                          (u_char *) opts, sizeof opts,
                                          NULL, 0, &pct);
       if (repstatus != DKIM_STAT_OK || addr[0] == '\0')
              return;

       if (pct < 100)
       {
              rn = random() % 100;
              if (rn > pct)
                     return;
       }

       /* ignore any domain name in "r=" */
       p = strchr((char *) addr, '@');
       if (p != NULL)
              *p = '\0';

       /* ensure the event being reported was requested */
       if (opts[0] == '\0')
       {
              sendreport = TRUE;
       }
       else
       {
              for (p = strtok_r(opts, ":", &last);
                   p != NULL;
                   p = strtok_r(NULL, ":", &last))
              {
                     if (strcasecmp(p, ARF_OPTIONS_DKIM_ALL) == 0)
                     {
                            sendreport = TRUE;
                            break;
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_SYNTAX) == 0)
                     {
                            int err;

                            err = dkim_sig_geterror(sig);

                            if (err == DKIM_SIGERROR_TIMESTAMPS ||
                                err == DKIM_SIGERROR_INVALID_HC ||
                                err == DKIM_SIGERROR_INVALID_BC ||
                                err == DKIM_SIGERROR_MISSING_A ||
                                err == DKIM_SIGERROR_INVALID_A ||
                                err == DKIM_SIGERROR_MISSING_H ||
                                err == DKIM_SIGERROR_INVALID_L ||
                                err == DKIM_SIGERROR_INVALID_Q ||
                                err == DKIM_SIGERROR_INVALID_QO ||
                                err == DKIM_SIGERROR_MISSING_D ||
                                err == DKIM_SIGERROR_EMPTY_D ||
                                err == DKIM_SIGERROR_MISSING_S ||
                                err == DKIM_SIGERROR_EMPTY_S ||
                                err == DKIM_SIGERROR_MISSING_B ||
                                err == DKIM_SIGERROR_EMPTY_B ||
                                err == DKIM_SIGERROR_CORRUPT_B ||
                                err == DKIM_SIGERROR_MISSING_BH ||
                                err == DKIM_SIGERROR_EMPTY_BH ||
                                err == DKIM_SIGERROR_CORRUPT_BH ||
                                err == DKIM_SIGERROR_EMPTY_H ||
                                err == DKIM_SIGERROR_INVALID_H ||
                                err == DKIM_SIGERROR_TOOLARGE_L ||
                                err == DKIM_SIGERROR_MISSING_V ||
                                err == DKIM_SIGERROR_EMPTY_V)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_EXPIRED) == 0)
                     {
                            if (dkim_sig_geterror(sig) == DKIM_SIGERROR_EXPIRED)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_VERIFY) == 0)
                     {
                            if (dkim_sig_geterror(sig) == DKIM_SIGERROR_BADSIG ||
                                dkim_sig_getbh(sig) == DKIM_SIGBH_MISMATCH)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_DNS) == 0)
                     {
                            int err;

                            err = dkim_sig_geterror(sig);

                            if (err == DKIM_SIGERROR_NOKEY ||
                                err == DKIM_SIGERROR_DNSSYNTAX ||
                                err == DKIM_SIGERROR_KEYFAIL ||
                                err == DKIM_SIGERROR_KEYDECODE ||
                                err == DKIM_SIGERROR_MULTIREPLY)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_POLICY) == 0)
                     {
                            int err;

                            err = dkim_sig_geterror(sig);

                            if (err == DKIM_SIGERROR_MBSFAILED)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
                     else if (strcasecmp(p, ARF_OPTIONS_DKIM_OTHER) == 0)
                     {
                            int err;

                            err = dkim_sig_geterror(sig);

                            if (err == DKIM_SIGERROR_SUBDOMAIN ||
                                err == DKIM_SIGERROR_KEYVERSION ||
                                err == DKIM_SIGERROR_KEYUNKNOWNHASH ||
                                err == DKIM_SIGERROR_KEYHASHMISMATCH ||
                                err == DKIM_SIGERROR_NOTEMAILKEY ||
                                err == DKIM_SIGERROR_KEYTYPEMISSING ||
                                err == DKIM_SIGERROR_KEYTYPEUNKNOWN ||
                                err == DKIM_SIGERROR_KEYREVOKED)
                            {
                                   sendreport = TRUE;
                                   break;
                            }
                     }
              }
       }

       if (!sendreport)
              return;

       out = popen(reportcmd, "w");
       if (out == NULL)
       {
              if (conf->conf_dolog)
              {
                     syslog(LOG_ERR, "%s: popen(): %s",
                            dfc->mctx_jobid, strerror(errno));
              }

              return;
       }

       /* determine the type of ARF failure and, if needed, a DKIM fail code */
       arftype = dkimf_arftype(dfc);
       if (arftype == ARF_TYPE_AUTHFAIL)
              arfdkim = dkimf_arfdkim(dfc);

       /* From: */
       fprintf(out, "From: %s\n", reportaddr);

       /* To: */
       fprintf(out, "To: %s@%s\n", addr, dkim_sig_getdomain(sig));

       /* Bcc: */
       if (conf->conf_reportaddrbcc != NULL)
              fprintf(out, "Bcc: %s\n", conf->conf_reportaddrbcc);

       /* Date: */
       memset(fmt, '\0', sizeof fmt);
       (void) time(&now);
       (void) localtime_r(&now, &tm);
       (void) strftime(fmt, sizeof fmt, "%a, %e %b %Y %H:%M:%S %z (%Z)", &tm);
       fprintf(out, "Date: %s\n", fmt);

       /* Subject: */
       fprintf(out, "Subject: DKIM failure report for %s\n",
               dfc->mctx_jobid);

       /* MIME stuff */
       fprintf(out, "MIME-Version: 1.0\n");
       fprintf(out,
               "Content-Type: multipart/report; report-type=feedback-report;\n\tboundary=\"dkimreport/%s/%s\"",
               hostname, dfc->mctx_jobid);

       /* ok, now then... */
       fprintf(out, "\n");

       /* first part: a text blob explaining what this is */
       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: text/plain\n");
       fprintf(out, "\n");
       fprintf(out, "DKIM failure report for job %s on %s\n\n",
               dfc->mctx_jobid, hostname);
       fprintf(out,
               "The canonicalized form of the failed message's header and body are\nattached.\n");
       fprintf(out, "\n");

       /* second part: formatted gunk */
       memset(ipstr, '\0', sizeof ipstr);

       switch (cc->cctx_ip.ss_family)
       {
         case AF_INET:
         {
              struct sockaddr_in sin4;

              memcpy(&sin4, &cc->cctx_ip, sizeof sin4);

              (void) inet_ntop(AF_INET, &sin4.sin_addr, ipstr, sizeof ipstr);

              break;
         }

#ifdef AF_INET6
         case AF_INET6:
         {
              struct sockaddr_in6 sin6;

              memcpy(&sin6, &cc->cctx_ip, sizeof sin6);

              (void) inet_ntop(AF_INET6, &sin6.sin6_addr, ipstr, sizeof ipstr);

              break;
         }
#endif /* AF_INET6 */
       }

       hdr = dkimf_findheader(dfc, (char *) "Message-ID", 0);

       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: message/feedback-report\n");
       fprintf(out, "\n");
       fprintf(out, "User-Agent: %s/%s\n", DKIMF_PRODUCTNS, VERSION);
       fprintf(out, "Version: %s\n", ARF_VERSION);
       fprintf(out, "Original-Envelope-Id: %s\n", dfc->mctx_jobid);
       fprintf(out, "Original-Mail-From: %s\n", dfc->mctx_envfrom);
       fprintf(out, "Reporting-MTA: %s\n", hostname);
       fprintf(out, "Source-IP: %s\n", ipstr);
       fprintf(out, "Message-ID:%s%s\n",
               cc->cctx_noleadspc ? "" : " ",
               hdr == NULL ? "(none)" : hdr->hdr_val);
       fprintf(out, "Arrival-Date: %s\n", fmt);
       fprintf(out, "Reported-Domain: %s\n", dkim_sig_getdomain(sig));
       fprintf(out, "Delivery-Result: other\n");
       fprintf(out, "Feedback-Type: %s\n", arf_type_string(arftype));
       if (arftype == ARF_TYPE_AUTHFAIL)
       {
              fprintf(out, "Auth-Failure: ");
              if (dkim_sig_getbh(sig) == DKIM_SIGBH_MISMATCH)
              {
                     fprintf(out, "bodyhash\n");
              }
              else
              {
                     const char *tmperror;

                     switch (dkim_sig_geterror(sig))
                     {
                       case DKIM_SIGERROR_KEYREVOKED:
                            fprintf(out, "revoked\n");
                            break;

                       default:
                            tmperror = dkim_sig_geterrorstr(dkim_sig_geterror(sig));
                            fprintf(out, "signature");
                            if (tmperror != NULL)
                                   fprintf(out, " (%s)", tmperror);
                            fprintf(out, "\n");
                            break;
                     }
              }

              memset(addr, '\0', sizeof addr);
              dkim_sig_getidentity(dfc->mctx_dkimv, sig, addr,
                                   sizeof addr - 1);

              /* fprintf(out, "Authentication-Results: %s\n", ...); */
              fprintf(out, "DKIM-Failure: %s\n",
                      arf_dkim_failure_string(arfdkim));
              fprintf(out, "DKIM-Domain: %s\n", dkim_sig_getdomain(sig));
              fprintf(out, "DKIM-Selector: %s\n", dkim_sig_getselector(sig));
              fprintf(out, "DKIM-Identity: %s\n", addr);
              if (hfd != -1)
              {
                     fprintf(out, "DKIM-Canonicalized-Header: ");
                     (void) dkimf_base64_encode_file(hfd, out, 4, 75, 27);
                     fprintf(out, "\n");
              }
              if (bfd != -1)
              {
                     fprintf(out, "DKIM-Canonicalized-Body: ");
                     (void) dkimf_base64_encode_file(bfd, out, 4, 75, 25);
                     fprintf(out, "\n");
              }
       }

       fprintf(out, "\n");

       /* third part: header block */
       fprintf(out, "--dkimreport/%s/%s\n", hostname, dfc->mctx_jobid);
       fprintf(out, "Content-Type: text/rfc822-headers\n");
       fprintf(out, "\n");

       for (hdr = dfc->mctx_hqhead; hdr != NULL; hdr = hdr->hdr_next)
       {
              fprintf(out, "%s:%s%s\n", hdr->hdr_hdr,
                      cc->cctx_noleadspc ? "" : " ", hdr->hdr_val);
       }

       /* end */
       fprintf(out, "\n--dkimreport/%s/%s--\n", hostname, dfc->mctx_jobid);

       /* send it */
       status = pclose(out);
       if (status != 0 && conf->conf_dolog)
       {
              syslog(LOG_ERR, "%s: pclose(): returned status %d",
                     dfc->mctx_jobid, status);
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkimf_stdio ( void  ) [static]

Definition at line 8734 of file opendkim.c.

{
       int devnull;

       /* this only fails silently, but that's OK */
       devnull = open(_PATH_DEVNULL, O_RDWR, 0);
       if (devnull != -1)
       {
              (void) dup2(devnull, 0);
              (void) dup2(devnull, 1);
              (void) dup2(devnull, 2);
              if (devnull > 2)
                     (void) close(devnull);
       }

       (void) setsid();
}

Here is the caller graph for this function:

static void dkimf_zapkey ( struct dkimf_config conf) [static]

Definition at line 5542 of file opendkim.c.

{
       assert(conf != NULL);

       if (conf->conf_seckey != NULL)
       {
              memset(conf->conf_seckey, '\0', conf->conf_keylen);
              free(conf->conf_seckey);
              conf->conf_seckey = NULL;
       }
}

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 15595 of file opendkim.c.

{
       _Bool autorestart = FALSE;
       _Bool gotp = FALSE;
       _Bool dofork = TRUE;
       _Bool stricttest = FALSE;
       _Bool configonly = FALSE;
       _Bool querytest = FALSE;
       int c;
       int status;
       int n;
       int verbose = 0;
       int maxrestarts = 0;
       int maxrestartrate_n = 0;
       int filemask = -1;
       int mdebug = 0;
#ifdef HAVE_SMFI_VERSION
       u_int mvmajor;
       u_int mvminor;
       u_int mvrelease;
#endif /* HAVE_SMFI_VERSION */
       time_t now;
       gid_t gid = (gid_t) -1;
       sigset_t sigset;
       uint64_t fixedtime = (uint64_t) -1;
       time_t maxrestartrate_t = 0;
       pthread_t rt;
       unsigned long tmpl;
       const char *args = CMDLINEOPTS;
       FILE *f;
       struct passwd *pw = NULL;
       struct group *gr = NULL;
       char *become = NULL;
       char *chrootdir = NULL;
       char *extract = NULL;
       char *p;
       char *pidfile = NULL;
#ifdef POPAUTH
       char *popdbfile = NULL;
#endif /* POPAUTH */
       char *testfile = NULL;
       char *testpubkeys = NULL;
       struct config *cfg = NULL;
       char *end;
       char argstr[MAXARGV];
       char err[BUFRSZ + 1];

       /* initialize */
       reload = FALSE;
       testmode = FALSE;
#ifdef QUERY_CACHE
       querycache = FALSE;
#endif /* QUERY_CACHE */
       sock = NULL;
#ifdef POPAUTH
       popdb = NULL;
#endif /* POPAUTH */
       no_i_whine = TRUE;
       quarantine = FALSE;
       conffile = NULL;

       memset(myhostname, '\0', sizeof myhostname);
       (void) gethostname(myhostname, sizeof myhostname);

       progname = (p = strrchr(argv[0], '/')) == NULL ? argv[0] : p + 1;

       (void) time(&now);
       srandom(now);

       curconf = dkimf_config_new();
       if (curconf == NULL)
       {
              fprintf(stderr, "%s: malloc(): %s\n", progname,
                      strerror(errno));

              return EX_OSERR;
       }

       /* process command line options */
       while ((c = getopt(argc, argv, args)) != -1)
       {
              switch (c)
              {
                case 'A':
                     autorestart = TRUE;
                     break;

                case 'b':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_modestr = optarg;
                     break;

                case 'c':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_canonstr = optarg;
                     break;

                case 'd':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_domlist = strdup(optarg);
                     if (curconf->conf_domlist == NULL)
                     {
                            fprintf(stderr, "%s: strdup(): %s\n", progname,
                                    strerror(errno));
                            return EX_SOFTWARE;
                     }
                     break;

                case 'D':
                     curconf->conf_subdomains = TRUE;
                     break;

                case 'e':
                     extract = optarg;
                     break;

                case 'f':
                     dofork = FALSE;
                     break;

                case 'F':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     errno = 0;
                     if (optarg[0] == '-')
                     {
                            errno = ERANGE;
                            fixedtime = ULONG_MAX;
                     }
                     else
                     {
                            fixedtime = strtoul(optarg, &p, 10);
                     }

                     if (fixedtime == (uint64_t) ULONG_MAX ||
                         errno != 0 ||
                         *p != '\0')
                     {
                            fprintf(stderr, "%s: invalid time value\n",
                                    progname);
                            return EX_USAGE;
                     }
                     break;

                case 'k':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_keyfile = optarg;
                     break;

                case 'l':
                     curconf->conf_dolog = TRUE;
                     break;

                case 'L':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_siglimit = optarg;
                     break;

                case 'n':
                     configonly = TRUE;
                     break;

                case 'o':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_omitlist = optarg;
                     break;

                case 'p':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     sock = optarg;
                     (void) smfi_setconn(optarg);
                     gotp = TRUE;
                     break;

                case 'P':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     pidfile = optarg;
                     break;

                case 'q':
                     quarantine = TRUE;
                     break;

                case 'Q':
                     querytest = TRUE;
                     testmode = TRUE;
                     break;

                case 'r':
                     curconf->conf_reqhdrs = TRUE;
                     break;

                case 's':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_selector = (u_char *) optarg;
                     break;

                case 'S':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     curconf->conf_signalgstr = optarg;
                     break;

                case 't':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     testmode = TRUE;
                     testfile = optarg;
                     break;

                case 'T':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     errno = 0;
                     if (optarg[0] == '-')
                     {
                            errno = ERANGE;
                            tmpl = ULONG_MAX;
                     }
                     else
                     {
                            tmpl = strtoul(optarg, &p, 10);
                     }

                     if (tmpl == ULONG_MAX || errno != 0 || *p != '\0')
                     {
                            fprintf(stderr, "%s: invalid value for -%c\n",
                                    progname, c);
                            return EX_USAGE;
                     }

                     curconf->conf_dnstimeout = (unsigned int) tmpl;

                     break;

                case 'u':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     become = optarg;
                     break;

                case 'v':
                     verbose++;
                     break;

                case 'V':
                     if (!dkimf_config_setlib(curconf, &p))
                     {
                            fprintf(stderr,
                                    "%s: can't configure DKIM library: %s\n",
                                    progname, p);

                            return EX_SOFTWARE;
                     }

                     printf("%s: %s v%s\n", progname, DKIMF_PRODUCT,
                            VERSION);
#ifdef USE_GNUTLS
                     printf("\tCompiled with GnuTLS %s\n", GNUTLS_VERSION);
#else /* USE_GNUTLS */
                     printf("\tCompiled with %s\n",
                            SSLeay_version(SSLEAY_VERSION));
#endif /* USE_GNUTLS */
                     printf("\tSMFI_VERSION 0x%x\n", SMFI_VERSION);
#ifdef HAVE_SMFI_VERSION
                     (void) smfi_version(&mvmajor, &mvminor, &mvrelease);
                     printf("\tlibmilter version %d.%d.%d\n",
                            mvmajor, mvminor, mvrelease);
#endif /* HAVE_SMFI_VERSION */
                     printf("\tSupported signing algorithms:\n");
                     for (c = 0; dkimf_sign[c].str != NULL; c++)
                     {
                            if (dkimf_sign[c].code != DKIM_SIGN_RSASHA256 ||
                                dkim_libfeature(curconf->conf_libopendkim,
                                                DKIM_FEATURE_SHA256))
                                   printf("\t\t%s\n", dkimf_sign[c].str);
                     }
                     printf("\tSupported canonicalization algorithms:\n");
                     for (c = 0; dkimf_canon[c].str != NULL; c++)
                            printf("\t\t%s\n", dkimf_canon[c].str);
                     dkimf_optlist(stdout);
                     return EX_OK;

                case 'W':
                     curconf->conf_logwhy = TRUE;
                     break;

                case 'x':
                     if (optarg == NULL || *optarg == '\0')
                            return usage();
                     else
                            conffile = optarg;
                     break;

                default:
                     return usage();
              }
       }

       if (optind != argc)
              return usage();

#ifdef USE_GNUTLS
       if (dkim_ssl_version() != GNUTLS_VERSION_NUMBER * 256)
#else /* USE_GNUTLS */
       if (dkim_ssl_version() != OPENSSL_VERSION_NUMBER)
#endif /* USE_GNUTLS */
       {
              fprintf(stderr,
                      "%s: incompatible SSL versions (library = 0x%09lx, filter = %09lx)\n",
                      progname, dkim_ssl_version(),
#ifdef USE_GNUTLS
                      GNUTLS_VERSION_NUMBER * 256);
#else /* USE_GNUTLS */
                      (unsigned long) OPENSSL_VERSION_NUMBER);
#endif /* USE_GNUTLS */

              return EX_SOFTWARE;
       }

       /* if there's a default config file readable, use it */
       if (conffile == NULL && access(DEFCONFFILE, R_OK) == 0)
              conffile = DEFCONFFILE;

       if (conffile != NULL)
       {
              u_int line = 0;
              char *missing;
              char path[MAXPATHLEN + 1];

              cfg = config_load(conffile, dkimf_config,
                                &line, path, sizeof path);

              if (cfg == NULL)
              {
                     fprintf(stderr,
                             "%s: %s: configuration error at line %u: %s\n",
                             progname, path, line,
                             config_error());
                     dkimf_config_free(curconf);
                     return EX_CONFIG;
              }

#ifdef DEBUG
              (void) config_dump(cfg, stdout, NULL);
#endif /* DEBUG */

              missing = config_check(cfg, dkimf_config);
              if (missing != NULL)
              {
                     fprintf(stderr,
                             "%s: %s: required parameter \"%s\" missing\n",
                             progname, conffile, missing);
                     config_free(cfg);
                     dkimf_config_free(curconf);
                     return EX_CONFIG;
              }
       }

       if (dkimf_config_load(cfg, curconf, err, sizeof err) != 0)
       {
              if (conffile == NULL)
                     conffile = "(stdin)";
              fprintf(stderr, "%s: %s: %s\n", progname, conffile, err);
              config_free(cfg);
              dkimf_config_free(curconf);
              return EX_CONFIG;
       }

       if (configonly)
       {
              config_free(cfg);
              dkimf_config_free(curconf);
              return EX_OK;
       }

       if (extract)
       {
              int ret = EX_OK;

              if (cfg != NULL)
              {
                     if (!config_validname(dkimf_config, extract))
                            ret = EX_DATAERR;
                     else if (config_dump(cfg, stdout, extract) == 0)
                            ret = EX_CONFIG;
                     config_free(cfg);
                     dkimf_config_free(curconf);
              }
              return ret;
       }

       dolog = curconf->conf_dolog;
       curconf->conf_data = cfg;

       if (querytest)
       {
              _Bool exists = FALSE;
              DKIMF_DB dbtest;
              DKIMF_DBDATA dbdp;
              char *p;
              char dbname[BUFRSZ + 1];
              char query[BUFRSZ + 1];
              char **result;

              if (isatty(0))
              {
                     fprintf(stdout, "%s: enter data set description\n",
                             progname);
                     fprintf(stdout, "\tcsl:entry1[,entry2[,...]]\n"
                                     "\tfile:path\n"
                                     "\trefile:path\n"
                                     "\tdb:path\n"
#ifdef USE_ODBX
                                     "\tdsn:<backend>://[user[:pwd]@][port+]host/dbase[/key=val[?...]]\n"
#endif /* USE_ODBX */
#ifdef USE_LDAP
                                     "\tldapscheme://host[:port][/dn[?attrs[?scope[?filter[?exts]]]]]\n"
#endif /* USE_LDAP */
#ifdef USE_LUA
                                     "\tlua:path\n"
#endif /* USE_LUA */
#ifdef USE_LIBMEMCACHED
                                     "\tmemcache:host[:port][,...]/prefix\n"
#endif /* USE_LIBMEMCACHED */
#ifdef _FFR_REPUTATION
                                     "\trepute:server[:reporter]\n"
#endif /* _FFR_REPUTATION */
#ifdef _FFR_SOCKETDB
                                     "\tsocket:{ port@host | path}\n"
#endif /* _FFR_SOCKETDB */
#ifdef USE_MDB
                                     "\tmdb:path\n"
#endif /* USE_MDB */
#ifdef USE_ERLANG
                                   "\terlang:node@host[,...]:cookie:module:function\n"
#endif /* USE_ERLANG */
                                     "> ");
              }

              memset(dbname, '\0', sizeof dbname);
              if (fgets(dbname, BUFRSZ, stdin) != dbname)
              {
                     fprintf(stderr, "%s: fgets(): %s\n", progname,
                             strerror(errno));
                     return EX_OSERR;
              }

              p = strchr(dbname, '\n');
              if (p != NULL)
                     *p = '\0';

              for (p = dbname; isspace(*p); p++)
                     continue;
              if (p != dbname)
                     memmove(dbname, p, strlen(p) + 1);

              p = NULL;
              status = dkimf_db_open(&dbtest, dbname,
                                     (DKIMF_DB_FLAG_READONLY |
                                      DKIMF_DB_FLAG_ASCIIONLY),
                                     NULL, &p);
              if (status != 0)
              {
                     fprintf(stderr, "%s: %s: dkimf_db_open(): %s\n",
                             progname, dbname, p);
                     return EX_SOFTWARE;
              }

              for (;;)
              {
                     if (isatty(0))
                     {
                            fprintf(stdout,
                                    "%s: enter 'query/n' where 'n' is number of fields to request\n> ",
                                    progname);
                     }

                     memset(query, '\0', sizeof query);
                     if (fgets(query, BUFRSZ, stdin) != query)
                            break;

                     p = strchr(query, '\n');
                     if (p != NULL)
                            *p = '\0';

                     if (dkimf_isblank(query))
                            continue;

                     p = strchr(query, '/');
                     if (p == NULL)
                     {
                            (void) dkimf_db_close(dbtest);
                            fprintf(stderr, "%s: invalid query '%s'\n",
                                    progname, query);
                            return EX_USAGE;
                     }

                     n = atoi(p + 1);
                     if (n < 0)
                     {
                            (void) dkimf_db_close(dbtest);
                            fprintf(stderr, "%s: invalid query '%s'\n",
                                    progname, query);
                            return EX_USAGE;
                     }
       
                     result = (char **) malloc(sizeof(char *) * n);
                     if (result == NULL)
                     {
                            fprintf(stderr, "%s: malloc(): %s\n", progname,
                                    strerror(errno));
                            return EX_OSERR;
                     }

                     for (c = 0; c < n; c++)
                     {
                            result[c] = (char *) malloc(BUFRSZ + 1);
                            if (result[c] == NULL)
                            {
                                   fprintf(stderr, "%s: malloc(): %s\n",
                                           progname, strerror(errno));
                                   free(result);
                                   return EX_OSERR;
                            }
                            memset(result[c], '\0', BUFRSZ + 1);
                     }

                     dbdp = (DKIMF_DBDATA) malloc(sizeof(struct dkimf_db_data) * n);
                     if (dbdp == NULL)
                     {
                            fprintf(stderr, "%s: malloc(): %s\n", progname,
                                    strerror(errno));
                            free(result);
                            return EX_OSERR;
                     }

                     for (c = 0; c < n; c++)
                     {
                            dbdp[c].dbdata_buffer = result[c];
                            dbdp[c].dbdata_buflen = BUFRSZ;
                            dbdp[c].dbdata_flags = 0;
                     }

                     *p = '\0';

                     status = dkimf_db_get(dbtest, query, strlen(query),
                                           dbdp, n, &exists);

                     if (status != 0)
                     {
                            char errbuf[BUFRSZ + 1];

                            memset(errbuf, '\0', sizeof errbuf);

                            dkimf_db_strerror(dbtest, errbuf,
                                              sizeof errbuf);

                            fprintf(stderr,
                                    "%s: dkimf_db_get() returned %d: \"%s\"\n",
                                    progname, status, errbuf);
                     }
                     else if (!exists)
                     {
                            fprintf(stdout,
                                    "%s: dkimf_db_get(): record not found\n",
                                    progname);
                     }
                     else
                     {
                            for (c = 0; c < n; c++)
                            {
                                   if (dbdp[c].dbdata_buflen == 0)
                                          fprintf(stdout, "<empty>\n");
                                   else if (dbdp[c].dbdata_buflen == (size_t) -1)
                                          fprintf(stdout, "<absent>\n");
                                   else
                                          fprintf(stdout, "'%s'\n", result[c]);
                            }
                     }

                     for (c = 0; c < n; c++)
                            free(result[c]);
                     free(result);
                     free(dbdp);
              }

              fprintf(stdout, "\n");

              dkimf_db_close(dbtest);

              return 0;
       }

       if (testmode && curconf->conf_modestr == NULL)
              curconf->conf_mode = DKIMF_MODE_VERIFIER;

       /*
       **  Use values found in the configuration file, if any.  Note that
       **  these are operational parameters for the filter (e.g which socket
       **  to use which userid to become, etc.) and aren't reloaded upon a
       **  reload signal.  Reloadable values are handled via the
       **  dkimf_config_load() function, which has already been called.
       */

       if (cfg != NULL)
       {
              if (!autorestart)
              {
                     (void) config_get(cfg, "AutoRestart", &autorestart,
                                       sizeof autorestart);
              }

              if (autorestart)
              {
                     char *rate = NULL;

                     (void) config_get(cfg, "AutoRestartCount",
                                       &maxrestarts, sizeof maxrestarts);

                     (void) config_get(cfg, "AutoRestartRate", &rate,
                                       sizeof rate);

                     if (rate != NULL)
                     {
                            time_t t;
                            char *q;

                            p = strchr(rate, '/');
                            if (p == NULL)
                            {
                                   fprintf(stderr,
                                           "%s: AutoRestartRate invalid\n",
                                           progname);
                                   config_free(cfg);
                                   return EX_CONFIG;
                            }

                            *p = '\0';
                            n = strtol(rate, &q, 10);
                            if (n < 0 || *q != '\0')
                            {
                                   fprintf(stderr,
                                           "%s: AutoRestartRate invalid\n",
                                           progname);
                                   config_free(cfg);
                                   return EX_CONFIG;
                            }

                            t = (time_t) strtoul(p + 1, &q, 10);
                            switch (*q)
                            {
                              case 'd':
                              case 'D':
                                   t *= 86400;
                                   break;

                              case 'h':
                              case 'H':
                                   t *= 3600;
                                   break;

                              case 'm':
                              case 'M':
                                   t *= 60;
                                   break;

                              case '\0':
                              case 's':
                              case 'S':
                                   break;

                              default:
                                   t = 0;
                                   break;
                            }

                            if (*q != '\0' && *(q + 1) != '\0')
                                   t = 0;

                            if (t == 0)
                            {
                                   fprintf(stderr,
                                           "%s: AutoRestartRate invalid\n",
                                           progname);
                                   config_free(cfg);
                                   return EX_CONFIG;
                            }

                            maxrestartrate_n = n;
                            maxrestartrate_t = t;
                     }
              }

              if (dofork)
              {
                     (void) config_get(cfg, "Background", &dofork,
                                       sizeof dofork);
              }

              (void) config_get(cfg, "TestPublicKeys",
                                &testpubkeys, sizeof testpubkeys);

              (void) config_get(cfg, "StrictTestMode", &stricttest,
                                sizeof stricttest);

              (void) config_get(cfg, "MilterDebug", &mdebug, sizeof mdebug);

              if (!quarantine)
              {
                     (void) config_get(cfg, "Quarantine", &quarantine,
                                       sizeof quarantine);
              }

              if (!gotp)
              {
                     (void) config_get(cfg, "Socket", &sock, sizeof sock);
                     if (sock != NULL)
                     {
                            gotp = TRUE;
                            (void) smfi_setconn(sock);
                     }
              }

              if (pidfile == NULL)
              {
                     (void) config_get(cfg, "PidFile", &pidfile,
                                       sizeof pidfile);
              }

#ifdef QUERY_CACHE
              (void) config_get(cfg, "QueryCache", &querycache,
                                sizeof querycache);
#endif /* QUERY_CACHE */

              (void) config_get(cfg, "UMask", &filemask, sizeof filemask);

              if (become == NULL)
              {
                     (void) config_get(cfg, "Userid", &become,
                                       sizeof become);
              }

#ifdef POPAUTH
              if (popdbfile == NULL)
              {
                     (void) config_get(cfg, "POPDBFile", &popdbfile,
                                       sizeof popdbfile);
              }
#endif /* POPAUTH */

              (void) config_get(cfg, "ChangeRootDirectory", &chrootdir,
                                sizeof chrootdir);
       }

#ifndef SMFIF_QUARANTINE
       if (quarantine)
       {
              fprintf(stderr, "%s: quarantine service not available\n",
                      progname);
              return EX_SOFTWARE;
       }
#endif /* ! SMFIF_QUARANTINE */

       if (!gotp && !testmode)
       {
              fprintf(stderr, "%s: milter socket must be specified\n",
                      progname);
              if (argc == 1)
                     fprintf(stderr, "\t(use \"-?\" for help)\n");
              return EX_CONFIG;
       }

       /* suppress a bunch of things if we're in test mode */
       if (testmode)
       {
              curconf->conf_dolog = FALSE;
              curconf->conf_sendreports = FALSE;
              curconf->conf_sendadspreports = FALSE;
              autorestart = FALSE;
              dofork = FALSE;
              become = NULL;
              pidfile = NULL;
              chrootdir = NULL;
       }

       dkimf_setmaxfd();

       /* prepare to change user if appropriate */
       if (become != NULL)
       {
              char *colon;

              /* see if there was a group specified; if so, validate */
              colon = strchr(become, ':');
              if (colon != NULL)
              {
                     *colon = '\0';

                     gr = getgrnam(colon + 1);
                     if (gr == NULL)
                     {
                            char *q;

                            gid = (gid_t) strtol(colon + 1, &q, 10);
                            if (*q == '\0')
                                   gr = getgrgid(gid);

                            if (gr == NULL)
                            {
                                   if (curconf->conf_dolog)
                                   {
                                          syslog(LOG_ERR,
                                                 "no such group or gid '%s'",
                                                 colon + 1);
                                   }

                                   fprintf(stderr,
                                           "%s: no such group '%s'\n",
                                           progname, colon + 1);

                                   return EX_DATAERR;
                            }
                     }
              }

              /* validate the user */
              pw = getpwnam(become);
              if (pw == NULL)
              {
                     char *q;
                     uid_t uid;

                     uid = (uid_t) strtoul(become, &q, 10);
                     if (*q == '\0')
                            pw = getpwuid(uid);

                     if (pw == NULL)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "no such user or uid '%s'",
                                          become);
                            }

                            fprintf(stderr, "%s: no such user '%s'\n",
                                    progname, become);

                            return EX_DATAERR;
                     }
              }

              if (gr == NULL)
                     gid = pw->pw_gid;
              else
                     gid = gr->gr_gid;

#ifdef _FFR_REPUTATION
              /* chown things that need chowning */
              if (curconf->conf_rep != NULL)
              {
                     (void) dkimf_rep_chown_cache(curconf->conf_rep,
                                                  pw->pw_uid);
              }
#endif /* _FFR_REPUTATION */
       }

       /* change root if requested */
       if (chrootdir != NULL)
       {
              /* warn if doing so as root without then giving up root */
              if (become == NULL && getuid() == 0)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_WARNING,
                                   "using ChangeRootDirectory without Userid not advised");
                     }

                     fprintf(stderr,
                             "%s: use of ChangeRootDirectory without Userid not advised\n",
                             progname);
              }

              /* change to the new root first */
              if (chdir(chrootdir) != 0)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "%s: chdir(): %s",
                                   chrootdir, strerror(errno));
                     }

                     fprintf(stderr, "%s: %s: chdir(): %s\n", progname,
                             chrootdir, strerror(errno));
                     return EX_OSERR;
              }

              /* now change the root */
              if (chroot(chrootdir) != 0)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "%s: chroot(): %s",
                                   chrootdir, strerror(errno));
                     }

                     fprintf(stderr, "%s: %s: chroot(): %s\n", progname,
                             chrootdir, strerror(errno));
                     return EX_OSERR;
              }
       }

       /* now enact the user change */
       if (become != NULL)
       {
              /* make all the process changes */
              if (getuid() != pw->pw_uid)
              {
                     if (initgroups(pw->pw_name, gid) != 0)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR, "initgroups(): %s",
                                          strerror(errno));
                            }

                            fprintf(stderr, "%s: initgroups(): %s\n",
                                    progname, strerror(errno));

                            return EX_NOPERM;
                     }
                     else if (setgid(gid) != 0)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR, "setgid(): %s",
                                          strerror(errno));
                            }

                            fprintf(stderr, "%s: setgid(): %s\n", progname,
                                    strerror(errno));

                            return EX_NOPERM;
                     }
                     else if (setuid(pw->pw_uid) != 0)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR, "setuid(): %s",
                                          strerror(errno));
                            }

                            fprintf(stderr, "%s: setuid(): %s\n", progname,
                                    strerror(errno));

                            return EX_NOPERM;
                     }
              }

              (void) endpwent();
       }

       if (curconf->conf_enablecores)
       {
              _Bool enabled = FALSE;

#ifdef __linux__
              if (prctl(PR_SET_DUMPABLE, 1) == -1)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "prctl(): %s",
                                   strerror(errno));
                     }

                     fprintf(stderr, "%s: prctl(): %s\n",
                             progname, strerror(errno));
              }
              else
              {
                     enabled = TRUE;
              }
#endif /* __linux__ */

              if (!enabled)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_WARNING,
                                   "can't enable coredumps; continuing");
                     }

                     fprintf(stderr,
                             "%s: can't enable coredumps; continuing\n",
                             progname);
              }
       }

       die = FALSE;

       /* initialize DKIM library */
       if (!dkimf_config_setlib(curconf, &p))
       {
              fprintf(stderr, "%s: can't configure DKIM library: %s\n",
                      progname, p);
              return EX_SOFTWARE;
       }

       if (autorestart)
       {
              _Bool quitloop = FALSE;
              int restarts = 0;
              int status;
              pid_t pid;
              pid_t wpid;
              struct sigaction sa;

              if (dofork)
              {
                     pid = fork();
                     switch (pid)
                     {
                       case -1:
                            if (curconf->conf_dolog)
                            {
                                   int saveerrno;

                                   saveerrno = errno;

                                   syslog(LOG_ERR, "fork(): %s",
                                          strerror(errno));

                                   errno = saveerrno;
                            }

                            fprintf(stderr, "%s: fork(): %s\n",
                                    progname, strerror(errno));

                            dkimf_zapkey(curconf);
                            return EX_OSERR;

                       case 0:
                            dkimf_stdio();
                            break;

                       default:
                            dkimf_zapkey(curconf);
                            return EX_OK;
                     }
              }

              if (pidfile != NULL)
              {
                     f = fopen(pidfile, "w");
                     if (f != NULL)
                     {
                            fprintf(f, "%ld\n", (long) getpid());
                            (void) fclose(f);
                     }
                     else
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "can't write pid to %s: %s",
                                          pidfile, strerror(errno));
                            }
                     }
              }

              sa.sa_handler = dkimf_sighandler;
              /* XXX -- HAHAHAH => sa.sa_sigaction = NULL; */
              sigemptyset(&sa.sa_mask);
              sigaddset(&sa.sa_mask, SIGHUP);
              sigaddset(&sa.sa_mask, SIGINT);
              sigaddset(&sa.sa_mask, SIGTERM);
              sigaddset(&sa.sa_mask, SIGUSR1);
              sa.sa_flags = 0;

              if (sigaction(SIGHUP, &sa, NULL) != 0 ||
                  sigaction(SIGINT, &sa, NULL) != 0 ||
                  sigaction(SIGTERM, &sa, NULL) != 0 ||
                  sigaction(SIGUSR1, &sa, NULL) != 0)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "[parent] sigaction(): %s",
                                   strerror(errno));
                     }
              }

              if (maxrestartrate_n > 0)
                     dkimf_restart_check(maxrestartrate_n, 0);

              while (!quitloop)
              {
                     status = dkimf_socket_cleanup(sock);
                     if (status != 0)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "[parent] socket cleanup failed: %s",
                                          strerror(status));
                            }
                            return EX_UNAVAILABLE;
                     }

                     pid = fork();
                     switch (pid)
                     {
                       case -1:
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR, "fork(): %s",
                                          strerror(errno));
                            }

                            dkimf_zapkey(curconf);
                            return EX_OSERR;

                       case 0:
                            sa.sa_handler = SIG_DFL;

                            if (sigaction(SIGHUP, &sa, NULL) != 0 ||
                                sigaction(SIGINT, &sa, NULL) != 0 ||
                                sigaction(SIGTERM, &sa, NULL) != 0)
                            {
                                   if (curconf->conf_dolog)
                                   {
                                          syslog(LOG_ERR,
                                                 "[child] sigaction(): %s",
                                                 strerror(errno));
                                   }
                            }

                            quitloop = TRUE;
                            break;

                       default:
                            for (;;)
                            {
                                   wpid = wait(&status);

                                   if (wpid == -1 && errno == EINTR)
                                   {
                                          if (die)
                                          {
                                                 dkimf_killchild(pid,
                                                                 diesig,
                                                                 curconf->conf_dolog);
                                                 dkimf_zapkey(curconf);

                                                 while (wpid != pid)
                                                        wpid = wait(&status);

                                                 if (pidfile != NULL)
                                                        (void) unlink(pidfile);

                                                 exit(EX_OK);
                                          }
                                          else if (reload)
                                          {
                                                 dkimf_killchild(pid,
                                                                 SIGUSR1,
                                                                 curconf->conf_dolog);

                                                 reload = FALSE;

                                                 continue;
                                          }
                                   }

                                   if (pid != wpid)
                                          continue;

                                   if (wpid != -1 && curconf->conf_dolog)
                                   {
                                          if (WIFSIGNALED(status))
                                          {
                                                 syslog(LOG_NOTICE,
                                                        "terminated with signal %d, restarting",
                                                        WTERMSIG(status));
                                          }
                                          else if (WIFEXITED(status))
                                          {
                                                 if (WEXITSTATUS(status) == EX_CONFIG ||
                                                     WEXITSTATUS(status) == EX_SOFTWARE)
                                                 {
                                                        syslog(LOG_NOTICE,
                                                               "exited with status %d",
                                                               WEXITSTATUS(status));
                                                        quitloop = TRUE;
                                                 }
                                                 else
                                                 {
                                                        syslog(LOG_NOTICE,
                                                               "exited with status %d, restarting",
                                                               WEXITSTATUS(status));
                                                 }
                                          }
                                   }

                                   if (conffile != NULL)
                                          reload = TRUE;

                                   break;
                            }
                            break;
                     }

                     if (maxrestarts > 0 && restarts >= maxrestarts)
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "maximum restart count exceeded");
                            }

                            return EX_UNAVAILABLE;
                     }

                     if (maxrestartrate_n > 0 &&
                         maxrestartrate_t > 0 &&
                         !dkimf_restart_check(0, maxrestartrate_t))
                     {
                            if (curconf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "maximum restart rate exceeded");
                            }

                            return EX_UNAVAILABLE;
                     }

                     restarts++;
              }
       }

       if (filemask != -1)
              (void) umask((mode_t) filemask);

       if (mdebug > 0)
              (void) smfi_setdbg(mdebug);

       if (!testmode)
       {
              /* try to clean up the socket */
              status = dkimf_socket_cleanup(sock);
              if (status != 0)
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "socket cleanup failed: %s",
                                   strerror(status));
                     }

                     fprintf(stderr, "%s: socket cleanup failed: %s\n",
                             progname, strerror(status));

                     dkimf_zapkey(curconf);

                     if (!autorestart && pidfile != NULL)
                            (void) unlink(pidfile);

                     return EX_UNAVAILABLE;
              }

              smfilter.xxfi_flags = SMFIF_ADDHDRS;
#ifdef SMFIF_SETSYMLIST
              smfilter.xxfi_flags |= SMFIF_SETSYMLIST;
#endif /* SMFIF_SETSYMLIST */
              if (curconf->conf_remarall ||
                  !curconf->conf_keepar ||
#ifdef _FFR_IDENTITY_HEADER
                  curconf->conf_rmidentityhdr ||
#endif /* _FFR_IDENTITY_HEADER */
#ifdef _FFR_VBR
                  curconf->conf_vbr_purge ||
#endif /* _FFR_VBR */
                  curconf->conf_remsigs)
                     smfilter.xxfi_flags |= SMFIF_CHGHDRS;
#ifdef SMFIF_QUARANTINE
              if (quarantine || curconf->conf_capture)
                     smfilter.xxfi_flags |= SMFIF_QUARANTINE;
#endif /* SMFIF_QUARANTINE */

              /* register with the milter interface */
              if (smfi_register(smfilter) == MI_FAILURE)
              {
                     if (curconf->conf_dolog)
                            syslog(LOG_ERR, "smfi_register() failed");

                     fprintf(stderr, "%s: smfi_register() failed\n",
                             progname);

                     dkimf_zapkey(curconf);

                     if (!autorestart && pidfile != NULL)
                            (void) unlink(pidfile);

                     return EX_UNAVAILABLE;
              }

#ifdef HAVE_SMFI_OPENSOCKET
              /* try to establish the milter socket */
              if (smfi_opensocket(FALSE) == MI_FAILURE)
              {
                     if (curconf->conf_dolog)
                            syslog(LOG_ERR, "smfi_opensocket() failed");

                     fprintf(stderr, "%s: smfi_opensocket() failed\n",
                             progname);

                     dkimf_zapkey(curconf);

                     return EX_UNAVAILABLE;
              }
#endif /* HAVE_SMFI_OPENSOCKET */
       }

       if (!autorestart && dofork)
       {
              pid_t pid;

              pid = fork();
              switch (pid)
              {
                case -1:
                     if (curconf->conf_dolog)
                     {
                            int saveerrno;

                            saveerrno = errno;

                            syslog(LOG_ERR, "fork(): %s", strerror(errno));

                            errno = saveerrno;
                     }

                     fprintf(stderr, "%s: fork(): %s\n", progname,
                             strerror(errno));

                     dkimf_zapkey(curconf);

                     return EX_OSERR;

                case 0:
                     dkimf_stdio();
                     break;

                default:
                     dkimf_zapkey(curconf);
                     return EX_OK;
              }
       }

       /* write out the pid */
       if (!autorestart && pidfile != NULL)
       {
              f = fopen(pidfile, "w");
              if (f != NULL)
              {
                     fprintf(f, "%ld\n", (long) getpid());
                     (void) fclose(f);
              }
              else
              {
                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "can't write pid to %s: %s",
                                   pidfile, strerror(errno));
                     }
              }
       }

       /*
       **  Block SIGUSR1 for use of our reload thread, and SIGHUP, SIGINT
       **  and SIGTERM for use of libmilter's signal handling thread.
       */

       sigemptyset(&sigset);
       sigaddset(&sigset, SIGUSR1);
       sigaddset(&sigset, SIGHUP);
       sigaddset(&sigset, SIGTERM);
       sigaddset(&sigset, SIGINT);
       status = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
       if (status != 0)
       {
              if (curconf->conf_dolog)
              {
                     syslog(LOG_ERR, "pthread_sigprocmask(): %s",
                            strerror(status));
              }

              fprintf(stderr, "%s: pthread_sigprocmask(): %s\n", progname,
                      strerror(status));

              dkimf_zapkey(curconf);

              return EX_OSERR;
       }

       /* initialize libcrypto mutexes */
       status = dkimf_crypto_init();
       if (status != 0)
       {
              fprintf(stderr, "%s: error initializing crypto library: %s\n",
                      progname, strerror(status));
       }

       if ((curconf->conf_mode & DKIMF_MODE_VERIFIER) != 0 &&
           !dkim_libfeature(curconf->conf_libopendkim, DKIM_FEATURE_SHA256))
       {
              if (curconf->conf_allowsha1only)
              {
                     if (dolog)
                     {
                            syslog(LOG_WARNING,
                                   "WARNING: verifier mode operating without rsa-sha256 support");
                     }
              }
              else
              {
                     if (dolog)
                     {
                            syslog(LOG_ERR,
                                   "verifier mode operating without rsa-sha256 support; terminating");
                     }

                     fprintf(stderr,
                             "%s: verify mode requires rsa-sha256 support\n",
                             progname);

                     if (!autorestart && pidfile != NULL)
                            (void) unlink(pidfile);

                     return EX_CONFIG;
              }
       }

       /* set up for test mode if selected */
       if (testpubkeys != NULL)
       {
              dkim_query_t qtype = DKIM_QUERY_FILE;

              (void) dkim_options(curconf->conf_libopendkim, DKIM_OP_SETOPT,
                                  DKIM_OPTS_QUERYMETHOD,
                                  &qtype, sizeof qtype);
              (void) dkim_options(curconf->conf_libopendkim, DKIM_OP_SETOPT,
                                  DKIM_OPTS_QUERYINFO,
                                  testpubkeys, strlen(testpubkeys));
       }

       pthread_mutex_init(&conf_lock, NULL);

       /* perform test mode */
       if (testfile != NULL)
       {
              status = dkimf_testfiles(curconf->conf_libopendkim, testfile,
                                       fixedtime, stricttest, verbose);
              dkim_close(curconf->conf_libopendkim);
              return status;
       }

       memset(argstr, '\0', sizeof argstr);
       end = &argstr[sizeof argstr - 1];
       n = sizeof argstr;
       for (c = 1, p = argstr; c < argc && p < end; c++)
       {
              if (strchr(argv[c], ' ') != NULL)
              {
                     status = snprintf(p, n, "%s \"%s\"",
                                       c == 1 ? "args:" : "",
                                       argv[c]);
              }
              else
              {
                     status = snprintf(p, n, "%s %s",
                                       c == 1 ? "args:" : "",
                                       argv[c]);
              }

              p += status;
              n -= status;
       }

#ifdef POPAUTH
       if (popdbfile != NULL)
       {
              char *err = NULL;

              status = dkimf_initpopauth();
              if (status != 0)
              {
                     fprintf(stderr,
                             "%s: can't initialize popauth mutex: %s\n",
                             progname, strerror(status));
                     syslog(LOG_ERR, "can't initialize mutex: %s",
                            popdbfile);
              }

              status = dkimf_db_open(&popdb, popdbfile,
                                     DKIMF_DB_FLAG_READONLY, NULL, &err);
              if (status != 0)
              {
                     fprintf(stderr, "%s: can't open database %s: %s\n",
                             progname, popdbfile, err);

                     if (dolog)
                     {
                            syslog(LOG_ERR, "can't open database %s: %s",
                                   popdbfile, err);
                     }

                     dkimf_zapkey(curconf);

                     if (!autorestart && pidfile != NULL)
                            (void) unlink(pidfile);

                     return EX_UNAVAILABLE;
              }
       }
#endif /* POPAUTH */

#ifdef _FFR_STATS
       dkimf_stats_init();
#endif /* _FFR_STATS */

#ifdef _FFR_REPUTATION
       repute_init();
#endif /* _FFR_REPUTATION */

       if (curconf->conf_dolog)
       {
              syslog(LOG_INFO, "%s v%s starting (%s)", DKIMF_PRODUCT,
                     VERSION, argstr);
       }

       /* spawn the SIGUSR1 handler */
       status = pthread_create(&rt, NULL, dkimf_reloader, NULL);
       if (status != 0)
       {
              if (curconf->conf_dolog)
              {
                     syslog(LOG_ERR, "pthread_create(): %s",
                            strerror(status));

                     if (!autorestart && pidfile != NULL)
                            (void) unlink(pidfile);

                     return EX_OSERR;
              }
       }

       /* call the milter mainline */
       errno = 0;
       status = smfi_main();

       if (curconf->conf_dolog)
       {
              syslog(LOG_INFO,
                     "%s v%s terminating with status %d, errno = %d",
                     DKIMF_PRODUCT, VERSION, status, errno);
       }

#ifdef POPAUTH
       if (popdb != NULL)
              dkimf_db_close(popdb);
#endif /* POPAUTH */

       dkimf_zapkey(curconf);

       /* tell the reloader thread to die */
       die = TRUE;
       (void) raise(SIGUSR1);

       if (!autorestart && pidfile != NULL)
              (void) unlink(pidfile);

       dkimf_crypto_free();

       return status;
}

Here is the call graph for this function:

sfsistat mlfi_abort ( SMFICTX *  ctx)

Definition at line 15441 of file opendkim.c.

{
       dkimf_cleanup(ctx);
       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

sfsistat mlfi_body ( SMFICTX *  ctx,
u_char *  bodyp,
size_t  bodylen 
)

Definition at line 12910 of file opendkim.c.

{
       int status;
       DKIM *last;
       msgctx dfc;
       connctx cc;
       struct dkimf_config *conf;

       assert(ctx != NULL);
       assert(bodyp != NULL);

       cc = (connctx) dkimf_getpriv(ctx);
       assert(cc != NULL);
       conf = cc->cctx_config;
       dfc = cc->cctx_msg;
       assert(dfc != NULL);

       /*
       **  No need to do anything if the body was empty.
       */

       if (bodylen == 0)
              return SMFIS_CONTINUE;

#ifdef _FFR_REPUTATION
       SHA1_Update(&dfc->mctx_hash, bodyp, bodylen);
#endif /* _FFR_REPUTATION */

       /*
       **  Tell the filter to skip it if we don't care about the body.
       */

       if (dfc->mctx_headeronly)
       {
#ifdef SMFIS_SKIP
              if (cc->cctx_milterv2)
                     return SMFIS_SKIP;
              else
                     return SMFIS_CONTINUE;
#else /* SMFIS_SKIP */
                     return SMFIS_CONTINUE;
#endif /* SMFIS_SKIP */
       }

       last = NULL;
       status = DKIM_STAT_OK;
#ifdef _FFR_RESIGN
       if (dfc->mctx_srhead != NULL &&
           (!dfc->mctx_resign || dfc->mctx_dkimv == NULL))
#else /* _FFR_RESIGN */
       if (dfc->mctx_srhead != NULL)
#endif /* _FFR_RESIGN */
       {
              status = dkimf_msr_body(dfc->mctx_srhead, &last,
                                      bodyp, bodylen);
       }
       if (status == DKIM_STAT_OK && dfc->mctx_dkimv != NULL)
       {
              last = dfc->mctx_dkimv;
              status = dkim_body(dfc->mctx_dkimv, bodyp, bodylen);
       }

       if (status != DKIM_STAT_OK)
              return dkimf_libstatus(ctx, last, "dkim_body()", status);

#ifdef SMFIS_SKIP
       if (dfc->mctx_srhead != NULL && cc->cctx_milterv2 &&
           dkimf_msr_minbody(dfc->mctx_srhead) == 0)
                     return SMFIS_SKIP;

       if (dfc->mctx_dkimv != NULL && cc->cctx_milterv2 &&
           dkim_minbody(dfc->mctx_dkimv) == 0)
                     return SMFIS_SKIP;
#endif /* SMFIS_SKIP */

       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat mlfi_close ( SMFICTX *  ctx)

Definition at line 15458 of file opendkim.c.

{
       connctx cc;

       dkimf_cleanup(ctx);

       cc = (connctx) dkimf_getpriv(ctx);
       if (cc != NULL)
       {
              pthread_mutex_lock(&conf_lock);

              cc->cctx_config->conf_refcnt--;

              if (cc->cctx_config->conf_refcnt == 0 &&
                  cc->cctx_config != curconf)
                     dkimf_config_free(cc->cctx_config);

              pthread_mutex_unlock(&conf_lock);

              free(cc);
              dkimf_setpriv(ctx, NULL);
       }

#ifdef QUERY_CACHE
       if (querycache)
       {
              time_t now;

              (void) time(&now);
              if (cache_lastlog + CACHESTATSINT < now)
              {
                     u_int c_hits;
                     u_int c_queries;
                     u_int c_expired;

                     dkim_getcachestats(&c_queries, &c_hits, &c_expired);

                     cache_lastlog = now;

                     syslog(LOG_INFO,
                            "cache: %u quer%s, %u hit%s (%d%%), %u expired",
                            c_queries, c_queries == 1 ? "y" : "ies",
                            c_hits, c_hits == 1 ? "" : "s",
                            (c_hits * 100) / c_queries,
                            c_expired);
              }
       }
#endif /* QUERY_CACHE */

       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat mlfi_connect ( SMFICTX *  ctx,
char *  host,
_SOCK_ADDR *  ip 
)

Definition at line 10748 of file opendkim.c.

{
       connctx cc;
       struct dkimf_config *conf;

       dkimf_config_reload();

       /* copy hostname and IP information to a connection context */
       cc = dkimf_getpriv(ctx);
       if (cc == NULL)
       {
              cc = malloc(sizeof(struct connctx));
              if (cc == NULL)
              {
                     pthread_mutex_lock(&conf_lock);

                     if (curconf->conf_dolog)
                     {
                            syslog(LOG_ERR, "%s malloc(): %s", host,
                                   strerror(errno));
                     }

                     pthread_mutex_unlock(&conf_lock);

                     /* XXX result should depend on On-InternalError */
                     return SMFIS_TEMPFAIL;
              }

              memset(cc, '\0', sizeof(struct connctx));

              pthread_mutex_lock(&conf_lock);

              cc->cctx_config = curconf;
              curconf->conf_refcnt++;

              conf = curconf;

              pthread_mutex_unlock(&conf_lock);

              dkimf_setpriv(ctx, cc);
       }
       else
       {
              conf = cc->cctx_config;
       }

       /* if the client is on an ignored host, then ignore it */
       if (conf->conf_peerdb != NULL)
       {
              /* try hostname, if available */
              if (host != NULL && host[0] != '\0' && host[0] != '[')
              {
                     dkimf_lowercase((u_char *) host);
                     if (dkimf_checkhost(conf->conf_peerdb, host))
                            return SMFIS_ACCEPT;
              }

              /* try IP address, if available */
              if (ip != NULL && (ip->sa_family == AF_INET
#ifdef AF_INET6
                     || ip->sa_family == AF_INET6
#endif /* AF_INET6 */
                     ))
              {
                     if (dkimf_checkip(conf->conf_peerdb, ip))
                            return SMFIS_ACCEPT;
              }
       }

       if (host != NULL)
              strlcpy(cc->cctx_host, host, sizeof cc->cctx_host);

       if (ip == NULL)
       {
              struct sockaddr_in sin;

              memset(&sin, '\0', sizeof sin);
              sin.sin_family = AF_INET;
              sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

              memcpy(&cc->cctx_ip, &sin, sizeof sin);
       }
       else if (ip->sa_family == AF_INET)
       {
              memcpy(&cc->cctx_ip, ip, sizeof(struct sockaddr_in));
       }
#ifdef AF_INET6
       else if (ip->sa_family == AF_INET6)
       {
              memcpy(&cc->cctx_ip, ip, sizeof(struct sockaddr_in6));
       }
#endif /* AF_INET6 */

       cc->cctx_msg = NULL;

       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat mlfi_envfrom ( SMFICTX *  ctx,
char **  envfrom 
)

Definition at line 10880 of file opendkim.c.

{
       connctx cc;
       msgctx dfc;
       struct dkimf_config *conf;

       assert(ctx != NULL);
       assert(envfrom != NULL);

       cc = (connctx) dkimf_getpriv(ctx);
       assert(cc != NULL);
       conf = cc->cctx_config;

       /*
       **  Initialize a filter context.
       */

       dkimf_cleanup(ctx);
       dfc = dkimf_initcontext(conf);
       if (dfc == NULL)
       {
              if (conf->conf_dolog)
              {
                     syslog(LOG_INFO,
                            "message requeueing (internal error)");
              }

              dkimf_cleanup(ctx);
              return SMFIS_TEMPFAIL;
       }

       if (envfrom[0] != NULL)
       {
              size_t len;
              unsigned char *p;
              unsigned char *q;

              strlcpy(dfc->mctx_envfrom, envfrom[0],
                      sizeof dfc->mctx_envfrom);

              len = strlen(dfc->mctx_envfrom);
              p = dfc->mctx_envfrom;
              q = dfc->mctx_envfrom + len - 1;

              while (len >= 2 && *p == '<' && *q == '>')
              {
                     p++;
                     q--;
                     len -= 2;
              }

              if (p != dfc->mctx_envfrom)
              {
                     *(q + 1) = '\0';
                     memmove(dfc->mctx_envfrom, p, len + 1);
              }
       }

       /*
       **  Save it in this thread's private space.
       */

       cc->cctx_msg = dfc;

       /*
       **  Continue processing.
       */

       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat mlfi_envrcpt ( SMFICTX *  ctx,
char **  envrcpt 
)

Definition at line 10963 of file opendkim.c.

{
       char *copy;
       connctx cc;
       msgctx dfc;
       struct dkimf_config *conf;
       char addr[MAXADDRESS + 1];

       assert(ctx != NULL);
       assert(envrcpt != NULL);

       cc = (connctx) dkimf_getpriv(ctx);
       assert(cc != NULL);
       dfc = cc->cctx_msg;
       assert(dfc != NULL);
       conf = cc->cctx_config;

       if (conf->conf_dontsigntodb != NULL
#ifdef _FFR_ADSP_LISTS
           || conf->conf_nodiscardto != NULL
#endif /* _FFR_ADSP_LISTS */
           || conf->conf_bldb != NULL
#ifdef _FFR_REDIRECT
           || conf->conf_redirect != NULL
#endif /* _FFR_REDIRECT */
#ifdef _FFR_RESIGN
           || conf->conf_resigndb != NULL
#endif /* _FFR_RESIGN */
#ifdef USE_LUA
           || conf->conf_setupscript != NULL
           || conf->conf_screenscript != NULL
           || conf->conf_finalscript != NULL
# ifdef _FFR_STATSEXT
           || conf->conf_statsscript != NULL
# endif /* _FFR_STATSEXT */
#endif /* USE_LUA */
          )
       {
              strlcpy(addr, envrcpt[0], sizeof addr);
              dkimf_stripbrackets(addr);
       }

       if (conf->conf_dontsigntodb != NULL
#ifdef _FFR_ADSP_LISTS
           || conf->conf_nodiscardto != NULL
#endif /* _FFR_ADSP_LISTS */
           || conf->conf_bldb != NULL
#ifdef _FFR_REDIRECT
           || conf->conf_redirect != NULL
#endif /* _FFR_REDIRECT */
#ifdef _FFR_RESIGN
           || conf->conf_resigndb != NULL
#endif /* _FFR_RESIGN */
#ifdef USE_LUA
           || conf->conf_setupscript != NULL
           || conf->conf_screenscript != NULL
           || conf->conf_finalscript != NULL
# ifdef _FFR_STATSEXT
           || conf->conf_statsscript != NULL
# endif /* _FFR_STATSEXT */
#endif /* USE_LUA */
          )
       {
              struct addrlist *a;

              copy = strdup(addr);
              if (copy == NULL)
              {
                     if (conf->conf_dolog)
                     {
                            syslog(LOG_ERR,
                                   "message requeueing (internal error)");
                     }

                     free(copy);
                     dkimf_cleanup(ctx);
                     return SMFIS_TEMPFAIL;
              }

              a = (struct addrlist *) malloc(sizeof(struct addrlist));
              if (a == NULL)
              {
                     if (conf->conf_dolog)
                     {
                            syslog(LOG_ERR,
                                   "message requeueing (internal error)");
                     }

                     free(copy);
                     dkimf_cleanup(ctx);
                     return SMFIS_TEMPFAIL;
              }

              a->a_next = dfc->mctx_rcptlist;
              a->a_addr = copy;

              dfc->mctx_rcptlist = a;
       }

       return SMFIS_CONTINUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

sfsistat mlfi_eoh ( SMFICTX *  ctx)

Definition at line 11372 of file opendkim.c.

{
       char last;
       _Bool setidentity = FALSE;
       _Bool domainok;
       _Bool originok;
       _Bool didfrom = FALSE;
       _Bool msgsigned = FALSE;
       int c;
       DKIM_STAT status;
       sfsistat ms = SMFIS_CONTINUE;
       connctx cc;
       msgctx dfc;
       DKIM *lastdkim;
       char *p;
#ifdef _FFR_SENDER_MACRO
       char *macrosender = NULL;
#endif /* _FFR_SENDER_MACRO */
       u_char *user;
       u_char *domain;
#ifdef _FFR_VBR
       char *vbr_cert = NULL;
       char *vbr_type = NULL;
#endif /* _FFR_VBR */
       struct dkimf_config *conf;
       Header from = NULL;
       Header hdr;
       u_char addr[MAXADDRESS + 1];

       assert(ctx != NULL);

       cc = (connctx) dkimf_getpriv(ctx);
       assert(cc != NULL);
       dfc = cc->cctx_msg;
       assert(dfc != NULL);
       conf = cc->cctx_config;

       /*
       **  Determine the message ID for logging.
       */

       dfc->mctx_jobid = (u_char *) dkimf_getsymval(ctx, "i");
       if (dfc->mctx_jobid == NULL)
              dfc->mctx_jobid = (u_char *) JOBIDUNKNOWN;

       /* find the Sender: or From: header */
       memset(addr, '\0', sizeof addr);

#ifdef _FFR_SENDER_MACRO
       if (conf->conf_sendermacro != NULL)
       {
              macrosender = dkimf_getsymval(ctx, conf->conf_sendermacro);
              if (macrosender != NULL)
                     strlcpy((char *) addr, macrosender, sizeof addr);
       }
#endif /* _FFR_SENDER_MACRO */

       if (addr[0] == '\0')
       {
              for (c = 0; conf->conf_senderhdrs[c] != NULL; c++)
              {
                     if (strcasecmp("from", conf->conf_senderhdrs[c]) == 0)
                            didfrom = TRUE;

                     from = dkimf_findheader(dfc, conf->conf_senderhdrs[c],
                                             0);
                     if (from != NULL)
                            break;
              }

              if (from == NULL && !didfrom)
                     from = dkimf_findheader(dfc, "from", 0);
       }

       if (from != NULL)
              strlcpy((char *) addr, from->hdr_val, sizeof addr);

       if (addr[0] == '\0')
       {
              if (conf->conf_dolog)
              {
                     syslog(LOG_INFO,
                            "%s: can't determine message sender; accepting",
                            dfc->mctx_jobid);
              }

              dfc->mctx_addheader = TRUE;
              dfc->mctx_headeronly = TRUE;
              dfc->mctx_status = DKIMF_STATUS_BADFORMAT;
              return SMFIS_CONTINUE;
       }

       status = dkim_mail_parse(addr, &user, &domain);

#ifdef _FFR_DEFAULT_SENDER
       if (conf->conf_defsender != NULL &&
           (status != 0 || user == NULL || domain == NULL ||
            user[0] == '\0' || domain[0] == '\0'))
       {
              strlcpy(addr, conf->conf_defsender, sizeof addr);
              status = dkim_mail_parse(addr, &user, &domain);
       }
#endif /* _FFR_DEFAULT_SENDER */

       if ((conf->conf_mode & DKIMF_MODE_SIGNER) != 0 &&
           (status != 0 || user == NULL || domain == NULL ||
            user[0] == '\0' || domain[0] == '\0'))
       {
              if (conf->conf_dolog)
              {
#ifdef _FFR_SENDER_MACRO
                     if (macrosender != NULL)
                     {
                            syslog(LOG_INFO,
                                   "%s: can't parse macro %s header value '%s'",
                                   dfc->mctx_jobid, conf->conf_sendermacro,
                                   macrosender);
                     }
                     else
#endif /* _FFR_SENDER_MACRO */
                     if (from != NULL)
                     {
                            syslog(LOG_INFO,
                                   "%s: can't parse %s: header value '%s'",
                                   dfc->mctx_jobid, from->hdr_hdr,
                                   from->hdr_val);
                     }
#ifdef _FFR_DEFAULT_SENDER
                     else if (conf->conf_defsender != NULL)
                     {
                            syslog(LOG_INFO,
                                   "%s: can't parse default sender value '%s'",
                                   dfc->mctx_jobid, from);
                     }
#endif /* _FFR_DEFAULT_SENDER */
              }

              dfc->mctx_addheader = TRUE;
              dfc->mctx_headeronly = TRUE;
              dfc->mctx_status = DKIMF_STATUS_BADFORMAT;
              return SMFIS_CONTINUE;
       }

       if (domain != NULL)
       {
              strlcpy((char *) dfc->mctx_domain, (char *) domain,
                      sizeof dfc->mctx_domain);
              dkimf_lowercase(dfc->mctx_domain);
       }

       /* if it's exempt, bail out */
       if (conf->conf_exemptdb != NULL && dfc->mctx_domain[0] != '\0')
       {
              _Bool match = FALSE;
              int status;

              status = dkimf_db_get(conf->conf_exemptdb,
                                    dfc->mctx_domain, 0, NULL, 0,
                                    &match);
              if (status != 0)
              {
                     if (dolog)
                     {
                            dkimf_db_error(conf->conf_exemptdb,
                                           (char *) dfc->mctx_domain);
                     }

                     return SMFIS_TEMPFAIL;
              }

              if (match)
              {
                     if (conf->conf_logwhy)
                     {
                            syslog(LOG_INFO,
                                   "%s: domain '%s' exempted, accepting",
                                   dfc->mctx_jobid, dfc->mctx_domain);
                     }

                     dkimf_cleanup(ctx);
                     return SMFIS_ACCEPT;
              }
       }

       /* apply BodyLengthDB if signing */
       if (conf->conf_bldb != NULL && !dfc->mctx_bldbdone)
       {
              struct addrlist *a;

              for (a = dfc->mctx_rcptlist; a != NULL; a = a->a_next)
              {
                     if (dkimf_checkbldb(conf->conf_bldb, a->a_addr,
                                         dfc->mctx_jobid))
                     {
                            dfc->mctx_ltag = TRUE;
                            dfc->mctx_laddr = a->a_addr;
                            break;
                     }
              }

              dfc->mctx_bldbdone = TRUE;
       }

       /* assume we're not signing */
       dfc->mctx_signalg = DKIM_SIGN_UNKNOWN;
       domainok = FALSE;
       originok = FALSE;
       msgsigned = (dkimf_findheader(dfc, DKIM_SIGNHEADER, 0) != NULL);

#ifdef _FFR_RESIGN
       /* check to see if it's a destination for which we resign */
       if (conf->conf_resigndb != NULL)
       {
              bool match = FALSE;
              char *at;
              char *dot;
              struct addrlist *a;
              char resignkey[BUFRSZ + 1];
              struct dkimf_db_data dbd;

              memset(resignkey, '\0', sizeof resignkey);

              dbd.dbdata_buffer = resignkey;
              dbd.dbdata_buflen = sizeof resignkey;
              dbd.dbdata_flags = 0;

              for (a = dfc->mctx_rcptlist; a != NULL; a = a->a_next)
              {
                     /* full recipient address */
                     if (dkimf_db_get(conf->conf_resigndb, a->a_addr, 0,
                                      &dbd, 1, &match) != 0)
                     {
                            if (dolog)
                            {
                                   dkimf_db_error(conf->conf_resigndb,
                                                  a->a_addr);
                            }
                            continue;
                     }

                     if (match)
                     {
                            domainok = TRUE;
                            originok = TRUE;
                            dfc->mctx_resign = TRUE;
                            break;
                     }

                     /* hostname only */
                     at = strchr(a->a_addr, '@');
                     if (at == NULL)
                            continue;

                     status = dkimf_db_get(conf->conf_resigndb,
                                           at + 1, 0, &dbd, 1,
                                           &match);

                     if (status != 0)
                     {
                            if (dolog)
                            {
                                   dkimf_db_error(conf->conf_resigndb,
                                                  at + 1);
                            }
                            continue;
                     }

                     if (match)
                     {
                            domainok = TRUE;
                            originok = TRUE;
                            dfc->mctx_resign = TRUE;
                            break;
                     }

                     /* iterate through ".domain" possibilities */
                     for (dot = strchr(at, '.');
                          dot != NULL;
                          dot = strchr(dot + 1, '.'))
                     {
                            status = dkimf_db_get(conf->conf_resigndb,
                                                  dot, 0, &dbd, 1,
                                                  &match);
                            if (status != 0)
                            {
                                   if (dolog)
                                   {
                                          dkimf_db_error(conf->conf_resigndb,
                                                          dot);
                                   }

                                   continue;
                            }

                            if (match)
                                   break;
                     }

                     if (match)
                     {
                            domainok = TRUE;
                            originok = TRUE;
                            dfc->mctx_resign = TRUE;
                            break;
                     }
              }

              if (match)
              {
                     if (conf->conf_keytabledb == NULL ||
                         resignkey[0] == '\0')
                     {
                            status = dkimf_add_signrequest(dfc, NULL, NULL,
                                                           NULL,
                                                           (ssize_t) -1);

                            if (status != 0)
                            {
                                   if (dolog)
                                   {
                                          syslog(LOG_ERR,
                                                 "%s: failed to add signature for default key",
                                                 dfc->mctx_jobid);
                                   }

                                   return SMFIS_TEMPFAIL;
                            }
                     }
                     else
                     {
                            status = dkimf_add_signrequest(dfc,
                                                           conf->conf_keytabledb,
                                                           resignkey,
                                                           NULL,
                                                           (ssize_t) -1);

                            if (status != 0)
                            {
                                   if (dolog)
                                   {
                                          syslog(LOG_ERR,
                                                 "%s: failed to add signature for key '%s'",
                                                 dfc->mctx_jobid,
                                                 resignkey);
                                   }

                                   return SMFIS_TEMPFAIL;
                            }
                     }
              }
       }
#endif /* _FFR_RESIGN */

       /* see if it came in on an authorized MSA/MTA connection */
       if (conf->conf_mtasdb != NULL)
       {
              char *mtaname;
              char *host;

              mtaname = dkimf_getsymval(ctx, "{daemon_name}");
              host = dkimf_getsymval(ctx, "j");

              if (mtaname != NULL)
              {
                     status = dkimf_db_get(conf->conf_mtasdb, mtaname, 0,
                                           NULL, 0, &originok);
                     if (status != 0 && dolog)
                            dkimf_db_error(conf->conf_mtasdb, mtaname);
              }

              if (!originok && !status && conf->conf_logwhy)
              {
                     syslog(LOG_INFO,
                            "%s: no MTA name match (host=%s, MTA=%s)",
                            dfc->mctx_jobid, host,
                            mtaname == NULL ? "?" : mtaname);
              }
       }

       /* see if macro tests passed */
       if (conf->conf_macrosdb != NULL)
       {
              _Bool done = FALSE;
              int n;
              char *val;
              char name[BUFRSZ + 1];
              struct dkimf_db_data dbd;

              if (dfc->mctx_tmpstr == NULL)
              {
                     dfc->mctx_tmpstr = dkimf_dstring_new(BUFRSZ, 0);
                     if (dfc->mctx_tmpstr == NULL)
                     {
                            if (conf->conf_dolog)
                            {
                                   syslog(LOG_ERR,
                                          "%s: dkimf_dstring_new() failed",
                                          dfc->mctx_jobid);
                            }

                            dkimf_cleanup(ctx);
                            return SMFIS_TEMPFAIL;
                     }
              }

              for (n = 0; !done && conf->conf_macros[n] != NULL; n++)
              {
                     /* retrieve the macro */
                     snprintf(name, sizeof name, "{%s}",
                              conf->conf_macros[n]);
                     val = dkimf_getsymval(ctx, name);

                     /* short-circuit if the macro's not set */
                     if (val == NULL)
                            continue;

                     memset(&dbd, '\0', sizeof dbd);
                     dbd.dbdata_buffer = val;
                     dbd.dbdata_buflen = strlen(val);
                     dbd.dbdata_flags = 0;

                     status = dkimf_db_get(conf->conf_macrosdb,
                                           conf->conf_macros[n], 0,
                                           &dbd, 1, &originok);
                     if (status != 0 && dolog)
                            dkimf_db_error(conf->conf_macrosdb, name);
              }

              if (!originok && conf->conf_logwhy)
              {
                     syslog(LOG_INFO, "%s: no macros match",
                            dfc->mctx_jobid);
              }
       }

       /* see if it came from an internal or authenticated source */
       if (!originok)
       {
              _Bool internal;
#ifdef POPAUTH
              _Bool popauth;
#endif /* POPAUTH */
              char *authtype;

              internal = dkimf_checkhost(conf->conf_internal, cc->cctx_host);
              internal = internal || dkimf_checkip(conf->conf_internal,
                                                   (struct sockaddr *) &cc->cctx_ip);

              authtype = dkimf_getsymval(ctx, "{auth_type}");

#ifdef POPAUTH
              popauth = dkimf_checkpopauth(popdb,
                                           (struct sockaddr *) &cc->cctx_ip);
#endif /* POPAUTH */

              if ((authtype != NULL && authtype[0] != '\0') || internal)
                     originok = TRUE;

#ifdef POPAUTH
              if (popauth)
                     originok = TRUE;
#endif /* POPAUTH */

              if (!originok && conf->conf_logwhy)
              {
                     if (!internal)
                     {
                            char ipbuf[BUFRSZ];

                            dkimf_ipstring(ipbuf, sizeof ipbuf,
                                           &cc->cctx_ip);
                            syslog(LOG_INFO, "%s: %s [%s] not internal",
                                   dfc->mctx_jobid, cc->cctx_host,
                                   ipbuf);
                     }

                     if (authtype == NULL || authtype[0] == '\0')
                     {
                            syslog(LOG_INFO, "%s: not authenticated",
                                   dfc->mctx_jobid);
                     }

#ifdef POPAUTH
                     if (!popauth)
                     {
                            syslog(LOG_INFO, "%s: not POP authenticated",
                                   dfc->mctx_jobid);
                     }
#endif /* POPAUTH */
              }
       }

       /* is it a domain we sign for? */
       if (!domainok && conf->conf_domainsdb != NULL)
       {
              status = dkimf_db_get(conf->conf_domainsdb, dfc->mctx_domain,
                                    0, NULL, 0, &domainok);

              if (!domainok)
              {
                     /* check for "*" for back-compatibility */
                     status = dkimf_db_get(conf->conf_domainsdb, "*",
                                           0, NULL, 0, &domainok);
                     if (status != 0 && dolog)
                            dkimf_db_error(conf->conf_domainsdb, "*");
              }

              if (!domainok && conf->conf_logwhy)
              {
                     syslog(LOG_INFO,
                            "%s: no signing domain match for '%s'",
                            dfc->mctx_jobid, dfc->mctx_domain);
              }

              if (conf->conf_subdomains && !domainok)
              {
                     for (p = strchr((char *) dfc->mctx_domain, '.');
                          p != NULL && !domainok;
                          p = strchr(p, '.'))
                     {
                            p++;
                            if (*p == '\0')
                                   break;

                            status = dkimf_db_get(conf->conf_domainsdb, p,
                                                  0, NULL, 0,
                                                  &domainok);
                            if (status != 0)
                            {
                                   if (dolog)
                                   {
                                          dkimf_db_error(conf->conf_domainsdb,
                                                         p);
                                   }

                                   continue;
                            }

                            if (domainok)
                            {
                                   strlcpy((char *) dfc->mctx_domain, p,
                                           sizeof dfc->mctx_domain);
                                   break;
                            }
                     }

                     if (domainok)
                            setidentity = TRUE;
              }

              if (!domainok && conf->conf_logwhy)
              {
                     syslog(LOG_INFO,
                            "%s: no signing subdomain match for '%s'",
                            dfc->mctx_jobid, dfc->mctx_domain);
              }
       }

       /* warn if the domain was OK but didn't come from a safe source */
       if (domainok && !originok)
       {
              if (domainok && conf->conf_dolog &&
                  !dkimf_checkhost(conf->conf_exignore, cc->cctx_host) &&
                  !dkimf_checkip(conf->conf_exignore,
                                 (struct sockaddr *) &cc->cctx_ip))
              {
                     syslog(LOG_NOTICE,
                            "%s: external host %s attempted to send as %s",
                            dfc->mctx_jobid, cc->cctx_host,
                            dfc->mctx_domain);
              }
       }

       /* still no key selected; check the signing table (if any) */
       if (originok && dfc->mctx_srhead == NULL &&
           (user != NULL && dfc->mctx_domain[0] != '\0') && 
           conf->conf_keytabledb != NULL && conf->conf_signtabledb != NULL)
       {
              int found;
              char errkey[BUFRSZ + 1];

              memset(errkey, '\0', sizeof errkey);
              found = dkimf_apply_signtable(dfc, conf->conf_keytabledb,
                                            conf->conf_signtabledb,
                                            user, dfc->mctx_domain,
                                            errkey, sizeof errkey,
                                            conf->conf_multisig);

              if (found < 0)
              {
                     if (conf->conf_dolog)
                     {
                            switch (found)
                            {
                              case -1:
                                   syslog(LOG_ERR,
                                          "%s: error reading signing table",
                                          dfc->mctx_jobid);
                                   break;

                              case -2:
                                   syslog(LOG_ERR,
                                          "%s: signing table references unknown key '%s'",
                                          dfc->mctx_jobid, errkey);
                                   break;

                              case -3:
                                   syslog(LOG_ERR,
                                          "%s: error loading key '%s'",
                                          dfc->mctx_jobid, errkey);
                                   break;

                              default:
                                   assert(0);
                            }
                     }

                     return SMFIS_TEMPFAIL;
              }
              else if (found > 0)
              {
                     domainok = TRUE;
              }

              if (!domainok && conf->conf_logwhy)
              {
                     syslog(LOG_INFO,
                            "%s: no signing table match for '%s@%s'",
                            dfc->mctx_jobid, user, dfc->