Back to index

opendkim  2.6.6
stats.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2007, 2008 Sendmail, Inc. and its suppliers.
00003 **     All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2011, The OpenDKIM Project.  All rights reserved.
00006 **
00007 **  $Id: stats.c,v 1.27.2.1 2010/10/27 21:43:09 cm-msk Exp $
00008 */
00009 
00010 #ifndef lint
00011 static char stats_c_id[] = "@(#)$Id: stats.c,v 1.27.2.1 2010/10/27 21:43:09 cm-msk Exp $";
00012 #endif /* !lint */
00013 
00014 #include "build-config.h"
00015 
00016 #ifdef _FFR_STATS
00017 
00018 /* system includes */
00019 #include <sys/param.h>
00020 #include <sys/types.h>
00021 #include <sys/socket.h>
00022 #include <netinet/in.h>
00023 #include <arpa/inet.h>
00024 #include <string.h>
00025 #include <errno.h>
00026 #include <pthread.h>
00027 #include <fcntl.h>
00028 #include <assert.h>
00029 #include <syslog.h>
00030 #include <stdlib.h>
00031 #include <ctype.h>
00032 #include <stdio.h>
00033 
00034 #ifdef USE_GNUTLS
00035 /* GnuTLS includes */
00036 # include <gnutls/gnutls.h>
00037 # include <gnutls/crypto.h>
00038 # ifndef MD5_DIGEST_LENGTH
00039 #  define MD5_DIGEST_LENGTH 16
00040 # endif /* ! MD5_DIGEST_LENGTH */
00041 #else /* USE_GNUTLS */
00042 /* libcrypto includes */
00043 # include <openssl/md5.h>
00044 #endif /* USE_GNUTLS */
00045 
00046 /* libopendkim includes */
00047 #include <dkim.h>
00048 #include <dkim-strl.h>
00049 
00050 /* opendkim includes */
00051 #include "stats.h"
00052 #include "util.h"
00053 #include "opendkim.h"
00054 #include "opendkim-db.h"
00055 
00056 /* macros, defaults */
00057 #define       DEFCT                "text/plain"
00058 #define       DEFCTE               "7bit"
00059 #define       DKIMF_STATS_MAXCOST  10
00060 
00061 /* globals */
00062 static pthread_mutex_t stats_lock;
00063 
00064 /*
00065 **  DKIMF_STATS_INIT -- initialize statistics
00066 **
00067 **  Parameters:
00068 **     None.
00069 **
00070 **  Return value:
00071 **     None.
00072 */
00073 
00074 void
00075 dkimf_stats_init(void)
00076 {
00077        pthread_mutex_init(&stats_lock, NULL);
00078 }
00079 
00080 /*
00081 **  DKIMF_STATS_RECORD -- record a DKIM result
00082 **
00083 **  Parameters:
00084 **     path -- path to the DB to update
00085 **     jobid -- job ID for the current message
00086 **     name -- reporter name to record
00087 **     prefix -- hashing prefix
00088 **     hdrlist -- list of headers on the message
00089 **     dkimv -- verifying handle from which data can be taken
00090 **     sa -- client socket information
00091 **
00092 **  Return value:
00093 **     0 on success, !0 on failure
00094 */
00095 
00096 int
00097 dkimf_stats_record(char *path, u_char *jobid, char *name, char *prefix,
00098                    Header hdrlist, DKIM *dkimv,
00099 #ifdef _FFR_STATSEXT
00100                    struct statsext *se,
00101 #endif /* _FFR_STATSEXT */
00102                    int atps,
00103                    int spam,
00104                    struct sockaddr *sa)
00105 {
00106        _Bool validauthorsig = FALSE;
00107        int status = 0;
00108        int nsigs = 0;
00109 #ifdef _FFR_DIFFHEADERS
00110        int nhdrs;
00111        int ndiffs;
00112 #endif /* _FFR_DIFFHEADERS */
00113        int err;
00114        int c;
00115        u_int keybits;
00116        dkim_alg_t alg;
00117        dkim_canon_t bc;
00118        dkim_canon_t hc;
00119        ssize_t canonlen;
00120        ssize_t signlen;
00121        ssize_t msglen;
00122        struct Header *hdr;
00123        FILE *out;
00124        unsigned char *from;
00125        char *p;
00126        char *q;
00127 #ifdef _FFR_DIFFHEADERS
00128        struct dkim_hdrdiff *diffs;
00129        unsigned char *ohdrs[MAXHDRCNT];
00130 #endif /* _FFR_DIFFHEADERS */
00131        DKIM_SIGINFO **sigs;
00132        char tmp[BUFRSZ + 1];
00133 
00134        assert(path != NULL);
00135        assert(jobid != NULL);
00136        assert(name != NULL);
00137 
00138        pthread_mutex_lock(&stats_lock);
00139 
00140        /* open the log file */
00141        out = fopen(path, "a");
00142        if (out == NULL)
00143        {
00144               if (dolog)
00145               {
00146                      syslog(LOG_ERR, "%s: fopen(): %s", path,
00147                             strerror(errno));
00148               }
00149 
00150               pthread_mutex_unlock(&stats_lock);
00151 
00152               return -1;
00153        }
00154 
00155        /* write version if file is new */
00156        if (ftell(out) == 0)
00157               fprintf(out, "V%d\n", DKIMS_VERSION);
00158 
00159        /* write info */
00160        status = dkim_getsiglist(dkimv, &sigs, &nsigs);
00161        if (status != DKIM_STAT_OK)
00162        {
00163               if (dolog)
00164                      syslog(LOG_ERR, "%s: dkim_getsiglist() failed", jobid);
00165 
00166               fclose(out);
00167 
00168               pthread_mutex_unlock(&stats_lock);
00169 
00170               return 0;
00171        }
00172 
00173        from = dkim_getdomain(dkimv);
00174        if (from == NULL)
00175        {
00176               if (dolog)
00177                      syslog(LOG_ERR, "%s: dkim_getdomain() failed", jobid);
00178 
00179               fclose(out);
00180 
00181               pthread_mutex_unlock(&stats_lock);
00182 
00183               return 0;
00184        }
00185 
00186        fprintf(out, "M%s\t%s\t%s", jobid, name, (char *) from);
00187 
00188        memset(tmp, '\0', sizeof tmp);
00189 
00190        switch (sa->sa_family)
00191        {
00192          case AF_INET:
00193          {
00194               struct sockaddr_in sin4;
00195 
00196               memcpy(&sin4, sa, sizeof sin4);
00197 
00198               (void) inet_ntop(AF_INET, &sin4.sin_addr, tmp, sizeof tmp);
00199 
00200               break;
00201          }
00202 #ifdef AF_INET6
00203 
00204          case AF_INET6:
00205          {
00206               struct sockaddr_in6 sin6;
00207 
00208               memcpy(&sin6, sa, sizeof sin6);
00209 
00210               (void) inet_ntop(AF_INET6, &sin6.sin6_addr, tmp, sizeof tmp);
00211 
00212               break;
00213          }
00214 #endif /* AF_INET6 */
00215        }
00216 
00217        if (tmp[0] == '\0')
00218               fprintf(out, "\tunknown");
00219        else
00220               fprintf(out, "\t%s", tmp);
00221 
00222        fprintf(out, "\t%lu", time(NULL));
00223 
00224        msglen = 0;
00225        canonlen = 0;
00226        signlen = 0;
00227        if (nsigs > 0)
00228        {
00229               (void) dkim_sig_getcanonlen(dkimv, sigs[0], &msglen,
00230                                           &canonlen, &signlen);
00231        }
00232 
00233        fprintf(out, "\t%lu", canonlen);
00234 
00235        fprintf(out, "\t%d", nsigs);
00236 
00237 #ifdef _FFR_ATPS
00238        fprintf(out, "\t%d", atps);
00239 #else /* _FFR_ATPS */
00240        fprintf(out, "\t-1");
00241 #endif /* _FFR_ATPS */
00242 
00243 #ifdef _FFR_REPUTATION
00244        fprintf(out, "\t%d", spam);
00245 #else /* _FFR_REPUTATION */
00246        fprintf(out, "\t-1");
00247 #endif /* _FFR_REPUTATION */
00248 
00249        fprintf(out, "\n");
00250 
00251        for (c = 0; c < nsigs; c++)
00252        {
00253               if ((dkim_sig_getflags(sigs[c]) & DKIM_SIGFLAG_IGNORE) != 0)
00254                      continue;
00255 
00256               fprintf(out, "S");
00257 
00258               p = (char *) dkim_sig_getdomain(sigs[c]);
00259               fprintf(out, "%s", p);
00260 
00261               fprintf(out, "\t%d",
00262                       (dkim_sig_getflags(sigs[c]) &
00263                        DKIM_SIGFLAG_PASSED) != 0);
00264 
00265               fprintf(out, "\t%d",
00266                       dkim_sig_getbh(sigs[c]) == DKIM_SIGBH_MISMATCH);
00267 
00268               (void) dkim_sig_getcanonlen(dkimv, sigs[c], &msglen,
00269                                           &canonlen, &signlen);
00270               fprintf(out, "\t%ld", (long) signlen);
00271 
00272               err = dkim_sig_geterror(sigs[c]);
00273 
00274               /* syntax error codes */
00275               fprintf(out, "\t%d", err);
00276 
00277               fprintf(out, "\t%d", dkim_sig_getdnssec(sigs[c]));
00278 
00279               fprintf(out, "\n");
00280        }
00281 
00282 #ifdef _FFR_STATSEXT
00283        if (se != NULL)
00284        {
00285               struct statsext *cur;
00286 
00287               for (cur = se; cur != NULL; cur = cur->se_next)
00288                      fprintf(out, "X%s\t%s\n", cur->se_name, cur->se_value);
00289        }
00290 #endif /* _FFR_STATSEXT */
00291 
00292        /* close output */
00293        fclose(out);
00294 
00295        pthread_mutex_unlock(&stats_lock);
00296 
00297        return 0;
00298 }
00299 #endif /* _FFR_STATS */