Back to index

opendkim  2.6.4
Defines | Functions | Variables
dkim.c File Reference
#include "build-config.h"
#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <pthread.h>
#include <resolv.h>
#include <regex.h>
#include <varargs.h>
#include <openssl/opensslv.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/sha.h>
#include "dkim-internal.h"
#include "dkim-types.h"
#include "dkim-tables.h"
#include "dkim-keys.h"
#include "dkim-policy.h"
#include "dkim-report.h"
#include "dkim-util.h"
#include "dkim-canon.h"
#include "dkim-dns.h"
#include "util.h"
#include "base64.h"
#include "dkim-strl.h"

Go to the source code of this file.

Defines

#define _REENTRANT
#define DKIM_STATE_INIT   0
#define DKIM_STATE_HEADER   1
#define DKIM_STATE_EOH1   2
#define DKIM_STATE_EOH2   3
#define DKIM_STATE_BODY   4
#define DKIM_STATE_EOM1   5
#define DKIM_STATE_EOM2   6
#define DKIM_STATE_UNUSABLE   99
#define DKIM_CHUNKSTATE_INIT   0
#define DKIM_CHUNKSTATE_HEADER   1
#define DKIM_CHUNKSTATE_BODY   2
#define DKIM_CHUNKSTATE_DONE   3
#define DKIM_CRLF_UNKNOWN   (-1)
#define DKIM_CRLF_LF   0
#define DKIM_CRLF_CRLF   1
#define DKIM_PHASH(x)   ((x) - 32)
#define BUFRSZ   1024
#define CRLF   "\r\n"
#define SP   " "
#define DEFCLOCKDRIFT   300
#define DEFTIMEOUT   10
#define MINSIGLEN   8
#define MAXPACKET   8192
#define RES_UNC_T   unsigned char *
#define T_AAAA   28
#define CLOBBER(x)
#define HCLOBBER(x)
#define DSTRING_CLOBBER(x)
#define BIO_CLOBBER(x)
#define RSA_CLOBBER(x)
#define EVP_CLOBBER(x)
#define DKIM_ISLWSP(x)   ((x) == 011 || (x) == 013 || (x) == 014 || (x) == 040)
#define FEATURE_INDEX(x)   ((x) / (8 * sizeof(u_int)))
#define FEATURE_OFFSET(x)   ((x) % (8 * sizeof(u_int)))
#define FEATURE_ADD(lib, x)   (lib)->dkiml_flist[FEATURE_INDEX((x))] |= (1 << FEATURE_OFFSET(x))
#define DELIMITER   "\001"

Functions

void dkim_error __P ((DKIM *, const char *,...))
static void dkim_set_free (DKIM *dkim, DKIM_SET *set)
static DKIM_SET * dkim_set_first (DKIM *dkim, dkim_set_t type)
static DKIM_SET * dkim_set_next (DKIM_SET *cur, dkim_set_t type)
static u_char * dkim_param_get (DKIM_SET *set, u_char *param)
static int dkim_add_plist (DKIM *dkim, DKIM_SET *set, u_char *param, u_char *value, _Bool force)
DKIM_STAT dkim_process_set (DKIM *dkim, dkim_set_t type, u_char *str, size_t len, void *udata, _Bool syntax, const char *name)
DKIM_STAT dkim_privkey_load (DKIM *dkim)
static const unsigned char * dkim_check_requiredhdrs (DKIM *dkim)
static void * dkim_set_getudata (DKIM_SET *set)
static struct dkim_headerdkim_get_header (DKIM *dkim, u_char *name, size_t namelen, int inst)
static _Bool dkim_key_smtp (DKIM_SET *set)
static _Bool dkim_key_hashok (DKIM_SIGINFO *sig, u_char *hashlist)
static _Bool dkim_key_hashesok (DKIM_LIB *lib, u_char *hashlist)
static _Bool dkim_sig_hdrlistok (DKIM *dkim, u_char *hdrlist)
static _Bool dkim_sig_domainok (DKIM *dkim, DKIM_SET *set)
static _Bool dkim_sig_expired (DKIM_SET *set, uint64_t drift)
static _Bool dkim_sig_timestampsok (DKIM_SET *set)
static _Bool dkim_sig_future (DKIM_SET *set, uint64_t drift)
static _Bool dkim_sig_versionok (DKIM *dkim, DKIM_SET *set)
DKIM_STAT dkim_siglist_setup (DKIM *dkim)
static size_t dkim_gensighdr (DKIM *dkim, DKIM_SIGINFO *sig, struct dkim_dstring *dstr, char *delim)
static DKIM_STAT dkim_getsender (DKIM *dkim, u_char **hdrs)
static DKIM_STAT dkim_get_policy (DKIM *dkim, u_char *query, _Bool excheck, int *qstatus, dkim_policy_t *policy, u_int *pflags)
DKIM_STAT dkim_get_key (DKIM *dkim, DKIM_SIGINFO *sig, _Bool test)
static _Bool dkim_headercheck (DKIM *dkim)
static DKIM_STAT dkim_eoh_sign (DKIM *dkim)
static DKIM_STAT dkim_eoh_verify (DKIM *dkim)
static DKIM_STAT dkim_eom_sign (DKIM *dkim)
static DKIM_STAT dkim_eom_verify (DKIM *dkim, _Bool *testkey)
static DKIM * dkim_new (DKIM_LIB *libhandle, const unsigned char *id, void *memclosure, dkim_canon_t hdrcanon_alg, dkim_canon_t bodycanon_alg, dkim_alg_t sign_alg, DKIM_STAT *statp)
static void dkim_init_openssl (void)
static void dkim_close_openssl (void)
DKIM_LIB * dkim_init (void *(*caller_mallocf)(void *closure, size_t nbytes), void(*caller_freef)(void *closure, void *p))
void dkim_close (DKIM_LIB *lib)
void dkim_error (DKIM *dkim, const char *format,...)
DKIM_STAT dkim_options (DKIM_LIB *lib, int op, dkim_opts_t opt, void *ptr, size_t len)
DKIM_STAT dkim_free (DKIM *dkim)
DKIM * dkim_sign (DKIM_LIB *libhandle, const unsigned char *id, void *memclosure, const dkim_sigkey_t secretkey, const unsigned char *selector, const unsigned char *domain, dkim_canon_t hdrcanonalg, dkim_canon_t bodycanonalg, dkim_alg_t signalg, ssize_t length, DKIM_STAT *statp)
DKIM * dkim_verify (DKIM_LIB *libhandle, const unsigned char *id, void *memclosure, DKIM_STAT *statp)
DKIM_STAT dkim_resign (DKIM *new, DKIM *old, _Bool hdrbind)
DKIM_PSTATE * dkim_policy_state_new (DKIM *dkim)
void dkim_policy_state_free (DKIM_PSTATE *pstate)
DKIM_STAT dkim_policy (DKIM *dkim, dkim_policy_t *pcode, u_int *pflags, DKIM_PSTATE *pstate)
int dkim_policy_getdnssec (DKIM *dkim)
DKIM_STAT dkim_policy_getreportinfo (DKIM *dkim, u_char *addr, size_t addrlen, u_char *opts, size_t optslen, u_char *smtp, size_t smtplen, u_int *pct)
DKIM_STAT dkim_sig_process (DKIM *dkim, DKIM_SIGINFO *sig)
DKIM_STAT dkim_ohdrs (DKIM *dkim, DKIM_SIGINFO *sig, u_char **ptrs, int *pcnt)
DKIM_STAT dkim_diffheaders (DKIM *dkim, dkim_canon_t canon, int maxcost, char **ohdrs, int nohdrs, struct dkim_hdrdiff **out, int *nout)
DKIM_STAT dkim_header (DKIM *dkim, u_char *hdr, size_t len)
DKIM_STAT dkim_eoh (DKIM *dkim)
DKIM_STAT dkim_body (DKIM *dkim, u_char *buf, size_t buflen)
DKIM_STAT dkim_eom (DKIM *dkim, _Bool *testkey)
DKIM_STAT dkim_chunk (DKIM *dkim, u_char *buf, size_t buflen)
u_long dkim_minbody (DKIM *dkim)
DKIM_STAT dkim_key_syntax (DKIM *dkim, u_char *str, size_t len)
DKIM_STAT dkim_policy_syntax (DKIM *dkim, u_char *str, size_t len)
DKIM_STAT dkim_sig_syntax (DKIM *dkim, u_char *str, size_t len)
const char * dkim_getid (DKIM *dkim)
DKIM_STAT dkim_getsiglist (DKIM *dkim, DKIM_SIGINFO ***sigs, int *nsigs)
DKIM_SIGINFO * dkim_getsignature (DKIM *dkim)
DKIM_STAT dkim_getsighdr_d (DKIM *dkim, size_t initial, u_char **buf, size_t *buflen)
DKIM_STAT dkim_getsighdr (DKIM *dkim, u_char *buf, size_t buflen, size_t initial)
_Bool dkim_sig_hdrsigned (DKIM_SIGINFO *sig, u_char *hdr)
int dkim_sig_getdnssec (DKIM_SIGINFO *sig)
DKIM_STAT dkim_sig_getreportinfo (DKIM *dkim, DKIM_SIGINFO *sig, int *hfd, int *bfd, u_char *addr, size_t addrlen, u_char *opts, size_t optslen, u_char *smtp, size_t smtplen, u_int *pct)
DKIM_STAT dkim_sig_getidentity (DKIM *dkim, DKIM_SIGINFO *sig, u_char *val, size_t vallen)
DKIM_STAT dkim_sig_getcanonlen (DKIM *dkim, DKIM_SIGINFO *sig, ssize_t *msglen, ssize_t *canonlen, ssize_t *signlen)
unsigned int dkim_sig_getflags (DKIM_SIGINFO *sig)
int dkim_sig_getbh (DKIM_SIGINFO *sig)
DKIM_STAT dkim_sig_getkeysize (DKIM_SIGINFO *sig, unsigned int *bits)
DKIM_STAT dkim_sig_getsignalg (DKIM_SIGINFO *sig, dkim_alg_t *alg)
DKIM_STAT dkim_sig_getsigntime (DKIM_SIGINFO *sig, uint64_t *when)
DKIM_STAT dkim_sig_getcanons (DKIM_SIGINFO *sig, dkim_canon_t *hdr, dkim_canon_t *body)
const unsigned char * dkim_get_signer (DKIM *dkim)
DKIM_STAT dkim_set_signer (DKIM *dkim, const unsigned char *signer)
const char * dkim_geterror (DKIM *dkim)
_Bool dkim_getpartial (DKIM *dkim)
DKIM_STAT dkim_setpartial (DKIM *dkim, _Bool value)
DKIM_STAT dkim_set_margin (DKIM *dkim, int value)
const char * dkim_getresultstr (DKIM_STAT result)
int dkim_getpresult (DKIM *dkim)
const char * dkim_getpresultstr (int presult)
const char * dkim_getpolicystr (int policy)
DKIM_STAT dkim_set_dns_callback (DKIM_LIB *libopendkim, void(*func)(const void *context), unsigned int interval)
DKIM_STAT dkim_set_user_context (DKIM *dkim, void *ctx)
void * dkim_get_user_context (DKIM *dkim)
int dkim_getmode (DKIM *dkim)
u_char * dkim_getdomain (DKIM *dkim)
u_char * dkim_getuser (DKIM *dkim)
DKIM_STAT dkim_set_key_lookup (DKIM_LIB *libopendkim, DKIM_STAT(*func)(DKIM *dkim, DKIM_SIGINFO *sig, u_char *buf, size_t buflen))
DKIM_STAT dkim_set_policy_lookup (DKIM_LIB *libopendkim, int(*func)(DKIM *dkim, u_char *query, _Bool excheck, u_char *buf, size_t buflen, int *qstat))
DKIM_STAT dkim_set_signature_handle (DKIM_LIB *libopendkim, void *(*func)(void *closure))
DKIM_STAT dkim_set_signature_handle_free (DKIM_LIB *libopendkim, void(*func)(void *closure, void *user))
DKIM_STAT dkim_set_signature_tagvalues (DKIM_LIB *libopendkim, void(*func)(void *user, dkim_param_t pcode, const u_char *param, const u_char *value))
DKIM_STAT dkim_set_prescreen (DKIM_LIB *libopendkim, DKIM_CBSTAT(*func)(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs))
DKIM_STAT dkim_set_final (DKIM_LIB *libopendkim, DKIM_CBSTAT(*func)(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs))
void * dkim_sig_getcontext (DKIM_SIGINFO *siginfo)
unsigned char * dkim_sig_getselector (DKIM_SIGINFO *siginfo)
unsigned char * dkim_sig_getdomain (DKIM_SIGINFO *siginfo)
int dkim_sig_geterror (DKIM_SIGINFO *siginfo)
const char * dkim_sig_geterrorstr (DKIM_SIGERROR sigerr)
void dkim_sig_ignore (DKIM_SIGINFO *siginfo)
unsigned long dkim_ssl_version (void)
int dkim_flush_cache (DKIM_LIB *lib)
DKIM_STAT dkim_getcachestats (u_int *queries, u_int *hits, u_int *expired)
DKIM_STAT dkim_get_reputation (DKIM *dkim, DKIM_SIGINFO *sig, char *qroot, int *rep)
DKIM_STAT dkim_get_sigsubstring (DKIM *dkim, DKIM_SIGINFO *sig, char *buf, size_t *buflen)
_Bool dkim_libfeature (DKIM_LIB *lib, u_int fc)
uint32_t dkim_libversion (void)
u_char * dkim_sig_gettagvalue (DKIM_SIGINFO *sig, _Bool keytag, u_char *tag)
DKIM_STAT dkim_sig_getsignedhdrs (DKIM *dkim, DKIM_SIGINFO *sig, u_char *hdrs, size_t hdrlen, u_int *nhdrs)
void * dkim_dns_set_query_service (DKIM_LIB *lib, void *h)
void dkim_dns_set_query_start (DKIM_LIB *lib, int(*func)(void *, int, unsigned char *, unsigned char *, size_t, void **))
void dkim_dns_set_query_cancel (DKIM_LIB *lib, int(*func)(void *, void *))
void dkim_dns_set_query_waitreply (DKIM_LIB *lib, int(*func)(void *, void *, struct timeval *, size_t *, int *, int *))
DKIM_STAT dkim_add_xtag (DKIM *dkim, const char *tag, const char *value)
const char * dkim_qi_getname (DKIM_QUERYINFO *query)
int dkim_qi_gettype (DKIM_QUERYINFO *query)
DKIM_STAT dkim_sig_getqueries (DKIM *dkim, DKIM_SIGINFO *sig, DKIM_QUERYINFO ***qi, unsigned int *nqi)
DKIM_STAT dkim_policy_getqueries (DKIM *dkim, DKIM_QUERYINFO ***qi, unsigned int *nqi)
DKIM_STAT dkim_sig_gethashes (DKIM_SIGINFO *sig, void **hh, size_t *hhlen, void **bh, size_t *bhlen)

Variables

static char dkim_c_id [] = "@(#)$Id: dkim.c,v 1.70.2.1 2010/10/27 21:43:08 cm-msk Exp $"
const u_char * dkim_default_senderhdrs []
const u_char * dkim_should_signhdrs []
const u_char * dkim_should_not_signhdrs []
const u_char * required_signhdrs []
static pthread_mutex_t openssl_lock = PTHREAD_MUTEX_INITIALIZER
static unsigned openssl_refcount = 0

Define Documentation

#define _REENTRANT

Definition at line 16 of file dkim.c.

#define BIO_CLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            BIO_free((x)); \
                            (x) = NULL; \
                     }

Definition at line 194 of file dkim.c.

#define BUFRSZ   1024

Definition at line 130 of file dkim.c.

#define CLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            dkim_mfree(dkim->dkim_libhandle, dkim->dkim_closure, (x)); \
                            (x) = NULL; \
                     }

Definition at line 156 of file dkim.c.

#define CRLF   "\r\n"

Definition at line 131 of file dkim.c.

#define DEFCLOCKDRIFT   300

Definition at line 134 of file dkim.c.

#define DEFTIMEOUT   10

Definition at line 135 of file dkim.c.

#define DELIMITER   "\001"
#define DKIM_CHUNKSTATE_BODY   2

Definition at line 115 of file dkim.c.

#define DKIM_CHUNKSTATE_DONE   3

Definition at line 116 of file dkim.c.

#define DKIM_CHUNKSTATE_HEADER   1

Definition at line 114 of file dkim.c.

#define DKIM_CHUNKSTATE_INIT   0

Definition at line 113 of file dkim.c.

#define DKIM_CRLF_CRLF   1

Definition at line 120 of file dkim.c.

#define DKIM_CRLF_LF   0

Definition at line 119 of file dkim.c.

#define DKIM_CRLF_UNKNOWN   (-1)

Definition at line 118 of file dkim.c.

#define DKIM_ISLWSP (   x)    ((x) == 011 || (x) == 013 || (x) == 014 || (x) == 040)

Definition at line 214 of file dkim.c.

#define DKIM_PHASH (   x)    ((x) - 32)

Definition at line 122 of file dkim.c.

#define DKIM_STATE_BODY   4

Definition at line 108 of file dkim.c.

#define DKIM_STATE_EOH1   2

Definition at line 106 of file dkim.c.

#define DKIM_STATE_EOH2   3

Definition at line 107 of file dkim.c.

#define DKIM_STATE_EOM1   5

Definition at line 109 of file dkim.c.

#define DKIM_STATE_EOM2   6

Definition at line 110 of file dkim.c.

#define DKIM_STATE_HEADER   1

Definition at line 105 of file dkim.c.

#define DKIM_STATE_INIT   0

Definition at line 104 of file dkim.c.

#define DKIM_STATE_UNUSABLE   99

Definition at line 111 of file dkim.c.

#define DSTRING_CLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            dkim_dstring_free((x)); \
                            (x) = NULL; \
                     }

Definition at line 168 of file dkim.c.

#define EVP_CLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            EVP_PKEY_free((x)); \
                            (x) = NULL; \
                     }

Definition at line 206 of file dkim.c.

#define FEATURE_ADD (   lib,
 
)    (lib)->dkiml_flist[FEATURE_INDEX((x))] |= (1 << FEATURE_OFFSET(x))
#define FEATURE_INDEX (   x)    ((x) / (8 * sizeof(u_int)))
#define FEATURE_OFFSET (   x)    ((x) % (8 * sizeof(u_int)))
#define HCLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            free((x)); \
                            (x) = NULL; \
                     }

Definition at line 162 of file dkim.c.

#define MAXPACKET   8192

Definition at line 139 of file dkim.c.

#define MINSIGLEN   8

Definition at line 136 of file dkim.c.

#define RES_UNC_T   unsigned char *

Definition at line 143 of file dkim.c.

#define RSA_CLOBBER (   x)
Value:
if ((x) != NULL) \
                     { \
                            RSA_free((x)); \
                            (x) = NULL; \
                     }

Definition at line 200 of file dkim.c.

#define SP   " "

Definition at line 132 of file dkim.c.

#define T_AAAA   28

Definition at line 147 of file dkim.c.


Function Documentation

void dkim_error __P ( (DKIM *, const char *,...)  )
static int dkim_add_plist ( DKIM *  dkim,
DKIM_SET *  set,
u_char *  param,
u_char *  value,
_Bool  force 
) [static]

Definition at line 410 of file dkim.c.

{
       DKIM_PLIST *plist;

       assert(dkim != NULL);
       assert(set != NULL);
       assert(param != NULL);
       assert(value != NULL);

       if (!isprint(param[0]))
       {
              dkim_error(dkim, "invalid parameter '%s'", param);
              return -1;
       }

       /* see if we have one already */
       for (plist = set->set_plist[DKIM_PHASH(param[0])];
            plist != NULL;
            plist = plist->plist_next)
       {
              if (strcasecmp((char *) plist->plist_param,
                             (char *) param) == 0)
                     break;
       }

       /* nope; make one and connect it */
       if (plist == NULL)
       {
              int n;

              plist = (DKIM_PLIST *) DKIM_MALLOC(dkim, sizeof(DKIM_PLIST));
              if (plist == NULL)
              {
                     dkim_error(dkim, "unable to allocate %d byte(s)",
                                sizeof(DKIM_PLIST));
                     return -1;
              }
              force = TRUE;
              n = DKIM_PHASH(param[0]);
              plist->plist_next = set->set_plist[n];
              set->set_plist[n] = plist;
              plist->plist_param = param;
       }

       /* set the value if "force" was set (or this was a new entry) */
       if (force)
              plist->plist_value = value;

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_add_xtag ( DKIM *  dkim,
const char *  tag,
const char *  value 
)

Definition at line 8916 of file dkim.c.

{
       u_char last = '\0';
       dkim_param_t pcode;
       u_char *p;
       struct dkim_xtag *x;

       assert(dkim != NULL);
       assert(tag != NULL);
       assert(value != NULL);

       if (dkim->dkim_mode != DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

       /* check that it's not in sigparams */
       if (tag[0] == '\0' || value[0] == '\0')
              return DKIM_STAT_INVALID;
       pcode = dkim_name_to_code(sigparams, tag);
       if (pcode != (dkim_param_t) -1)
              return DKIM_STAT_INVALID;

       /* confirm valid syntax, per RFC6376 */
       for (p = (u_char *) tag; *p != '\0'; p++)
       {
              if (!(isascii(*p) && (isalnum(*p) || *p == '_')))
                     return DKIM_STAT_INVALID;
       }

       if (value[0] == '\n' ||
           value[0] == '\r' ||
           value[0] == '\t' ||
           value[0] == ' ')
              return DKIM_STAT_INVALID;

       for (p = (u_char *) value; *p != '\0'; p++)
       {
              /* valid characters in general */
              if (!(*p == '\n' ||
                    *p == '\r' ||
                    *p == '\t' ||
                    *p == ' ' ||
                    (*p >= 0x21 && *p <= 0x7e && *p != 0x3b)))
                     return DKIM_STAT_INVALID;

              /* CR has to be followed by LF */
              if (last == '\r' && *p != '\n')
                     return DKIM_STAT_INVALID;

              /* LF has to be followed by space or tab */
              if (last == '\n' && *p != ' ' && *p != '\t')
                     return DKIM_STAT_INVALID;

              last = *p;
       }

       /* can't end with space */
       if (last == '\n' || last == '\r' ||
           last == '\t' || last == ' ')
              return DKIM_STAT_INVALID;

       /* check for dupicates */
       for (x = dkim->dkim_xtags; x != NULL; x = x->xt_next)
       {
              if (strcmp(x->xt_tag, tag) == 0)
                     return DKIM_STAT_INVALID;
       }

       x = (struct dkim_xtag *) DKIM_MALLOC(dkim, sizeof(struct dkim_xtag));
       if (x == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)",
                         sizeof(struct dkim_xtag));
              return DKIM_STAT_NORESOURCE;
       }

       x->xt_tag = tag;
       x->xt_value = value;
       x->xt_next = dkim->dkim_xtags;
       dkim->dkim_xtags = x;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_body ( DKIM *  dkim,
u_char *  buf,
size_t  buflen 
)

Definition at line 6519 of file dkim.c.

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

#ifdef _FFR_RESIGN
       if (dkim->dkim_resign != NULL)
              return DKIM_STAT_INVALID;
#endif /* _FFR_RESIGN */

       if (dkim->dkim_state > DKIM_STATE_BODY ||
           dkim->dkim_state < DKIM_STATE_EOH1)
              return DKIM_STAT_INVALID;
       dkim->dkim_state = DKIM_STATE_BODY;

       if (dkim->dkim_skipbody)
              return DKIM_STAT_OK;

       return dkim_canon_bodychunk(dkim, buf, buflen);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const unsigned char* dkim_check_requiredhdrs ( DKIM *  dkim) [static]

Definition at line 1075 of file dkim.c.

{
       _Bool found;
       int c;
       size_t len;
       struct dkim_header *hdr;

       assert(dkim != NULL);

       for (c = 0; required_signhdrs[c] != NULL; c++)
       {
              found = FALSE;
              len = strlen((char *) required_signhdrs[c]);

              for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
              {
                     if (hdr->hdr_namelen == len &&
                         strncasecmp((char *) hdr->hdr_text,
                                     (char *) required_signhdrs[c],
                                     len) == 0)
                     {
                            found = TRUE;
                            break;
                     }
              }

              if (!found)
                     return required_signhdrs[c];
       }

       return NULL;
}

Here is the caller graph for this function:

DKIM_STAT dkim_chunk ( DKIM *  dkim,
u_char *  buf,
size_t  buflen 
)

Definition at line 6576 of file dkim.c.

{
       _Bool bso;
       DKIM_STAT status;
       unsigned char *p;
       unsigned char *end;

       assert(dkim != NULL);

       bso = ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);

       if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) == 0)
              dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;

       /* verify chunking state */
       if (dkim->dkim_chunkstate >= DKIM_CHUNKSTATE_DONE)
       {
              return DKIM_STAT_INVALID;
       }
       else if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_INIT)
       {
              if (dkim->dkim_hdrbuf == NULL)
              {
                     dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ,
                                                          MAXBUFRSZ);
                     if (dkim->dkim_hdrbuf == NULL)
                            return DKIM_STAT_NORESOURCE;
              }
              else
              {
                     dkim_dstring_blank(dkim->dkim_hdrbuf);
              }

              dkim->dkim_chunkstate = DKIM_CHUNKSTATE_HEADER;
              dkim->dkim_chunksm = 0;
       }

       /* process an "end" call */
       if (buf == NULL || buflen == 0)
       {
              if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER)
              {
                     if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
                     {
                            status = dkim_header(dkim,
                                                 dkim_dstring_get(dkim->dkim_hdrbuf),
                                                 dkim_dstring_len(dkim->dkim_hdrbuf));
                            if (status != DKIM_STAT_OK &&
                                !(status == DKIM_STAT_SYNTAX && bso))
                                   return status;
                     }

                     status = dkim_eoh(dkim);
                     if (status != DKIM_STAT_OK)
                            return status;
              }

              dkim->dkim_chunkstate = DKIM_CHUNKSTATE_DONE;

              return DKIM_STAT_OK;
       }

       /* if we're in body state, just call dkim_body() */
       if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_BODY)
              return dkim_body(dkim, buf, buflen);

       assert(dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER);

       end = buf + buflen - 1;

       /* process headers */
       for (p = buf; p <= end; p++)
       {
              switch (dkim->dkim_chunksm)
              {
                case 0:
                     if (*p == '\n' &&
                         dkim->dkim_chunkcrlf != DKIM_CRLF_CRLF)
                     {
                            dkim->dkim_chunkcrlf = DKIM_CRLF_LF;

                            /*
                            **  If this is a CRLF up front, change state
                            **  and write the rest as part of the body.
                            */

                            if (dkim->dkim_hhead == NULL &&
                                dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
                            {
                                   status = dkim_eoh(dkim);
                                   if (status != DKIM_STAT_OK)
                                          return status;

                                   dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
                                   if (p < end)
                                   {
                                          return dkim_body(dkim, p + 1,
                                                           end - p);
                                   }
                                   else
                                   {
                                          return DKIM_STAT_OK;
                                   }
                            }

                            dkim_dstring_catn(dkim->dkim_hdrbuf, CRLF, 2);
                            dkim->dkim_chunksm = 2;
                     }
                     else
                     {
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
                            if (*p == '\r')
                                   dkim->dkim_chunksm = 1;
                     }
                     break;

                case 1:
                     dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
                     if (*p == '\n')
                     {
                            if (dkim->dkim_chunkcrlf == DKIM_CRLF_UNKNOWN)
                                   dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;

                            /*
                            **  If this is a CRLF up front, change state
                            **  and write the rest as part of the body.
                            */

                            if (dkim->dkim_hhead == NULL &&
                                dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
                            {
                                   status = dkim_eoh(dkim);
                                   if (status != DKIM_STAT_OK)
                                          return status;

                                   dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
                                   if (p < end)
                                   {
                                          return dkim_body(dkim, p + 1,
                                                           end - p);
                                   }
                                   else
                                   {
                                          return DKIM_STAT_OK;
                                   }
                            }

                            dkim->dkim_chunksm = 2;
                     }
                     else if (*p != '\r')
                     {
                            dkim->dkim_chunksm = 0;
                     }
                     break;
                     
                case 2:
                     if (DKIM_ISLWSP(*p))
                     {
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
                            dkim->dkim_chunksm = 0;
                            break;
                     }
                     else if (*p == '\r' &&
                              dkim->dkim_chunkcrlf == DKIM_CRLF_CRLF)
                     {
                            dkim->dkim_chunksm = 3;
                            break;
                     }
                     else if (*p != '\n' ||
                              dkim->dkim_chunkcrlf != DKIM_CRLF_LF)
                     {
                            status = dkim_header(dkim,
                                                 dkim_dstring_get(dkim->dkim_hdrbuf),
                                                 dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
                            if (status != DKIM_STAT_OK &&
                                !(status == DKIM_STAT_SYNTAX && bso))
                                   return status;

                            dkim_dstring_blank(dkim->dkim_hdrbuf);
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
                            dkim->dkim_chunksm = 0;
                            break;
                     }
                     /* FALLTHROUGH */
                            
                case 3:
                     if (*p == '\n')
                     {
                            if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
                            {
                                   status = dkim_header(dkim,
                                                        dkim_dstring_get(dkim->dkim_hdrbuf),
                                                        dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
                                   if (status != DKIM_STAT_OK &&
                                       !(status == DKIM_STAT_SYNTAX &&
                                         bso))
                                          return status;
                            }

                            status = dkim_eoh(dkim);
                            if (status != DKIM_STAT_OK)
                                   return status;

                            dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;

                            if (p < end)
                                   return dkim_body(dkim, p + 1, end - p);
                            else
                                   return DKIM_STAT_OK;
                     }
                     else
                     {
                            status = dkim_header(dkim,
                                                 dkim_dstring_get(dkim->dkim_hdrbuf),
                                                 dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
                            if (status != DKIM_STAT_OK &&
                                !(status == DKIM_STAT_SYNTAX && bso))
                                   return status;

                            dkim_dstring_blank(dkim->dkim_hdrbuf);
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, '\r');
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
                            dkim->dkim_chunksm = 0;
                     }
                     break;

                default:
                     assert(0);
                     /* NOTREACHED */
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_close ( DKIM_LIB *  lib)

Definition at line 4438 of file dkim.c.

{
       assert(lib != NULL);

#ifdef QUERY_CACHE
       if (lib->dkiml_cache != NULL)
              (void) dkim_cache_close(lib->dkiml_cache);
#endif /* QUERY_CACHE */

       if (lib->dkiml_skipre)
              (void) regfree(&lib->dkiml_skiphdrre);
       
       if (lib->dkiml_signre)
              (void) regfree(&lib->dkiml_hdrre);


#ifdef _FFR_OVERSIGN
       if (lib->dkiml_oversignhdrs != NULL)
              dkim_clobber_array((char **) lib->dkiml_oversignhdrs);
#endif /* _FFR_OVERSIGN */

       if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
              dkim_clobber_array((char **) lib->dkiml_senderhdrs);

       if (lib->dkiml_alwayshdrs != NULL)
              dkim_clobber_array((char **) lib->dkiml_alwayshdrs);

       if (lib->dkiml_mbs != NULL)
              dkim_clobber_array((char **) lib->dkiml_mbs);

       free(lib->dkiml_flist);
       
       free((void *) lib);

#ifndef USE_GNUTLS
       dkim_close_openssl();
#endif /* ! USE_GNUTLS */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkim_close_openssl ( void  ) [static]

Definition at line 4292 of file dkim.c.

{
       assert(openssl_refcount > 0);

       pthread_mutex_lock(&openssl_lock);

       openssl_refcount--;
       if (openssl_refcount == 0)
              EVP_cleanup();

       pthread_mutex_unlock(&openssl_lock);
}

Here is the caller graph for this function:

DKIM_STAT dkim_diffheaders ( DKIM *  dkim,
dkim_canon_t  canon,
int  maxcost,
char **  ohdrs,
int  nohdrs,
struct dkim_hdrdiff **  out,
int *  nout 
)

Definition at line 6064 of file dkim.c.

{
#ifdef _FFR_DIFFHEADERS
       int n = 0;
       int a = 0;
       int c;
       int status;
       u_char *p;
       u_char *q;
       u_char *end;
       void *cls;
       struct dkim_header *hdr;
       struct dkim_hdrdiff *diffs = NULL;
       struct dkim_dstring *tmphdr;
       struct dkim_dstring **cohdrs;
       DKIM_LIB *lib;
       regaparams_t params;
       regamatch_t matches;
       regex_t re;
       u_char restr[BUFRSZ + 1];

       assert(dkim != NULL);
       assert(out != NULL);
       assert(nout != NULL);

       if (dkim->dkim_mode != DKIM_MODE_VERIFY)
              return DKIM_STAT_INVALID;
       if (maxcost == 0)
              return DKIM_STAT_INVALID;

       tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
       if (tmphdr == NULL)
       {
              dkim_error(dkim, "failed to allocate dynamic string");
              return DKIM_STAT_NORESOURCE;
       }

       lib = dkim->dkim_libhandle;
       cls = dkim->dkim_closure;

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

       params.cost_ins = COST_INSERT;
       params.cost_del = COST_DELETE;
       params.cost_subst = COST_SUBST;

       params.max_cost = maxcost;
       params.max_ins = DKIM_MAXHEADER;
       params.max_del = DKIM_MAXHEADER;
       params.max_subst = DKIM_MAXHEADER;
       params.max_err = maxcost;

       matches.nmatch = 0;
       matches.pmatch = NULL;

       /* canonicalize all the original header fields */
       cohdrs = DKIM_MALLOC(dkim, sizeof(struct dkim_dstring *) * nohdrs);
       if (cohdrs == NULL)
       {
              dkim_error(dkim, strerror(errno));
              return DKIM_STAT_NORESOURCE;
       }

       for (c = 0; c < nohdrs; c++)
       {
              cohdrs[c] = dkim_dstring_new(dkim, DKIM_MAXHEADER, 0);
              if (cohdrs[c] == NULL)
              {
                     for (n = 0; n < c; n++)
                            dkim_dstring_free(cohdrs[n]);

                     DKIM_FREE(dkim, cohdrs);

                     dkim_error(dkim, strerror(errno));

                     return DKIM_STAT_NORESOURCE;
              }

              status = dkim_canon_header_string(cohdrs[c], canon,
                                                ohdrs[c], strlen(ohdrs[c]),
                                                FALSE);
              if (status != DKIM_STAT_OK)
              {
                     for (n = 0; n < c; n++)
                            dkim_dstring_free(cohdrs[n]);

                     DKIM_FREE(dkim, cohdrs);

                     dkim_error(dkim, strerror(errno));

                     return status;
              }
       }

       for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
       {
              dkim_dstring_blank(tmphdr);

              status = dkim_canon_header_string(tmphdr, canon,
                                                hdr->hdr_text,
                                                hdr->hdr_textlen, FALSE);
              if (status != DKIM_STAT_OK)
              {
                     dkim_dstring_free(tmphdr);
                     for (c = 0; c < nohdrs; c++)
                            dkim_dstring_free(cohdrs[c]);
                     DKIM_FREE(dkim, cohdrs);
                     return status;
              }

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

              end = restr + sizeof restr;

              for (p = dkim_dstring_get(tmphdr), q = restr;
                   *p != '\0' && q < end - 3;
                   p++)
              {
                     if (q == restr)
                            *q++ = '^';

                     if (*p == '*' ||
                         *p == '\\' ||
                         *p == '$' ||
                         *p == '+' ||
                         *p == '[' ||
                         *p == ']' ||
                         *p == '(' ||
                         *p == ')' ||
                         *p == '.' ||
                         *p == '|')
                            *q++ = '\\';

                     *q++ = *p;
              }

              *q = '$';

              status = tre_regcomp(&re, restr, REG_NOSUB);
              if (status != 0)
              {
                     char err[BUFRSZ + 1];

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

                     (void) tre_regerror(status, &re, err, sizeof err);

                     dkim_error(dkim, err);

                     if (diffs != NULL)
                            dkim_mfree(lib, cls, diffs);

                     dkim_dstring_free(tmphdr);
                     for (c = 0; c < nohdrs; c++)
                            dkim_dstring_free(cohdrs[c]);
                     DKIM_FREE(dkim, cohdrs);

                     return DKIM_STAT_INTERNAL;
              }

              for (c = 0; c < nohdrs; c++)
              {
                     /* not even the same header field */
                     if (hdr->hdr_namelen != hdr->hdr_textlen &&
                         strncmp(dkim_dstring_get(cohdrs[c]),
                                 dkim_dstring_get(tmphdr),
                                 hdr->hdr_namelen + 1) != 0)
                            continue;

                     /* same, no changes at all */
                     if (strcmp(dkim_dstring_get(cohdrs[c]),
                                dkim_dstring_get(tmphdr)) == 0)
                            continue;

                     /* check for approximate match */
                     status = tre_regaexec(&re, dkim_dstring_get(cohdrs[c]),
                                           &matches, params, 0);

                     if (status == 0)
                     {
                            if (n + 1 > a)
                            {
                                   int sz;
                                   struct dkim_hdrdiff *new;

                                   if (a == 0)
                                          a = 16;
                                   else
                                          a *= 2;

                                   sz = a * sizeof(struct dkim_hdrdiff);

                                   new = (struct dkim_hdrdiff *) dkim_malloc(lib,
                                                                             cls,
                                                                             sz);

                                   if (new == NULL)
                                   {
                                          dkim_error(dkim,
                                                     "unable to allocate %d byte(s)",
                                                     sz);

                                          if (diffs != NULL)
                                          {
                                                 dkim_mfree(lib, cls,
                                                            diffs);
                                          }

                                          dkim_dstring_free(tmphdr);
                                          for (c = 0; c < nohdrs; c++)
                                                 dkim_dstring_free(cohdrs[c]);
                                          DKIM_FREE(dkim, cohdrs);

                                          return DKIM_STAT_NORESOURCE;
                                   }

                                   dkim_mfree(lib, cls, diffs);

                                   diffs = new;

                                   sz = (a - n) & sizeof(struct dkim_hdrdiff);
                                   memset(&diffs[n], '\0', sz);
                            }

                            diffs[n].hd_old = ohdrs[c];
                            diffs[n].hd_new = hdr->hdr_text;

                            n++;
                     }
              }

              tre_regfree(&re);
       }

       *out = diffs;
       *nout = n;

       dkim_dstring_free(tmphdr);
       for (c = 0; c < nohdrs; c++)
              dkim_dstring_free(cohdrs[c]);
       DKIM_FREE(dkim, cohdrs);

       return DKIM_STAT_OK;
#else /* _FFR_DIFFHEADERS */
       return DKIM_STAT_NOTIMPLEMENT;
#endif /* _FFR_DIFFHEADERS */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_dns_set_query_cancel ( DKIM_LIB *  lib,
int(*)(void *, void *)  func 
)

Definition at line 8854 of file dkim.c.

{
       assert(lib != NULL);

       if (func != NULL)
              lib->dkiml_dns_cancel = func;
       else
              lib->dkiml_dns_cancel = dkim_res_cancel;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* dkim_dns_set_query_service ( DKIM_LIB *  lib,
void *  h 
)

Definition at line 8789 of file dkim.c.

{
       void *old;

       old = lib->dkiml_dns_service;

       lib->dkiml_dns_service = h;

       return old;
}

Here is the caller graph for this function:

void dkim_dns_set_query_start ( DKIM_LIB *  lib,
int(*)(void *, int, unsigned char *, unsigned char *, size_t, void **)  func 
)

Definition at line 8823 of file dkim.c.

{
       assert(lib != NULL);

       if (func != NULL)
              lib->dkiml_dns_start = func;
       else
              lib->dkiml_dns_start = dkim_res_query;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_dns_set_query_waitreply ( DKIM_LIB *  lib,
int(*)(void *, void *, struct timeval *, size_t *, int *, int *)  func 
)

Definition at line 8886 of file dkim.c.

{
       assert(lib != NULL);

       if (func != NULL)
              lib->dkiml_dns_waitreply = func;
       else
              lib->dkiml_dns_waitreply = dkim_res_waitreply;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_eoh ( DKIM *  dkim)

Definition at line 6496 of file dkim.c.

{
       assert(dkim != NULL);

       if (dkim->dkim_mode == DKIM_MODE_VERIFY)
              return dkim_eoh_verify(dkim);
       else
              return dkim_eoh_sign(dkim);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_eoh_sign ( DKIM *  dkim) [static]

Definition at line 3279 of file dkim.c.

{
       _Bool keep;
       _Bool tmp;
       u_char *hn = NULL;
       DKIM_STAT status;
       int hashtype = DKIM_HASHTYPE_UNKNOWN;
       DKIM_CANON *bc;
       DKIM_CANON *hc;
       DKIM_LIB *lib;

       assert(dkim != NULL);

#ifdef _FFR_RESIGN
       if (dkim->dkim_hdrbind)
              return DKIM_STAT_INVALID;
#endif /* _FFR_RESIGN */

       if (dkim->dkim_state >= DKIM_STATE_EOH2)
              return DKIM_STAT_INVALID;
       if (dkim->dkim_state < DKIM_STATE_EOH2)
              dkim->dkim_state = DKIM_STATE_EOH2;

       lib = dkim->dkim_libhandle;
       assert(lib != NULL);

       tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
       keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);

       dkim->dkim_version = lib->dkiml_version;

       /* check for header validity */
       if (!dkim_headercheck(dkim))
       {
              dkim->dkim_state = DKIM_STATE_UNUSABLE;
              return DKIM_STAT_SYNTAX;
       }

       /*
       **  Verify that all the required headers are present and
       **  marked for signing.
       */

       hn = (u_char *) dkim_check_requiredhdrs(dkim);
       if (hn != NULL)
       {
              dkim_error(dkim, "required header \"%s\" not found", hn);
              dkim->dkim_state = DKIM_STATE_UNUSABLE;
              return DKIM_STAT_SYNTAX;
       }

       /* determine hash type */
       switch (dkim->dkim_signalg)
       {
         case DKIM_SIGN_RSASHA1:
              hashtype = DKIM_HASHTYPE_SHA1;
              break;

         case DKIM_SIGN_RSASHA256:
              hashtype = DKIM_HASHTYPE_SHA256;
              break;

         default:
              assert(0);
              /* NOTREACHED */
       }

       if (dkim->dkim_siglist == NULL)
       {
              /* initialize signature and canonicalization for signing */
              dkim->dkim_siglist = DKIM_MALLOC(dkim, sizeof(DKIM_SIGINFO **));
              if (dkim->dkim_siglist == NULL)
              {
                     dkim_error(dkim, "failed to allocate %d byte(s)",
                                sizeof(DKIM_SIGINFO *));
                     return DKIM_STAT_NORESOURCE;
              }

              dkim->dkim_siglist[0] = DKIM_MALLOC(dkim,
                                                  sizeof(struct dkim_siginfo));
              if (dkim->dkim_siglist[0] == NULL)
              {
                     dkim_error(dkim, "failed to allocate %d byte(s)",
                                sizeof(struct dkim_siginfo));
                     return DKIM_STAT_NORESOURCE;
              }
              dkim->dkim_sigcount = 1;
              memset(dkim->dkim_siglist[0], '\0',
                     sizeof(struct dkim_siginfo));
              dkim->dkim_siglist[0]->sig_domain = dkim->dkim_domain;
              dkim->dkim_siglist[0]->sig_selector = dkim->dkim_selector;
              dkim->dkim_siglist[0]->sig_hashtype = hashtype;
              dkim->dkim_siglist[0]->sig_signalg = dkim->dkim_signalg;

              status = dkim_add_canon(dkim, TRUE, dkim->dkim_hdrcanonalg,
                                      hashtype, NULL, NULL, 0, &hc);
              if (status != DKIM_STAT_OK)
                     return status;

              status = dkim_add_canon(dkim, FALSE, dkim->dkim_bodycanonalg,
                                      hashtype, NULL, NULL,
                                      dkim->dkim_signlen, &bc);
              if (status != DKIM_STAT_OK)
                     return status;

              dkim->dkim_siglist[0]->sig_hdrcanon = hc;
              dkim->dkim_siglist[0]->sig_hdrcanonalg = dkim->dkim_hdrcanonalg;
              dkim->dkim_siglist[0]->sig_bodycanon = bc;
              dkim->dkim_siglist[0]->sig_bodycanonalg = dkim->dkim_bodycanonalg;

              if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
              {
                     dkim->dkim_siglist[0]->sig_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
              }
              else
              {
                     time_t now;

                     (void) time(&now);

                     dkim->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
              }
       }

       /* initialize all canonicalizations */
       status = dkim_canon_init(dkim, tmp, keep);
       if (status != DKIM_STAT_OK)
              return status;

       /* run the headers */
       status = dkim_canon_runheaders(dkim);
       if (status != DKIM_STAT_OK)
              return status;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_eoh_verify ( DKIM *  dkim) [static]

Definition at line 3427 of file dkim.c.

{
       _Bool keep;
       _Bool tmp;
       _Bool bsh;
       DKIM_STAT status;
       int c;
       DKIM_LIB *lib;
       DKIM_SET *set;

       assert(dkim != NULL);

       if (dkim->dkim_state >= DKIM_STATE_EOH2)
              return DKIM_STAT_INVALID;
       if (dkim->dkim_state < DKIM_STATE_EOH1)
              dkim->dkim_state = DKIM_STATE_EOH1;

       lib = dkim->dkim_libhandle;
       assert(lib != NULL);

       bsh = ((lib->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
       tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
       keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);

       /* populate some stuff like dkim_sender, dkim_domain, dkim_user */
       status = dkim_getsender(dkim, dkim->dkim_libhandle->dkiml_senderhdrs);
       if (status != DKIM_STAT_OK && !bsh)
       {
              dkim->dkim_state = DKIM_STATE_UNUSABLE;
              return status;
       }

       /* check for header validity */
       if (!dkim_headercheck(dkim))
       {
              dkim->dkim_state = DKIM_STATE_UNUSABLE;
              return DKIM_STAT_SYNTAX;
       }

       /* allocate the siginfo array if not already done */
       if (dkim->dkim_siglist == NULL)
       {
              /* count the signatures */
              for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGNATURE);
                   set != NULL;
                   set = dkim_set_next(set, DKIM_SETTYPE_SIGNATURE))
              {
                     if (!set->set_bad || bsh)
                            dkim->dkim_sigcount++;
              }

              /* if no signatures, return such */
              if (dkim->dkim_sigcount == 0)
              {
                     dkim->dkim_skipbody = TRUE;
                     return DKIM_STAT_NOSIG;
              }

              status = dkim_siglist_setup(dkim);
              if (status != DKIM_STAT_OK)
                     return status;

              /* initialize all discovered canonicalizations */
              status = dkim_canon_init(dkim, tmp, keep);
              if (status != DKIM_STAT_OK)
                     return status;
       }

       /* call the prescreen callback, if defined */
       if (lib->dkiml_prescreen != NULL && !dkim->dkim_eoh_reentry)
       {
              status = lib->dkiml_prescreen(dkim,
                                            dkim->dkim_siglist,
                                            dkim->dkim_sigcount);
              switch (status)
              {
                case DKIM_CBSTAT_CONTINUE:
                     break;

                case DKIM_CBSTAT_REJECT:
                     return DKIM_STAT_CBREJECT;

                case DKIM_CBSTAT_TRYAGAIN:
                     return DKIM_STAT_CBTRYAGAIN;

                case DKIM_CBSTAT_ERROR:
                     return DKIM_STAT_CBERROR;

                default:
                     return DKIM_STAT_CBINVALID;
              }
       }

       dkim->dkim_state = DKIM_STATE_EOH2;

       /* if set to ignore everything, treat message as unsigned */
       set = NULL;
       for (c = 0; c < dkim->dkim_sigcount; c++)
       {
              if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE))
              {
                     set = dkim->dkim_siglist[c]->sig_taglist;
                     break;
              }
       }

       if (set == NULL)
       {
              dkim->dkim_skipbody = TRUE;
              return DKIM_STAT_NOSIG;
       }

       /* run the headers */
       if (!dkim->dkim_eoh_reentry)
       {
              status = dkim_canon_runheaders(dkim);
              if (status != DKIM_STAT_OK)
                     return status;
       }

       /* do public key verification of all still-enabled signatures here */
       if ((lib->dkiml_flags & DKIM_LIBFLAGS_DELAYSIGPROC) == 0)
       {
              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_PROCESSED) &&
                         !(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE) &&
                         dkim->dkim_siglist[c]->sig_error == DKIM_SIGERROR_UNKNOWN)
                     {
                            status = dkim_sig_process(dkim,
                                                      dkim->dkim_siglist[c]);
                            if (status != DKIM_STAT_OK)
                            {
                                   if (status == DKIM_STAT_CBTRYAGAIN)
                                          dkim->dkim_eoh_reentry = TRUE;

                                   return status;
                            }
                     }
              }
       }

       /*
       **  Possible short-circuit here if all signatures are:
       **  - marked to be ignored
       **  - definitely invalid
       **  - verification attempted but failed
       */

       if ((lib->dkiml_flags & DKIM_LIBFLAGS_EOHCHECK) != 0)
       {
              _Bool good = FALSE;
              DKIM_SIGINFO *sig;

              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     sig = dkim->dkim_siglist[c];

                     /* ignored? */
                     if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
                            continue;

                     /* had a processing error? */
                     if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
                         sig->sig_error != DKIM_SIGERROR_OK)
                            continue;

                     /* processed but didn't pass? */
                     if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
                         (sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
                            continue;

                     /* OK we had a good one */
                     good = TRUE;
                     break;
              }

              /* no good ones */
              if (!good)
              {
                     /* report error on the last one */
                     if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
                         sig->sig_error != DKIM_SIGERROR_OK)
                     {
                            dkim_error(dkim,
                                       dkim_code_to_name(sigerrors,
                                                         sig->sig_error));
                     }

                     return DKIM_STAT_CANTVRFY;
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_eom ( DKIM *  dkim,
_Bool *  testkey 
)

Definition at line 6553 of file dkim.c.

{
       assert(dkim != NULL);

       if (dkim->dkim_mode == DKIM_MODE_SIGN)
              return dkim_eom_sign(dkim);
       else
              return dkim_eom_verify(dkim, testkey);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_eom_sign ( DKIM *  dkim) [static]

Definition at line 3634 of file dkim.c.

{
       int status;
       u_int l;
       size_t diglen;
       size_t siglen = 0;
       size_t len;
       DKIM_STAT ret;
       u_char *digest;
       u_char *sighdr;
       u_char *signature = NULL;
       DKIM_SIGINFO *sig;
       DKIM_CANON *hc;
       struct dkim_dstring *tmphdr;
       struct dkim_rsa *rsa = NULL;
       struct dkim_header hdr;

       assert(dkim != NULL);

#ifdef _FFR_RESIGN
       if (dkim->dkim_resign != NULL)
       {
              if (dkim->dkim_hdrbind)
              {
                     if (dkim->dkim_state != DKIM_STATE_INIT ||
                         dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
                            return DKIM_STAT_INVALID;
              }
              else
              {
                     if (dkim->dkim_state < DKIM_STATE_EOH1 ||
                         dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
                            return DKIM_STAT_INVALID;
              }
       }
       else if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
                dkim->dkim_state < DKIM_STATE_EOH1)
       {
              return DKIM_STAT_INVALID;
       }
#else /* _FFR_RESIGN */
       if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
           dkim->dkim_state < DKIM_STATE_EOH1)
              return DKIM_STAT_INVALID;
#endif /* _FFR_RESIGN */

       if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
           dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
              return DKIM_STAT_INVALID;

       if (dkim->dkim_state < DKIM_STATE_EOM2)
              dkim->dkim_state = DKIM_STATE_EOM2;

#ifdef _FFR_RESIGN
       /*
       **  Verify that all the required headers are present and
       **  marked for signing.
       */

       if (dkim->dkim_resign != NULL)
       {
              char *hn;

              if (dkim->dkim_hdrbind)
                     dkim->dkim_hhead = dkim->dkim_resign->dkim_hhead;

              hn = (u_char *) dkim_check_requiredhdrs(dkim);
              if (hn != NULL)
              {
                     dkim_error(dkim, "required header \"%s\" not found",
                                hn);
                     dkim->dkim_state = DKIM_STATE_UNUSABLE;
                     return DKIM_STAT_SYNTAX;
              }
       }
#endif /* _FFR_RESIGN */

       /* finalize body canonicalizations */
       (void) dkim_canon_closebody(dkim);

       dkim->dkim_bodydone = TRUE;

       /* set signature timestamp */
       if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
       {
              dkim->dkim_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
       }
       else
       {
              time_t now;

              (void) time(&now);
              dkim->dkim_timestamp = (uint64_t) now;
       }

       /* sign with l= if requested */
       if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_SIGNLEN) != 0)
              dkim->dkim_partial = TRUE;

       /* get signature and canonicalization handles */
       assert(dkim->dkim_siglist != NULL);
       assert(dkim->dkim_siglist[0] != NULL);
       sig = dkim->dkim_siglist[0];
       hc = sig->sig_hdrcanon;

       if (dkim->dkim_keydata == NULL)
       {
              if (dkim_privkey_load(dkim) != DKIM_STAT_OK)
                     return DKIM_STAT_NORESOURCE;
       }

       rsa = dkim->dkim_keydata;
#ifdef USE_GNUTLS
       if (rsa->rsa_privkey == NULL)
#else /* USE_GNUTLS */
       if (rsa->rsa_rsa == NULL)
#endif /* USE_GNUTLS */
       {
              dkim_error(dkim, "private key load failed");
              return DKIM_STAT_NORESOURCE;
       }

       sig->sig_keybits = rsa->rsa_keysize;
       sig->sig_signature = dkim->dkim_keydata;
       sig->sig_flags |= DKIM_SIGFLAG_KEYLOADED;

       switch (sig->sig_signalg)
       {
         case DKIM_SIGN_RSASHA1:
         case DKIM_SIGN_RSASHA256:
         {
              assert(sig->sig_hashtype == DKIM_HASHTYPE_SHA1 ||
                     sig->sig_hashtype == DKIM_HASHTYPE_SHA256);

              if (sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
              {
                     assert(dkim_libfeature(dkim->dkim_libhandle,
                                             DKIM_FEATURE_SHA256));
              }

              sig->sig_signature = (void *) dkim->dkim_keydata;
              sig->sig_keytype = DKIM_KEYTYPE_RSA;

              break;
         }

         default:
              assert(0);
       }

       /* construct the DKIM signature header to be canonicalized */
       tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
       if (tmphdr == NULL)
              return DKIM_STAT_NORESOURCE;

       dkim_dstring_catn(tmphdr, (u_char *) DKIM_SIGNHEADER ": ",
                         sizeof DKIM_SIGNHEADER + 1);

       ret = dkim_getsighdr_d(dkim, dkim_dstring_len(tmphdr), &sighdr, &len);
       if (ret != DKIM_STAT_OK)
       {
              dkim_dstring_free(tmphdr);
              return ret;
       }

       dkim_dstring_catn(tmphdr, sighdr, len);
       len = dkim_dstring_len(tmphdr);

       hdr.hdr_text = dkim_dstring_get(tmphdr);
       hdr.hdr_colon = hdr.hdr_text + DKIM_SIGNHEADER_LEN;
       hdr.hdr_namelen = DKIM_SIGNHEADER_LEN;
       hdr.hdr_textlen = len;
       hdr.hdr_flags = 0;
       hdr.hdr_next = NULL;

       /* canonicalize */
#ifdef _FFR_RESIGN
       if (dkim->dkim_resign != NULL && dkim->dkim_hdrbind)
              dkim->dkim_canonhead = dkim->dkim_resign->dkim_canonhead;
#endif /* _FFR_RESIGN */
       dkim_canon_signature(dkim, &hdr);

       dkim_dstring_free(tmphdr);

       /* finalize */
       ret = dkim_canon_getfinal(hc, &digest, &diglen);
       if (ret != DKIM_STAT_OK)
       {
              dkim_error(dkim, "dkim_canon_getfinal() failed");
              return DKIM_STAT_INTERNAL;
       }

       /* compute and store the signature */
       switch (sig->sig_signalg)
       {
#ifdef USE_GNUTLS
         case DKIM_SIGN_RSASHA1:
         case DKIM_SIGN_RSASHA256:
         {
              int alg;
              gnutls_datum_t dd;
              struct dkim_rsa *rsa;

              rsa = (struct dkim_rsa *) sig->sig_signature;

              dd.data = digest;
              dd.size = diglen;

              if (sig->sig_signalg == DKIM_SIGN_RSASHA1)
                     alg = GNUTLS_DIG_SHA1;
              else
                     alg = GNUTLS_DIG_SHA256;

              status = gnutls_privkey_sign_hash(rsa->rsa_privkey, alg, 0,
                                                &dd, &rsa->rsa_rsaout);
              if (status != GNUTLS_E_SUCCESS)
              {
                     dkim_error(dkim,
                                "signature generation failed (status %d)",
                                status);
                     return DKIM_STAT_INTERNAL;
              }

              signature = rsa->rsa_rsaout.data;
              siglen = rsa->rsa_rsaout.size;

              break;
         }
#else /* USE_GNUTLS */
         case DKIM_SIGN_RSASHA1:
         case DKIM_SIGN_RSASHA256:
         {
              int nid;
              struct dkim_rsa *rsa;

              rsa = (struct dkim_rsa *) sig->sig_signature;

              nid = NID_sha1;

              if (dkim_libfeature(dkim->dkim_libhandle,
                                  DKIM_FEATURE_SHA256) &&
                  sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
                     nid = NID_sha256;

              status = RSA_sign(nid, digest, diglen,
                                 rsa->rsa_rsaout, &l, rsa->rsa_rsa);
              if (status != 1 || l == 0)
              {
                     RSA_free(rsa->rsa_rsa);
                     rsa->rsa_rsa = NULL;
                     BIO_free(rsa->rsa_keydata);
                     rsa->rsa_keydata = NULL;
                     dkim_error(dkim,
                                "signature generation failed (status %d, length %d)",
                                status, l);
                     return DKIM_STAT_INTERNAL;
              }

              rsa->rsa_rsaoutlen = l;

              signature = rsa->rsa_rsaout;
              siglen = rsa->rsa_rsaoutlen;

              break;
         }
#endif /* USE_GNUTLS */

         default:
              assert(0);
       }

       /* base64-encode the signature */
       dkim->dkim_b64siglen = siglen * 3 + 5;
       dkim->dkim_b64siglen += (dkim->dkim_b64siglen / 60);
       dkim->dkim_b64sig = DKIM_MALLOC(dkim, dkim->dkim_b64siglen);
       if (dkim->dkim_b64sig == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)",
                         dkim->dkim_b64siglen);
#ifndef USE_GNUTLS
              BIO_free(rsa->rsa_keydata);
              rsa->rsa_keydata = NULL;
#endif /* ! USE_GNUTLS */
              return DKIM_STAT_NORESOURCE;
       }
       memset(dkim->dkim_b64sig, '\0', dkim->dkim_b64siglen);

       status = dkim_base64_encode(signature, siglen, dkim->dkim_b64sig,
                                   dkim->dkim_b64siglen);

#ifndef USE_GNUTLS
       BIO_free(rsa->rsa_keydata);
       rsa->rsa_keydata = NULL;
#endif /* ! USE_GNUTLS */

       if (status == -1)
       {
              dkim_error(dkim,
                         "base64 encoding error (buffer too small)");
              return DKIM_STAT_NORESOURCE;
       }

       dkim->dkim_signature = sig;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_eom_verify ( DKIM *  dkim,
_Bool *  testkey 
) [static]

Definition at line 3954 of file dkim.c.

{
       DKIM_STAT ret;
       int c;
       int status;
       DKIM_SIGINFO *sig = NULL;
       struct dkim_header *hdr;
       DKIM_LIB *lib;

       assert(dkim != NULL);

       if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
           dkim->dkim_state < DKIM_STATE_EOH1)
              return DKIM_STAT_INVALID;
       if (dkim->dkim_state < DKIM_STATE_EOM1)
              dkim->dkim_state = DKIM_STATE_EOM1;

       if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
           dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
              return DKIM_STAT_INVALID;

       /* finalize body canonicalizations */
       (void) dkim_canon_closebody(dkim);

       dkim->dkim_bodydone = TRUE;

       if (dkim->dkim_sigcount == 0)
       {                                  /* unsigned */
              if (dkim->dkim_domain == NULL)
              {
                     u_char *domain;
                     u_char *user;

                     hdr = dkim_get_header(dkim, (u_char *) DKIM_FROMHEADER,
                                           DKIM_FROMHEADER_LEN, 0);
                     if (hdr == NULL)
                     {
                            dkim_error(dkim, "no %s header found",
                                       DKIM_FROMHEADER);
                            return DKIM_STAT_CANTVRFY;
                     }

                     if (hdr->hdr_colon == NULL)
                     {
                            dkim_error(dkim, "%s header malformed",
                                       DKIM_FROMHEADER);
                            return DKIM_STAT_CANTVRFY;
                     }

                     status = dkim_mail_parse(hdr->hdr_colon + 1,
                                              &user, &domain);
                     if (status != 0 || domain == NULL || domain[0] == '\0')
                     {
                            dkim_error(dkim, "%s header malformed",
                                       DKIM_FROMHEADER);
                            return DKIM_STAT_CANTVRFY;
                     }

                     dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
                     if (dkim->dkim_domain == NULL)
                            return DKIM_STAT_NORESOURCE;
              }

              dkim->dkim_state = DKIM_STATE_EOM2;

              return DKIM_STAT_NOSIG;
       }

       lib = dkim->dkim_libhandle;

       /*
       **  If a signature has "l=" set but it was greater than the
       **  canonicalized body length, the signature is invalid.
       */

       for (c = 0; c < dkim->dkim_sigcount; c++)
       {
              sig = dkim->dkim_siglist[c];

              if (sig->sig_bodycanon != NULL &&
                  sig->sig_bodycanon->canon_length != (ssize_t) -1 &&
                  sig->sig_bodycanon->canon_wrote < sig->sig_bodycanon->canon_length)
                     sig->sig_error = DKIM_SIGERROR_TOOLARGE_L;
       }

       /* invoke the final callback if defined */
       if (lib->dkiml_final != NULL)
       {
              status = lib->dkiml_final(dkim, dkim->dkim_siglist,
                                        dkim->dkim_sigcount);
              switch (status)
              {
                case DKIM_CBSTAT_CONTINUE:
                     break;

                case DKIM_CBSTAT_REJECT:
                     return DKIM_STAT_CBREJECT;

                case DKIM_CBSTAT_TRYAGAIN:
                     return DKIM_STAT_CBTRYAGAIN;

                case DKIM_CBSTAT_ERROR:
                     return DKIM_STAT_CBERROR;

                default:
                     return DKIM_STAT_CBINVALID;
              }
       }

       dkim->dkim_state = DKIM_STATE_EOM2;

       /* see if we have a passing signature with bh match */
       for (c = 0; c < dkim->dkim_sigcount; c++)
       {
              sig = dkim->dkim_siglist[c];

              if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
                  (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0 &&
                  sig->sig_bh == DKIM_SIGBH_MATCH)
                     break;

              sig = NULL;
       }

       /* run 'em until we get one */
       if (sig == NULL)
       {
              DKIM_SIGINFO *firstgood = NULL;

              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     sig = dkim->dkim_siglist[c];

                     /* if not ignoring */
                     if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
                     {
                            /* run this signature */
                            status = dkim_sig_process(dkim, sig);
                            if (status != DKIM_STAT_OK)
                            {
                                   sig = NULL;
                                   continue;
                            }

                            /* pass and bh match? */
                            if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
                                sig->sig_bh == DKIM_SIGBH_MATCH)
                            {
                                   if (firstgood == NULL)
                                          firstgood = sig;

                                   /* continue? */
                                   if ((lib->dkiml_flags & DKIM_LIBFLAGS_VERIFYONE) != 0)
                                          break;
                            }
                     }

                     sig = NULL;
              }

              if (sig == NULL)
                     sig = firstgood;
       }

       /*
       **  If still none, we're going to fail so just use the
       **  first one.
       */

       if (sig == NULL)
       {
              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     sig = dkim->dkim_siglist[c];
                     if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
                            break;
                     sig = NULL;
              }
       }

       /* caller marked everything with "ignore" */
       if (sig == NULL)
       {
              dkim_error(dkim, "all signatures ignored by caller");
              return DKIM_STAT_NOSIG;
       }

       dkim->dkim_signature = sig;

       /* things for which we return DKIM_STAT_CANTVRFY */
       if (sig->sig_error != DKIM_SIGERROR_OK &&
           sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
           sig->sig_error != DKIM_SIGERROR_KEYFAIL &&
           sig->sig_error != DKIM_SIGERROR_BADSIG &&
           sig->sig_error != DKIM_SIGERROR_KEYREVOKED &&
           sig->sig_error != DKIM_SIGERROR_NOKEY)
       {
              if (dkim->dkim_error == NULL ||
                  dkim->dkim_error[0] == '\0')
              {
                     dkim_error(dkim, dkim_code_to_name(sigerrors,
                                                        sig->sig_error));
              }

              return DKIM_STAT_CANTVRFY;
       }

       /* initialize final result */
       ret = DKIM_STAT_OK;
       if (sig->sig_error == DKIM_SIGERROR_NOKEY)
              ret = DKIM_STAT_NOKEY;
       else if (sig->sig_error == DKIM_SIGERROR_KEYFAIL)
              ret = DKIM_STAT_KEYFAIL;
       else if (sig->sig_error == DKIM_SIGERROR_KEYREVOKED)
              ret = DKIM_STAT_REVOKED;
       else if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
              ret = DKIM_STAT_BADSIG;
       else if (sig->sig_bh == DKIM_SIGBH_MISMATCH)
              ret = DKIM_STAT_BADSIG;
       else if (sig->sig_error == DKIM_SIGERROR_BADSIG)
              ret = DKIM_STAT_BADSIG;

       /* set testkey based on the key flags */
       if (testkey != NULL &&
           (sig->sig_flags & DKIM_SIGFLAG_TESTKEY) != 0)
              *testkey = TRUE;

       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_error ( DKIM *  dkim,
const char *  format,
  ... 
)

Definition at line 4490 of file dkim.c.

{
       int flen;
       int saverr;
       u_char *new;
       va_list va;

       assert(dkim != NULL);
       assert(format != NULL);

       saverr = errno;

       if (dkim->dkim_error == NULL)
       {
              dkim->dkim_error = DKIM_MALLOC(dkim, DEFERRLEN);
              if (dkim->dkim_error == NULL)
              {
                     errno = saverr;
                     return;
              }
              dkim->dkim_errlen = DEFERRLEN;
       }

       for (;;)
       {
              va_start(va, format);
              flen = vsnprintf((char *) dkim->dkim_error, dkim->dkim_errlen,
                               format, va);
              va_end(va);

              /* compensate for broken vsnprintf() implementations */
              if (flen == -1)
                     flen = dkim->dkim_errlen * 2;

              if (flen >= dkim->dkim_errlen)
              {
                     new = DKIM_MALLOC(dkim, flen + 1);
                     if (new == NULL)
                     {
                            errno = saverr;
                            return;
                     }

                     DKIM_FREE(dkim, dkim->dkim_error);
                     dkim->dkim_error = new;
                     dkim->dkim_errlen = flen + 1;
              }
              else
              {
                     break;
              }
       }

       errno = saverr;
}
int dkim_flush_cache ( DKIM_LIB *  lib)

Definition at line 8470 of file dkim.c.

{
#ifdef QUERY_CACHE
       int err;
#endif /* QUERY_CACHE */

       assert(lib != NULL);

#ifdef QUERY_CACHE
       if (lib->dkiml_cache == NULL)
              return -1;

       return dkim_cache_expire(lib->dkiml_cache, 0, &err);
#else /* QUERY_CACHE */
       return -1;
#endif /* QUERY_CACHE */
}
DKIM_STAT dkim_free ( DKIM *  dkim)

Definition at line 4933 of file dkim.c.

{
       assert(dkim != NULL);

#ifdef _FFR_RESIGN
       /* XXX -- this should be mutex-protected */
       if (dkim->dkim_resign != NULL)
       {
              if (dkim->dkim_resign->dkim_refcnt == 0)
                     dkim_free(dkim->dkim_resign);
              else
                     dkim->dkim_resign->dkim_refcnt--;
       }
       else if (dkim->dkim_refcnt != 0)
       {
              return DKIM_STAT_INVALID;
       }
#endif /* _FFR_RESIGN */

       /* blast the headers */
#ifdef _FFR_RESIGN
       if (dkim->dkim_resign == NULL && dkim->dkim_hhead != NULL)
#else /* _FFR_RESIGN */
       if (dkim->dkim_hhead != NULL)
#endif /* _FFR_RESIGN */
       {
              struct dkim_header *next;
              struct dkim_header *hdr;

              for (hdr = dkim->dkim_hhead; hdr != NULL; )
              {
                     next = hdr->hdr_next;

                     CLOBBER(hdr->hdr_text);
                     CLOBBER(hdr);

                     hdr = next;
              }
       }

       /* blast the data sets */
#ifdef _FFR_RESIGN
       if (dkim->dkim_resign == NULL && dkim->dkim_sethead != NULL)
#else /* _FFR_RESIGN */
       if (dkim->dkim_sethead != NULL)
#endif /* _FFR_RESIGN */
       {
              DKIM_SET *set;
              DKIM_SET *next;

              for (set = dkim->dkim_sethead; set != NULL; )
              {
                     next = set->set_next;

                     dkim_set_free(dkim, set);

                     set = next;
              }
       }

       /* trash the signature list */
       if (dkim->dkim_siglist != NULL)
       {
              int c;

              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     if (dkim->dkim_siglist[c]->sig_context != NULL &&
                         dkim->dkim_libhandle->dkiml_sig_handle_free != NULL)
                     {
                            dkim->dkim_libhandle->dkiml_sig_handle_free(dkim->dkim_closure,
                                                                        dkim->dkim_siglist[c]->sig_context);
                     }

                     CLOBBER(dkim->dkim_siglist[c]->sig_key);
                     CLOBBER(dkim->dkim_siglist[c]->sig_sig);
                     if (dkim->dkim_siglist[c]->sig_keytype == DKIM_KEYTYPE_RSA)
                     {
                            struct dkim_rsa *rsa;

                            rsa = dkim->dkim_siglist[c]->sig_signature;
                            if (rsa != NULL)
                            {
#ifdef USE_GNUTLS
                                   KEY_CLOBBER(rsa->rsa_key);
                                   PUBKEY_CLOBBER(rsa->rsa_pubkey);
                                   PRIVKEY_CLOBBER(rsa->rsa_privkey);
                                   HCLOBBER(rsa->rsa_rsaout.data);
#else /* USE_GNUTLS */
                                   BIO_CLOBBER(rsa->rsa_keydata);
                                   EVP_CLOBBER(rsa->rsa_pkey);
                                   RSA_CLOBBER(rsa->rsa_rsa);
                                   CLOBBER(rsa->rsa_rsaout);
#endif /* USE_GNUTLS */
                            }
                     }
                     CLOBBER(dkim->dkim_siglist[c]->sig_signature);
                     CLOBBER(dkim->dkim_siglist[c]);
              }

              CLOBBER(dkim->dkim_siglist);
       }

       if (dkim->dkim_xtags != NULL)
       {
              struct dkim_xtag *cur;
              struct dkim_xtag *next;

              cur = dkim->dkim_xtags;
              while (cur != NULL)
              {
                     next = cur->xt_next;
                     free(cur);
                     cur = next;
              }
       }

       /* destroy canonicalizations */
       dkim_canon_cleanup(dkim);

       CLOBBER(dkim->dkim_b64sig);
       CLOBBER(dkim->dkim_selector);
       CLOBBER(dkim->dkim_domain);
       CLOBBER(dkim->dkim_user);
       CLOBBER(dkim->dkim_key);
       CLOBBER(dkim->dkim_sender);
       CLOBBER(dkim->dkim_signer);
       CLOBBER(dkim->dkim_error);
       CLOBBER(dkim->dkim_zdecode);
       CLOBBER(dkim->dkim_hdrlist);

       DSTRING_CLOBBER(dkim->dkim_hdrbuf);
       DSTRING_CLOBBER(dkim->dkim_canonbuf);

       dkim_mfree(dkim->dkim_libhandle, dkim->dkim_closure, dkim);

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static size_t dkim_gensighdr ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
struct dkim_dstring dstr,
char *  delim 
) [static]

Definition at line 2271 of file dkim.c.

{
       _Bool firsthdr;
       _Bool nosigner = FALSE;
       int n;
       int status;
       int delimlen;
       size_t hashlen;
       size_t tmplen;
       char *format;
       u_char *hash;
       struct dkim_header *hdr;
       _Bool *always = NULL;
       u_char tmp[DKIM_MAXHEADER + 1];
       u_char b64hash[DKIM_MAXHEADER + 1];

       assert(dkim != NULL);
       assert(sig != NULL);
       assert(dstr != NULL);
       assert(delim != NULL);

       delimlen = strlen(delim);

       n = dkim->dkim_libhandle->dkiml_nalwayshdrs * sizeof(_Bool);
       if (n > 0)
       {
              always = DKIM_MALLOC(dkim, n);
              if (always == NULL)
                     return (size_t) -1;
              memset(always, '\0', n);
       }

       /* bail if we were asked to generate an invalid signature */
       if (dkim->dkim_signer != NULL)
       {
              _Bool match = FALSE;
              u_char *sd;

              sd = strchr(dkim->dkim_signer, '@');
              if (sd == NULL)
              {
                     dkim_error(dkim, "syntax error in signer value");
                     return 0;
              }

              if (strcasecmp(sd + 1, sig->sig_domain) == 0)
              {
                     match = TRUE;
              }
              else
              {
                     for (sd = strchr(sd + 1, '.');
                          sd != NULL && !match;
                          sd = strchr(sd + 1, '.'))
                     {
                            if (strcasecmp(sd + 1, sig->sig_domain) == 0)
                                   match = TRUE;
                     }
              }

              if (!match)
              {
                     if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_DROPSIGNER) == 0)
                     {
                            dkim_error(dkim,
                                       "d=/i= mismatch on signature generation");
                            return 0;
                     }
                     else
                     {
                            nosigner = TRUE;
                     }
              }
       }

       /*
       **  We need to generate a DKIM-Signature: header template
       **  and include it in the canonicalization.
       */

       /* basic required stuff */
       if (sizeof(sig->sig_timestamp) == sizeof(unsigned long long))
              format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%llu";
       else if (sizeof(sig->sig_timestamp) == sizeof(unsigned long))
              format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%lu";
       else 
              format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%u";

       tmplen = dkim_dstring_printf(dstr, format,
                                    DKIM_VERSION_SIG, delim,
                                    dkim_code_to_name(algorithms,
                                                      sig->sig_signalg),
                                    delim,
                                    dkim_code_to_name(canonicalizations,
                                                      sig->sig_hdrcanonalg),
                                    dkim_code_to_name(canonicalizations,
                                                      sig->sig_bodycanonalg),
                                    delim,
                                    sig->sig_domain, delim,
                                    sig->sig_selector, delim,
                                    sig->sig_timestamp);

       if (dkim->dkim_libhandle->dkiml_sigttl != 0)
       {
              uint64_t expire;

              expire = sig->sig_timestamp + dkim->dkim_libhandle->dkiml_sigttl;
              if (sizeof(expire) == sizeof(unsigned long long))
                     dkim_dstring_printf(dstr, ";%sx=%llu", delim, expire);
              else if (sizeof(expire) == sizeof(unsigned long))
                     dkim_dstring_printf(dstr, ";%sx=%lu", delim, expire);
              else
                     dkim_dstring_printf(dstr, ";%sx=%u", delim, expire);
       }

       if (dkim->dkim_signer != NULL && !nosigner)
       {
              dkim_dstring_printf(dstr, ";%si=%s", delim,
                                  dkim->dkim_signer);
       }

       if (dkim->dkim_xtags != NULL)
       {
              struct dkim_xtag *x;

              for (x = dkim->dkim_xtags; x != NULL; x = x->xt_next)
              {
                     dkim_dstring_printf(dstr, ";%s%s=%s", delim,
                                         x->xt_tag, x->xt_value);
              }
       }

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

       (void) dkim_canon_closebody(dkim);
       status = dkim_canon_getfinal(sig->sig_bodycanon, &hash, &hashlen);
       if (status != DKIM_STAT_OK)
       {
              dkim_error(dkim, "dkim_canon_getfinal() failed");
              if (always != NULL)
                     (void) DKIM_FREE(dkim, always);
              return (size_t) -1;
       }

       status = dkim_base64_encode(hash, hashlen,
                                   b64hash, sizeof b64hash);

       dkim_dstring_printf(dstr, ";%sbh=%s", delim, b64hash);

       /* l= */
       if (dkim->dkim_partial)
       {
              dkim_dstring_printf(dstr, ";%sl=%lu", delim,
                                  (u_long) sig->sig_bodycanon->canon_wrote);
       }

       /* h= */
       for (n = 0; n < dkim->dkim_libhandle->dkiml_nalwayshdrs; n++)
              always[n] = TRUE;

       firsthdr = TRUE;

       for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
       {
              if ((hdr->hdr_flags & DKIM_HDR_SIGNED) == 0)
                     continue;

              if (!firsthdr)
              {
                     dkim_dstring_cat1(dstr, ':');
              }
              else
              {
                     dkim_dstring_cat1(dstr, ';');
                     dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
                     dkim_dstring_catn(dstr, (u_char *) "h=", 2);
              }

              firsthdr = FALSE;

              dkim_dstring_catn(dstr, hdr->hdr_text, hdr->hdr_namelen);

              if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
              {
                     u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;

                     for (n = 0; ah[n] != NULL; n++)
                     {
                            if (strncasecmp((char *) hdr->hdr_text,
                                            (char *) ah[n],
                                            hdr->hdr_namelen) == 0)
                            {
                                   always[n] = FALSE;
                                   break;
                            }
                     }
              }
       }

       /* apply any "always sign" list */
       if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
       {
              u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;

              for (n = 0; ah[n] != NULL; n++)
              {
                     if (always[n])
                     {
                            if (!firsthdr)
                            {
                                   dkim_dstring_cat1(dstr, ':');
                            }
                            else
                            {
                                   dkim_dstring_cat1(dstr, ';');
                                   dkim_dstring_catn(dstr,
                                                     (u_char *) delim,
                                                     delimlen);
                                   dkim_dstring_catn(dstr,
                                                     (u_char *) "h=", 2);
                            }

                            firsthdr = FALSE;

                            dkim_dstring_cat(dstr, ah[n]);
                     }
              }
       }

#ifdef _FFR_OVERSIGN
       if (dkim->dkim_libhandle->dkiml_oversignhdrs != NULL)
       {
              if (firsthdr)
              {
                     dkim_dstring_cat1(dstr, ';');
                     dkim_dstring_catn(dstr, delim, delimlen);
                     dkim_dstring_catn(dstr, "h=", 2);
              }
              else
              {
                     dkim_dstring_cat1(dstr, ':');
              }

              for (n = 0;
                   dkim->dkim_libhandle->dkiml_oversignhdrs[n] != NULL;
                   n++)
              {
                     if (n != 0)
                            dkim_dstring_cat1(dstr, ':');

                     dkim_dstring_cat(dstr,
                                      dkim->dkim_libhandle->dkiml_oversignhdrs[n]);
              }
       }
#endif /* _FFR_OVERSIGN */

       /* if diagnostic headers were requested, include 'em */
       if (dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_ZTAGS)
       {
              _Bool first;
              int status;
              size_t len;
              u_char *p;
              u_char *q;
              u_char *end;
              u_char *hend;
              u_char *colon;
              unsigned char name[DKIM_MAXHEADER + 1];

              dkim_dstring_cat1(dstr, ';');
              dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
              dkim_dstring_catn(dstr, (u_char *) "z=", 2);

              first = TRUE;
              end = tmp + sizeof tmp - 1;

              for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
              {
                     /* apply "skip" header and "sign" header lists */
                     hend = hdr->hdr_text + hdr->hdr_textlen;
                     colon = memchr(hdr->hdr_text, ':', hdr->hdr_textlen);
                     if (colon != NULL)
                     {
                            hend = colon;

                            while (hend > hdr->hdr_text &&
                                   isascii(*(hend - 1)) &&
                                   isspace(*(hend - 1)))
                                   hend--;
                     }

                     strlcpy((char *) name, (char *) hdr->hdr_text,
                             sizeof name);
                     if (hend != NULL)
                            name[hend - hdr->hdr_text] = '\0';

                     if (dkim->dkim_libhandle->dkiml_skipre)
                     {
                            status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
                                             (char *) name, 0, NULL, 0);

                            if (status == 0)
                                   continue;
                            else
                                   assert(status == REG_NOMATCH);
                     }

                     if (dkim->dkim_libhandle->dkiml_signre)
                     {
                            status = regexec(&dkim->dkim_libhandle->dkiml_hdrre,
                                             (char *) name, 0, NULL, 0);

                            if (status == REG_NOMATCH)
                                   continue;
                            else
                                   assert(status == 0);
                     }

                     q = tmp;
                     len = 0;

                     if (!first)
                     {
                            *q = '|';
                            q++;
                            len++;
                     }

                     first = FALSE;

                     for (p = hdr->hdr_text; *p != '\0'; p++)
                     {
                            if (q >= end)
                                   break;

                            if ((*p >= 0x21 && *p <= 0x3a) ||
                                *p == 0x3c ||
                                (*p >= 0x3e && *p <= 0x7e))
                            {
                                   *q = *p;
                                   q++;
                                   len++;
                            }
                            else if (q < end - 4)
                            {
                                   snprintf((char *) q, 4,
                                            "=%02X", *p);
                                   q += 3;
                                   len += 3;
                            }
                     }

                     dkim_dstring_catn(dstr, tmp, len);
              }
       }

       /* and finally, an empty b= */
       dkim_dstring_cat1(dstr, ';');
       dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
       dkim_dstring_catn(dstr, (u_char *) "b=", 2);

       if (always != NULL)
              DKIM_FREE(dkim, always);

       return dkim_dstring_len(dstr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct dkim_header* dkim_get_header ( DKIM *  dkim,
u_char *  name,
size_t  namelen,
int  inst 
) [static, read]

Definition at line 1140 of file dkim.c.

{
       size_t len;
       struct dkim_header *hdr;

       assert(dkim != NULL);
       assert(name != NULL);

       if (namelen == 0)
              len = strlen((char *) name);
       else
              len = namelen;

       for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
       {
              if (hdr->hdr_namelen == len &&
                  strncasecmp((char *) hdr->hdr_text,
                              (char *) name, len) == 0)
              {
                     if (inst == 0)
                            return hdr;
                     else
                            inst--;
              }
       }

       return NULL;
}

Here is the caller graph for this function:

DKIM_STAT dkim_get_key ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
_Bool  test 
)

Definition at line 2866 of file dkim.c.

{
       _Bool gotkey = FALSE;                     /* key stored */
       _Bool gotset = FALSE;                     /* set parsed */
       _Bool gotreply = FALSE;                   /* reply received */
       int status;
       int c;
       DKIM_SIGINFO *osig;
       struct dkim_set *set = NULL;
       struct dkim_set *nextset;
       unsigned char *p;
       unsigned char buf[BUFRSZ + 1];

       assert(dkim != NULL);
       assert(sig != NULL);
       assert(sig->sig_selector != NULL);
       assert(sig->sig_domain != NULL);

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

       /* see if one of the other signatures already has the key we need */
       for (c = 0; c < dkim->dkim_sigcount; c++)
       {
              osig = dkim->dkim_siglist[c];

              /* don't self-search */
              if (sig == osig)
                     continue;

              /* skip unprocessed signatures */
              if ((osig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
                     continue;

              /* skip unless selector and domain match */
              if (strcmp((char *) osig->sig_domain,
                         (char *) sig->sig_domain) != 0 ||
                  strcmp((char *) osig->sig_selector,
                         (char *) sig->sig_selector) != 0)
                     continue;

              /* we got a match!  copy the key data (if any)... */
              if (osig->sig_key != NULL)
              {
                     sig->sig_key = DKIM_MALLOC(dkim, osig->sig_b64keylen);
                     if (sig->sig_key == NULL)
                     {
                            dkim_error(dkim,
                                       "unable to allocate %d byte(s)",
                                       osig->sig_b64keylen);
                            return DKIM_STAT_NORESOURCE;
                     }

                     memcpy(sig->sig_key, osig->sig_key,
                            osig->sig_b64keylen);

                     sig->sig_keylen = osig->sig_keylen;

                     gotkey = TRUE;
              }

              /* ...and the key tag list (if any) */
              if (osig->sig_keytaglist != NULL)
              {
                     sig->sig_keytaglist = osig->sig_keytaglist;
                     set = sig->sig_keytaglist;

                     gotset = TRUE;
                     gotreply = TRUE;
              }

              break;
       }

       /* try a local function if there was one defined */
       if (!gotkey && dkim->dkim_libhandle->dkiml_key_lookup != NULL)
       {
              DKIM_CBSTAT cbstatus;

              cbstatus = dkim->dkim_libhandle->dkiml_key_lookup(dkim,
                                                                sig,
                                                                buf,
                                                                sizeof buf);
              switch (cbstatus)
              {
                case DKIM_CBSTAT_CONTINUE:
                     gotreply = TRUE;
                     break;

                case DKIM_CBSTAT_REJECT:
                     return DKIM_STAT_CBREJECT;

                case DKIM_CBSTAT_TRYAGAIN:
                     return DKIM_STAT_CBTRYAGAIN;

                case DKIM_CBSTAT_NOTFOUND:
                     return DKIM_STAT_NOKEY;

                case DKIM_CBSTAT_ERROR:
                     return DKIM_STAT_CBERROR;

                default:
                     return DKIM_STAT_CBINVALID;
              }
       }

       /* if no local function or it returned no result, make the query */
       if (!gotreply)
       {
              /* use appropriate get method */
              switch (sig->sig_query)
              {
                case DKIM_QUERY_DNS:
                     status = (int) dkim_get_key_dns(dkim, sig, buf,
                                                     sizeof buf);
                     if (status != (int) DKIM_STAT_OK)
                            return (DKIM_STAT) status;
                     break;

                case DKIM_QUERY_FILE:
                     status = (int) dkim_get_key_file(dkim, sig, buf,
                                                      sizeof buf);
                     if (status != (int) DKIM_STAT_OK)
                            return (DKIM_STAT) status;
                     break;

                default:
                     assert(0);
              }
       }

       /* decode the payload */
       if (!gotset)
       {
              if (buf[0] == '\0')
              {
                     dkim_error(dkim, "empty key record");
                     return DKIM_STAT_SYNTAX;
              }

              status = dkim_process_set(dkim, DKIM_SETTYPE_KEY, buf,
                                        strlen((char *) buf), NULL, FALSE,
                                        NULL);
              if (status != DKIM_STAT_OK)
                     return status;

              /* get the last key */
              set = dkim_set_first(dkim, DKIM_SETTYPE_KEY);
              assert(set != NULL);
              for (;;)
              {
                     nextset = dkim_set_next(set, DKIM_SETTYPE_KEY);
                     if (nextset == NULL)
                            break;
                     set = nextset;
              }
              assert(set != NULL);

              sig->sig_keytaglist = set;
       }

       /* verify key version first */
       p = dkim_param_get(set, (u_char *) "v");
       if (p != NULL && strcmp((char *) p, DKIM_VERSION_KEY) != 0)
       {
              dkim_error(dkim, "invalid key version '%s'", p);
              sig->sig_error = DKIM_SIGERROR_KEYVERSION;
              return DKIM_STAT_SYNTAX;
       }

       /* then make sure the hash type is something we can handle */
       p = dkim_param_get(set, (u_char *) "h");
       if (!dkim_key_hashesok(dkim->dkim_libhandle, p))
       {
              dkim_error(dkim, "unknown hash '%s'", p);
              sig->sig_error = DKIM_SIGERROR_KEYUNKNOWNHASH;
              return DKIM_STAT_SYNTAX;
       }
       /* ...and that this key is approved for this signature's hash */
       else if (!test && !dkim_key_hashok(sig, p))
       {
              dkim_error(dkim, "signature-key hash mismatch");
              sig->sig_error = DKIM_SIGERROR_KEYHASHMISMATCH;
              return DKIM_STAT_CANTVRFY;
       }

       /* make sure it's a key designated for e-mail */
       if (!dkim_key_smtp(set))
       {
              dkim_error(dkim, "key type mismatch");
              sig->sig_error = DKIM_SIGERROR_NOTEMAILKEY;
              return DKIM_STAT_CANTVRFY;
       }

       /* then key type */
       p = dkim_param_get(set, (u_char *) "k");
       if (p == NULL)
       {
              dkim_error(dkim, "key type missing");
              sig->sig_error = DKIM_SIGERROR_KEYTYPEMISSING;
              return DKIM_STAT_SYNTAX;
       }
       else if (dkim_name_to_code(keytypes, (char *) p) == -1)
       {
              dkim_error(dkim, "unknown key type '%s'", p);
              sig->sig_error = DKIM_SIGERROR_KEYTYPEUNKNOWN;
              return DKIM_STAT_SYNTAX;
       }

       if (!gotkey)
       {
              /* decode the key */
              sig->sig_b64key = dkim_param_get(set, (u_char *) "p");
              if (sig->sig_b64key == NULL)
              {
                     dkim_error(dkim, "key missing");
                     return DKIM_STAT_SYNTAX;
              }
              else if (sig->sig_b64key[0] == '\0')
              {
                     return DKIM_STAT_REVOKED;
              }
              sig->sig_b64keylen = strlen((char *) sig->sig_b64key);

              sig->sig_key = DKIM_MALLOC(dkim, sig->sig_b64keylen);
              if (sig->sig_key == NULL)
              {
                     dkim_error(dkim, "unable to allocate %d byte(s)",
                                sig->sig_b64keylen);
                     return DKIM_STAT_NORESOURCE;
              }

              status = dkim_base64_decode(sig->sig_b64key, sig->sig_key,
                                          sig->sig_b64keylen);
              if (status < 0)
              {
                     dkim_error(dkim, "key missing");
                     return DKIM_STAT_SYNTAX;
              }

              sig->sig_keylen = status;
       }

       /* store key flags */
       p = dkim_param_get(set, (u_char *) "t");
       if (p != NULL)
       {
              u_int flag;
              char *t;
              char *last;
              char tmp[BUFRSZ + 1];

              strlcpy(tmp, (char *) p, sizeof tmp);

              for (t = strtok_r(tmp, ":", &last);
                   t != NULL;
                   t = strtok_r(NULL, ":", &last))
              {
                     flag = (u_int) dkim_name_to_code(keyflags, t);
                     if (flag != (u_int) -1)
                            sig->sig_flags |= flag;
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_get_policy ( DKIM *  dkim,
u_char *  query,
_Bool  excheck,
int *  qstatus,
dkim_policy_t policy,
u_int *  pflags 
) [static]

Definition at line 2739 of file dkim.c.

{
       int status = 0;
       int qstat = NOERROR;
       unsigned int lpflags;
       dkim_policy_t lpolicy;
       DKIM_STAT pstatus;
       unsigned char buf[BUFRSZ + 1];

       assert(dkim != NULL);
       assert(query != NULL);
       assert(qstatus != NULL);
       assert(policy != NULL);
       assert(pflags != NULL);

       if (dkim->dkim_libhandle->dkiml_policy_lookup != NULL)
       {
              DKIM_CBSTAT cbstatus;

              cbstatus = dkim->dkim_libhandle->dkiml_policy_lookup(dkim,
                                                                   query,
                                                                   excheck,
                                                                   buf,
                                                                   sizeof buf,
                                                                   &qstat);

              switch (cbstatus)
              {
                case DKIM_CBSTAT_CONTINUE:
                     status = 1;
                     break;

                case DKIM_CBSTAT_REJECT:
                     return DKIM_STAT_CBREJECT;

                case DKIM_CBSTAT_TRYAGAIN:
                     return DKIM_STAT_CBTRYAGAIN;

                case DKIM_CBSTAT_NOTFOUND:
                     break;

                case DKIM_CBSTAT_ERROR:
                     return DKIM_STAT_CBERROR;

                default:
                     return DKIM_STAT_CBINVALID;
              }
       }
       else
       {
              switch (dkim->dkim_libhandle->dkiml_querymethod)
              {
                case DKIM_QUERY_UNKNOWN:
                case DKIM_QUERY_DNS:
                     status = dkim_get_policy_dns(dkim, query, excheck,
                                                  buf, sizeof buf, &qstat);
                     break;

                case DKIM_QUERY_FILE:
                     status = dkim_get_policy_file(dkim, query, buf,
                                                   sizeof buf, &qstat);
                     break;

                default:
                     assert(0);
                     /* just to silence -Wall */
                     return -1;
              }
       }

       if (status == -1)
              return DKIM_STAT_CANTVRFY;
       else if (status == 0)
              qstat = NXDOMAIN;

       *qstatus = qstat;

       if (!excheck && qstat == NOERROR && status == 1)
       {
              u_char *p;
              struct dkim_set *set;

              pstatus = dkim_process_set(dkim, DKIM_SETTYPE_POLICY,
                                         buf, strlen((char *) buf),
                                         NULL, FALSE, NULL);
              if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_REPORTBADADSP) == 0 &&
                  pstatus == DKIM_STAT_SYNTAX)
              {
                     *policy = DKIM_POLICY_DEFAULT;
                     *qstatus = NXDOMAIN;
                     *pflags = 0;
              }
              else if (pstatus != DKIM_STAT_OK)
              {
                     return pstatus;
              }

              lpolicy = DKIM_POLICY_DEFAULT;
              lpflags = 0;

              set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);

              p = dkim_param_get(set, (u_char *) "dkim");
              if (p != NULL)
                     lpolicy = dkim_name_to_code(policies, (char *) p);

              *policy = lpolicy;
              *pflags = lpflags;
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_get_reputation ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
char *  qroot,
int *  rep 
)

Definition at line 8531 of file dkim.c.

const unsigned char* dkim_get_signer ( DKIM *  dkim)

Definition at line 7845 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_signer;
}
DKIM_STAT dkim_get_sigsubstring ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
char *  buf,
size_t *  buflen 
)

Definition at line 8551 of file dkim.c.

{
       int c;
       int d;
       int x;
       int b1len;
       int b2len;
       int minlen;
       char *b1;
       char *b2;

       assert(dkim != NULL);
       assert(sig != NULL);
       assert(buf != NULL);
       assert(buflen != NULL);

       if (dkim->dkim_minsiglen == 0)
       {
              dkim->dkim_minsiglen = MINSIGLEN;

              for (c = 0; c < dkim->dkim_sigcount - 1; c++)
              {
                     b1 = (char *) dkim_param_get(dkim->dkim_siglist[c]->sig_taglist,
                                                  (u_char *) "b");
                     if (b1 == NULL)
                            continue;

                     b1len = strlen(b1);

                     for (d = c + 1; d < dkim->dkim_sigcount; d++)
                     {
                            b2 = (char *) dkim_param_get(dkim->dkim_siglist[d]->sig_taglist,
                                                         (u_char *) "b");
                            if (b2 == NULL)
                                   continue;

                            if (strncmp(b1, b2, dkim->dkim_minsiglen) != 0)
                                   continue;

                            b2len = strlen(b2);

                            minlen = MIN(strlen(b1), strlen(b2));

                            for (x = dkim->dkim_minsiglen; x < minlen; x++)
                            {
                                   if (b1[x] != b2[x])
                                          break;
                            }

                            dkim->dkim_minsiglen = x + 1;
                     }
              }
       }

       b1 = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "b");
       if (b1 == NULL)
              return DKIM_STAT_SYNTAX;

       minlen = MIN(*buflen, dkim->dkim_minsiglen);
       strncpy(buf, b1, minlen);
       if (minlen < *buflen)
              buf[minlen] = '\0';
       *buflen = minlen;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* dkim_get_user_context ( DKIM *  dkim)

Definition at line 8107 of file dkim.c.

{
       assert(dkim != NULL);

       return (void *) dkim->dkim_user_context;
}

Here is the caller graph for this function:

DKIM_STAT dkim_getcachestats ( u_int *  queries,
u_int *  hits,
u_int *  expired 
)

Definition at line 8506 of file dkim.c.

{
#ifdef QUERY_CACHE
       dkim_cache_stats(queries, hits, expired);
       return DKIM_STAT_OK;
#else /* QUERY_CACHE */
       return DKIM_STAT_NOTIMPLEMENT;
#endif /* QUERY_CACHE */
}

Here is the caller graph for this function:

u_char* dkim_getdomain ( DKIM *  dkim)

Definition at line 8144 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_domain;
}

Here is the caller graph for this function:

const char* dkim_geterror ( DKIM *  dkim)

Definition at line 7900 of file dkim.c.

{
       assert(dkim != NULL);

       return (const char *) dkim->dkim_error;
}

Here is the caller graph for this function:

const char* dkim_getid ( DKIM *  dkim)

Definition at line 6900 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_id;
}

Here is the caller graph for this function:

int dkim_getmode ( DKIM *  dkim)

Definition at line 8125 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_mode;
}

Here is the caller graph for this function:

_Bool dkim_getpartial ( DKIM *  dkim)

Definition at line 7919 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_partial;
}
const char* dkim_getpolicystr ( int  policy)

Definition at line 8041 of file dkim.c.

{
       return dkim_code_to_name(policies, policy);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dkim_getpresult ( DKIM *  dkim)

Definition at line 8007 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_presult;
}

Here is the caller graph for this function:

const char* dkim_getpresultstr ( int  presult)

Definition at line 8025 of file dkim.c.

{
       return dkim_code_to_name(policyresults, presult);
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* dkim_getresultstr ( DKIM_STAT  result)

Definition at line 7991 of file dkim.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM_STAT dkim_getsender ( DKIM *  dkim,
u_char **  hdrs 
) [static]

Definition at line 2651 of file dkim.c.

{
       int c;
       size_t hlen;
       DKIM_STAT status;
       unsigned char *domain;
       unsigned char *user;
       struct dkim_header *sender = NULL;
       struct dkim_header *cur;

       assert(dkim != NULL);
       assert(hdrs != NULL);

       if (dkim->dkim_sender != NULL)
              return DKIM_STAT_OK;

       for (c = 0; hdrs[c] != NULL; c++)
       {
              hlen = strlen((char *) hdrs[c]);

              for (cur = dkim->dkim_hhead; cur != NULL; cur = cur->hdr_next)
              {
                     if (hlen == cur->hdr_namelen &&
                         strncasecmp((char *) hdrs[c],
                                     (char *) cur->hdr_text,
                                     hlen) == 0)
                     {
                            sender = cur;
                            break;
                     }
              }
       }

       if (sender == NULL)
       {
              dkim_error(dkim, "no sender headers detected");
              return DKIM_STAT_SYNTAX;
       }
       dkim->dkim_senderhdr = sender;

       if (sender->hdr_colon == NULL)
       {
              dkim_error(dkim, "syntax error in headers");
              return DKIM_STAT_SYNTAX;
       }

       dkim->dkim_sender = dkim_strdup(dkim, sender->hdr_colon + 1, 0);
       if (dkim->dkim_sender == NULL)
              return DKIM_STAT_NORESOURCE;

       status = dkim_mail_parse(dkim->dkim_sender, &user, &domain);
       if (status != 0 || domain == NULL || user == NULL ||
           domain[0] == '\0' || user[0] == '\0')
       {
              dkim_error(dkim, "can't determine sender address");
              return DKIM_STAT_SYNTAX;
       }

       if (dkim->dkim_domain == NULL)
       {
              dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
              if (dkim->dkim_domain == NULL)
                     return DKIM_STAT_NORESOURCE;
       }

       dkim->dkim_user = dkim_strdup(dkim, user, 0);
       if (dkim->dkim_user == NULL)
              return DKIM_STAT_NORESOURCE;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_getsighdr ( DKIM *  dkim,
u_char *  buf,
size_t  buflen,
size_t  initial 
)

Definition at line 7247 of file dkim.c.

{
       u_char *p;
       size_t len;
       DKIM_STAT status;

       assert(dkim != NULL);
       assert(buf != NULL);
       assert(buflen > 0);

       status = dkim_getsighdr_d(dkim, initial, &p, &len);
       if (status != DKIM_STAT_OK)
              return status;

       if (len > buflen)
       {
              dkim_error(dkim, "generated signature header too large");
              return DKIM_STAT_NORESOURCE;
       }

       strlcpy((char *) buf, (char *) p, buflen);

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_getsighdr_d ( DKIM *  dkim,
size_t  initial,
u_char **  buf,
size_t *  buflen 
)

Definition at line 6973 of file dkim.c.

{
       size_t len;
       char *ctx;
       char *pv;
       DKIM_SIGINFO *sig;
       struct dkim_dstring *tmpbuf;

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

       if (dkim->dkim_state != DKIM_STATE_EOM2 ||
           dkim->dkim_mode != DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

#define       DELIMITER     "\001"

       sig = dkim->dkim_signature;
       if (sig == NULL)
              sig = dkim->dkim_siglist[0];

       if ((sig->sig_flags & DKIM_SIGFLAG_KEYLOADED) == 0)
       {
              dkim_error(dkim, "private key load failure");
              return DKIM_STAT_INVALID;
       }

       tmpbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
       if (tmpbuf == NULL)
       {
              dkim_error(dkim, "failed to allocate dynamic string");
              return DKIM_STAT_NORESOURCE;
       }

       if (dkim->dkim_hdrbuf == NULL)
       {
              dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
              if (dkim->dkim_hdrbuf == NULL)
              {
                     dkim_dstring_free(tmpbuf);
                     dkim_error(dkim, "failed to allocate dynamic string");
                     return DKIM_STAT_NORESOURCE;
              }
       }
       else
       {
              dkim_dstring_blank(dkim->dkim_hdrbuf);
       }

       /* compute and extract the signature header */
       len = dkim_gensighdr(dkim, sig, tmpbuf, DELIMITER);
       if (len == 0)
              return DKIM_STAT_INVALID;

       if (dkim->dkim_b64sig != NULL)
              dkim_dstring_cat(tmpbuf, dkim->dkim_b64sig);

       if (dkim->dkim_margin == 0)
       {
              _Bool first = TRUE;

              for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
                                 DELIMITER, &ctx);
                   pv != NULL;
                   pv = strtok_r(NULL, DELIMITER, &ctx))
              {
                     if (!first)
                            dkim_dstring_cat1(dkim->dkim_hdrbuf, ' ');

                     dkim_dstring_cat(dkim->dkim_hdrbuf, (u_char *) pv);

                     first = FALSE;
              }
       }
       else
       {
              _Bool first = TRUE;
              _Bool forcewrap;
              int pvlen;
              int whichlen;
              char *p;
              char *q;
              char *end;
              char which[MAXTAGNAME + 1];

              len = initial;
              end = which + MAXTAGNAME;

              for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
                                 DELIMITER, &ctx);
                   pv != NULL;
                   pv = strtok_r(NULL, DELIMITER, &ctx))
              {
                     for (p = pv, q = which; *p != '=' && q <= end; p++, q++)
                     {
                            *q = *p;
                            *(q + 1) = '\0';
                     }

                     whichlen = strlen(which);

                     /* force wrapping of "b=" ? */

                     forcewrap = FALSE;
                     if (sig->sig_keytype == DKIM_KEYTYPE_RSA)
                     {
                            u_int siglen;

                            siglen = BASE64SIZE(sig->sig_keybits / 8);
                            if (strcmp(which, "b") == 0 &&
                                len + whichlen + siglen + 1 >= dkim->dkim_margin)
                                   forcewrap = TRUE;
                     }

                     pvlen = strlen(pv);

                     if (len == 0 || first)
                     {
                            dkim_dstring_catn(dkim->dkim_hdrbuf,
                                              (u_char *) pv,
                                              pvlen);
                            len += pvlen;
                            first = FALSE;
                     }
                     else if (forcewrap || len + pvlen > dkim->dkim_margin)
                     {
                            forcewrap = FALSE;
                            dkim_dstring_catn(dkim->dkim_hdrbuf,
                                              (u_char *) "\r\n\t", 3);
                            len = 8;

                            if (strcmp(which, "h") == 0)
                            {                    /* break at colons */
                                   _Bool ifirst = TRUE;
                                   int tmplen;
                                   char *tmp;
                                   char *ctx2;

                                   for (tmp = strtok_r(pv, ":", &ctx2);
                                        tmp != NULL;
                                        tmp = strtok_r(NULL, ":", &ctx2))
                                   {
                                          tmplen = strlen(tmp);

                                          if (ifirst)
                                          {
                                                 dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                                   (u_char *) tmp,
                                                                   tmplen);
                                                 len += tmplen;
                                                 ifirst = FALSE;
                                          }
                                          else if (len + tmplen + 1 > dkim->dkim_margin)
                                          {
                                                 dkim_dstring_cat1(dkim->dkim_hdrbuf,
                                                                   ':');
                                                 len += 1;
                                                 dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                                   (u_char *) "\r\n\t ",
                                                                   4);
                                                 len = 9;
                                                 dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                                   (u_char *) tmp,
                                                                   tmplen);
                                                 len += tmplen;
                                          }
                                          else
                                          {
                                                 dkim_dstring_cat1(dkim->dkim_hdrbuf,
                                                                   ':');
                                                 len += 1;
                                                 dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                                   (u_char *) tmp,
                                                                   tmplen);
                                                 len += tmplen;
                                          }
                                   }

                            }
                            else if (strcmp(which, "b") == 0 ||
                                     strcmp(which, "bh") == 0 ||
                                     strcmp(which, "z") == 0)
                            {                    /* break at margins */
                                   int offset;
                                   int n;
                                   char *x;
                                   char *y;

                                   offset = whichlen + 1;

                                   dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                     (u_char *) which,
                                                     whichlen);
                                   dkim_dstring_cat1(dkim->dkim_hdrbuf,
                                                     '=');

                                   len += offset;

                                   dkim_dstring_cat1(dkim->dkim_hdrbuf,
                                                     *(pv + offset));
                                   len++;

                                   x = pv + offset + 1;
                                   y = pv + pvlen;

                                   while (x < y)
                                   {
                                          if (dkim->dkim_margin - len == 0)
                                          {
                                                 dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                                   (u_char *) "\r\n\t ",
                                                                   4);
                                                 len = 9;
                                          }

                                          n = MIN(dkim->dkim_margin - len,
                                                  y - x);
                                          dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                            (u_char *) x,
                                                            n);
                                          x += n;
                                          len += n;
                                          
                                   }
                            }
                            else
                            {                    /* break at delimiter */
                                   dkim_dstring_catn(dkim->dkim_hdrbuf,
                                                     (u_char *) pv,
                                                     pvlen);
                                   len += pvlen;
                            }
                     }
                     else
                     {
                            if (!first)
                            {
                                   dkim_dstring_cat1(dkim->dkim_hdrbuf,
                                                     ' ');
                                   len += 1;
                            }

                            first = FALSE;
                            dkim_dstring_catn(dkim->dkim_hdrbuf,
                                              (u_char *) pv,
                                              pvlen);
                            len += pvlen;
                     }
              }
       }

       *buf = dkim_dstring_get(dkim->dkim_hdrbuf);
       *buflen = dkim_dstring_len(dkim->dkim_hdrbuf);

       dkim_dstring_free(tmpbuf);

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_getsiglist ( DKIM *  dkim,
DKIM_SIGINFO ***  sigs,
int *  nsigs 
)

Definition at line 6920 of file dkim.c.

{
       assert(dkim != NULL);
       assert(sigs != NULL);
       assert(nsigs != NULL);

       if (dkim->dkim_state < DKIM_STATE_EOH2)
              return DKIM_STAT_INVALID;

       *sigs = dkim->dkim_siglist;
       *nsigs = dkim->dkim_sigcount;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_SIGINFO* dkim_getsignature ( DKIM *  dkim)

Definition at line 6947 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_signature;
}

Here is the caller graph for this function:

u_char* dkim_getuser ( DKIM *  dkim)

Definition at line 8162 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_user;
}

Here is the caller graph for this function:

DKIM_STAT dkim_header ( DKIM *  dkim,
u_char *  hdr,
size_t  len 
)

Definition at line 6327 of file dkim.c.

{
       u_char *colon;
       u_char *semicolon;
       u_char *end = NULL;
       struct dkim_header *h;

       assert(dkim != NULL);
       assert(hdr != NULL);
       assert(len != 0);

#ifdef _FFR_RESIGN
       if (dkim->dkim_hdrbind)
              return DKIM_STAT_INVALID;
#endif /* _FFR_RESIGN */

       if (dkim->dkim_state > DKIM_STATE_HEADER)
              return DKIM_STAT_INVALID;
       dkim->dkim_state = DKIM_STATE_HEADER;

       colon = memchr(hdr, ':', len);
       if (colon != NULL)
       {
              end = colon;

              while (end > hdr && isascii(*(end - 1)) && isspace(*(end - 1)))
                     end--;
       }

       /* don't allow a field name containing a semicolon */
       semicolon = memchr(hdr, ';', len);
       if (semicolon != NULL && colon != NULL && semicolon < colon)
              return DKIM_STAT_SYNTAX;

       /* see if this is one we should skip */
       if (dkim->dkim_mode == DKIM_MODE_SIGN &&
           dkim->dkim_libhandle->dkiml_skipre)
       {
              int status;
              unsigned char name[DKIM_MAXHEADER + 1];

              strlcpy((char *) name, (char *) hdr, sizeof name);
              if (end != NULL)
                     name[end - hdr] = '\0';

              status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
                               (char *) name, 0, NULL, 0);

              if (status == 0)
                     return DKIM_STAT_OK;
              else
                     assert(status == REG_NOMATCH);
       }

       h = DKIM_MALLOC(dkim, sizeof(struct dkim_header));

       if (h == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)",
                         sizeof(struct dkim_header));
              return DKIM_STAT_NORESOURCE;
       }

       if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) != 0)
       {
              u_char prev = '\0';
              u_char *p;
              struct dkim_dstring *tmphdr;

              tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
              if (tmphdr == NULL)
              {
                     DKIM_FREE(dkim, h);
                     return DKIM_STAT_NORESOURCE;
              }

              for (p = hdr; *p != '\0'; p++)
              {
                     if (*p == '\n' && prev != '\r')           /* bare LF */
                     {
                            dkim_dstring_catn(tmphdr, CRLF, 2);
                     }
                     else if (prev == '\r' && *p != '\n')      /* bare CR */
                     {
                            dkim_dstring_cat1(tmphdr, '\n');
                            dkim_dstring_cat1(tmphdr, *p);
                     }
                     else                               /* other */
                     {
                            dkim_dstring_cat1(tmphdr, *p);
                     }

                     prev = *p;
              }

              if (prev == '\r')                         /* end CR */
                     dkim_dstring_cat1(tmphdr, '\n');

              h->hdr_text = dkim_strdup(dkim, dkim_dstring_get(tmphdr),
                                        dkim_dstring_len(tmphdr));

              dkim_dstring_free(tmphdr);
       }
       else
       {
              h->hdr_text = dkim_strdup(dkim, hdr, len);
       }

       if (h->hdr_text == NULL)
       {
              DKIM_FREE(dkim, h);
              return DKIM_STAT_NORESOURCE;
       }

       h->hdr_namelen = end != NULL ? end - hdr : len;
       h->hdr_textlen = len;
       if (colon == NULL)
              h->hdr_colon = NULL;
       else
              h->hdr_colon = h->hdr_text + (colon - hdr);
       h->hdr_flags = 0;
       h->hdr_next = NULL;

       if (dkim->dkim_hhead == NULL)
       {
              dkim->dkim_hhead = h;
              dkim->dkim_htail = h;
       }
       else
       {
              dkim->dkim_htail->hdr_next = h;
              dkim->dkim_htail = h;
       }

       dkim->dkim_hdrcnt++;

       if (h->hdr_colon != NULL)
       {
              if (h->hdr_namelen == DKIM_SIGNHEADER_LEN &&
                  strncasecmp((char *) hdr, DKIM_SIGNHEADER,
                              DKIM_SIGNHEADER_LEN) == 0)
              {
                     DKIM_STAT status;
                     size_t plen;

                     plen = len - (h->hdr_colon - h->hdr_text) - 1;
                     status = dkim_process_set(dkim, DKIM_SETTYPE_SIGNATURE,
                                               h->hdr_colon + 1, plen, h,
                                               FALSE, NULL);

                     if (status != DKIM_STAT_OK)
                            return status;
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_headercheck ( DKIM *  dkim) [static]

Definition at line 3143 of file dkim.c.

{
       struct dkim_header *hdr;

       assert(dkim != NULL);

       if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_STRICTHDRS) != 0)
       {
              /* Date (must be exactly one) */
              hdr = dkim_get_header(dkim, "Date", 4, 0);
              if (hdr == NULL)
              {
                     dkim_error(dkim, "Date: header field absent");
                     return FALSE;
              }

              hdr = dkim_get_header(dkim, "Date", 4, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Date: header fields present");
                     return FALSE;
              }

              /* From (must be exactly one) */
              hdr = dkim_get_header(dkim, "From", 4, 0);
              if (hdr == NULL)
              {
                     dkim_error(dkim, "From: header field absent");
                     return FALSE;
              }

              hdr = dkim_get_header(dkim, "From", 4, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple From: header fields present");
                     return FALSE;
              }

              /* Sender (no more than one) */
              hdr = dkim_get_header(dkim, "Sender", 6, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Sender: header fields present");
                     return FALSE;
              }

              /* Reply-To (no more than one) */
              hdr = dkim_get_header(dkim, "Reply-To", 8, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Reply-To: header fields present");
                     return FALSE;
              }

              /* To (no more than one) */
              hdr = dkim_get_header(dkim, "To", 2, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple To: header fields present");
                     return FALSE;
              }

              /* Cc (no more than one) */
              hdr = dkim_get_header(dkim, "Cc", 2, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Cc: header fields present");
                     return FALSE;
              }

              /* Bcc (should we even bother?) */
              hdr = dkim_get_header(dkim, "Bcc", 3, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Bcc: header fields present");
                     return FALSE;
              }

              /* Message-ID (no more than one) */
              hdr = dkim_get_header(dkim, "Message-ID", 10, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Message-ID: header fields present");
                     return FALSE;
              }

              /* In-Reply-To (no more than one) */
              hdr = dkim_get_header(dkim, "In-Reply-To", 11, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple In-Reply-To: header fields present");
                     return FALSE;
              }

              /* References (no more than one) */
              hdr = dkim_get_header(dkim, "References", 10, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple References: header fields present");
                     return FALSE;
              }

              /* Subject (no more than one) */
              hdr = dkim_get_header(dkim, "Subject", 7, 1);
              if (hdr != NULL)
              {
                     dkim_error(dkim,
                                "multiple Subject: header fields present");
                     return FALSE;
              }
       }

       return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_LIB* dkim_init ( void *(*)(void *closure, size_t nbytes)  caller_mallocf,
void(*)(void *closure, void *p)  caller_freef 
)

Definition at line 4324 of file dkim.c.

{
       u_char *td;
       DKIM_LIB *libhandle;

#ifndef USE_GNUTLS
       /* initialize OpenSSL algorithms */
       dkim_init_openssl();
#endif /* USE_GNUTLS */

       /* copy the parameters */
       libhandle = (DKIM_LIB *) malloc(sizeof(struct dkim_lib));
       if (libhandle == NULL)
              return NULL;

       td = (u_char *) getenv("DKIM_TMPDIR");
       if (td == NULL || td[0] == '\0')
              td = (u_char *) DEFTMPDIR;

       libhandle->dkiml_signre = FALSE;
       libhandle->dkiml_skipre = FALSE;
       libhandle->dkiml_malloc = caller_mallocf;
       libhandle->dkiml_free = caller_freef;
       strlcpy((char *) libhandle->dkiml_tmpdir, (char *) td, 
               sizeof libhandle->dkiml_tmpdir);
       libhandle->dkiml_flags = DKIM_LIBFLAGS_DEFAULT;
       libhandle->dkiml_timeout = DEFTIMEOUT;
       libhandle->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
       libhandle->dkiml_alwayshdrs = NULL;
#ifdef _FFR_OVERSIGN
       libhandle->dkiml_oversignhdrs = NULL;
#endif /* _FFR_OVERSIGN */
       libhandle->dkiml_nalwayshdrs = 0;
       libhandle->dkiml_mbs = NULL;
       libhandle->dkiml_querymethod = DKIM_QUERY_UNKNOWN;
       memset(libhandle->dkiml_queryinfo, '\0',
              sizeof libhandle->dkiml_queryinfo);
#ifdef QUERY_CACHE
       libhandle->dkiml_cache = NULL;
#endif /* QUERY_CACHE */
       libhandle->dkiml_fixedtime = 0;
       libhandle->dkiml_sigttl = 0;
       libhandle->dkiml_clockdrift = DEFCLOCKDRIFT;

       libhandle->dkiml_key_lookup = NULL;
       libhandle->dkiml_policy_lookup = NULL;
       libhandle->dkiml_sig_handle = NULL;
       libhandle->dkiml_sig_handle_free = NULL;
       libhandle->dkiml_sig_tagvalues = NULL;
       libhandle->dkiml_prescreen = NULL;
       libhandle->dkiml_final = NULL;
       libhandle->dkiml_dns_callback = NULL;
       libhandle->dkiml_dns_start = dkim_res_query;
       libhandle->dkiml_dns_cancel = dkim_res_cancel;
       libhandle->dkiml_dns_waitreply = dkim_res_waitreply;
       
#define FEATURE_INDEX(x)    ((x) / (8 * sizeof(u_int)))
#define FEATURE_OFFSET(x)   ((x) % (8 * sizeof(u_int)))
#define FEATURE_ADD(lib,x)  (lib)->dkiml_flist[FEATURE_INDEX((x))] |= (1 << FEATURE_OFFSET(x))

       libhandle->dkiml_flsize = (FEATURE_INDEX(DKIM_FEATURE_MAX)) + 1;
       libhandle->dkiml_flist = (u_int *) malloc(sizeof(u_int) * libhandle->dkiml_flsize);
       if (libhandle->dkiml_flist == NULL)
       {
              free(libhandle);
              return NULL;
       }
       memset(libhandle->dkiml_flist, '\0',
              sizeof(u_int) * libhandle->dkiml_flsize);

#ifdef _FFR_DIFFHEADERS
       FEATURE_ADD(libhandle, DKIM_FEATURE_DIFFHEADERS);
#endif /* _FFR_DIFFHEADERS */
#ifdef QUERY_CACHE
       FEATURE_ADD(libhandle, DKIM_FEATURE_QUERY_CACHE);
#endif /* QUERY_CACHE */
#ifdef HAVE_SHA256
       FEATURE_ADD(libhandle, DKIM_FEATURE_SHA256);
#endif /* HAVE_SHA256 */
#ifdef _FFR_DNSSEC
       FEATURE_ADD(libhandle, DKIM_FEATURE_DNSSEC);
#endif /* _FFR_DNSSEC */
#ifdef _FFR_RESIGN
       FEATURE_ADD(libhandle, DKIM_FEATURE_RESIGN);
#endif /* _FFR_RESIGN */
#ifdef _FFR_ATPS
       FEATURE_ADD(libhandle, DKIM_FEATURE_ATPS);
#endif /* _FFR_ATPS */
#ifdef _FFR_OVERSIGN
       FEATURE_ADD(libhandle, DKIM_FEATURE_OVERSIGN);
#endif /* _FFR_OVERSIGN */
       FEATURE_ADD(libhandle, DKIM_FEATURE_XTAGS);
#ifdef _FFR_DKIM_REPUTATION
       FEATURE_ADD(libhandle, DKIM_FEATURE_DKIM_REPUTATION);
#endif /* _FFR_DKIM_REPUTATION */

       /* initialize the resolver */
       (void) res_init();

       return libhandle;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dkim_init_openssl ( void  ) [static]

Definition at line 4270 of file dkim.c.

{
       pthread_mutex_lock(&openssl_lock);

       if (openssl_refcount == 0)
              OpenSSL_add_all_algorithms();
       openssl_refcount++;

       pthread_mutex_unlock(&openssl_lock);
}

Here is the caller graph for this function:

static _Bool dkim_key_hashesok ( DKIM_LIB *  lib,
u_char *  hashlist 
) [static]

Definition at line 1280 of file dkim.c.

{
       u_char *x, *y;
       u_char tmp[BUFRSZ + 1];

       assert(lib != NULL);

       if (hashlist == NULL)
              return TRUE;

       x = NULL;
       memset(tmp, '\0', sizeof tmp);

       y = hashlist;
       for (;;)
       {
              if (*y == ':' || *y == '\0')
              {
                     if (x != NULL)
                     {
                            int hashcode;

                            strlcpy((char *) tmp, (char *) x, sizeof tmp);
                            tmp[y - x] = '\0';

                            hashcode = dkim_name_to_code(hashes,
                                                         (char *) tmp);

                            if (hashcode != -1 &&
                                (hashcode != DKIM_HASHTYPE_SHA256 ||
                                 dkim_libfeature(lib, DKIM_FEATURE_SHA256)))
                                   return TRUE;
                     }

                     x = NULL;
              }
              else if (x == NULL)
              {
                     x = y;
              }

              if (*y == '\0')
                     return FALSE;
              y++;
       }

       /* NOTREACHED */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_key_hashok ( DKIM_SIGINFO *  sig,
u_char *  hashlist 
) [static]

Definition at line 1223 of file dkim.c.

{
       int hashalg;
       u_char *x, *y;
       u_char tmp[BUFRSZ + 1];

       assert(sig != NULL);

       if (hashlist == NULL)
              return TRUE;

       x = NULL;
       memset(tmp, '\0', sizeof tmp);

       y = hashlist;
       for (;;)
       {
              if (*y == ':' || *y == '\0')
              {
                     if (x != NULL)
                     {
                            strlcpy((char *) tmp, (char *) x, sizeof tmp);
                            tmp[y - x] = '\0';
                            hashalg = dkim_name_to_code(hashes,
                                                        (char *) tmp);
                            if (hashalg == sig->sig_hashtype)
                                   return TRUE;
                     }

                     x = NULL;
              }
              else if (x == NULL)
              {
                     x = y;
              }

              if (*y == '\0')
                     return FALSE;
              y++;
       }

       /* NOTREACHED */
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_key_smtp ( DKIM_SET *  set) [static]

Definition at line 1181 of file dkim.c.

{
       u_char *val;
       char *last;
       u_char *p;
       char buf[BUFRSZ + 1];

       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_KEY);

       val = dkim_param_get(set, (u_char * ) "s");

       if (val == NULL)
              return TRUE;

       strlcpy(buf, (char *) val, sizeof buf);

       for (p = (u_char *) strtok_r(buf, ":", &last);
            p != NULL;
            p = (u_char *) strtok_r(NULL, ":", &last))
       {
              if (strcmp((char *) p, "*") == 0 ||
                  strcasecmp((char *) p, "email") == 0)
                     return TRUE;
       }

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_key_syntax ( DKIM *  dkim,
u_char *  str,
size_t  len 
)

Definition at line 6844 of file dkim.c.

{
       return dkim_process_set(dkim, DKIM_SETTYPE_KEY, str, len, NULL, TRUE,
                               NULL);
}

Here is the call graph for this function:

_Bool dkim_libfeature ( DKIM_LIB *  lib,
u_int  fc 
)

Definition at line 8631 of file dkim.c.

{
       u_int idx;
       u_int offset;

       idx = fc / (8 * sizeof(int));
       offset = fc % (8 * sizeof(int));

       if (idx > lib->dkiml_flsize)
              return FALSE;
       return ((lib->dkiml_flist[idx] & (1 << offset)) != 0);
}

Here is the caller graph for this function:

uint32_t dkim_libversion ( void  )

Definition at line 8655 of file dkim.c.

Here is the caller graph for this function:

u_long dkim_minbody ( DKIM *  dkim)

Definition at line 6824 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim_canon_minbody(dkim);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static DKIM* dkim_new ( DKIM_LIB *  libhandle,
const unsigned char *  id,
void *  memclosure,
dkim_canon_t  hdrcanon_alg,
dkim_canon_t  bodycanon_alg,
dkim_alg_t  sign_alg,
DKIM_STAT statp 
) [static]

Definition at line 4201 of file dkim.c.

{
       DKIM *new;

       assert(libhandle != NULL);

       /* allocate the handle */
       new = (DKIM *) dkim_malloc(libhandle, memclosure,
                                  sizeof(struct dkim));
       if (new == NULL)
       {
              *statp = DKIM_STAT_NORESOURCE;
              return NULL;
       }

       /* populate defaults */
       memset(new, '\0', sizeof(struct dkim));
       new->dkim_id = id;
       new->dkim_signalg = (sign_alg == -1 ? DKIM_SIGN_DEFAULT
                                           : sign_alg);
       new->dkim_hdrcanonalg = (hdrcanon_alg == -1 ? DKIM_CANON_DEFAULT
                                                   : hdrcanon_alg);
       new->dkim_bodycanonalg = (bodycanon_alg == -1 ? DKIM_CANON_DEFAULT
                                                     : bodycanon_alg);
       new->dkim_querymethod = DKIM_QUERY_DEFAULT;
       new->dkim_mode = DKIM_MODE_UNKNOWN;
       new->dkim_chunkcrlf = DKIM_CRLF_UNKNOWN;
       new->dkim_state = DKIM_STATE_INIT;
       new->dkim_presult = DKIM_PRESULT_NONE;
       new->dkim_dnssec_policy = DKIM_DNSSEC_UNKNOWN;
       new->dkim_margin = (size_t) DKIM_HDRMARGIN;
       new->dkim_closure = memclosure;
       new->dkim_libhandle = libhandle;
       new->dkim_tmpdir = libhandle->dkiml_tmpdir;
       new->dkim_timeout = libhandle->dkiml_timeout;

       *statp = DKIM_STAT_OK;

#ifdef QUERY_CACHE
       if ((libhandle->dkiml_flags & DKIM_LIBFLAGS_CACHE) != 0 &&
           libhandle->dkiml_cache == NULL)
       {
              int err = 0;

              libhandle->dkiml_cache = dkim_cache_init(&err,
                                                       libhandle->dkiml_tmpdir);
       }
#endif /* QUERY_CACHE */

       return new;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_ohdrs ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
u_char **  ptrs,
int *  pcnt 
)

Definition at line 5937 of file dkim.c.

{
       int n = 0;
       char *z;
       u_char *ch;
       u_char *p;
       u_char *q;
       char *last;

       assert(dkim != NULL);
       assert(ptrs != NULL);
       assert(pcnt != NULL);

       if (dkim->dkim_mode != DKIM_MODE_VERIFY)
              return DKIM_STAT_INVALID;

       /* pick the one we're going to use */
       if (sig == NULL)
       {
              int c;

              for (c = 0; c < dkim->dkim_sigcount; c++)
              {
                     sig = dkim->dkim_siglist[c];
                     if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
                         (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
                            break;

                     sig = NULL;
              }
       }

       /* none useable; return error */
       if (sig == NULL)
              return DKIM_STAT_INVALID;

       /* find the tag */
       z = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "z");
       if (z == NULL || *z == '\0')
       {
              *pcnt = 0;
              return DKIM_STAT_OK;
       }

       /* get memory for the decode */
       if (dkim->dkim_zdecode == NULL)
       {
              dkim->dkim_zdecode = DKIM_MALLOC(dkim, MAXHEADERS);
              if (dkim->dkim_zdecode == NULL)
              {
                     dkim_error(dkim, "unable to allocate %d byte(s)",
                                strlen(z));
                     return DKIM_STAT_NORESOURCE;
              }
       }

       /* copy it */
       strlcpy((char *) dkim->dkim_zdecode, z, strlen(z));

       /* decode */
       for (ch = (u_char *) strtok_r(z, "|", &last);
            ch != NULL;
            ch = (u_char *) strtok_r(NULL, "|", &last))
       {
              for (p = ch, q = ch; *p != '\0'; p++)
              {
                     if (*p == '=')
                     {
                            char c;

                            if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))
                            {
                                   dkim_error(dkim,
                                              "invalid trailing character (0x%02x 0x%02x) in z= tag value",
                                              *(p + 1), *(p + 2));

                                   return DKIM_STAT_INVALID;
                            }

                            c = 16 * dkim_hexchar(*(p + 1)) + dkim_hexchar(*(p + 2));

                            p += 2;

                            *q = c;
                            q++;
                     }
                     else
                     {
                            if (q != p)
                                   *q = *p;
                            q++;
                     }
              }

              *q = '\0';

              if (n < *pcnt)
                     ptrs[n] = ch;
              n++;
       }

       *pcnt = n;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_options ( DKIM_LIB *  lib,
int  op,
dkim_opts_t  opt,
void *  ptr,
size_t  len 
)

Definition at line 4561 of file dkim.c.

{
       assert(lib != NULL);
       assert(op == DKIM_OP_SETOPT || op == DKIM_OP_GETOPT);
       assert(len != 0);

       switch (opt)
       {
         case DKIM_OPTS_TMPDIR:
              if (op == DKIM_OP_GETOPT)
              {
                     strlcpy((char *) ptr, (char *) lib->dkiml_tmpdir, len);
              }
              else if (ptr == NULL)
              {
                     strlcpy((char *) lib->dkiml_tmpdir, DEFTMPDIR,
                             sizeof lib->dkiml_tmpdir);
              }
              else
              {
                     strlcpy((char *) lib->dkiml_tmpdir, (char *) ptr,
                             sizeof lib->dkiml_tmpdir);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_FIXEDTIME:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_fixedtime)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_fixedtime, len);
              }
              else
              {
                     memcpy(&lib->dkiml_fixedtime, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_SIGNATURETTL:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_sigttl)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_sigttl, len);
              }
              else
              {
                     memcpy(&lib->dkiml_sigttl, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_CLOCKDRIFT:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_clockdrift)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_clockdrift, len);
              }
              else
              {
                     memcpy(&lib->dkiml_clockdrift, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_FLAGS:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_flags)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_flags, len);
              }
              else
              {
                     memcpy(&lib->dkiml_flags, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_TIMEOUT:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_timeout)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_timeout, len);
              }
              else
              {
                     memcpy(&lib->dkiml_timeout, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_SENDERHDRS:
              if (len != sizeof lib->dkiml_senderhdrs)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_senderhdrs, len);
              }
              else if (ptr == NULL)
              {
                     if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
                            dkim_clobber_array((char **) lib->dkiml_senderhdrs);

                     lib->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
              }
              else
              {
                     const char **tmp;

                     tmp = dkim_copy_array(ptr);
                     if (tmp == NULL)
                            return DKIM_STAT_NORESOURCE;

                     if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
                            dkim_clobber_array((char **) lib->dkiml_senderhdrs);

                     lib->dkiml_senderhdrs = (u_char **) tmp;
              }
              return DKIM_STAT_OK;

#ifdef _FFR_OVERSIGN
         case DKIM_OPTS_OVERSIGNHDRS:
              if (len != sizeof lib->dkiml_oversignhdrs)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_oversignhdrs, len);
              }
              else
              {
                     const char **tmp;

                     tmp = dkim_copy_array(ptr);
                     if (tmp == NULL)
                            return DKIM_STAT_NORESOURCE;

                     if (lib->dkiml_oversignhdrs != NULL)
                            dkim_clobber_array((char **) lib->dkiml_oversignhdrs);

                     lib->dkiml_oversignhdrs = (u_char **) tmp;
              }
              return DKIM_STAT_OK;
#endif /* _FFR_OVERSIGN */

         case DKIM_OPTS_ALWAYSHDRS:
              if (len != sizeof lib->dkiml_alwayshdrs)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_alwayshdrs, len);
              }
              else if (ptr == NULL)
              {
                     if (lib->dkiml_alwayshdrs != NULL)
                            dkim_clobber_array((char **) lib->dkiml_alwayshdrs);

                     lib->dkiml_alwayshdrs = NULL;
                     lib->dkiml_nalwayshdrs = 0;
              }
              else
              {
                     u_int n;
                     const char **tmp;

                     tmp = dkim_copy_array(ptr);
                     if (tmp == NULL)
                            return DKIM_STAT_NORESOURCE;

                     if (lib->dkiml_alwayshdrs != NULL)
                            dkim_clobber_array((char **) lib->dkiml_alwayshdrs);

                     lib->dkiml_alwayshdrs = (u_char **) tmp;
                     for (n = 0; lib->dkiml_alwayshdrs[n] != NULL; n++)
                            continue;
                     lib->dkiml_nalwayshdrs = n;
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_MUSTBESIGNED:
              if (len != sizeof lib->dkiml_mbs)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_mbs, len);
              }
              else if (ptr == NULL)
              {
                     lib->dkiml_mbs = NULL;
              }
              else
              {
                     const char **tmp;

                     tmp = dkim_copy_array(ptr);
                     if (tmp == NULL)
                            return DKIM_STAT_NORESOURCE;

                     if (lib->dkiml_mbs != NULL)
                            dkim_clobber_array((char **) lib->dkiml_mbs);

                     lib->dkiml_mbs = (u_char **) tmp;
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_SIGNHDRS:
              if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
              {
                     return DKIM_STAT_INVALID;
              }
              else if (ptr == NULL)
              {
                     if (lib->dkiml_signre)
                     {
                            (void) regfree(&lib->dkiml_hdrre);
                            lib->dkiml_signre = FALSE;
                     }
              }
              else
              {
                     int status;
                     u_char **hdrs;
                     char buf[BUFRSZ + 1];

                     if (lib->dkiml_signre)
                     {
                            (void) regfree(&lib->dkiml_hdrre);
                            lib->dkiml_signre = FALSE;
                     }

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

                     hdrs = (u_char **) ptr;

                     (void) strlcpy(buf, "^(", sizeof buf);

                     if (!dkim_hdrlist((u_char *) buf, sizeof buf,
                                       (u_char **) required_signhdrs, TRUE))
                            return DKIM_STAT_INVALID;
                     if (!dkim_hdrlist((u_char *) buf, sizeof buf,
                                       hdrs, FALSE))
                            return DKIM_STAT_INVALID;

                     if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
                            return DKIM_STAT_INVALID;

                     status = regcomp(&lib->dkiml_hdrre, buf,
                                      (REG_EXTENDED|REG_ICASE));
                     if (status != 0)
                            return DKIM_STAT_INTERNAL;

                     lib->dkiml_signre = TRUE;
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_SKIPHDRS:
              if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
              {
                     return DKIM_STAT_INVALID;
              }
              else if (ptr == NULL)
              {
                     if (lib->dkiml_skipre)
                     {
                            (void) regfree(&lib->dkiml_skiphdrre);
                            lib->dkiml_skipre = FALSE;
                     }
              }
              else
              {
                     int status;
                     u_char **hdrs;
                     char buf[BUFRSZ + 1];

                     if (lib->dkiml_skipre)
                     {
                            (void) regfree(&lib->dkiml_skiphdrre);
                            lib->dkiml_skipre = FALSE;
                     }

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

                     hdrs = (u_char **) ptr;

                     (void) strlcpy(buf, "^(", sizeof buf);

                     if (!dkim_hdrlist((u_char *) buf, sizeof buf,
                                       hdrs, TRUE))
                            return DKIM_STAT_INVALID;

                     if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
                            return DKIM_STAT_INVALID;

                     status = regcomp(&lib->dkiml_skiphdrre, buf,
                                      (REG_EXTENDED|REG_ICASE));
                     if (status != 0)
                            return DKIM_STAT_INTERNAL;

                     lib->dkiml_skipre = TRUE;
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_QUERYMETHOD:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (len != sizeof lib->dkiml_querymethod)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     memcpy(ptr, &lib->dkiml_querymethod, len);
              }
              else
              {
                     memcpy(&lib->dkiml_querymethod, ptr, len);
              }
              return DKIM_STAT_OK;

         case DKIM_OPTS_QUERYINFO:
              if (ptr == NULL)
                     return DKIM_STAT_INVALID;

              if (op == DKIM_OP_GETOPT)
              {
                     strlcpy(ptr, (char *) lib->dkiml_queryinfo, len);
              }
              else
              {
                     strlcpy((char *) lib->dkiml_queryinfo, ptr,
                             sizeof lib->dkiml_queryinfo);
              }
              return DKIM_STAT_OK;

         default:
              return DKIM_STAT_INVALID;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static u_char* dkim_param_get ( DKIM_SET *  set,
u_char *  param 
) [static]

Definition at line 374 of file dkim.c.

{
       DKIM_PLIST *plist;

       assert(set != NULL);
       assert(param != NULL);

       for (plist = set->set_plist[DKIM_PHASH(param[0])];
            plist != NULL;
            plist = plist->plist_next)
       {
              if (strcmp((char *) plist->plist_param, (char *) param) == 0)
                     return plist->plist_value;
       }

       return NULL;
}

Here is the caller graph for this function:

DKIM_STAT dkim_policy ( DKIM *  dkim,
dkim_policy_t pcode,
u_int *  pflags,
DKIM_PSTATE *  pstate 
)

Definition at line 5408 of file dkim.c.

{
       int wlen;
       int qstatus = NOERROR;
       unsigned int lpflags;
       DKIM_STAT status;
       dkim_policy_t policy = DKIM_POLICY_NONE;
       unsigned char query[DKIM_MAXHOSTNAMELEN + 1];

       assert(dkim != NULL);

       /* fail for signing handles */
       if (dkim->dkim_mode == DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

       /* fail if no domain could be determined */
       if (dkim->dkim_domain == NULL)
              return DKIM_STAT_SYNTAX;

       /* initialize */
       dkim->dkim_presult = DKIM_PRESULT_NONE;
       if (pstate != NULL)
       {
              qstatus = pstate->ps_qstatus;
              policy = pstate->ps_policy;
              lpflags = pstate->ps_pflags;
       }

       /*
       **  Apply RFC5617: Verify domain existence.
       */

       if (pstate == NULL || pstate->ps_state < 1)
       {
              status = dkim_get_policy(dkim, dkim->dkim_domain, TRUE,
                                       &qstatus, &policy, &lpflags);
              if (status != DKIM_STAT_OK)
              {
                     if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
                     {
                            pstate->ps_qstatus = qstatus;
                            pstate->ps_policy = policy;
                            pstate->ps_pflags = lpflags;
                     }

                     return status;
              }

              if (pstate != NULL)
                     pstate->ps_state = 1;
       }

       if (qstatus == NXDOMAIN)
       {
              dkim->dkim_presult = DKIM_PRESULT_NXDOMAIN;
              if (pcode != NULL)
                     *pcode = policy;
              return DKIM_STAT_OK;
       }

       /*
       **  Apply RFC5617: Retrieve policy.
       */

       if (pstate == NULL || pstate->ps_state < 2)
       {
              wlen = snprintf((char *) query, sizeof query, "%s.%s.%s",
                              DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
                              dkim->dkim_domain);
              if (wlen >= sizeof query)
              {
                     dkim_error(dkim, "policy query name overflow");
                     return DKIM_STAT_NORESOURCE;
              }

              status = dkim_get_policy(dkim, query, FALSE,
                                       &qstatus, &policy, &lpflags);
              if (status != DKIM_STAT_OK)
              {
                     if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
                     {
                            pstate->ps_qstatus = qstatus;
                            pstate->ps_policy = policy;
                            pstate->ps_pflags = lpflags;
                     }

                     return status;
              }

              if (pstate != NULL)
                     pstate->ps_state = 2;
       }

       if (qstatus == NOERROR)
              dkim->dkim_presult = DKIM_PRESULT_FOUND;
       if (pcode != NULL)
              *pcode = policy;
       if (pflags != NULL)
              *pflags = lpflags;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

int dkim_policy_getdnssec ( DKIM *  dkim)

Definition at line 5523 of file dkim.c.

{
       assert(dkim != NULL);

       return dkim->dkim_dnssec_policy;
}

Here is the caller graph for this function:

DKIM_STAT dkim_policy_getqueries ( DKIM *  dkim,
DKIM_QUERYINFO ***  qi,
unsigned int *  nqi 
)

Definition at line 9104 of file dkim.c.

{
       int c;
       DKIM_QUERYINFO **new;

       assert(dkim != NULL);
       assert(qi != NULL);
       assert(nqi != NULL);

       new = DKIM_MALLOC(dkim, 4 * sizeof(struct dkim_queryinfo *));
       if (new == NULL)
              return DKIM_STAT_NORESOURCE;

       memset(new, '\0', 4 * sizeof(struct dkim_queryinfo *));

       for (c = 0; c < 4; c++)
       {
              new[c] = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
              if (new[c] == NULL)
              {
                     int d;

                     for (d = 0; d < c; d++)
                            free(new[d]);

                     free(new);

                     return DKIM_STAT_NORESOURCE;
              }

              memset(new[c], '\0', sizeof(struct dkim_queryinfo));

              switch (c)
              {
                case 0:
                     new[c]->dq_type = T_A;
                     break;

                case 1:
                     new[c]->dq_type = T_AAAA;
                     break;

                case 2:
                     new[c]->dq_type = T_MX;
                     break;

                case 3:
                     new[c]->dq_type = T_TXT;
                     break;
              }

              if (dkim->dkim_domain != NULL)
              {
                     if (c != 3)
                     {
                            strlcpy((char *) new[c]->dq_name,
                                    dkim->dkim_domain,
                                     sizeof new[c]->dq_name);
                     }
                     else
                     {
                            snprintf((char *) new[c]->dq_name,
                                     sizeof new[c]->dq_name,
                                     "%s.%s.%s",
                                     DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
                                     dkim->dkim_domain);
                     }
              }
       }

       *qi = new;
       *nqi = 4;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_policy_getreportinfo ( DKIM *  dkim,
u_char *  addr,
size_t  addrlen,
u_char *  opts,
size_t  optslen,
u_char *  smtp,
size_t  smtplen,
u_int *  pct 
)

Definition at line 5548 of file dkim.c.

{
       u_char *p;
       DKIM_SET *set;

       assert(dkim != NULL);

       if (dkim->dkim_state != DKIM_STATE_EOM2 ||
           dkim->dkim_mode != DKIM_MODE_VERIFY)
              return DKIM_STAT_INVALID;

       set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);
       if (set == NULL)
              return DKIM_STAT_CANTVRFY;

       if (addr != NULL)
       {
              p = dkim_param_get(set, (u_char *) "ra");
              if (p != NULL)
              {
                     memset(addr, '\0', addrlen);
                     (void) dkim_qp_decode(p, addr, addrlen - 1);
                     p = (u_char *) strchr((char *) addr, '@');
                     if (p != NULL)
                            *p = '\0';
              }
       }

       if (opts != NULL)
       {
              p = dkim_param_get(set, (u_char *) "ro");
              if (p != NULL)
                     strlcpy((char *) opts, (char *) p, optslen);
       }

       if (smtp != NULL)
       {
              p = dkim_param_get(set, (u_char *) "rs");
              if (p != NULL)
              {
                     memset(smtp, '\0', smtplen);
                     (void) dkim_qp_decode(p, smtp, smtplen - 1);
              }
       }

       if (pct != NULL)
       {
              p = dkim_param_get(set, (u_char *) "rp");
              if (p != NULL)
              {
                     u_int out;
                     char *q;

                     out = strtoul((char *) p, &q, 10);
                     if (*q == '\0')
                            *pct = out;
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_policy_state_free ( DKIM_PSTATE *  pstate)

Definition at line 5387 of file dkim.c.

{
       assert(pstate != NULL);

       DKIM_FREE(pstate->ps_dkim, pstate);
}

Here is the caller graph for this function:

DKIM_PSTATE* dkim_policy_state_new ( DKIM *  dkim)

Definition at line 5359 of file dkim.c.

{
       DKIM_PSTATE *ret;

       assert(dkim != NULL);

       ret = DKIM_MALLOC(dkim, sizeof(DKIM_PSTATE));

       if (ret != NULL)
       {
              memset(ret, '\0', sizeof(DKIM_PSTATE));
              ret->ps_dkim = dkim;
       }

       return ret;
}
DKIM_STAT dkim_policy_syntax ( DKIM *  dkim,
u_char *  str,
size_t  len 
)

Definition at line 6864 of file dkim.c.

Here is the call graph for this function:

DKIM_STAT dkim_privkey_load ( DKIM *  dkim)

Definition at line 920 of file dkim.c.

{
#ifdef USE_GNUTLS
       int status;
#endif /* USE_GNUTLS */
       struct dkim_rsa *rsa;

       assert(dkim != NULL);

       if (dkim->dkim_mode != DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

       if (dkim->dkim_signalg != DKIM_SIGN_RSASHA1 &&
           dkim->dkim_signalg != DKIM_SIGN_RSASHA256)
              return DKIM_STAT_INVALID;

       rsa = (struct dkim_rsa *) dkim->dkim_keydata;

       if (rsa == NULL)
       {
              rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa));
              if (rsa == NULL)
              {
                     dkim_error(dkim, "unable to allocate %d byte(s)",
                                sizeof(struct dkim_rsa));
                     return DKIM_STAT_NORESOURCE;
              }
              memset(rsa, '\0', sizeof(struct dkim_rsa));
       }

       dkim->dkim_keydata = rsa;

#ifdef USE_GNUTLS
       rsa->rsa_keydata.data = dkim->dkim_key;
       rsa->rsa_keydata.size = dkim->dkim_keylen;
#else /* USE_GNUTLS */
       if (rsa->rsa_keydata == NULL)
       {
              rsa->rsa_keydata = BIO_new_mem_buf(dkim->dkim_key,
                                                 dkim->dkim_keylen);
              if (rsa->rsa_keydata == NULL)
              {
                     dkim_error(dkim, "BIO_new_mem_buf() failed");
                     return DKIM_STAT_NORESOURCE;
              }
       }
#endif /* USE_GNUTLS */

#ifdef USE_GNUTLS 
       if (gnutls_x509_privkey_init(&rsa->rsa_key) != GNUTLS_E_SUCCESS)
       {
              dkim_error(dkim, "gnutls_x509_privkey_init() failed");
              return DKIM_STAT_NORESOURCE;
       }

       status = gnutls_x509_privkey_import(rsa->rsa_key, &rsa->rsa_keydata,
                                           GNUTLS_X509_FMT_PEM);
       if (status != GNUTLS_E_SUCCESS)
       {
              status = gnutls_x509_privkey_import(rsa->rsa_key,
                                                  &rsa->rsa_keydata,
                                                   GNUTLS_X509_FMT_DER);
       }

       if (status != GNUTLS_E_SUCCESS)
       {
              dkim_error(dkim, "gnutls_x509_privkey_import() failed");
              return DKIM_STAT_NORESOURCE;
       }

       if (gnutls_privkey_init(&rsa->rsa_privkey) != GNUTLS_E_SUCCESS)
       {
              dkim_error(dkim, "gnutls_privkey_init() failed");
              return DKIM_STAT_NORESOURCE;
       }

       if (gnutls_privkey_import_x509(rsa->rsa_privkey, rsa->rsa_key,
                                      0) != GNUTLS_E_SUCCESS)
       {
              dkim_error(dkim,
                         "gnutls_privkey_import_x509() failed");
              (void) gnutls_privkey_deinit(rsa->rsa_privkey);
              return DKIM_STAT_NORESOURCE;
       }

       (void) gnutls_privkey_get_pk_algorithm(rsa->rsa_privkey,
                                              &rsa->rsa_keysize);

#else /* USE_GNUTLS */

       if (strncmp((char *) dkim->dkim_key, "-----", 5) == 0)
       {                                         /* PEM */
              rsa->rsa_pkey = PEM_read_bio_PrivateKey(rsa->rsa_keydata, NULL,
                                                      NULL, NULL);

              if (rsa->rsa_pkey == NULL)
              {
                     dkim_error(dkim, "PEM_read_bio_PrivateKey() failed");
                     BIO_free(rsa->rsa_keydata);
                     rsa->rsa_keydata = NULL;
                     return DKIM_STAT_NORESOURCE;
              }
       }
       else
       {                                         /* DER */
              rsa->rsa_pkey = d2i_PrivateKey_bio(rsa->rsa_keydata, NULL);

              if (rsa->rsa_pkey == NULL)
              {
                     dkim_error(dkim, "d2i_PrivateKey_bio() failed");
                     BIO_free(rsa->rsa_keydata);
                     rsa->rsa_keydata = NULL;
                     return DKIM_STAT_NORESOURCE;
              }
       }

       rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey);
       if (rsa->rsa_rsa == NULL)
       {
              dkim_error(dkim, "EVP_PKEY_get1_RSA() failed");
              BIO_free(rsa->rsa_keydata);
              rsa->rsa_keydata = NULL;
              return DKIM_STAT_NORESOURCE;
       }

       rsa->rsa_keysize = RSA_size(rsa->rsa_rsa) * 8;
       rsa->rsa_pad = RSA_PKCS1_PADDING;
       rsa->rsa_rsaout = DKIM_MALLOC(dkim, rsa->rsa_keysize / 8);
       if (rsa->rsa_rsaout == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)",
                                rsa->rsa_keysize / 8);
              RSA_free(rsa->rsa_rsa);
              rsa->rsa_rsa = NULL;
              BIO_free(rsa->rsa_keydata);
              rsa->rsa_keydata = NULL;
              return DKIM_STAT_NORESOURCE;
       }
#endif /* USE_GNUTLS */

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_process_set ( DKIM *  dkim,
dkim_set_t  type,
u_char *  str,
size_t  len,
void *  udata,
_Bool  syntax,
const char *  name 
)

Definition at line 481 of file dkim.c.

{
       _Bool spaced;
       int state;
       int status;
       u_char *p;
       u_char *param;
       u_char *value;
       u_char *hcopy;
       DKIM_SET *set;
       const char *settype;

       assert(dkim != NULL);
       assert(str != NULL);
       assert(type == DKIM_SETTYPE_SIGNATURE ||
              type == DKIM_SETTYPE_SIGREPORT ||
              type == DKIM_SETTYPE_KEY ||
              type == DKIM_SETTYPE_POLICY);

       param = NULL;
       value = NULL;
       state = 0;
       spaced = FALSE;

       hcopy = (u_char *) DKIM_MALLOC(dkim, len + 1);
       if (hcopy == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)", len + 1);
              return DKIM_STAT_INTERNAL;
       }
       strlcpy((char *) hcopy, (char *) str, len + 1);

       set = (DKIM_SET *) DKIM_MALLOC(dkim, sizeof(DKIM_SET));
       if (set == NULL)
       {
              DKIM_FREE(dkim, hcopy);
              dkim_error(dkim, "unable to allocate %d byte(s)",
                         sizeof(DKIM_SET));
              return DKIM_STAT_INTERNAL;
       }

       set->set_type = type;
       settype = dkim_code_to_name(settypes, type);
       set->set_name = name;

       if (!syntax)
       {
              if (dkim->dkim_sethead == NULL)
                     dkim->dkim_sethead = set;
              else
                     dkim->dkim_settail->set_next = set;

              dkim->dkim_settail = set;
       }

       set->set_next = NULL;
       memset(&set->set_plist, '\0', sizeof set->set_plist);
       set->set_data = hcopy;
       set->set_udata = udata;
       set->set_bad = FALSE;

       for (p = hcopy; *p != '\0'; p++)
       {
              if (!isascii(*p) || (!isprint(*p) && !isspace(*p)))
              {
                     dkim_error(dkim,
                                "invalid character (ASCII 0x%02x at offset %d) in %s data",
                                *p, p - hcopy, settype);
                     if (syntax)
                            dkim_set_free(dkim, set);
                     else
                            set->set_bad = TRUE;
                     return DKIM_STAT_SYNTAX;
              }

              switch (state)
              {
                case 0:                          /* before param */
                     if (isspace(*p))
                     {
                            continue;
                     }
                     else if (isalnum(*p))
                     {
                            param = p;
                            state = 1;
                     }
                     else
                     {
                            dkim_error(dkim,
                                       "syntax error in %s data (ASCII 0x%02x at offset %d)",
                                       settype, *p, p - hcopy);
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_SYNTAX;
                     }
                     break;

                case 1:                          /* in param */
                     if (isspace(*p))
                     {
                            spaced = TRUE;
                     }
                     else if (*p == '=')
                     {
                            *p = '\0';
                            state = 2;
                            spaced = FALSE;
                     }
                     else if (*p == ';' || spaced)
                     {
                            dkim_error(dkim,
                                       "syntax error in %s data (ASCII 0x%02x at offset %d)",
                                       settype, *p, p - hcopy);
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_SYNTAX;
                     }
                     break;

                case 2:                          /* before value */
                     if (isspace(*p))
                     {
                            continue;
                     }
                     else if (*p == ';')         /* empty value */
                     {
                            *p = '\0';
                            value = p;

                            /* collapse the parameter */
                            dkim_collapse(param);

                            /* create the DKIM_PLIST entry */
                            status = dkim_add_plist(dkim, set, param,
                                                    value, TRUE);
                            if (status == -1)
                            {
                                   if (syntax)
                                          dkim_set_free(dkim, set);
                                   else
                                          set->set_bad = TRUE;
                                   return DKIM_STAT_INTERNAL;
                            }

                            /* reset */
                            param = NULL;
                            value = NULL;
                            state = 0;
                     }
                     else
                     {
                            value = p;
                            state = 3;
                     }
                     break;

                case 3:                          /* in value */
                     if (*p == ';')
                     {
                            *p = '\0';

                            /* collapse the parameter and value */
                            dkim_collapse(param);
                            dkim_collapse(value);

                            /* create the DKIM_PLIST entry */
                            status = dkim_add_plist(dkim, set, param,
                                                    value, TRUE);
                            if (status == -1)
                            {
                                   if (syntax)
                                          dkim_set_free(dkim, set);
                                   else
                                          set->set_bad = TRUE;
                                   return DKIM_STAT_INTERNAL;
                            }

                            /* reset */
                            param = NULL;
                            value = NULL;
                            state = 0;
                     }
                     break;

                default:                         /* shouldn't happen */
                     assert(0);
              }
       }

       switch (state)
       {
         case 0:                                 /* before param */
         case 3:                                 /* in value */
              /* parse the data found, if any */
              if (value != NULL)
              {
                     /* collapse the parameter and value */
                     dkim_collapse(param);
                     dkim_collapse(value);

                     /* create the DKIM_PLIST entry */
                     status = dkim_add_plist(dkim, set, param, value, TRUE);
                     if (status == -1)
                     {
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_INTERNAL;
                     }
              }
              break;

         case 2:                                 /* before value */
              /* create an empty DKIM_PLIST entry */
              status = dkim_add_plist(dkim, set, param, (u_char *) "", TRUE);
              if (status == -1)
              {
                     if (syntax)
                            dkim_set_free(dkim, set);
                     else
                            set->set_bad = TRUE;
                     return DKIM_STAT_INTERNAL;
              }
              break;

         case 1:                                 /* after param */
              dkim_error(dkim, "tag without value at end of %s data",
                         settype);
              if (syntax)
                     dkim_set_free(dkim, set);
              else
                     set->set_bad = TRUE;
              return DKIM_STAT_SYNTAX;

         default:                                /* shouldn't happen */
              assert(0);
       }

       /* load up defaults, assert requirements */
       switch (set->set_type)
       {
         case DKIM_SETTYPE_SIGREPORT:
              /* check validity of "rp" */
              value = dkim_param_get(set, (u_char *) "rp");
              if (value != NULL)
              {
                     unsigned int tmp = 0;

                     tmp = (unsigned int) strtoul(value, (char **) &p, 10);
                     if (tmp > 100 || *p != '\0')
                     {
                            dkim_error(dkim,
                                       "invalid parameter(s) in %s data",
                                       settype);
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_SYNTAX;
                     }
              }
              break;
              
         case DKIM_SETTYPE_SIGNATURE:
              /* make sure required stuff is here */
              if (dkim_param_get(set, (u_char *) "s") == NULL ||
                  dkim_param_get(set, (u_char *) "h") == NULL ||
                  dkim_param_get(set, (u_char *) "d") == NULL ||
                  dkim_param_get(set, (u_char *) "b") == NULL ||
                  dkim_param_get(set, (u_char *) "v") == NULL ||
                  dkim_param_get(set, (u_char *) "a") == NULL)
              {
                     dkim_error(dkim, "missing parameter(s) in %s data",
                                settype);
                     if (syntax)
                            dkim_set_free(dkim, set);
                     else
                            set->set_bad = TRUE;
                     return DKIM_STAT_SYNTAX;
              }

              /* test validity of "t" and "x" */
              value = dkim_param_get(set, (u_char *) "t");
              if (value != NULL)
              {
                     uint64_t tmp = 0;
                     char *end;

                     errno = 0;

                     if (value[0] == '-')
                     {
                            errno = ERANGE;
                            tmp = (uint64_t) -1;
                     }
                     else if (value[0] == '\0')
                     {
                            errno = EINVAL;
                            tmp = (uint64_t) -1;
                     }
                     else
                     {
                            tmp = strtoull((char *) value, &end, 10);
                     }

                     if (tmp == (uint64_t) -1 || errno != 0 ||
                         *end != '\0')
                     {
                            dkim_error(dkim,
                                       "invalid \"t\" value in %s data",
                                       settype);
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_SYNTAX;
                     }
              }

              value = dkim_param_get(set, (u_char *) "x");
              if (value != NULL)
              {
                     uint64_t tmp = 0;
                     char *end;

                     errno = 0;

                     if (value[0] == '-')
                     {
                            errno = ERANGE;
                            tmp = (uint64_t) -1;
                     }
                     else if (value[0] == '\0')
                     {
                            errno = EINVAL;
                            tmp = (uint64_t) -1;
                     }
                     else
                     {
                            tmp = strtoull((char *) value, &end, 10);
                     }

                     if (tmp == (uint64_t) -1 || errno != 0 ||
                         *end != '\0')
                     {
                            dkim_error(dkim,
                                       "invalid \"x\" value in %s data",
                                       settype);
                            if (syntax)
                                   dkim_set_free(dkim, set);
                            else
                                   set->set_bad = TRUE;
                            return DKIM_STAT_SYNTAX;
                     }
              }

              if (syntax)
              {
                     dkim_set_free(dkim, set);
                     return DKIM_STAT_OK;
              }

              /* default for "c" */
              status = dkim_add_plist(dkim, set, (u_char *) "c",
                                      (u_char *) "simple/simple",
                                      FALSE);
              if (status == -1)
              {
                     set->set_bad = TRUE;
                     return DKIM_STAT_INTERNAL;
              }

              /* default for "q" */
              status = dkim_add_plist(dkim, set, (u_char *) "q",
                                      (u_char *) "dns/txt", FALSE);
              if (status == -1)
              {
                     set->set_bad = TRUE;
                     return DKIM_STAT_INTERNAL;
              }

              break;

         case DKIM_SETTYPE_POLICY:
              if (dkim_param_get(set, (u_char *) "dkim") == NULL)
              {
                     dkim_error(dkim, "missing parameter(s) in %s data",
                                settype);
                     if (syntax)
                            dkim_set_free(dkim, set);
                     else
                            set->set_bad = TRUE;
                     return DKIM_STAT_SYNTAX;
              }

              break;

         case DKIM_SETTYPE_KEY:
              if (syntax)
              {
                     dkim_set_free(dkim, set);
                     return DKIM_STAT_OK;
              }

              status = dkim_add_plist(dkim, set, (u_char *) "k",
                                      (u_char *) "rsa", FALSE);
              if (status == -1)
              {
                     set->set_bad = TRUE;
                     return DKIM_STAT_INTERNAL;
              }

              break;
                     
         default:
              assert(0);
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* dkim_qi_getname ( DKIM_QUERYINFO *  query)

Definition at line 9011 of file dkim.c.

{
       assert(query != NULL);

       return query->dq_name;
}

Here is the caller graph for this function:

int dkim_qi_gettype ( DKIM_QUERYINFO *  query)

Definition at line 9029 of file dkim.c.

{
       assert(query != NULL);

       return query->dq_type;
}

Here is the caller graph for this function:

DKIM_STAT dkim_resign ( DKIM *  new,
DKIM *  old,
_Bool  hdrbind 
)

Definition at line 5237 of file dkim.c.

{
#ifdef _FFR_RESIGN
       _Bool keep;
       _Bool tmp;
       DKIM_STAT status;
       int hashtype = DKIM_HASHTYPE_UNKNOWN;
       DKIM_CANON *bc;
       DKIM_CANON *hc;
       DKIM_LIB *lib;

       assert(new != NULL);
       assert(old != NULL);

       if (new->dkim_mode != DKIM_MODE_SIGN ||
           new->dkim_state != DKIM_STATE_INIT)
              return DKIM_STAT_INVALID;

       if (old->dkim_mode != DKIM_MODE_VERIFY ||
           old->dkim_state >= DKIM_STATE_EOH1 ||
           old->dkim_resign != NULL)
              return DKIM_STAT_INVALID;

       new->dkim_resign = old;
       new->dkim_hdrbind = hdrbind;
       /* XXX -- should be mutex-protected? */
       old->dkim_refcnt++;

       lib = old->dkim_libhandle;
       assert(lib != NULL);

       tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
       keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);

       new->dkim_version = lib->dkiml_version;

       /* determine hash type */
       switch (new->dkim_signalg)
       {
         case DKIM_SIGN_RSASHA1:
              hashtype = DKIM_HASHTYPE_SHA1;
              break;

         case DKIM_SIGN_RSASHA256:
              hashtype = DKIM_HASHTYPE_SHA256;
              break;

         default:
              assert(0);
              /* NOTREACHED */
       }

       /* initialize signature and canonicalization for signing */
       new->dkim_siglist = DKIM_MALLOC(new, sizeof(DKIM_SIGINFO *));
       if (new->dkim_siglist == NULL)
       {
              dkim_error(new, "failed to allocate %d byte(s)",
                         sizeof(DKIM_SIGINFO *));
              return DKIM_STAT_NORESOURCE;
       }

       new->dkim_siglist[0] = DKIM_MALLOC(new, sizeof(struct dkim_siginfo));
       if (new->dkim_siglist[0] == NULL)
       {
              dkim_error(new, "failed to allocate %d byte(s)",
                         sizeof(struct dkim_siginfo));
              return DKIM_STAT_NORESOURCE;
       }

       new->dkim_sigcount = 1;
       memset(new->dkim_siglist[0], '\0', sizeof(struct dkim_siginfo));
       new->dkim_siglist[0]->sig_domain = new->dkim_domain;
       new->dkim_siglist[0]->sig_selector = new->dkim_selector;
       new->dkim_siglist[0]->sig_hashtype = hashtype;
       new->dkim_siglist[0]->sig_signalg = new->dkim_signalg;

       status = dkim_add_canon(hdrbind ? old : new, TRUE,
                               new->dkim_hdrcanonalg, hashtype,
                               NULL, NULL, 0, &hc);
       if (status != DKIM_STAT_OK)
              return status;

       status = dkim_add_canon(old, FALSE, new->dkim_bodycanonalg,
                               hashtype, NULL, NULL, new->dkim_signlen, &bc);
       if (status != DKIM_STAT_OK)
              return status;

       new->dkim_siglist[0]->sig_hdrcanon = hc;
       new->dkim_siglist[0]->sig_hdrcanonalg = new->dkim_hdrcanonalg;
       new->dkim_siglist[0]->sig_bodycanon = bc;
       new->dkim_siglist[0]->sig_bodycanonalg = new->dkim_bodycanonalg;

       if (new->dkim_libhandle->dkiml_fixedtime != 0)
       {
              new->dkim_siglist[0]->sig_timestamp = new->dkim_libhandle->dkiml_fixedtime;
       }
       else
       {
              time_t now;

              (void) time(&now);

              new->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
       }

       return DKIM_STAT_OK;
#else /* _FFR_RESIGN */
       return DKIM_STAT_NOTIMPLEMENT;
#endif /* _FFR_RESIGN */
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_set_dns_callback ( DKIM_LIB *  libopendkim,
void(*)(const void *context)  func,
unsigned int  interval 
)

Definition at line 8061 of file dkim.c.

{
       assert(libopendkim != NULL);

       if (func != NULL && interval == 0)
              return DKIM_STAT_INVALID;

       libopendkim->dkiml_dns_callback = func;
       libopendkim->dkiml_callback_int = interval;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_final ( DKIM_LIB *  libopendkim,
DKIM_CBSTAT(*)(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs)  func 
)

Definition at line 8317 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_final = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

static DKIM_SET* dkim_set_first ( DKIM *  dkim,
dkim_set_t  type 
) [static]

Definition at line 314 of file dkim.c.

{
       DKIM_SET *set;

       assert(dkim != NULL);

       if (type == DKIM_SETTYPE_ANY)
              return dkim->dkim_sethead;

       for (set = dkim->dkim_sethead; set != NULL; set = set->set_next)
       {
              if (set->set_type == type)
                     return set;
       }

       return NULL;
}

Here is the caller graph for this function:

static void dkim_set_free ( DKIM *  dkim,
DKIM_SET *  set 
) [static]

Definition at line 280 of file dkim.c.

{
       int c;
       DKIM_PLIST *plist;
       DKIM_PLIST *pnext;

       assert(set != NULL);

       for (c = 0; c < NPRINTABLE; c++)
       {
              for (plist = set->set_plist[c]; plist != NULL; plist = pnext)
              {
                     pnext = plist->plist_next;

                     CLOBBER(plist);
              }
       }

       CLOBBER(set->set_data);
       CLOBBER(set);
}

Here is the caller graph for this function:

static void* dkim_set_getudata ( DKIM_SET *  set) [static]

Definition at line 1119 of file dkim.c.

{
       assert(set != NULL);

       return set->set_udata;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_key_lookup ( DKIM_LIB *  libopendkim,
DKIM_STAT(*)(DKIM *dkim, DKIM_SIGINFO *sig, u_char *buf, size_t buflen)  func 
)

Definition at line 8181 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_key_lookup = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_margin ( DKIM *  dkim,
int  value 
)

Definition at line 7967 of file dkim.c.

{
       assert(dkim != NULL);

       if (dkim->dkim_mode != DKIM_MODE_SIGN || value < 0 ||
           dkim->dkim_state >= DKIM_STATE_EOM2)
              return DKIM_STAT_INVALID;

       dkim->dkim_margin = (size_t) value;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

static DKIM_SET* dkim_set_next ( DKIM_SET *  cur,
dkim_set_t  type 
) [static]

Definition at line 344 of file dkim.c.

{
       DKIM_SET *set;

       assert(cur != NULL);

       if (type == DKIM_SETTYPE_ANY)
              return cur->set_next;

       for (set = cur->set_next; set != NULL; set = set->set_next)
       {
              if (set->set_type == type)
                     return set;
       }

       return NULL;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_policy_lookup ( DKIM_LIB *  libopendkim,
int(*)(DKIM *dkim, u_char *query, _Bool excheck, u_char *buf, size_t buflen, int *qstat)  func 
)

Definition at line 8204 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_policy_lookup = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_prescreen ( DKIM_LIB *  libopendkim,
DKIM_CBSTAT(*)(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs)  func 
)

Definition at line 8294 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_prescreen = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_signature_handle ( DKIM_LIB *  libopendkim,
void *(*)(void *closure)  func 
)

Definition at line 8227 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_sig_handle = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_signature_handle_free ( DKIM_LIB *  libopendkim,
void(*)(void *closure, void *user)  func 
)

Definition at line 8248 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_sig_handle_free = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_signature_tagvalues ( DKIM_LIB *  libopendkim,
void(*)(void *user, dkim_param_t pcode, const u_char *param, const u_char *value)  func 
)

Definition at line 8270 of file dkim.c.

{
       assert(libopendkim != NULL);

       libopendkim->dkiml_sig_tagvalues = func;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_set_signer ( DKIM *  dkim,
const unsigned char *  signer 
)

Definition at line 7864 of file dkim.c.

{
       assert(dkim != NULL);
       assert(signer != NULL);

       if (dkim->dkim_mode != DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

       if (dkim->dkim_signer == NULL)
       {
              dkim->dkim_signer = DKIM_MALLOC(dkim, MAXADDRESS + 1);
              if (dkim->dkim_signer == NULL)
              {
                     dkim_error(dkim, "unable to allocate %d byte(s)",
                                MAXADDRESS + 1);
                     return DKIM_STAT_NORESOURCE;
              }
       }

       strlcpy((char *) dkim->dkim_signer, (char *) signer, MAXADDRESS + 1);

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_set_user_context ( DKIM *  dkim,
void *  ctx 
)

Definition at line 8087 of file dkim.c.

{
       assert(dkim != NULL);

       dkim->dkim_user_context = (const void *) ctx;

       return DKIM_STAT_OK;
}
DKIM_STAT dkim_setpartial ( DKIM *  dkim,
_Bool  value 
)

Definition at line 7940 of file dkim.c.

{
       assert(dkim != NULL);

       if (dkim->dkim_mode != DKIM_MODE_SIGN)
              return DKIM_STAT_INVALID;

       dkim->dkim_partial = value;

       return DKIM_STAT_OK;
}
static _Bool dkim_sig_domainok ( DKIM *  dkim,
DKIM_SET *  set 
) [static]

Definition at line 1540 of file dkim.c.

{
       char *at;
       char *dot;
       u_char *i;
       u_char *d;
       u_char addr[MAXADDRESS + 1];

       assert(dkim != NULL);
       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_SIGNATURE);

       i = dkim_param_get(set, (u_char *) "i");
       d = dkim_param_get(set, (u_char *) "d");

       assert(d != NULL);

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

       if (i == NULL)
              snprintf((char *) addr, sizeof addr, "@%s", d);
       else
              dkim_qp_decode(i, addr, sizeof addr - 1);

       at = strchr((char *) addr, '@');
       if (at == NULL)
              return FALSE;

       if (strcasecmp(at + 1, (char *) d) == 0)
              return TRUE;

       for (dot = strchr(at, '.'); dot != NULL; dot = strchr(dot + 1, '.'))
       {
              if (strcasecmp(dot + 1, (char *) d) == 0)
              {
                     dkim->dkim_subdomain = TRUE;
                     return TRUE;
              }
       }

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_sig_expired ( DKIM_SET *  set,
uint64_t  drift 
) [static]

Definition at line 1599 of file dkim.c.

{
       time_t now;
       uint64_t expire;
       uint64_t nowl;
       u_char *val;

       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_SIGNATURE);

       val = dkim_param_get(set, (u_char *) "x");
       if (val == NULL)
              return FALSE;

       if (sizeof(uint64_t) == sizeof(unsigned long long))
              expire = strtoull((char *) val, NULL, 10);
       else if (sizeof(uint64_t) == sizeof(unsigned long))
              expire = strtoul((char *) val, NULL, 10);
       else
              expire = (unsigned int) strtoul((char *) val, NULL, 10);

       (void) time(&now);
       nowl = (uint64_t) now;

       return (nowl >= expire + drift);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_sig_future ( DKIM_SET *  set,
uint64_t  drift 
) [static]

Definition at line 1694 of file dkim.c.

{
       uint64_t signtime;
       uint64_t nowl;
       time_t now;
       u_char *val;

       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_SIGNATURE);

       val = dkim_param_get(set, (u_char *) "t");
       if (val == NULL)
              return FALSE;

       if (sizeof(uint64_t) == sizeof(unsigned long long))
              signtime = strtoull((char *) val, NULL, 10);
       else if (sizeof(uint64_t) == sizeof(unsigned long))
              signtime = strtoul((char *) val, NULL, 10);
       else
              signtime = (unsigned int) strtoul((char *) val, NULL, 10);

       (void) time(&now);
       nowl = (uint64_t) now;

       return (nowl < signtime - drift);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dkim_sig_getbh ( DKIM_SIGINFO *  sig)

Definition at line 7727 of file dkim.c.

{
       assert(sig != NULL);

       return sig->sig_bh;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getcanonlen ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
ssize_t *  msglen,
ssize_t *  canonlen,
ssize_t *  signlen 
)

Definition at line 7670 of file dkim.c.

{
       assert(dkim != NULL);
       assert(sig != NULL);

       if (msglen != NULL)
              *msglen = dkim->dkim_bodylen;

       if (canonlen != NULL)
       {
              if (sig->sig_bodycanon == NULL)
                     return DKIM_STAT_INTERNAL;
              *canonlen = sig->sig_bodycanon->canon_wrote;
       }

       if (signlen != NULL)
       {
              if (sig->sig_bodycanon == NULL)
                     return DKIM_STAT_INTERNAL;
              *signlen = sig->sig_bodycanon->canon_length;
       }

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getcanons ( DKIM_SIGINFO *  sig,
dkim_canon_t hdr,
dkim_canon_t body 
)

Definition at line 7821 of file dkim.c.

{
       assert(sig != NULL);

       if (hdr != NULL)
              *hdr = sig->sig_hdrcanonalg;
       if (body != NULL)
              *body = sig->sig_bodycanonalg;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

void* dkim_sig_getcontext ( DKIM_SIGINFO *  siginfo)

Definition at line 8340 of file dkim.c.

{
       assert(siginfo != NULL);

       return siginfo->sig_context;
}

Here is the caller graph for this function:

int dkim_sig_getdnssec ( DKIM_SIGINFO *  sig)

Definition at line 7364 of file dkim.c.

{
       assert(sig != NULL);

       return sig->sig_dnssec_key;
}

Here is the caller graph for this function:

unsigned char* dkim_sig_getdomain ( DKIM_SIGINFO *  siginfo)

Definition at line 8376 of file dkim.c.

{
       assert(siginfo != NULL);

       return siginfo->sig_domain;
}

Here is the caller graph for this function:

int dkim_sig_geterror ( DKIM_SIGINFO *  siginfo)

Definition at line 8394 of file dkim.c.

{
       assert(siginfo != NULL);

       return siginfo->sig_error;
}

Here is the caller graph for this function:

const char* dkim_sig_geterrorstr ( DKIM_SIGERROR  sigerr)

Definition at line 8413 of file dkim.c.

{
       return dkim_code_to_name(sigerrors, sigerr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

unsigned int dkim_sig_getflags ( DKIM_SIGINFO *  sig)

Definition at line 7708 of file dkim.c.

{
       assert(sig != NULL);

       return sig->sig_flags;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_gethashes ( DKIM_SIGINFO *  sig,
void **  hh,
size_t *  hhlen,
void **  bh,
size_t *  bhlen 
)

Definition at line 9197 of file dkim.c.

{
       return dkim_canon_gethashes(sig, hh, hhlen, bh, bhlen);
}

Here is the call graph for this function:

DKIM_STAT dkim_sig_getidentity ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
u_char *  val,
size_t  vallen 
)

Definition at line 7602 of file dkim.c.

{
       int len;
       char *param;
       struct dkim_set *set;

       assert(val != NULL);
       assert(vallen != 0);

       if (sig == NULL)
       {
              if (dkim == NULL)
                     return DKIM_STAT_INVALID;

              sig = dkim->dkim_signature;
              if (sig == NULL)
                     return DKIM_STAT_INVALID;
       }

       set = sig->sig_taglist;

       param = (char *) dkim_param_get(set, (u_char *) "i");
       if (param == NULL)
       {
              param = (char *) dkim_param_get(set, (u_char *) "d");
              if (param == NULL)
                     return DKIM_STAT_INTERNAL;

              len = snprintf((char *) val, vallen, "@%s", param);

              return (len < vallen ? DKIM_STAT_OK : DKIM_STAT_NORESOURCE);
       }
       else
       {
              len = dkim_qp_decode((u_char *) param, (u_char *) val,
                                   vallen - 1);

              if (len == -1)
              {
                     return DKIM_STAT_SYNTAX;
              }
              else if (len >= vallen)
              {
                     return DKIM_STAT_NORESOURCE;
              }
              else
              {
                     val[len] = '\0';
                     return DKIM_STAT_OK;
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getkeysize ( DKIM_SIGINFO *  sig,
unsigned int *  bits 
)

Definition at line 7746 of file dkim.c.

{
       assert(sig != NULL);
       assert(bits != NULL);

       if (sig->sig_keybits == 0)
              return DKIM_STAT_INVALID;

       *bits = sig->sig_keybits;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getqueries ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
DKIM_QUERYINFO ***  qi,
unsigned int *  nqi 
)

Definition at line 9050 of file dkim.c.

{
       DKIM_QUERYINFO **new;
       DKIM_QUERYINFO *newp;

       assert(dkim != NULL);
       assert(sig != NULL);
       assert(qi != NULL);
       assert(nqi != NULL);

       new = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo *));
       if (new == NULL)
              return DKIM_STAT_NORESOURCE;

       newp = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
       if (newp == NULL)
       {
              DKIM_FREE(dkim, new);
              return DKIM_STAT_NORESOURCE;
       }

       memset(newp, '\0', sizeof(struct dkim_queryinfo));

       if (sig->sig_selector != NULL && sig->sig_domain != NULL)
       {
              newp->dq_type = T_TXT;
              snprintf((char *) newp->dq_name, sizeof newp->dq_name,
                       "%s.%s.%s",
                       sig->sig_selector, DKIM_DNSKEYNAME, sig->sig_domain);
       }

       new[0] = newp;

       *qi = new;
       *nqi = 1;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getreportinfo ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
int *  hfd,
int *  bfd,
u_char *  addr,
size_t  addrlen,
u_char *  opts,
size_t  optslen,
u_char *  smtp,
size_t  smtplen,
u_int *  pct 
)

Definition at line 7392 of file dkim.c.

{
       DKIM_STAT status;
       u_char *p;
       char *sdomain;
       DKIM_SET *set;
       struct timeval timeout;
       unsigned char buf[BUFRSZ];

       assert(dkim != NULL);
       assert(sig != NULL);

       if (dkim->dkim_state != DKIM_STATE_EOM2 ||
           dkim->dkim_mode != DKIM_MODE_VERIFY)
              return DKIM_STAT_INVALID;

       sdomain = dkim_sig_getdomain(sig);

       /* see if the signature had an "r=y" tag */
       set = sig->sig_taglist;
       if (set == NULL)
              return DKIM_STAT_INTERNAL;

       p = dkim_param_get(set, (u_char *) "r");
       if (p == NULL || p[0] != 'y' || p[1] != '\0')
       {
              if (addr != NULL)
                     addr[0] = '\0';
              if (opts != NULL)
                     opts[0] = '\0';
              if (smtp != NULL)
                     smtp[0] = '\0';
              if (pct != NULL)
                     *pct = (u_int) -1;

              return DKIM_STAT_OK;
       }

       /* see if we've grabbed this set already */
       for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
            set != NULL;
            set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
       {
              if (set->set_name != NULL &&
                  strcasecmp(set->set_name, sdomain) == 0)
                     break;
       }

       /* guess not; go to the DNS to get reporting parameters */
       if (set == NULL)
       {
              timeout.tv_sec = dkim->dkim_timeout;
              timeout.tv_usec = 0;

              memset(buf, '\0', sizeof buf);
              status = dkim_repinfo(dkim, sig, &timeout, buf, sizeof buf);
              if (status != DKIM_STAT_OK)
                     return status;
              if (buf[0] == '\0')
                     return DKIM_STAT_OK;

              status = dkim_process_set(dkim, DKIM_SETTYPE_SIGREPORT,
                                        buf, strlen(buf), NULL, FALSE,
                                        sdomain);
              if (status != DKIM_STAT_OK)
                     return status;

              for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
                   set != NULL;
                   set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
              {
                     if (set->set_name != NULL &&
                         strcasecmp(set->set_name, sdomain) == 0)
                            break;
              }

              assert(set != NULL);
       }

       if (addr != NULL)
       {
              p = dkim_param_get(set, (u_char *) "ra");
              if (p != NULL)
              {
                     memset(addr, '\0', addrlen);
                     (void) dkim_qp_decode(p, addr, addrlen - 1);
                     p = (u_char *) strchr((char *) addr, '@');
                     if (p != NULL)
                            *p = '\0';
              }
       }

       if (opts != NULL)
       {
              p = dkim_param_get(set, (u_char *) "ro");
              if (p != NULL)
                     strlcpy((char *) opts, (char *) p, optslen);
       }

       if (smtp != NULL)
       {
              p = dkim_param_get(set, (u_char *) "rs");
              if (p != NULL)
              {
                     memset(smtp, '\0', smtplen);
                     (void) dkim_qp_decode(p, smtp, smtplen - 1);
              }
       }

       if (pct != NULL)
       {
              p = dkim_param_get(set, (u_char *) "rp");
              if (p != NULL)
              {
                     u_int out;
                     char *q;

                     out = strtoul((char *) p, &q, 10);
                     if (*q == '\0')
                            *pct = out;
              }
       }

       if (sig->sig_hdrcanon != NULL)
       {
              switch (sig->sig_hashtype)
              {
#ifdef USE_GNUTLS
                case DKIM_HASHTYPE_SHA1:
                case DKIM_HASHTYPE_SHA256:
                {
                     struct dkim_sha *sha;

                     sha = (struct dkim_sha *) sig->sig_hdrcanon->canon_hash;
                     if (hfd != NULL)
                            *hfd = sha->sha_tmpfd;

                     if (bfd != NULL)
                     {
                            sha = (struct dkim_sha *) sig->sig_bodycanon->canon_hash;
                            *bfd = sha->sha_tmpfd;
                     }

                     break;
                }
#else /* USE_GNUTLS */
                case DKIM_HASHTYPE_SHA1:
                {
                     struct dkim_sha1 *sha1;

                     sha1 = (struct dkim_sha1 *) sig->sig_hdrcanon->canon_hash;
                     if (hfd != NULL)
                            *hfd = sha1->sha1_tmpfd;

                     if (bfd != NULL)
                     {
                            sha1 = (struct dkim_sha1 *) sig->sig_bodycanon->canon_hash;
                            *bfd = sha1->sha1_tmpfd;
                     }

                     break;
                }

# ifdef HAVE_SHA256
                case DKIM_HASHTYPE_SHA256:
                {
                     struct dkim_sha256 *sha256;

                     sha256 = (struct dkim_sha256 *) sig->sig_hdrcanon->canon_hash;
                     if (hfd != NULL)
                            *hfd = sha256->sha256_tmpfd;

                     if (bfd != NULL)
                     {
                            sha256 = (struct dkim_sha256 *) sig->sig_bodycanon->canon_hash;
                            *bfd = sha256->sha256_tmpfd;
                     }

                     break;
                }
# endif /* HAVE_SHA256 */
#endif /* USE_GNUTLS */

                default:
                     assert(0);
              }
       }

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

unsigned char* dkim_sig_getselector ( DKIM_SIGINFO *  siginfo)

Definition at line 8358 of file dkim.c.

{
       assert(siginfo != NULL);

       return siginfo->sig_selector;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getsignalg ( DKIM_SIGINFO *  sig,
dkim_alg_t alg 
)

Definition at line 7771 of file dkim.c.

{
       assert(sig != NULL);
       assert(alg != NULL);

       *alg = sig->sig_signalg;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getsignedhdrs ( DKIM *  dkim,
DKIM_SIGINFO *  sig,
u_char *  hdrs,
size_t  hdrlen,
u_int *  nhdrs 
)

Definition at line 8715 of file dkim.c.

{
       int status;
       u_int n;
       u_char *h;
       u_char *p;
       struct dkim_header **sighdrs;

       assert(dkim != NULL);
       assert(sig != NULL);
       assert(nhdrs != NULL);

       if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0 ||
           sig->sig_bh != DKIM_SIGBH_MATCH)
              return DKIM_STAT_INVALID;

       h = dkim_param_get(sig->sig_taglist, "h");
       assert(h != NULL);

       n = 1;
       for (p = h; *p != '\0'; p++)
       {
              if (*p == ':')
                     n++;
       }

       if (*nhdrs < n)
       {
              *nhdrs = n;
              return DKIM_STAT_NORESOURCE;
       }

       assert(hdrs != NULL);

       sighdrs = (struct dkim_header **) DKIM_MALLOC(dkim,
                                                     sizeof(struct dkim_header *) * n);
       if (sighdrs == NULL)
       {
              *nhdrs = 0;
              return DKIM_STAT_NORESOURCE;
       }

       status = dkim_canon_selecthdrs(dkim, h, sighdrs, n);
       if (status == -1)
       {
              DKIM_FREE(dkim, sighdrs);
              return DKIM_STAT_INTERNAL;
       }

       *nhdrs = status;

       for (n = 0; n < status; n++)
              strlcpy(&hdrs[n * hdrlen], sighdrs[n]->hdr_text, hdrlen);

       DKIM_FREE(dkim, sighdrs);

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_sig_getsigntime ( DKIM_SIGINFO *  sig,
uint64_t *  when 
)

Definition at line 7793 of file dkim.c.

{
       assert(sig != NULL);
       assert(when != NULL);

       if (sig->sig_timestamp == 0)
              return DKIM_STAT_INVALID;

       *when = sig->sig_timestamp;

       return DKIM_STAT_OK;
}

Here is the caller graph for this function:

u_char* dkim_sig_gettagvalue ( DKIM_SIGINFO *  sig,
_Bool  keytag,
u_char *  tag 
)

Definition at line 8681 of file dkim.c.

{
       DKIM_SET *set;

       assert(sig != NULL);
       assert(tag != NULL);

       if (keytag)
              set = sig->sig_keytaglist;
       else
              set = sig->sig_taglist;

       if (set == NULL)
              return NULL;
       else
              return dkim_param_get(set, tag);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_sig_hdrlistok ( DKIM *  dkim,
u_char *  hdrlist 
) [static]

Definition at line 1436 of file dkim.c.

{
       _Bool in = FALSE;
       _Bool found;
       int c;
       int d;
       int nh;
       u_char *p;
       u_char **ptrs;
       u_char tmp[DKIM_MAXHEADER + 1];

       assert(dkim != NULL);
       assert(hdrlist != NULL);

       strlcpy((char *) tmp, (char *) hdrlist, sizeof tmp);

       /* figure out how many headers were named */
       c = 0;
       for (p = tmp; *p != '\0'; p++)
       {
              if (*p == ':')
              {
                     in = FALSE;
              }
              else if (isascii(*p) && !isspace(*p) && !in)
              {
                     c++;
                     in = TRUE;
              }
       }

       nh = c;

       /* allocate an array of pointers to them */
       ptrs = DKIM_MALLOC(dkim, sizeof(u_char *) * nh);
       if (ptrs == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)",
                         sizeof(u_char *) * nh);
              return -1;
       }

       /* set the pointers */
       c = 0;
       in = FALSE;
       for (p = tmp; *p != '\0'; p++)
       {
              if (*p == ':')
              {
                     *p = '\0';
                     in = FALSE;
              }
              else if (isascii(*p) && !isspace(*p) && !in)
              {
                     ptrs[c++] = p;
                     in = TRUE;
              }
       }

       /* verify that each required header was represented */
       for (d = 0; ; d++)
       {
              if (required_signhdrs[d] == NULL)
                     break;

              found = FALSE;

              for (c = 0; c < nh; c++)
              {
                     if (strcasecmp((char *) required_signhdrs[d],
                                    (char *) ptrs[c]) == 0)
                     {
                            found = TRUE;
                            break;
                     }
              }

              if (!found)
              {
                     DKIM_FREE(dkim, ptrs);

                     return 0;
              }
       }

       DKIM_FREE(dkim, ptrs);

       return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

_Bool dkim_sig_hdrsigned ( DKIM_SIGINFO *  sig,
u_char *  hdr 
)

Definition at line 7285 of file dkim.c.

{
       size_t len;
       u_char *c1 = NULL;
       u_char *c2 = NULL;
       u_char *start;
       u_char *p;
       u_char *hdrlist;

       assert(sig != NULL);
       assert(hdr != NULL);

       hdrlist = dkim_param_get(sig->sig_taglist, (u_char *) "h");
       if (hdrlist == NULL)
              return FALSE;

       for (p = hdrlist; ; p++)
       {
              len = -1;

              if (*p == ':')
              {
                     c1 = c2;
                     c2 = p;

                     if (c1 == NULL)
                     {
                            start = hdrlist;
                            len = c2 - start; 
                     }
                     else
                     {
                            start = c1 + 1;
                            len = c2 - c1 - 1;
                     }
              }
              else if (*p == '\0')
              {
                     if (c2 != NULL)
                     {
                            start = c2 + 1;
                            len = p - c2 - 1;

                            if (strncasecmp((char *) hdr, (char *) start,
                                            len) == 0)
                                   return TRUE;
                     }
                     else
                     {
                            if (strcasecmp((char *) hdr,
                                           (char *) hdrlist) == 0)
                                   return TRUE;
                     }

                     break;
              }

              if (len != -1)
              {
                     if (strncasecmp((char *) hdr, (char *) start,
                                     len) == 0)
                            return TRUE;
              }
       }

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dkim_sig_ignore ( DKIM_SIGINFO *  siginfo)

Definition at line 8430 of file dkim.c.

{
       assert(siginfo != NULL);

       siginfo->sig_flags |= DKIM_SIGFLAG_IGNORE;
}

Here is the caller graph for this function:

DKIM_STAT dkim_sig_process ( DKIM *  dkim,
DKIM_SIGINFO *  sig 
)

Definition at line 5626 of file dkim.c.

{
       DKIM_STAT status;
       int nid;
       int rsastat;
       size_t diglen = 0;
#ifdef USE_GNUTLS
       gnutls_datum_t key;
#else /* USE_GNUTLS */
       BIO *key;
#endif /* USE_GNUTLS */
       u_char *digest = NULL;
       struct dkim_rsa *rsa;

       assert(dkim != NULL);
       assert(sig != NULL);

       /* skip it if we're supposed to ignore it */
       if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
              return DKIM_STAT_OK;

       /* skip it if there was a syntax or other error */
       if (sig->sig_error != DKIM_SIGERROR_UNKNOWN)
              return DKIM_STAT_OK;

       /* skip the DNS part if we've already done it */
       if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
       {
              /* get the digest */
              status = dkim_canon_getfinal(sig->sig_hdrcanon, &digest,
                                           &diglen);
              if (status != DKIM_STAT_OK)
              {
                     dkim_error(dkim, "dkim_canon_getfinal() failed");
                     return DKIM_STAT_INTERNAL;
              }
              assert(digest != NULL && diglen != 0);

              /* retrieve the key */
              status = dkim_get_key(dkim, sig, FALSE);
              if (status == DKIM_STAT_NOKEY)
              {
                     sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
                     sig->sig_error = DKIM_SIGERROR_NOKEY;
                     return DKIM_STAT_OK;
              }
              else if (status == DKIM_STAT_KEYFAIL)
              {
                     sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
                     sig->sig_error = DKIM_SIGERROR_KEYFAIL;
                     return DKIM_STAT_OK;
              }
              else if (status == DKIM_STAT_CANTVRFY ||
                       status == DKIM_STAT_SYNTAX)
              {
                     sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
                     if (sig->sig_error == DKIM_SIGERROR_UNKNOWN)
                            sig->sig_error = DKIM_SIGERROR_DNSSYNTAX;
                     return DKIM_STAT_OK;
              }
              else if (status == DKIM_STAT_MULTIDNSREPLY)
              {
                     sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
                     sig->sig_error = DKIM_SIGERROR_MULTIREPLY;
                     return DKIM_STAT_OK;
              }
              else if (status == DKIM_STAT_REVOKED)
              {
                     sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
                     sig->sig_error = DKIM_SIGERROR_KEYREVOKED;
                     return DKIM_STAT_OK;
              }
              else if (status != DKIM_STAT_OK)
              {
                     return status;
              }

#ifdef USE_GNUTLS
              key.data = sig->sig_key;
              key.size = sig->sig_keylen;
#else /* USE_GNUTLS */
              /* load the public key */
              key = BIO_new_mem_buf(sig->sig_key, sig->sig_keylen);
              if (key == NULL)
              {
                     dkim_error(dkim, "BIO_new_mem_buf() failed");
                     return DKIM_STAT_NORESOURCE;
              }
#endif /* USE_GNUTLS */

              /* set up to verify */
              if (sig->sig_signature == NULL)
              {
                     rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa));
                     if (rsa == NULL)
                     {
                            dkim_error(dkim,
                                       "unable to allocate %d byte(s)",
                                       sizeof(struct dkim_rsa));
#ifndef USE_GNUTLS
                            BIO_free(key);
#endif /* ! USE_GNUTLS */
                            return DKIM_STAT_NORESOURCE;
                     }

                     sig->sig_signature = rsa;
              }
              else
              {
                     rsa = sig->sig_signature;
              }
              memset(rsa, '\0', sizeof(struct dkim_rsa));

#ifdef USE_GNUTLS
              rsa->rsa_sig.data = sig->sig_sig;
              rsa->rsa_sig.size = sig->sig_siglen;

              rsa->rsa_digest.data = digest;
              rsa->rsa_digest.size = diglen;

              if (gnutls_pubkey_init(&rsa->rsa_pubkey) != GNUTLS_E_SUCCESS)
              {
                     dkim_error(dkim,
                                "s=%s d=%s: gnutls_pubkey_init() failed",
                                dkim_sig_getselector(sig),
                                dkim_sig_getdomain(sig));

                     sig->sig_error = DKIM_SIGERROR_KEYDECODE;

                     return DKIM_STAT_OK;
              }

              status = gnutls_pubkey_import(rsa->rsa_pubkey, &key,
                                            GNUTLS_X509_FMT_DER);
              if (status != GNUTLS_E_SUCCESS)
              {
                     dkim_error(dkim,
                                "s=%s d=%s: gnutls_pubkey_import() failed",
                                dkim_sig_getselector(sig),
                                dkim_sig_getdomain(sig));

                     sig->sig_error = DKIM_SIGERROR_KEYDECODE;

                     return DKIM_STAT_OK;
              }

              rsastat = gnutls_pubkey_verify_hash(rsa->rsa_pubkey, 0,
                                                  &rsa->rsa_digest,
                                                  &rsa->rsa_sig);

              (void) gnutls_pubkey_get_pk_algorithm(rsa->rsa_pubkey,
                                                    &rsa->rsa_keysize);

              sig->sig_keybits = rsa->rsa_keysize;
#else /* USE_GNUTLS */
              rsa->rsa_pkey = d2i_PUBKEY_bio(key, NULL);
              if (rsa->rsa_pkey == NULL)
              {
                     dkim_error(dkim, "s=%s d=%s: d2i_PUBKEY_bio() failed",
                                dkim_sig_getselector(sig),
                                dkim_sig_getdomain(sig));
                     BIO_free(key);

                     sig->sig_error = DKIM_SIGERROR_KEYDECODE;

                     return DKIM_STAT_OK;
              }

              /* set up the RSA object */
              rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey);
              if (rsa->rsa_rsa == NULL)
              {
                     dkim_error(dkim,
                                "s=%s d=%s: EVP_PKEY_get1_RSA() failed",
                                dkim_sig_getselector(sig),
                                dkim_sig_getdomain(sig));
                     BIO_free(key);

                     sig->sig_error = DKIM_SIGERROR_KEYDECODE;

                     return DKIM_STAT_OK;
              }

              rsa->rsa_keysize = RSA_size(rsa->rsa_rsa);
              rsa->rsa_pad = RSA_PKCS1_PADDING;

              rsa->rsa_rsain = sig->sig_sig;
              rsa->rsa_rsainlen = sig->sig_siglen;

              sig->sig_keybits = 8 * rsa->rsa_keysize;

              nid = NID_sha1;

              if (dkim_libfeature(dkim->dkim_libhandle,
                                  DKIM_FEATURE_SHA256) &&
                  sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
                     nid = NID_sha256;

              rsastat = RSA_verify(nid, digest, diglen, rsa->rsa_rsain,
                            rsa->rsa_rsainlen, rsa->rsa_rsa);

              BIO_free(key);
              RSA_free(rsa->rsa_rsa);
              rsa->rsa_rsa = NULL;
#endif /* USE_GNUTLS */

              if (rsastat == 1)
                     sig->sig_flags |= DKIM_SIGFLAG_PASSED;
              else
                     sig->sig_error = DKIM_SIGERROR_BADSIG;

              sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
       }

       /* do the body hash check if possible */
       if (dkim->dkim_bodydone && sig->sig_bh == DKIM_SIGBH_UNTESTED &&
           (sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0)
       {
              u_char *bhash;
              u_char b64buf[BUFRSZ];

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

              dkim_canon_getfinal(sig->sig_bodycanon, &digest, &diglen);

              bhash = dkim_param_get(sig->sig_taglist, (u_char *) "bh");

              dkim_base64_encode(digest, diglen, b64buf, sizeof b64buf);

              if (strcmp((char *) bhash, (char *) b64buf) == 0)
                     sig->sig_bh = DKIM_SIGBH_MATCH;
              else
                     sig->sig_bh = DKIM_SIGBH_MISMATCH;
       }

       /*
       **  Fail if t=s was present in the key and the i= and d= domains
       **  don't match.
       */

       if ((sig->sig_flags & DKIM_SIGFLAG_NOSUBDOMAIN) != 0)
       {
              char *d;
              char *i;

              d = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "d");
              i = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "i");

              if (i != NULL && d != NULL)
              {
                     char *at;

                     at = strchr(i, '@');
                     if (at == NULL)
                            at = i;
                     else
                            at++;

                     if (strcasecmp(at, d) != 0)
                            sig->sig_error = DKIM_SIGERROR_SUBDOMAIN;
              }
       }

       /*
       **  Fail if the "must be signed" list was set and this signature didn't
       **  cover a must-be-signed header which was present.
       */

       if (dkim->dkim_libhandle->dkiml_mbs != NULL)
       {
              int c;

              for (c = 0; dkim->dkim_libhandle->dkiml_mbs[c] != NULL; c++)
              {
                     if (dkim_get_header(dkim,
                                         dkim->dkim_libhandle->dkiml_mbs[c],
                                         0, 0) != NULL &&
                         !dkim_sig_hdrsigned(sig,
                                             dkim->dkim_libhandle->dkiml_mbs[c]))
                     {
                            sig->sig_error = DKIM_SIGERROR_MBSFAILED;
                            break;
                     }
              }
       }

       if (sig->sig_error == DKIM_SIGERROR_UNKNOWN &&
           sig->sig_bh != DKIM_SIGBH_UNTESTED)
              sig->sig_error = DKIM_SIGERROR_OK;

       return DKIM_STAT_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_sig_syntax ( DKIM *  dkim,
u_char *  str,
size_t  len 
)

Definition at line 6883 of file dkim.c.

Here is the call graph for this function:

static _Bool dkim_sig_timestampsok ( DKIM_SET *  set) [static]

Definition at line 1645 of file dkim.c.

{
       uint64_t signtime;
       uint64_t expire;
       u_char *val;

       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_SIGNATURE);

       val = dkim_param_get(set, (u_char *) "t");
       if (val == NULL)
              return TRUE;
       if (sizeof(uint64_t) == sizeof(unsigned long long))
              signtime = strtoull((char *) val, NULL, 10);
       else if (sizeof(uint64_t) == sizeof(unsigned long))
              signtime = strtoul((char *) val, NULL, 10);
       else
              signtime = (unsigned int) strtoul((char *) val, NULL, 10);

       val = dkim_param_get(set, (u_char *) "x");
       if (val == NULL)
              return TRUE;
       if (sizeof(uint64_t) == sizeof(unsigned long long))
              expire = strtoull((char *) val, NULL, 10);
       else if (sizeof(uint64_t) == sizeof(unsigned long))
              expire = strtoul((char *) val, NULL, 10);
       else
              expire = (unsigned int) strtoul((char *) val, NULL, 10);

       return (signtime < expire);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _Bool dkim_sig_versionok ( DKIM *  dkim,
DKIM_SET *  set 
) [static]

Definition at line 1735 of file dkim.c.

{
       char *v;

       assert(set != NULL);
       assert(set->set_type == DKIM_SETTYPE_SIGNATURE);

       v = (char *) dkim_param_get(set, (u_char *) "v");

       assert(v != NULL);

       /* check for DKIM_VERSION_SIG */
       if (strcmp(v, DKIM_VERSION_SIG) == 0)
              return TRUE;

       /* check for DKIM_VERSION_SIGOLD if allowed */
       if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_ACCEPTV05) &&
           strcmp(v, DKIM_VERSION_SIGOLD) == 0)
              return TRUE;

       return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

DKIM_STAT dkim_siglist_setup ( DKIM *  dkim)

Definition at line 1769 of file dkim.c.

{
       _Bool bsh;
       int c;
       int hashtype = DKIM_HASHTYPE_UNKNOWN;
       int hstatus;
       size_t b64siglen;
       size_t len;
       DKIM_STAT status;
       ssize_t signlen = (ssize_t) -1;
       uint64_t drift;
       dkim_canon_t bodycanon;
       dkim_canon_t hdrcanon;
       dkim_alg_t signalg;
       DKIM_SET *set;
       DKIM_LIB *lib;
       DKIM_CANON *hc;
       DKIM_CANON *bc;
       u_char *param;
       u_char *hdrlist;

       assert(dkim != NULL);

       lib = dkim->dkim_libhandle;
       drift = lib->dkiml_clockdrift;

       bsh = ((lib->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);

       len = dkim->dkim_sigcount * sizeof(DKIM_SIGINFO *);
       dkim->dkim_siglist = DKIM_MALLOC(dkim, len);
       if (dkim->dkim_siglist == NULL)
       {
              dkim_error(dkim, "unable to allocate %d byte(s)", len);
              return DKIM_STAT_NORESOURCE;
       }

       /* allocate the siginfo elements */
       for (c = 0; c < dkim->dkim_sigcount; c++)
       {
              dkim->dkim_siglist[c] = DKIM_MALLOC(dkim,
                                                  sizeof(DKIM_SIGINFO));
              if (dkim->dkim_siglist[c] == NULL)
              {
                     int n;

                     dkim_error(dkim,
                                "unable to allocate %d byte(s)",
                                sizeof(DKIM_SIGINFO));
                     for (n = 0; n < c; n++)
                            DKIM_FREE(dkim, dkim->dkim_siglist[n]);
                     return DKIM_STAT_NORESOURCE;
              }

              memset(dkim->dkim_siglist[c], '\0', sizeof(DKIM_SIGINFO));
       }

       /* populate the elements */
       for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGNATURE), c = 0;
            set != NULL && c < dkim->dkim_sigcount;
            set = dkim_set_next(set, DKIM_SETTYPE_SIGNATURE), c++)
       {
              /* cope with bad ones */
              if (set->set_bad && !bsh)
              {
                     c--;
                     continue;
              }

              dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_UNKNOWN;
              dkim->dkim_siglist[c]->sig_dnssec_key = DKIM_DNSSEC_UNKNOWN;

              /* store the set */
              dkim->dkim_siglist[c]->sig_taglist = set;

              /* override query method? */
              if (lib->dkiml_querymethod != DKIM_QUERY_UNKNOWN)
                     dkim->dkim_siglist[c]->sig_query = lib->dkiml_querymethod;

              /* critical stuff: signing domain */
              param = dkim_param_get(set, (u_char *) "d");
              if (param == NULL)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_D;
                     continue;
              }
              else if (param[0] == '\0')
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_D;
                     continue;
              }
              dkim->dkim_siglist[c]->sig_domain = param;

              /* critical stuff: selector */
              param = dkim_param_get(set, (u_char *) "s");
              if (param == NULL)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_S;
                     continue;
              }
              else if (param[0] == '\0')
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_S;
                     continue;
              }
              dkim->dkim_siglist[c]->sig_selector = param;

              /* some basic checks first */
              param = dkim_param_get(set, (u_char *) "v");
              if (param == NULL)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_V;
                     continue;
              }
              else if (param[0] == '\0')
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_V;
                     continue;
              }
              else if (!dkim_sig_versionok(dkim, set))
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_VERSION;
                     continue;
              }
              else if (!dkim_sig_domainok(dkim, set))
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_DOMAIN;
                     continue;
              }
              else if (dkim_sig_expired(set, drift))
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EXPIRED;
                     continue;
              }
              else if (dkim_sig_future(set, drift))
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_FUTURE;
                     continue;
              }
              else if (!dkim_sig_timestampsok(set))
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_TIMESTAMPS;
                     continue;
              }

              /* determine canonicalizations */
              param = dkim_param_get(set, (u_char *) "c");
              if (param == NULL)
              {
                     hdrcanon = DKIM_CANON_SIMPLE;
                     bodycanon = DKIM_CANON_SIMPLE;
              }
              else
              {
                     char *q;
                     char value[BUFRSZ + 1];

                     strlcpy(value, (char *) param, sizeof value);

                     q = strchr(value, '/');
                     if (q != NULL)
                            *q = '\0';

                     hdrcanon = dkim_name_to_code(canonicalizations, value);
                     if (hdrcanon == -1)
                     {
                            dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_HC;
                            continue;
                     }

                     if (q == NULL)
                     {
                            bodycanon = DKIM_CANON_SIMPLE;
                     }
                     else
                     {
                            bodycanon = dkim_name_to_code(canonicalizations,
                                                          q + 1);

                            if (bodycanon == -1)
                            {
                                   dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_BC;
                                   continue;
                            }
                     }
              }

              /* determine hash type */
              param = dkim_param_get(set, (u_char *) "a");
              if (param == NULL)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_A;
                     continue;
              }
              else
              {
                     signalg = dkim_name_to_code(algorithms,
                                                 (char *) param);

                     if (signalg == -1)
                     {
                            dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_A;
                            continue;
                     }

                     switch (signalg)
                     {
                       case DKIM_SIGN_RSASHA1:
                            hashtype = DKIM_HASHTYPE_SHA1;
                            break;

                       case DKIM_SIGN_RSASHA256:
                            if (dkim_libfeature(lib, DKIM_FEATURE_SHA256))
                            {
                                   hashtype = DKIM_HASHTYPE_SHA256;
                            }
                            else
                            {
                                   dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_A;
                                   continue;
                            }
                            break;

                       default:
                            assert(0);
                            /* NOTREACHED */
                     }

                     dkim->dkim_siglist[c]->sig_signalg = signalg;
                     dkim->dkim_siglist[c]->sig_hashtype = hashtype;
              }

              /* determine header list */
              param = dkim_param_get(set, (u_char *) "h");
              if (param == NULL)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_H;
                     continue;
              }
              else if (param[0] == '\0')
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_H;
                     continue;
              }

              hstatus = dkim_sig_hdrlistok(dkim, param);
              if (hstatus == 0)
              {
                     dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_H;
                     continue;
              }
              else if (hstatus == -1)
              {
                     return DKIM_STAT_NORESOURCE;
              }

              hdrlist = param;

              /* determine signing length */
              param = dkim_param_get(set, (u_char *) "l");
              if (param != NULL)
              {
                     char *q;

                     errno = 0;
                     if (param[0] == '-')
                     {
                            errno = ERANGE;
                            signlen = ULONG_MAX;
                     }
                     else
                     {
                            signlen = (ssize_t) strtoul((char *) param,
                                                      &q, 10);
                     }

                     if (signlen == ULONG_MAX || errno != 0 || *q != '\0')
                     {
                            dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_L;
                            continue;
                     }
              }

              /* query method */
              param = dkim_param_get(set, (u_char *)