"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/spfquery/spfquery.c" (28 Jan 2012, 17113 Bytes) of package /linux/privat/libspf2-1.2.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spfquery.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *  spfquery - Sender Policy Framwork command line utility
    3  *
    4  *  Author: Wayne Schlitt <wayne@midwestcs.com>
    5  *
    6  *  File:   spfquery.c
    7  *  Desc:   SPF command line utility
    8  *
    9  *
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of either:
   12  *
   13  *   a) The GNU Lesser General Public License as published by the Free
   14  *    Software Foundation; either version 2.1, or (at your option) any
   15  *    later version,
   16  *
   17  *   OR
   18  *
   19  *   b) The two-clause BSD license.
   20  *
   21  *
   22  * The two-clause BSD license:
   23  *
   24  *
   25  * Redistribution and use in source and binary forms, with or without
   26  * modification, are permitted provided that the following conditions
   27  * are met:
   28  *
   29  * 1. Redistributions of source code must retain the above copyright
   30  *  notice, this list of conditions and the following disclaimer.
   31  * 2. Redistributions in binary form must reproduce the above copyright
   32  *  notice, this list of conditions and the following disclaimer in the
   33  *  documentation and/or other materials provided with the distribution.
   34  *
   35  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   36  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   38  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   39  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   40  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   41  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   42  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   43  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   44  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   45  */
   46 
   47 #define SPF_TEST_VERSION  "3.0"
   48 
   49 #include "libreplace/win32_config.h"
   50 
   51 #ifdef HAVE_CONFIG_H
   52 # include "config.h"
   53 #endif
   54 
   55 #ifdef STDC_HEADERS
   56 # include <stdio.h>
   57 # include <stdlib.h>       /* malloc / free */
   58 #endif
   59 
   60 #ifdef HAVE_SYS_TYPES_H
   61 #include <sys/types.h>  /* types (u_char .. etc..) */
   62 #endif
   63 
   64 #ifdef HAVE_INTTYPES_H
   65 #include <inttypes.h>
   66 #endif
   67 
   68 #ifdef HAVE_STRING_H
   69 # include <string.h>       /* strstr / strdup */
   70 #else
   71 # ifdef HAVE_STRINGS_H
   72 #  include <strings.h>     /* strstr / strdup */
   73 # endif
   74 #endif
   75 
   76 #ifdef HAVE_SYS_SOCKET_H
   77 # include <sys/socket.h>   /* inet_ functions / structs */
   78 #endif
   79 #ifdef HAVE_NETINET_IN_H
   80 # include <netinet/in.h>   /* inet_ functions / structs */
   81 #endif
   82 
   83 #ifdef HAVE_ARPA_NAMESER_H
   84 # include <arpa/nameser.h> /* DNS HEADER struct */
   85 #endif
   86 
   87 #ifdef HAVE_ARPA_INET_H
   88 # include <arpa/inet.h> /* in_addr struct */
   89 #endif
   90 
   91 #ifdef HAVE_GETOPT_LONG_ONLY
   92 #define _GNU_SOURCE
   93 #include <getopt.h>
   94 #else
   95 #include "libreplace/getopt.h"
   96 #endif
   97 
   98 #ifdef _WIN32
   99 #include "spf_win32.h"
  100 #endif
  101 
  102 #include "spf.h"
  103 #include "spf_dns.h"
  104 #include "spf_dns_null.h"
  105 #include "spf_dns_test.h"
  106 #include "spf_dns_cache.h"
  107 #ifndef _WIN32
  108 #include "spf_dns_resolv.h"
  109 #else
  110 #include "spf_dns_windns.h"
  111 #endif
  112 
  113 
  114 
  115 #define TRUE 1
  116 #define FALSE 0
  117 
  118 #define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
  119 #define FREE_REQUEST(x) FREE((x), SPF_request_free)
  120 #define FREE_RESPONSE(x) FREE((x), SPF_response_free)
  121 
  122 #define CONTINUE_ERROR do { res = 255; continue; } while(0)
  123 #define WARN_ERROR do { res = 255; } while(0)
  124 #define FAIL_ERROR do { res = 255; goto error; } while(0)
  125 
  126 #define RESIZE_RESULT(n) do { \
  127     if (result == NULL) { \
  128         result_len = 256 + n; \
  129         result = malloc(result_len); \
  130         result[0] = '\0'; \
  131     } \
  132     else if (strlen(result) + n >= result_len) { \
  133         result_len = result_len + (result_len >> 1) + 8 + n; \
  134         result = realloc(result, result_len); \
  135     } \
  136 } while(0)
  137 #define APPEND_RESULT(n) do { \
  138     partial_result = SPF_strresult(n); \
  139     RESIZE_RESULT(strlen(partial_result)); \
  140     strcat(result, partial_result); \
  141 } while(0)
  142 
  143 #define X_OR_EMPTY(x) ((x) ? (x) : "")
  144 
  145 static struct option long_options[] = {
  146     {"file", 1, 0, 'f'},
  147 
  148     {"ip", 1, 0, 'i'},
  149     {"sender", 1, 0, 's'},
  150     {"helo", 1, 0, 'h'},
  151     {"rcpt-to", 1, 0, 'r'},
  152 
  153     {"debug", 2, 0, 'd'},
  154     {"local", 1, 0, 'l'},
  155     {"trusted", 1, 0, 't'},
  156     {"guess", 1, 0, 'g'},
  157     {"default-explanation", 1, 0, 'e'},
  158     {"max-lookup", 1, 0, 'm'},
  159     {"sanitize", 1, 0, 'c'},
  160     {"name", 1, 0, 'n'},
  161     {"override", 1, 0, 'a'},
  162     {"fallback", 1, 0, 'z'},
  163 
  164     {"keep-comments", 0, 0, 'k'},
  165     {"version", 0, 0, 'v'},
  166     {"help", 0, 0, '?'},
  167 
  168     {0, 0, 0, 0}
  169 };
  170 
  171 static void
  172 unimplemented(const char flag)
  173 {
  174     struct option   *opt;
  175     int              i;
  176 
  177     for (i = 0; (opt = &long_options[i])->name; i++) {
  178         if (flag == opt->val) {
  179             fprintf(stderr, "Unimplemented option: -%s or -%c\n",
  180                             opt->name, flag);
  181             return;
  182         }
  183     }
  184 
  185     fprintf(stderr, "Unimplemented option: -%c\n", flag);
  186 }
  187 
  188 
  189 static void
  190 usage()
  191 {
  192     fprintf(
  193     stderr,
  194     "Usage:\n"
  195     "\n"
  196     "spfquery [control options | data options] ...\n"
  197     "\n"
  198     "Use the -help option for more information\n"
  199     );
  200 }
  201 
  202 static void
  203 help()
  204 {
  205     fprintf(
  206     stderr,
  207     "Usage:\n"
  208     "\n"
  209     "spfquery [control options | data options] ...\n"
  210     "\n"
  211     "Valid data options are:\n"
  212     "    -file <filename>           read spf data from a file.  Use '-'\n"
  213     "                               to read from stdin.\n"
  214     "\n"
  215     "    -ip <IP address>           The IP address that is sending email\n"
  216     "    -sender <email address>    The email address used as the\n"
  217     "                               envelope-from.  If no username (local\n"
  218     "                               part) is given, 'postmaster' will be\n"
  219     "                               assumed.\n"
  220     "    -helo <domain name>        The domain name given on the SMTP HELO\n"
  221     "                               command.  This is only needed if the\n"
  222     "                               -sender option is not given.\n"
  223     "    -rcpt-to <email addresses> A comma separated lists of email addresses\n"
  224     "                               that will have email from their secondary\n"
  225     "                               MXes automatically allowed.\n"
  226     "\n"
  227     "The data options are required.  The -file option conflicts with all\n"
  228     "the other data options.  The -helo and -rcpt-to are optional.\n"
  229     "\n"
  230     "\n"
  231     "Valid control options are:\n"
  232     "    -debug [debug level]       debug level.\n"
  233     "    -local <SPF mechanisms>    Local policy for whitelisting.\n"
  234     "    -trusted <0|1>             Should trusted-forwarder.org be checked?\n"
  235     "    -guess <SPF mechanisms>    Default checks if no SPF record is found.\n"
  236     "    -default-explanation <str> Default explanation string to use.\n"
  237     "    -max-lookup <number>       Maximum number of DNS lookups to allow\n"
  238     "    -sanitize <0|1>            Clean up invalid characters in output?\n"
  239     "    -name <domain name>        The name of the system doing the SPF\n"
  240     "                               checking\n"
  241     "    -override <...>            Override SPF records for domains\n"
  242     "    -fallback <...>            Fallback SPF records for domains\n"
  243     "\n"
  244     "    -keep-comments             Print comments found when reading\n"
  245     "                               from a file.\n"
  246     "    -version                   Print version of spfquery.\n"
  247     "    -help                      Print out these options.\n"
  248     "\n"
  249     "Examples:\n"
  250     "\n"
  251     "spfquery -ip=11.22.33.44 -sender=user@aol.com -helo=spammer.tld\n"
  252     "spfquery -f test_data\n"
  253     "echo \"127.0.0.1 myname@mydomain.com helohost.com\" | spfquery -f -\n"
  254     );
  255 }
  256 
  257 
  258 static void
  259 response_print_errors(const char *context,
  260                 SPF_response_t *spf_response, SPF_errcode_t err)
  261 {
  262     SPF_error_t     *spf_error;
  263     int              i;
  264 
  265     printf("StartError\n");
  266 
  267     if (context != NULL)
  268         printf("Context: %s\n", context);
  269     if (err != SPF_E_SUCCESS)
  270         printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
  271 
  272     if (spf_response != NULL) {
  273         for (i = 0; i < SPF_response_messages(spf_response); i++) {
  274             spf_error = SPF_response_message(spf_response, i);
  275             printf( "%s: %s%s\n",
  276                     SPF_error_errorp(spf_error) ? "Error" : "Warning",
  277                     // SPF_error_code(spf_error),
  278                     // SPF_strerror(SPF_error_code(spf_error)),
  279                     ((SPF_error_errorp(spf_error) && (!err))
  280                             ? "[UNRETURNED] "
  281                             : ""),
  282                     SPF_error_message(spf_error) );
  283         }
  284     }
  285     else {
  286         printf("libspf2 gave a NULL spf_response\n");
  287     }
  288     printf("EndError\n");
  289 }
  290 
  291 static void
  292 response_print(const char *context, SPF_response_t *spf_response)
  293 {
  294     printf("--vv--\n");
  295     printf("Context: %s\n", context);
  296     if (spf_response == NULL) {
  297         printf("NULL RESPONSE!\n");
  298     }
  299     else {
  300         printf("Response result: %s\n",
  301                     SPF_strresult(SPF_response_result(spf_response)));
  302         printf("Response reason: %s\n",
  303                     SPF_strreason(SPF_response_reason(spf_response)));
  304         printf("Response err: %s\n",
  305                     SPF_strerror(SPF_response_errcode(spf_response)));
  306         response_print_errors(NULL, spf_response,
  307                         SPF_response_errcode(spf_response));
  308     }
  309     printf("--^^--\n");
  310 }
  311 
  312 typedef
  313 struct SPF_client_options_struct {
  314     // void     *hook;
  315     char        *localpolicy;
  316     const char  *explanation;
  317     const char  *fallback;
  318     const char  *rec_dom;
  319     int          use_trusted;
  320     int          max_lookup;
  321     int          sanitize;
  322     int          debug;
  323 } SPF_client_options_t;
  324 
  325 typedef
  326 struct SPF_client_request_struct {
  327     char        *ip;
  328     char        *sender;
  329     char        *helo;
  330     char        *rcpt_to;
  331 } SPF_client_request_t;
  332 
  333 int main( int argc, char *argv[] )
  334 {
  335     SPF_client_options_t    *opts;
  336     SPF_client_request_t    *req;
  337 
  338     SPF_server_t    *spf_server = NULL;
  339     SPF_request_t   *spf_request = NULL;
  340     SPF_response_t  *spf_response = NULL;
  341     SPF_response_t  *spf_response_2mx = NULL;
  342     SPF_response_t  *spf_response_fallback = NULL;
  343     SPF_errcode_t    err;
  344 
  345     char            *opt_file = NULL;
  346     int              opt_keep_comments = 0;
  347 
  348     FILE            *fin;
  349     char             in_line[4096];
  350     char            *p, *p_end;
  351     int              done_once;
  352     int              major, minor, patch;
  353 
  354     int              res = 0;
  355     int              c;
  356 
  357     const char      *partial_result;
  358     char            *result = NULL;
  359     int              result_len = 0;
  360 
  361     opts = (SPF_client_options_t *)malloc(sizeof(SPF_client_options_t));
  362     memset(opts, 0, sizeof(SPF_client_options_t));
  363 
  364     req = (SPF_client_request_t *)malloc(sizeof(SPF_client_request_t));
  365     memset(req, 0, sizeof(SPF_client_request_t));
  366     
  367     opts->rec_dom = "spfquery";
  368 
  369 #ifdef _WIN32
  370     if (SPF_win32_startup() == 0) {
  371         fprintf( stderr, "Could not startup WinSock, wrong version." );
  372         FAIL_ERROR;
  373     }
  374 #endif
  375 
  376     /*
  377      * check the arguments
  378      */
  379 
  380     for (;;) {
  381         int option_index;   /* Largely unused */
  382 
  383         c = getopt_long_only (argc, argv, "f:i:s:h:r:lt::gemcnd::kz:a:v",
  384                   long_options, &option_index);
  385 
  386         if (c == -1)
  387             break;
  388 
  389         switch (c) {
  390             case 'f':
  391                 opt_file = optarg;
  392                 break;
  393 
  394 
  395             case 'i':
  396                 req->ip = optarg;
  397                 break;
  398 
  399             case 's':
  400                 req->sender = optarg;
  401                 break;
  402 
  403             case 'h':
  404                 req->helo = optarg;
  405                 break;
  406 
  407             case 'r':
  408                 req->rcpt_to = optarg;
  409                 break;
  410 
  411 
  412             case 'l':
  413                 opts->localpolicy = optarg;
  414                 break;
  415 
  416             case 't':
  417                 if (optarg == NULL)
  418                     opts->use_trusted = 1;
  419                 else
  420                     opts->use_trusted = atoi(optarg);
  421                 break;
  422 
  423             case 'g':
  424                 opts->fallback = optarg;
  425                 break;
  426 
  427             case 'e':
  428                 opts->explanation = optarg;
  429                 break;
  430 
  431             case 'm':
  432                 opts->max_lookup = atoi(optarg);
  433                 break;
  434 
  435             case 'c':       /* "clean" */
  436                 opts->sanitize = atoi(optarg);
  437                 break;
  438 
  439             case 'n':       /* name of host doing SPF checking */
  440                 opts->rec_dom = optarg;
  441                 break;
  442 
  443             case 'a':
  444                 unimplemented('a');
  445                 break;
  446 
  447             case 'z':
  448                 unimplemented('z');
  449                 break;
  450 
  451 
  452             case 'v':
  453                 fprintf( stderr, "spfquery version information:\n" );
  454                 fprintf( stderr, "SPF test system version: %s\n",
  455                  SPF_TEST_VERSION );
  456                 fprintf( stderr, "Compiled with SPF library version: %d.%d.%d\n",
  457                  SPF_LIB_VERSION_MAJOR, SPF_LIB_VERSION_MINOR,
  458                  SPF_LIB_VERSION_PATCH );
  459                 SPF_get_lib_version( &major, &minor, &patch );
  460                 fprintf( stderr, "Running with SPF library version: %d.%d.%d\n",
  461                  major, minor, patch );
  462                 fprintf( stderr, "\n" );
  463                 usage();
  464                 FAIL_ERROR;
  465                 break;
  466 
  467             case 0:
  468             case '?':
  469                 help();
  470                 FAIL_ERROR;
  471                 break;
  472 
  473             case 'k':
  474                 opt_keep_comments = 1;
  475                 break;
  476 
  477             case 'd':
  478                 if (optarg == NULL)
  479                     opts->debug = 1;
  480                 else
  481                     opts->debug = atoi( optarg );
  482                 break;
  483 
  484             default:
  485                 fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c);
  486                 FAIL_ERROR;
  487         }
  488     }
  489 
  490     if (optind != argc) {
  491         help();
  492         FAIL_ERROR;
  493     }
  494 
  495     /*
  496      * set up the SPF configuration
  497      */
  498 
  499     spf_server = SPF_server_new(SPF_DNS_CACHE, opts->debug);
  500 
  501     if ( opts->rec_dom )
  502         SPF_server_set_rec_dom( spf_server, opts->rec_dom );
  503     if ( opts->sanitize )
  504         SPF_server_set_sanitize( spf_server, opts->sanitize );
  505     if ( opts->max_lookup )
  506         SPF_server_set_max_dns_mech(spf_server, opts->max_lookup);
  507 
  508     if (opts->localpolicy) {
  509         err = SPF_server_set_localpolicy( spf_server, opts->localpolicy, opts->use_trusted, &spf_response);
  510         if ( err ) {
  511             response_print_errors("Error setting local policy",
  512                             spf_response, err);
  513             WARN_ERROR;
  514         }
  515         FREE_RESPONSE(spf_response);
  516     }
  517 
  518 
  519     if ( opts->explanation ) {
  520         err = SPF_server_set_explanation( spf_server, opts->explanation, &spf_response );
  521         if ( err ) {
  522             response_print_errors("Error setting default explanation",
  523                             spf_response, err);
  524             WARN_ERROR;
  525         }
  526         FREE_RESPONSE(spf_response);
  527     }
  528 
  529     /*
  530      * process the SPF request
  531      */
  532 
  533     if (opt_file) {
  534         /*
  535          * the requests are on STDIN
  536          */
  537         if (strcmp(opt_file, "-" ) == 0)
  538             fin = stdin;
  539         else
  540             fin = fopen( opt_file, "r" );
  541 
  542         if (!fin) {
  543             fprintf( stderr, "Could not open: %s\n", opt_file );
  544             FAIL_ERROR;
  545         }
  546     }
  547     else {
  548         fin = NULL;
  549 
  550         if ((req->ip == NULL) ||
  551             (req->sender == NULL && req->helo == NULL) ) {
  552             usage();
  553             FAIL_ERROR;
  554         }
  555     }
  556 
  557     done_once = FALSE;
  558 
  559     while ( TRUE ) {
  560         if ( fin ) {
  561             if ( fgets( in_line, sizeof( in_line ), fin ) == NULL )
  562                 break;
  563 
  564             in_line[strcspn(in_line, "\r\n")] = '\0';
  565             p = in_line;
  566 
  567             p += strspn( p, " \t\n" );
  568             {
  569                 if ( *p == '\0' || *p == '#' ) {
  570                     if ( opt_keep_comments )
  571                         printf( "%s\n", in_line );
  572                     continue;
  573                 }
  574             }
  575             req->ip = p;
  576             p += strcspn( p, " \t\n" );
  577             *p++ = '\0';
  578 
  579             p += strspn( p, " \t\n" );
  580             req->sender = p;
  581             p += strcspn( p, " \t\n" );
  582             *p++ = '\0';
  583 
  584             p += strspn( p, " \t\n" );
  585             req->helo = p;
  586             p += strcspn( p, " \t\n" );
  587             *p++ = '\0';
  588 
  589             p += strspn( p, " \t\n" );
  590             req->rcpt_to = p;
  591             p += strcspn( p, " \t\n" );
  592             *p++ = '\0';
  593         }
  594         else {
  595             if ( done_once )
  596                 break;
  597             done_once = TRUE;
  598         }
  599 
  600         /* We have to do this here else we leak on CONTINUE_ERROR */
  601         FREE_REQUEST(spf_request);
  602         FREE_RESPONSE(spf_response);
  603 
  604         spf_request = SPF_request_new(spf_server);
  605 
  606         if (SPF_request_set_ipv4_str(spf_request, req->ip)
  607                 && SPF_request_set_ipv6_str(spf_request, req->ip)) {
  608             printf( "Invalid IP address.\n" );
  609             CONTINUE_ERROR;
  610         }
  611 
  612     if (req->helo) {
  613         if (SPF_request_set_helo_dom( spf_request, req->helo ) ) {
  614             printf( "Invalid HELO domain.\n" );
  615             CONTINUE_ERROR;
  616         }
  617     }
  618 
  619         if (SPF_request_set_env_from( spf_request, req->sender ) ) {
  620             printf( "Invalid envelope from address.\n" );
  621             CONTINUE_ERROR;
  622         }
  623 
  624         err = SPF_request_query_mailfrom(spf_request, &spf_response);
  625         if (opts->debug)
  626             response_print("Main query", spf_response);
  627         if (err) {
  628             response_print_errors("Failed to query MAIL-FROM",
  629                             spf_response, err);
  630             CONTINUE_ERROR;
  631         }
  632 
  633         if (result != NULL)
  634             result[0] = '\0';
  635         APPEND_RESULT(SPF_response_result(spf_response));
  636         
  637         if (req->rcpt_to != NULL  && *req->rcpt_to != '\0' ) {
  638             p = req->rcpt_to;
  639             p_end = p + strcspn(p, ",;");
  640 
  641             /* This is some incarnation of 2mx mode. */
  642             while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
  643                 if (*p_end)
  644                     *p_end = '\0';
  645                 else
  646                     p_end = NULL;   /* Note this is last rcpt */
  647 
  648                 err = SPF_request_query_rcptto(spf_request,
  649                                 &spf_response_2mx, p);
  650                 if (opts->debug)
  651                     response_print("2mx query", spf_response_2mx);
  652                 if (err) {
  653                     response_print_errors("Failed to query RCPT-TO",
  654                                     spf_response, err);
  655                     CONTINUE_ERROR;
  656                 }
  657 
  658                 /* append the result */
  659                 APPEND_RESULT(SPF_response_result(spf_response_2mx));
  660 
  661                 spf_response = SPF_response_combine(spf_response,
  662                                 spf_response_2mx);
  663 
  664                 if (!p_end)
  665                     break;
  666                 p = p_end + 1;
  667             }
  668         }
  669 
  670         /* We now have an option to call SPF_request_query_fallback */
  671         if (opts->fallback) {
  672             err = SPF_request_query_fallback(spf_request,
  673                             &spf_response_fallback, opts->fallback);
  674             if (opts->debug)
  675                 response_print("fallback query", spf_response_fallback);
  676             if (err) {
  677                 response_print_errors("Failed to query best-guess",
  678                                 spf_response_fallback, err);
  679                 CONTINUE_ERROR;
  680             }
  681 
  682             /* append the result */
  683             APPEND_RESULT(SPF_response_result(spf_response_fallback));
  684 
  685             spf_response = SPF_response_combine(spf_response,
  686                             spf_response_fallback);
  687         }
  688 
  689         printf( "%s\n%s\n%s\n%s\n",
  690             result,
  691             X_OR_EMPTY(SPF_response_get_smtp_comment(spf_response)),
  692             X_OR_EMPTY(SPF_response_get_header_comment(spf_response)),
  693             X_OR_EMPTY(SPF_response_get_received_spf(spf_response))
  694             );
  695 
  696         res = SPF_response_result(spf_response);
  697 
  698         fflush(stdout);
  699     }
  700 
  701   error:
  702     FREE(result, free);
  703     FREE_RESPONSE(spf_response);
  704     FREE_REQUEST(spf_request);
  705     FREE(spf_server, SPF_server_free);
  706 
  707     FREE(req, free);
  708     FREE(opts, free);
  709 
  710 #ifdef _WIN32
  711     SPF_win32_cleanup();
  712 #endif
  713 
  714     return res;
  715 }