Back to index

opendkim  2.6.2
test.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2007-2009 Sendmail, Inc. and its suppliers.
00003 **     All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2011, The OpenDKIM Project.  All rights reserved.
00006 **
00007 **  $Id: test.c,v 1.15 2010/09/02 04:04:20 cm-msk Exp $
00008 */
00009 
00010 #ifndef lint
00011 static char test_c_id[] = "@(#)$Id: test.c,v 1.15 2010/09/02 04:04:20 cm-msk Exp $";
00012 #endif /* !lint */
00013 
00014 /* system includes */
00015 #include <sys/param.h>
00016 #include <sys/types.h>
00017 #include <netinet/in.h>
00018 #include <string.h>
00019 #include <errno.h>
00020 #include <stdio.h>
00021 #include <sysexits.h>
00022 #include <stdlib.h>
00023 #include <time.h>
00024 #include <assert.h>
00025 
00026 /* libopendkim includes */
00027 #include "build-config.h"
00028 #include <dkim.h>
00029 #include <dkim-strl.h>
00030 
00031 /* libmilter includes */
00032 #include <libmilter/mfapi.h>
00033 
00034 /* opendkim includes */
00035 #define DKIMF_MILTER_PROTOTYPES
00036 #include "test.h"
00037 #include "opendkim.h"
00038 
00039 /* local types and definitions*/
00040 #define       CRLF          "\r\n"
00041 
00042 struct test_context
00043 {
00044        void * tc_priv;             /* private data pointer */
00045 };
00046 
00047 char *milter_status[] =
00048 {
00049        "SMFIS_CONTINUE",
00050        "SMFIS_REJECT",
00051        "SMFIS_DISCARD",
00052        "SMFIS_ACCEPT",
00053        "SMFIS_TEMPFAIL"
00054 };
00055 
00056 char *envfrom[] =
00057 {
00058        "<sender@example.org>",
00059        NULL
00060 };
00061 
00062 char *envrcpt[] =
00063 {
00064        "<recipient@example.com>",
00065        NULL
00066 };
00067 
00068 #define       FCLOSE(x)            if ((x) != stdin) \
00069                                    fclose((x));
00070 #define       MLFI_OUTPUT(x,y)     ((y) > 1 || ((y) == 1 && (x) != SMFIS_CONTINUE))
00071 #define       STRORNULL(x)         ((x) == NULL ? "(null)" : (x))
00072 
00073 /* globals */
00074 static int tverbose = 0;
00075 
00076 /*
00077 **  DKIMF_TEST_SETPRIV -- store private pointer
00078 **
00079 **  Parameters:
00080 **     ctx -- context pointer
00081 **     ptr -- pointer to store
00082 **
00083 **  Return value:
00084 **     MI_SUCCESS
00085 */
00086 
00087 int
00088 dkimf_test_setpriv(void *ctx, void *ptr)
00089 {
00090        struct test_context *tc;
00091 
00092        assert(ctx != NULL);
00093 
00094        tc = ctx;
00095        tc->tc_priv = ptr;
00096 
00097        return MI_SUCCESS;
00098 }
00099 
00100 /*
00101 **  DKIMF_TEST_GETPRIV -- retrieve private pointer
00102 **
00103 **  Parameters:
00104 **     ctx -- context pointer
00105 **
00106 **  Return value:
00107 **     The private pointer.
00108 */
00109 
00110 void *
00111 dkimf_test_getpriv(void *ctx)
00112 {
00113        struct test_context *tc;
00114 
00115        assert(ctx != NULL);
00116 
00117        tc = ctx;
00118 
00119        return tc->tc_priv;
00120 }
00121 
00122 /*
00123 **  DKIMF_TEST_PROGRESS -- send progress message
00124 **
00125 **  Parameters:
00126 **     ctx -- context pointer
00127 **
00128 **  Return value:
00129 **     MI_SUCCESS
00130 */
00131 
00132 int
00133 dkimf_test_progress(void *ctx)
00134 {
00135        assert(ctx != NULL);
00136 
00137        if (tverbose > 1)
00138               fprintf(stdout, "### PROGRESS\n");
00139 
00140        return MI_SUCCESS;
00141 }
00142 
00143 /*
00144 **  DKIMF_TEST_SETREPLY -- set reply to use
00145 **
00146 **  Parameters:
00147 **     ctx -- context pointer
00148 **     rcode -- SMTP reply code
00149 **     xcode -- SMTP enhanced reply code
00150 **     replytxt -- SMTP reply text
00151 **
00152 **  Return value:
00153 **     MI_SUCCESS
00154 */
00155 
00156 int
00157 dkimf_test_setreply(void *ctx, char *rcode, char *xcode, char *replytxt)
00158 {
00159        assert(ctx != NULL);
00160 
00161        if (tverbose > 1)
00162        {
00163               fprintf(stdout,
00164                       "### SETREPLY: rcode='%s' xcode='%s' replytxt='%s'\n",
00165                       STRORNULL(rcode), STRORNULL(xcode),
00166                       STRORNULL(replytxt));
00167        }
00168 
00169        return MI_SUCCESS;
00170 }
00171 
00172 /*
00173 **  DKIMF_TEST_INSHEADER -- insert a header
00174 **
00175 **  Parameters:
00176 **     ctx -- context pointer
00177 **     idx -- insertion index
00178 **     hname -- header name
00179 **     hvalue -- header value
00180 **
00181 **  Return value:
00182 **     MI_SUCCESS
00183 */
00184 
00185 int
00186 dkimf_test_insheader(void *ctx, int idx, char *hname, char *hvalue)
00187 {
00188        assert(ctx != NULL);
00189 
00190        if (tverbose > 1)
00191        {
00192               fprintf(stdout,
00193                       "### INSHEADER: idx=%d hname='%s' hvalue='%s'\n",
00194                       idx, STRORNULL(hname), STRORNULL(hvalue));
00195        }
00196 
00197        return MI_SUCCESS;
00198 }
00199 
00200 /*
00201 **  DKIMF_TEST_CHGHEADER -- change a header
00202 **
00203 **  Parameters:
00204 **     ctx -- context pointer
00205 **     hname -- header name
00206 **     idx -- header index
00207 **     hvalue -- header value
00208 **
00209 **  Return value:
00210 **     MI_SUCCESS
00211 */
00212 
00213 int
00214 dkimf_test_chgheader(void *ctx, char *hname, int idx, char *hvalue)
00215 {
00216        assert(ctx != NULL);
00217 
00218        if (tverbose > 1)
00219        {
00220               fprintf(stdout,
00221                       "### CHGHEADER: hname='%s' idx=%d hvalue='%s'\n",
00222                       STRORNULL(hname), idx, STRORNULL(hvalue));
00223        }
00224 
00225        return MI_SUCCESS;
00226 }
00227 
00228 /*
00229 **  DKIMF_TEST_QUARANTINE -- request message quarantine
00230 **
00231 **  Parameters:
00232 **     ctx -- context pointer
00233 **     reason -- reason string
00234 **
00235 **  Return value:
00236 **     MI_SUCCESS
00237 */
00238 
00239 int
00240 dkimf_test_quarantine(void *ctx, char *reason)
00241 {
00242        assert(ctx != NULL);
00243 
00244        if (tverbose > 1)
00245        {
00246               fprintf(stdout,
00247                       "### QUARANTINE: reason='%s'\n", STRORNULL(reason));
00248        }
00249 
00250        return MI_SUCCESS;
00251 }
00252 
00253 /*
00254 **  DKIMF_TEST_ADDHEADER -- append a header
00255 **
00256 **  Parameters:
00257 **     ctx -- context pointer
00258 **     hname -- header name
00259 **     hvalue -- header value
00260 **
00261 **  Return value:
00262 **     MI_SUCCESS
00263 */
00264 
00265 int
00266 dkimf_test_addheader(void *ctx, char *hname, char *hvalue)
00267 {
00268        assert(ctx != NULL);
00269 
00270        if (tverbose > 1)
00271        {
00272               fprintf(stdout,
00273                       "### ADDHEADER: hname='%s' hvalue='%s'\n",
00274                       STRORNULL(hname), STRORNULL(hvalue));
00275        }
00276 
00277        return MI_SUCCESS;
00278 }
00279 
00280 /*
00281 **  DKIMF_TEST_DELRCPT -- request recipient delete
00282 **
00283 **  Parameters:
00284 **     ctx -- context pointer
00285 **     addr -- address
00286 **
00287 **  Return value:
00288 **     MI_SUCCESS
00289 */
00290 
00291 int
00292 dkimf_test_delrcpt(void *ctx, char *addr)
00293 {
00294        assert(ctx != NULL);
00295        assert(addr != NULL);
00296 
00297        if (tverbose > 1)
00298               fprintf(stdout, "### DELRCPT: '%s'\n", addr);
00299 
00300        return MI_SUCCESS;
00301 }
00302 
00303 /*
00304 **  DKIMF_TEST_ADDRCPT -- request recipient add
00305 **
00306 **  Parameters:
00307 **     ctx -- context pointer
00308 **     addr -- address
00309 **
00310 **  Return value:
00311 **     MI_SUCCESS
00312 */
00313 
00314 int
00315 dkimf_test_addrcpt(void *ctx, char *addr)
00316 {
00317        assert(ctx != NULL);
00318        assert(addr != NULL);
00319 
00320        if (tverbose > 1)
00321               fprintf(stdout, "### ADDRCPT: '%s'\n", addr);
00322 
00323        return MI_SUCCESS;
00324 }
00325 
00326 /*
00327 **  DKIMF_TEST_GETSYMVAL -- retrieve a symbol value
00328 **
00329 **  Parameters:
00330 **     ctx -- context pointer
00331 **     sym -- symbol name
00332 **
00333 **  Return value:
00334 **     Pointer to (static) string name.
00335 **
00336 **  Note:
00337 **     This isn't thread-safe, but test mode is single-threaded anyway.
00338 **     This is also a memory leak, but it's a short-lived test program
00339 **     anyway.
00340 */
00341 
00342 char *
00343 dkimf_test_getsymval(void *ctx, char *sym)
00344 {
00345        static char symout[MAXBUFRSZ];
00346 
00347        assert(ctx != NULL);
00348        assert(sym != NULL);
00349 
00350        snprintf(symout, sizeof symout, "DEBUG-%s", sym);
00351 
00352        return strdup(symout);
00353 }
00354 
00355 /*
00356 **  DKIMF_TESTFILE -- read a message and test it
00357 **
00358 **  Parameters:
00359 **     libopendkim -- DKIM_LIB handle
00360 **     file -- input file path
00361 **     fixedtime -- time to use on signatures (or -1)
00362 **     strict -- strict CRLF mode?
00363 **     verbose -- verbose level
00364 **
00365 **  Return value:
00366 **     An EX_* constant (see sysexits.h)
00367 */
00368 
00369 static int
00370 dkimf_testfile(DKIM_LIB *libopendkim, struct test_context *tctx,
00371                FILE *f, char *file, _Bool strict, int tverbose)
00372 {
00373        bool inheaders = TRUE;
00374        int len = 0;
00375        int buflen = 0;
00376        int lineno = 0;
00377        int hslineno = 0;
00378        int c;
00379        DKIM_SIGINFO *sig;
00380        struct signreq *srlist = NULL;
00381        DKIM *dkim;
00382        char *p;
00383        sfsistat ms;
00384        struct sockaddr_in sin;
00385        char buf[MAXBUFRSZ];
00386        char line[MAXBUFRSZ];
00387 
00388        assert(libopendkim != NULL);
00389        assert(tctx != NULL);
00390        assert(f != NULL);
00391 
00392        memset(buf, '\0', sizeof buf);
00393        memset(line, '\0', sizeof buf);
00394 
00395        ms = mlfi_envfrom((SMFICTX *) tctx, envfrom);
00396        if (MLFI_OUTPUT(ms, tverbose))
00397        {
00398               fprintf(stderr, "%s: %s: mlfi_envfrom() returned %s\n",
00399                       progname, file, milter_status[ms]);
00400        }
00401        if (ms != SMFIS_CONTINUE)
00402               return EX_SOFTWARE;
00403 
00404        ms = mlfi_envrcpt((SMFICTX *) tctx, envrcpt);
00405        if (MLFI_OUTPUT(ms, tverbose))
00406        {
00407               fprintf(stderr, "%s: %s: mlfi_envrcpt() returned %s\n",
00408                       progname, file, milter_status[ms]);
00409        }
00410        if (ms != SMFIS_CONTINUE)
00411               return EX_SOFTWARE;
00412 
00413        while (!feof(f))
00414        {
00415               if (fgets(line, sizeof line, f) == NULL)
00416                      break;
00417 
00418               lineno++;
00419 
00420               c = '\0';
00421               for (p = line; *p != '\0'; p++)
00422               {
00423                      if (*p == '\n')
00424                      {
00425                             *p = '\0';
00426                             break;
00427                      }
00428 
00429                      c = *p;
00430               }
00431 
00432               if (c != '\r')
00433               {
00434                      if (strict)                 /* error */
00435                      {
00436                             fprintf(stderr,
00437                                     "%s: %s: line %d: not CRLF-terminated\n",
00438                                     progname, file, lineno);
00439                             return EX_DATAERR;
00440                      }
00441               }
00442               else if (p != line)                /* eat the CR */
00443               {
00444                      *(p - 1) = '\0';
00445               }
00446 
00447               if (inheaders)
00448               {
00449                      if (line[0] == '\0')
00450                      {
00451                             if (buf[0] != '\0')
00452                             {
00453                                    char *colon;
00454 
00455                                    colon = strchr(buf, ':');
00456                                    if (colon == NULL)
00457                                    {
00458                                           fprintf(stderr,
00459                                                   "%s: %s: line %d: header malformed\n",
00460                                                   progname, file,
00461                                                   lineno);
00462                                           return EX_DATAERR;
00463                                    }
00464 
00465                                    *colon = '\0';
00466                                    if (*(colon + 1) == ' ')
00467                                           colon++;
00468 
00469                                    ms = mlfi_header((SMFICTX *) tctx, buf,
00470                                                     colon + 1);
00471                                    if (MLFI_OUTPUT(ms, tverbose))
00472                                    {
00473                                           fprintf(stderr,
00474                                                   "%s: %s: line %d: mlfi_header() returned %s\n",
00475                                                    progname, file,
00476                                                    hslineno,
00477                                                    milter_status[ms]);
00478                                    }
00479 
00480                                    if (ms != SMFIS_CONTINUE)
00481                                           return EX_SOFTWARE;
00482                             }
00483 
00484                             inheaders = FALSE;
00485                             memset(buf, '\0', sizeof buf);
00486                             memset(line, '\0', sizeof buf);
00487 
00488                             ms = mlfi_eoh((SMFICTX *) tctx);
00489                             if (MLFI_OUTPUT(ms, tverbose))
00490                             {
00491                                    fprintf(stderr,
00492                                            "%s: %s: mlfi_eoh() returned %s\n",
00493                                             progname, file,
00494                                             milter_status[ms]);
00495                             }
00496                             if (ms != SMFIS_CONTINUE)
00497                                    return EX_SOFTWARE;
00498 
00499                             continue;
00500                      }
00501 
00502                      if (line[0] == ' ' || line[0] == '\t')
00503                      {
00504                             (void) strlcat(buf, CRLF, sizeof buf);
00505 
00506                             if (strlcat(buf, line,
00507                                         sizeof buf) >= sizeof buf)
00508                             {
00509                                    fprintf(stderr,
00510                                            "%s: %s: line %d: header '%*s...' too large\n",
00511                                            progname, file, lineno,
00512                                            20, buf);
00513                                    return EX_DATAERR;
00514                             }
00515                      }
00516                      else
00517                      {
00518                             if (buf[0] != '\0')
00519                             {
00520                                    char *colon;
00521 
00522                                    colon = strchr(buf, ':');
00523                                    if (colon == NULL)
00524                                    {
00525                                           fprintf(stderr,
00526                                                   "%s: %s: line %d: header malformed\n",
00527                                                   progname, file,
00528                                                   lineno);
00529                                           return EX_DATAERR;
00530                                    }
00531 
00532                                    *colon = '\0';
00533                                    if (*(colon + 1) == ' ')
00534                                           colon++;
00535 
00536                                    ms = mlfi_header((SMFICTX *) tctx, buf,
00537                                                     colon + 1);
00538                                    if (MLFI_OUTPUT(ms, tverbose))
00539                                    {
00540                                           fprintf(stderr,
00541                                                   "%s: %s: line %d: mlfi_header() returned %s\n",
00542                                                   progname, file,
00543                                                   hslineno,
00544                                                   milter_status[ms]);
00545                                    }
00546                                    if (ms != SMFIS_CONTINUE)
00547                                           return EX_SOFTWARE;
00548                                    hslineno = 0;
00549                             }
00550 
00551                             if (hslineno == 0)
00552                                    hslineno = lineno;
00553 
00554                             strlcpy(buf, line, sizeof buf);
00555                      }
00556               }
00557               else
00558               {
00559                      len = strlen(line);
00560 
00561                      if (len + buflen >= (int) sizeof buf - 3)
00562                      {
00563                             ms = mlfi_body((SMFICTX *) tctx,
00564                                            (u_char *) buf,
00565                                            strlen(buf));
00566                             if (MLFI_OUTPUT(ms, tverbose))
00567                             {
00568                                    fprintf(stderr,
00569                                            "%s: %s: mlfi_body() returned %s\n",
00570                                            progname, file,
00571                                            milter_status[ms]);
00572                             }
00573                             if (ms != SMFIS_CONTINUE)
00574                                    return EX_SOFTWARE;
00575 
00576                             memset(buf, '\0', sizeof buf);
00577                             buflen = 0;
00578                      }
00579 
00580                      memcpy(&buf[buflen], line, len);
00581                      buflen += len;
00582                      memcpy(&buf[buflen], CRLF, 2);
00583                      buflen += 2;
00584               }
00585        }
00586 
00587        /* unprocessed partial header? */
00588        if (inheaders && buf[0] != '\0')
00589        {
00590               char *colon;
00591 
00592               colon = strchr(buf, ':');
00593               if (colon == NULL)
00594               {
00595                      fprintf(stderr,
00596                              "%s: %s: line %d: header malformed\n",
00597                              progname, file, lineno);
00598                      return EX_DATAERR;
00599               }
00600 
00601               *colon = '\0';
00602               if (*(colon + 1) == ' ')
00603                      colon++;
00604 
00605               ms = mlfi_header((SMFICTX *) tctx, buf, colon + 1);
00606               if (MLFI_OUTPUT(ms, tverbose))
00607               {
00608                      fprintf(stderr,
00609                              "%s: %s: line %d: mlfi_header() returned %s\n",
00610                              progname, file, lineno, milter_status[ms]);
00611               }
00612               if (ms != SMFIS_CONTINUE)
00613                      return EX_SOFTWARE;
00614 
00615               ms = mlfi_eoh((SMFICTX *) tctx);
00616               if (MLFI_OUTPUT(ms, tverbose))
00617               {
00618                      fprintf(stderr,
00619                              "%s: %s: mlfi_eoh() returned %s\n",
00620                               progname, file, milter_status[ms]);
00621               }
00622               if (ms != SMFIS_CONTINUE)
00623                      return EX_SOFTWARE;
00624 
00625               inheaders = FALSE;
00626               memset(buf, '\0', sizeof buf);
00627        }
00628 
00629        /* no headers found */
00630        if (inheaders)
00631        {
00632               fprintf(stderr, "%s: %s: warning: no headers on input\n",
00633                       progname, file);
00634 
00635               ms = mlfi_eoh((SMFICTX *) tctx);
00636               if (MLFI_OUTPUT(ms, tverbose))
00637               {
00638                      fprintf(stderr, "%s: %s: mlfi_eoh() returned %s\n",
00639                              progname, file, milter_status[ms]);
00640               }
00641               if (ms != SMFIS_CONTINUE)
00642                      return EX_SOFTWARE;
00643        }
00644 
00645        /* some body left */
00646        if (!inheaders && buf[0] != '\0')
00647        {
00648               ms = mlfi_body((SMFICTX *) tctx, (u_char *) buf, strlen(buf));
00649               if (MLFI_OUTPUT(ms, tverbose))
00650               {
00651                      fprintf(stderr, "%s: %s: mlfi_body() returned %s\n",
00652                              progname, file, milter_status[ms]);
00653               }
00654               if (ms != SMFIS_CONTINUE)
00655                      return EX_SOFTWARE;
00656        }
00657 
00658        ms = mlfi_eom((SMFICTX *) tctx);
00659        if (MLFI_OUTPUT(ms, tverbose))
00660        {
00661               fprintf(stderr, "%s: %s: mlfi_eom() returned %s\n",
00662                       progname, file, milter_status[ms]);
00663        }
00664 
00665        dkim = dkimf_getdkim(tctx->tc_priv);
00666        if (dkim != NULL)
00667        {
00668               int mode;
00669 
00670               mode = dkim_getmode(dkim);
00671 
00672               sig = dkim_getsignature(dkim);
00673 
00674               if (sig != NULL)
00675               {
00676                      const u_char *domain;
00677                      const u_char *selector;
00678                      u_int flags;
00679                      u_int bh;
00680                      u_int keysize;
00681 
00682                      domain = dkim_sig_getdomain(sig);
00683                      selector = dkim_sig_getselector(sig);
00684                      flags = dkim_sig_getflags(sig);
00685                      bh = dkim_sig_getbh(sig);
00686                      dkim_sig_getkeysize(sig, &keysize);
00687 
00688                      if ((flags & DKIM_SIGFLAG_PASSED) != 0 &&
00689                          bh == DKIM_SIGBH_MATCH)
00690                      {
00691                             fprintf(stdout,
00692                                     "%s: %s: verification (s=%s, d=%s, %d-bit key) succeeded\n",
00693                                     progname, file, selector, domain,
00694                                     keysize);
00695                      }
00696                      else
00697                      {
00698                             const char *err;
00699                             int errcode;
00700 
00701                             errcode = dkim_sig_geterror(sig);
00702                             if (errcode == DKIM_SIGERROR_OK &&
00703                                 bh == DKIM_SIGBH_MISMATCH)
00704                                    err = "body hash mismatch";
00705                             else
00706                                    err = dkim_sig_geterrorstr(errcode);
00707 
00708                             if (selector != NULL || domain != NULL)
00709                             {
00710 #ifdef USE_UNBOUND
00711                                    char *dnssec;
00712                                    int dnsseccode = DKIM_DNSSEC_UNKNOWN;
00713                             
00714                                    dnsseccode = dkim_sig_getdnssec(sig);
00715 
00716                                    switch (dnsseccode)
00717                                    {
00718                                      case DKIM_DNSSEC_BOGUS:
00719                                           dnssec = "bogus";
00720                                           break;
00721 
00722                                      case DKIM_DNSSEC_INSECURE:
00723                                           dnssec = "insecure";
00724                                           break;
00725 
00726                                      case DKIM_DNSSEC_SECURE:
00727                                           dnssec = "secure";
00728                                           break;
00729 
00730                                      case DKIM_DNSSEC_UNKNOWN:
00731                                      default:
00732                                           dnssec = "unknown";
00733                                           break;
00734                                    }
00735 
00736                                    fprintf(stdout,
00737                                            "%s: %s: verification (s=%s d=%s, %d-bit key, %s) failed: %s\n",
00738                                            progname, file, selector,
00739                                            domain, keysize, dnssec, err);
00740 #else /* USE_UNBOUND */
00741                                    fprintf(stdout,
00742                                            "%s: %s: verification (s=%s d=%s, %d-bit key) failed: %s\n",
00743                                            progname, file, selector,
00744                                            domain, keysize, err);
00745 #endif /* USE_UNBOUND */
00746                             }
00747                             else
00748                             {
00749                                    fprintf(stdout,
00750                                            "%s: %s: verification failed: %s\n",
00751                                            progname, file, err);
00752                             }
00753                      }
00754               }
00755               else if (sig == NULL && mode == DKIM_MODE_VERIFY)
00756               {
00757                      fprintf(stdout, "%s: %s: message not signed\n",
00758                              progname, file);
00759               }
00760        }
00761 
00762        for (srlist = dkimf_getsrlist(tctx->tc_priv);
00763             srlist != NULL;
00764             srlist = srlist->srq_next)
00765        {
00766               dkim = srlist->srq_dkim;
00767               sig = dkim_getsignature(dkim);
00768 
00769               if (sig == NULL)
00770               {
00771                      const char *err;
00772 
00773                      err = dkim_geterror(dkim);
00774                      if (err == NULL)
00775                             err = "unknown error";
00776 
00777                      fprintf(stdout, "%s: %s: no signature added: %s\n",
00778                              progname, file, err);
00779               }
00780               else
00781               {
00782                      if (tverbose < 2)
00783                      {
00784                             DKIM_STAT status;
00785                             size_t hlen;
00786                             size_t rem;
00787                             unsigned char hdr[DKIM_MAXHEADER + 1];
00788 
00789                             hlen = strlen(DKIM_SIGNHEADER);
00790                             rem = sizeof hdr - hlen - 2;
00791                             memset(hdr, '\0', sizeof hdr);
00792 
00793                             strlcpy((char *) hdr, DKIM_SIGNHEADER ": ",
00794                                     sizeof hdr);
00795 
00796                             status = dkim_getsighdr(dkim, hdr + hlen + 2,
00797                                                     rem, hlen + 2);
00798 
00799                             if (status != DKIM_STAT_OK)
00800                             {
00801                                    fprintf(stderr,
00802                                            "%s: %s: dkim_getsighdr(): %s\n",
00803                                            progname, file,
00804                                            dkim_getresultstr(status));
00805                             }
00806                             else
00807                             {
00808                                    fprintf(stdout,
00809                                            "%s: %s:\n%s\n",
00810                                            progname, file, hdr);
00811                             }
00812                      }
00813               }
00814        }
00815 
00816        return EX_OK;
00817 }
00818 
00819 /*
00820 **  DKIMF_TESTFILES -- test one or more input messages
00821 **
00822 **  Parameters:
00823 **     libopendkim -- DKIM_LIB handle
00824 **     flist -- input file list
00825 **     fixedtime -- time to use on signatures (or -1)
00826 **     strict -- strict CRLF mode?
00827 **     verbose -- verbose level
00828 **
00829 **  Return value:
00830 **     An EX_* constant (see sysexits.h)
00831 */
00832 
00833 int
00834 dkimf_testfiles(DKIM_LIB *libopendkim, char *flist, uint64_t fixedtime,
00835                 bool strict, int verbose)
00836 {
00837        char *file;
00838        char *ctx;
00839        FILE *f;
00840        int status;
00841        sfsistat ms;
00842        struct test_context *tctx;
00843        struct sockaddr_in sin;
00844 
00845        assert(libopendkim != NULL);
00846        assert(flist != NULL);
00847 
00848        tverbose = verbose;
00849 
00850        /* pass fixed signing time to the library */
00851        if (fixedtime != (uint64_t) -1)
00852        {
00853               (void) dkim_options(libopendkim, DKIM_OP_SETOPT,
00854                                   DKIM_OPTS_FIXEDTIME,
00855                                   &fixedtime, sizeof fixedtime);
00856        }
00857 
00858        /* set up a fake SMFICTX */
00859        tctx = (struct test_context *) malloc(sizeof(struct test_context));
00860        if (tctx == NULL)
00861        {
00862               fprintf(stderr, "%s: malloc(): %s\n", progname,
00863                       strerror(errno));
00864               return EX_OSERR;
00865        }
00866        tctx->tc_priv = NULL;
00867 
00868        (void) memset(&sin, '\0', sizeof sin);
00869        sin.sin_family = AF_INET;
00870        sin.sin_port = htons(time(NULL) % 65536);
00871        sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00872 
00873        ms = mlfi_connect((SMFICTX *) tctx, "localhost", (_SOCK_ADDR *) &sin);
00874        if (MLFI_OUTPUT(ms, tverbose))
00875        {
00876               fprintf(stderr, "%s: mlfi_connect() returned %s\n",
00877                       progname, milter_status[ms]);
00878        }
00879        if (ms != SMFIS_CONTINUE)
00880               return EX_SOFTWARE;
00881 
00882        /* loop through inputs */
00883        for (file = strtok_r(flist, ",", &ctx);
00884             file != NULL;
00885             file = strtok_r(NULL, ",", &ctx))
00886        {
00887               /* open the input */
00888               if (strcmp(file, "-") == 0)
00889               {
00890                      f = stdin;
00891                      file = "(stdin)";
00892               }
00893               else
00894               {
00895                      f = fopen(file, "r");
00896                      if (f == NULL)
00897                      {
00898                             fprintf(stderr, "%s: %s: fopen(): %s\n",
00899                                     progname, file, strerror(errno));
00900                             return EX_UNAVAILABLE;
00901                      }
00902               }
00903 
00904               status = dkimf_testfile(libopendkim, tctx, f, file, strict,
00905                                       tverbose);
00906 
00907               FCLOSE(f);
00908 
00909               if (status != EX_OK)
00910                      return status;
00911        }
00912 
00913        ms = mlfi_close((SMFICTX *) tctx);
00914        if (MLFI_OUTPUT(ms, tverbose))
00915        {
00916               fprintf(stderr, "%s: mlfi_close() returned %s\n",
00917                       progname, milter_status[ms]);
00918        }
00919 
00920        return EX_OK;
00921 }