spfquery.c

Go to the documentation of this file.
00001 /*
00002  *  spfquery - Sender Policy Framwork command line utility
00003  *
00004  *  Author: Wayne Schlitt <wayne@midwestcs.com>
00005  *
00006  *  File:   spfquery.c
00007  *  Desc:   SPF command line utility
00008  *
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of either:
00012  *
00013  *   a) The GNU Lesser General Public License as published by the Free
00014  *        Software Foundation; either version 2.1, or (at your option) any
00015  *        later version,
00016  *
00017  *   OR
00018  *
00019  *   b) The two-clause BSD license.
00020  *
00021  *
00022  * The two-clause BSD license:
00023  *
00024  *
00025  * Redistribution and use in source and binary forms, with or without
00026  * modification, are permitted provided that the following conditions
00027  * are met:
00028  *
00029  * 1. Redistributions of source code must retain the above copyright
00030  *      notice, this list of conditions and the following disclaimer.
00031  * 2. Redistributions in binary form must reproduce the above copyright
00032  *      notice, this list of conditions and the following disclaimer in the
00033  *      documentation and/or other materials provided with the distribution.
00034  *
00035  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00036  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00037  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00038  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00039  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00040  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00041  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00042  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00043  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00044  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045  */
00046 
00047 #define SPF_TEST_VERSION  "3.0"
00048 
00049 #include "libreplace/win32_config.h"
00050 
00051 #ifdef HAVE_CONFIG_H
00052 # include "config.h"
00053 #endif
00054 
00055 #ifdef STDC_HEADERS
00056 # include <stdio.h>
00057 # include <stdlib.h>       /* malloc / free */
00058 #endif
00059 
00060 #ifdef HAVE_SYS_TYPES_H
00061 #include <sys/types.h>  /* types (u_char .. etc..) */
00062 #endif
00063 
00064 #ifdef HAVE_INTTYPES_H
00065 #include <inttypes.h>
00066 #endif
00067 
00068 #ifdef HAVE_STRING_H
00069 # include <string.h>       /* strstr / strdup */
00070 #else
00071 # ifdef HAVE_STRINGS_H
00072 #  include <strings.h>     /* strstr / strdup */
00073 # endif
00074 #endif
00075 
00076 #ifdef HAVE_SYS_SOCKET_H
00077 # include <sys/socket.h>   /* inet_ functions / structs */
00078 #endif
00079 #ifdef HAVE_NETINET_IN_H
00080 # include <netinet/in.h>   /* inet_ functions / structs */
00081 #endif
00082 
00083 #ifdef HAVE_ARPA_NAMESER_H
00084 # include <arpa/nameser.h> /* DNS HEADER struct */
00085 #endif
00086 
00087 #ifdef HAVE_ARPA_INET_H
00088 # include <arpa/inet.h> /* in_addr struct */
00089 #endif
00090 
00091 #ifdef HAVE_GETOPT_LONG_ONLY
00092 #define _GNU_SOURCE
00093 #include <getopt.h>
00094 #else
00095 #include "libreplace/getopt.h"
00096 #endif
00097 
00098 #ifdef _WIN32
00099 #include "spf_win32.h"
00100 #endif
00101 
00102 #include "spf.h"
00103 #include "spf_dns.h"
00104 #include "spf_dns_null.h"
00105 #include "spf_dns_test.h"
00106 #include "spf_dns_cache.h"
00107 #ifndef _WIN32
00108 #include "spf_dns_resolv.h"
00109 #else
00110 #include "spf_dns_windns.h"
00111 #endif
00112 
00113 
00114 
00115 #define TRUE 1
00116 #define FALSE 0
00117 
00118 #define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
00119 #define FREE_REQUEST(x) FREE((x), SPF_request_free)
00120 #define FREE_RESPONSE(x) FREE((x), SPF_response_free)
00121 
00122 #define CONTINUE_ERROR do { res = 255; continue; } while(0)
00123 #define WARN_ERROR do { res = 255; } while(0)
00124 #define FAIL_ERROR do { res = 255; goto error; } while(0)
00125 
00126 #define RESIZE_RESULT(n) do { \
00127         if (result == NULL) { \
00128                 result_len = 256 + n; \
00129                 result = malloc(result_len); \
00130                 result[0] = '\0'; \
00131         } \
00132         else if (strlen(result) + n >= result_len) { \
00133                 result_len = result_len + (result_len >> 1) + 8 + n; \
00134                 result = realloc(result, result_len); \
00135         } \
00136 } while(0)
00137 #define APPEND_RESULT(n) do { \
00138         partial_result = SPF_strresult(n); \
00139         RESIZE_RESULT(strlen(partial_result)); \
00140         strcat(result, partial_result); \
00141 } while(0)
00142 
00143 #define X_OR_EMPTY(x) ((x) ? (x) : "")
00144 
00145 static struct option long_options[] = {
00146         {"file", 1, 0, 'f'},
00147 
00148         {"ip", 1, 0, 'i'},
00149         {"sender", 1, 0, 's'},
00150         {"helo", 1, 0, 'h'},
00151         {"rcpt-to", 1, 0, 'r'},
00152 
00153         {"debug", 2, 0, 'd'},
00154         {"local", 1, 0, 'l'},
00155         {"trusted", 1, 0, 't'},
00156         {"guess", 1, 0, 'g'},
00157         {"default-explanation", 1, 0, 'e'},
00158         {"max-lookup", 1, 0, 'm'},
00159         {"sanitize", 1, 0, 'c'},
00160         {"name", 1, 0, 'n'},
00161         {"override", 1, 0, 'a'},
00162         {"fallback", 1, 0, 'z'},
00163 
00164         {"keep-comments", 0, 0, 'k'},
00165         {"version", 0, 0, 'v'},
00166         {"help", 0, 0, '?'},
00167 
00168         {0, 0, 0, 0}
00169 };
00170 
00171 static void
00172 unimplemented(const char flag)
00173 {
00174         struct option   *opt;
00175         int                              i;
00176 
00177         for (i = 0; (opt = &long_options[i])->name; i++) {
00178                 if (flag == opt->val) {
00179                         fprintf(stderr, "Unimplemented option: -%s or -%c\n",
00180                                                         opt->name, flag);
00181                         return;
00182                 }
00183         }
00184 
00185         fprintf(stderr, "Unimplemented option: -%c\n", flag);
00186 }
00187 
00188 
00189 static void
00190 usage()
00191 {
00192         fprintf(
00193         stderr,
00194         "Usage:\n"
00195         "\n"
00196         "spfquery [control options | data options] ...\n"
00197         "\n"
00198         "Use the -help option for more information\n"
00199         );
00200 }
00201 
00202 static void
00203 help()
00204 {
00205         fprintf(
00206         stderr,
00207         "Usage:\n"
00208         "\n"
00209         "spfquery [control options | data options] ...\n"
00210         "\n"
00211         "Valid data options are:\n"
00212         "    -file <filename>           read spf data from a file.  Use '-'\n"
00213         "                               to read from stdin.\n"
00214         "\n"
00215         "    -ip <IP address>           The IP address that is sending email\n"
00216         "    -sender <email address>    The email address used as the\n"
00217         "                               envelope-from.  If no username (local\n"
00218         "                               part) is given, 'postmaster' will be\n"
00219         "                               assumed.\n"
00220         "    -helo <domain name>        The domain name given on the SMTP HELO\n"
00221         "                               command.  This is only needed if the\n"
00222         "                               -sender option is not given.\n"
00223         "    -rcpt-to <email addresses> A comma separated lists of email addresses\n"
00224         "                               that will have email from their secondary\n"
00225         "                               MXes automatically allowed.\n"
00226         "\n"
00227         "The data options are required.  The -file option conflicts with all\n"
00228         "the other data options.  The -helo and -rcpt-to are optional.\n"
00229         "\n"
00230         "\n"
00231         "Valid control options are:\n"
00232         "    -debug [debug level]       debug level.\n"
00233         "    -local <SPF mechanisms>    Local policy for whitelisting.\n"
00234         "    -trusted <0|1>             Should trusted-forwarder.org be checked?\n"
00235         "    -guess <SPF mechanisms>    Default checks if no SPF record is found.\n"
00236         "    -default-explanation <str> Default explanation string to use.\n"
00237         "    -max-lookup <number>       Maximum number of DNS lookups to allow\n"
00238         "    -sanitize <0|1>            Clean up invalid characters in output?\n"
00239         "    -name <domain name>        The name of the system doing the SPF\n"
00240         "                               checking\n"
00241         "    -override <...>            Override SPF records for domains\n"
00242         "    -fallback <...>            Fallback SPF records for domains\n"
00243         "\n"
00244         "    -keep-comments             Print comments found when reading\n"
00245         "                               from a file.\n"
00246         "    -version                   Print version of spfquery.\n"
00247         "    -help                      Print out these options.\n"
00248         "\n"
00249         "Examples:\n"
00250         "\n"
00251         "spfquery -ip=11.22.33.44 -sender=user@aol.com -helo=spammer.tld\n"
00252         "spfquery -f test_data\n"
00253         "echo \"127.0.0.1 myname@mydomain.com helohost.com\" | spfquery -f -\n"
00254         );
00255 }
00256 
00257 
00258 static void
00259 response_print_errors(const char *context,
00260                                 SPF_response_t *spf_response, SPF_errcode_t err)
00261 {
00262         SPF_error_t             *spf_error;
00263         int                              i;
00264 
00265         printf("StartError\n");
00266 
00267         if (context != NULL)
00268                 printf("Context: %s\n", context);
00269         if (err != SPF_E_SUCCESS)
00270                 printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
00271 
00272         if (spf_response != NULL) {
00273                 for (i = 0; i < SPF_response_messages(spf_response); i++) {
00274                         spf_error = SPF_response_message(spf_response, i);
00275                         printf( "%s: %s%s\n",
00276                                         SPF_error_errorp(spf_error) ? "Error" : "Warning",
00277                                         // SPF_error_code(spf_error),
00278                                         // SPF_strerror(SPF_error_code(spf_error)),
00279                                         ((SPF_error_errorp(spf_error) && (!err))
00280                                                         ? "[UNRETURNED] "
00281                                                         : ""),
00282                                         SPF_error_message(spf_error) );
00283                 }
00284         }
00285         else {
00286                 printf("libspf2 gave a NULL spf_response\n");
00287         }
00288         printf("EndError\n");
00289 }
00290 
00291 static void
00292 response_print(const char *context, SPF_response_t *spf_response)
00293 {
00294         printf("--vv--\n");
00295         printf("Context: %s\n", context);
00296         if (spf_response == NULL) {
00297                 printf("NULL RESPONSE!\n");
00298         }
00299         else {
00300                 printf("Response result: %s\n",
00301                                         SPF_strresult(SPF_response_result(spf_response)));
00302                 printf("Response reason: %s\n",
00303                                         SPF_strreason(SPF_response_reason(spf_response)));
00304                 printf("Response err: %s\n",
00305                                         SPF_strerror(SPF_response_errcode(spf_response)));
00306                 response_print_errors(NULL, spf_response,
00307                                                 SPF_response_errcode(spf_response));
00308         }
00309         printf("--^^--\n");
00310 }
00311 
00312 typedef
00313 struct SPF_client_options_struct {
00314         // void         *hook;
00315         char            *localpolicy;
00316         const char      *explanation;
00317         const char      *fallback;
00318         const char      *rec_dom;
00319         int              use_trusted;
00320         int                      max_lookup;
00321         int                      sanitize;
00322         int                      debug;
00323 } SPF_client_options_t;
00324 
00325 typedef
00326 struct SPF_client_request_struct {
00327         char            *ip;
00328         char            *sender;
00329         char            *helo;
00330         char            *rcpt_to;
00331 } SPF_client_request_t;
00332 
00333 int main( int argc, char *argv[] )
00334 {
00335         SPF_client_options_t    *opts;
00336         SPF_client_request_t    *req;
00337 
00338         SPF_server_t    *spf_server = NULL;
00339         SPF_request_t   *spf_request = NULL;
00340         SPF_response_t  *spf_response = NULL;
00341         SPF_response_t  *spf_response_2mx = NULL;
00342         SPF_response_t  *spf_response_fallback = NULL;
00343         SPF_errcode_t    err;
00344 
00345         char                    *opt_file = NULL;
00346         int                      opt_keep_comments = 0;
00347 
00348         FILE                    *fin;
00349         char                     in_line[4096];
00350         char                    *p, *p_end;
00351         int                      done_once;
00352         int                              major, minor, patch;
00353 
00354         int                              res = 0;
00355         int                              c;
00356 
00357         const char              *partial_result;
00358         char                    *result = NULL;
00359         int                              result_len = 0;
00360 
00361         opts = (SPF_client_options_t *)malloc(sizeof(SPF_client_options_t));
00362         memset(opts, 0, sizeof(SPF_client_options_t));
00363 
00364         req = (SPF_client_request_t *)malloc(sizeof(SPF_client_request_t));
00365         memset(req, 0, sizeof(SPF_client_request_t));
00366         
00367         opts->rec_dom = "spfquery";
00368 
00369 #ifdef _WIN32
00370         if (SPF_win32_startup() == 0) {
00371                 fprintf( stderr, "Could not startup WinSock, wrong version." );
00372                 FAIL_ERROR;
00373         }
00374 #endif
00375 
00376         /*
00377          * check the arguments
00378          */
00379 
00380         for (;;) {
00381                 int option_index;       /* Largely unused */
00382 
00383                 c = getopt_long_only (argc, argv, "f:i:s:h:r:lt::gemcnd::kz:a:v",
00384                                   long_options, &option_index);
00385 
00386                 if (c == -1)
00387                         break;
00388 
00389                 switch (c) {
00390                         case 'f':
00391                                 opt_file = optarg;
00392                                 break;
00393 
00394 
00395                         case 'i':
00396                                 req->ip = optarg;
00397                                 break;
00398 
00399                         case 's':
00400                                 req->sender = optarg;
00401                                 break;
00402 
00403                         case 'h':
00404                                 req->helo = optarg;
00405                                 break;
00406 
00407                         case 'r':
00408                                 req->rcpt_to = optarg;
00409                                 break;
00410 
00411 
00412                         case 'l':
00413                                 opts->localpolicy = optarg;
00414                                 break;
00415 
00416                         case 't':
00417                                 if (optarg == NULL)
00418                                         opts->use_trusted = 1;
00419                                 else
00420                                         opts->use_trusted = atoi(optarg);
00421                                 break;
00422 
00423                         case 'g':
00424                                 opts->fallback = optarg;
00425                                 break;
00426 
00427                         case 'e':
00428                                 opts->explanation = optarg;
00429                                 break;
00430 
00431                         case 'm':
00432                                 opts->max_lookup = atoi(optarg);
00433                                 break;
00434 
00435                         case 'c':               /* "clean" */
00436                                 opts->sanitize = atoi(optarg);
00437                                 break;
00438 
00439                         case 'n':               /* name of host doing SPF checking */
00440                                 opts->rec_dom = optarg;
00441                                 break;
00442 
00443                         case 'a':
00444                                 unimplemented('a');
00445                                 break;
00446 
00447                         case 'z':
00448                                 unimplemented('z');
00449                                 break;
00450 
00451 
00452                         case 'v':
00453                                 fprintf( stderr, "spfquery version information:\n" );
00454                                 fprintf( stderr, "SPF test system version: %s\n",
00455                                  SPF_TEST_VERSION );
00456                                 fprintf( stderr, "Compiled with SPF library version: %d.%d.%d\n",
00457                                  SPF_LIB_VERSION_MAJOR, SPF_LIB_VERSION_MINOR,
00458                                  SPF_LIB_VERSION_PATCH );
00459                                 SPF_get_lib_version( &major, &minor, &patch );
00460                                 fprintf( stderr, "Running with SPF library version: %d.%d.%d\n",
00461                                  major, minor, patch );
00462                                 fprintf( stderr, "\n" );
00463                                 usage();
00464                                 FAIL_ERROR;
00465                                 break;
00466 
00467                         case 0:
00468                         case '?':
00469                                 help();
00470                                 FAIL_ERROR;
00471                                 break;
00472 
00473                         case 'k':
00474                                 opt_keep_comments = 1;
00475                                 break;
00476 
00477                         case 'd':
00478                                 if (optarg == NULL)
00479                                         opts->debug = 1;
00480                                 else
00481                                         opts->debug = atoi( optarg );
00482                                 break;
00483 
00484                         default:
00485                                 fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c);
00486                                 FAIL_ERROR;
00487                 }
00488         }
00489 
00490         if (optind != argc) {
00491                 help();
00492                 FAIL_ERROR;
00493         }
00494 
00495         /*
00496          * set up the SPF configuration
00497          */
00498 
00499         spf_server = SPF_server_new(SPF_DNS_CACHE, opts->debug);
00500 
00501         if ( opts->rec_dom )
00502                 SPF_server_set_rec_dom( spf_server, opts->rec_dom );
00503         if ( opts->sanitize )
00504                 SPF_server_set_sanitize( spf_server, opts->sanitize );
00505         if ( opts->max_lookup )
00506                 SPF_server_set_max_dns_mech(spf_server, opts->max_lookup);
00507 
00508         if (opts->localpolicy) {
00509                 err = SPF_server_set_localpolicy( spf_server, opts->localpolicy, opts->use_trusted, &spf_response);
00510                 if ( err ) {
00511                         response_print_errors("Error setting local policy",
00512                                                         spf_response, err);
00513                         WARN_ERROR;
00514                 }
00515                 FREE_RESPONSE(spf_response);
00516         }
00517 
00518 
00519         if ( opts->explanation ) {
00520                 err = SPF_server_set_explanation( spf_server, opts->explanation, &spf_response );
00521                 if ( err ) {
00522                         response_print_errors("Error setting default explanation",
00523                                                         spf_response, err);
00524                         WARN_ERROR;
00525                 }
00526                 FREE_RESPONSE(spf_response);
00527         }
00528 
00529         /*
00530          * process the SPF request
00531          */
00532 
00533         if (opt_file) {
00534                 /*
00535                  * the requests are on STDIN
00536                  */
00537                 if (strcmp(opt_file, "-" ) == 0)
00538                         fin = stdin;
00539                 else
00540                         fin = fopen( opt_file, "r" );
00541 
00542                 if (!fin) {
00543                         fprintf( stderr, "Could not open: %s\n", opt_file );
00544                         FAIL_ERROR;
00545                 }
00546         }
00547         else {
00548                 fin = NULL;
00549 
00550                 if ((req->ip == NULL) ||
00551                         (req->sender == NULL && req->helo == NULL) ) {
00552                         usage();
00553                         FAIL_ERROR;
00554                 }
00555         }
00556 
00557         done_once = FALSE;
00558 
00559         while ( TRUE ) {
00560                 if ( fin ) {
00561                         if ( fgets( in_line, sizeof( in_line ), fin ) == NULL )
00562                                 break;
00563 
00564                         in_line[strcspn(in_line, "\r\n")] = '\0';
00565                         p = in_line;
00566 
00567                         p += strspn( p, " \t\n" );
00568                         {
00569                                 if ( *p == '\0' || *p == '#' ) {
00570                                         if ( opt_keep_comments )
00571                                                 printf( "%s\n", in_line );
00572                                         continue;
00573                                 }
00574                         }
00575                         req->ip = p;
00576                         p += strcspn( p, " \t\n" );
00577                         *p++ = '\0';
00578 
00579                         p += strspn( p, " \t\n" );
00580                         req->sender = p;
00581                         p += strcspn( p, " \t\n" );
00582                         *p++ = '\0';
00583 
00584                         p += strspn( p, " \t\n" );
00585                         req->helo = p;
00586                         p += strcspn( p, " \t\n" );
00587                         *p++ = '\0';
00588 
00589                         p += strspn( p, " \t\n" );
00590                         req->rcpt_to = p;
00591                         p += strcspn( p, " \t\n" );
00592                         *p++ = '\0';
00593                 }
00594                 else {
00595                         if ( done_once )
00596                                 break;
00597                         done_once = TRUE;
00598                 }
00599 
00600                 /* We have to do this here else we leak on CONTINUE_ERROR */
00601                 FREE_REQUEST(spf_request);
00602                 FREE_RESPONSE(spf_response);
00603 
00604                 spf_request = SPF_request_new(spf_server);
00605 
00606                 if (SPF_request_set_ipv4_str(spf_request, req->ip)
00607                                 && SPF_request_set_ipv6_str(spf_request, req->ip)) {
00608                         printf( "Invalid IP address.\n" );
00609                         CONTINUE_ERROR;
00610                 }
00611 
00612         if (req->helo) {
00613                 if (SPF_request_set_helo_dom( spf_request, req->helo ) ) {
00614                         printf( "Invalid HELO domain.\n" );
00615                         CONTINUE_ERROR;
00616                 }
00617         }
00618 
00619                 if (SPF_request_set_env_from( spf_request, req->sender ) ) {
00620                         printf( "Invalid envelope from address.\n" );
00621                         CONTINUE_ERROR;
00622                 }
00623 
00624                 err = SPF_request_query_mailfrom(spf_request, &spf_response);
00625                 if (opts->debug)
00626                         response_print("Main query", spf_response);
00627                 if (err) {
00628                         response_print_errors("Failed to query MAIL-FROM",
00629                                                         spf_response, err);
00630                         CONTINUE_ERROR;
00631                 }
00632 
00633                 if (result != NULL)
00634                         result[0] = '\0';
00635                 APPEND_RESULT(SPF_response_result(spf_response));
00636                 
00637                 if (req->rcpt_to != NULL  && *req->rcpt_to != '\0' ) {
00638                         p = req->rcpt_to;
00639                         p_end = p + strcspn(p, ",;");
00640 
00641                         /* This is some incarnation of 2mx mode. */
00642                         while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
00643                                 if (*p_end)
00644                                         *p_end = '\0';
00645                                 else
00646                                         p_end = NULL;   /* Note this is last rcpt */
00647 
00648                                 err = SPF_request_query_rcptto(spf_request,
00649                                                                 &spf_response_2mx, p);
00650                                 if (opts->debug)
00651                                         response_print("2mx query", spf_response_2mx);
00652                                 if (err) {
00653                                         response_print_errors("Failed to query RCPT-TO",
00654                                                                         spf_response, err);
00655                                         CONTINUE_ERROR;
00656                                 }
00657 
00658                                 /* append the result */
00659                                 APPEND_RESULT(SPF_response_result(spf_response_2mx));
00660 
00661                                 spf_response = SPF_response_combine(spf_response,
00662                                                                 spf_response_2mx);
00663 
00664                                 if (!p_end)
00665                                         break;
00666                                 p = p_end + 1;
00667                         }
00668                 }
00669 
00670                 /* We now have an option to call SPF_request_query_fallback */
00671                 if (opts->fallback) {
00672                         err = SPF_request_query_fallback(spf_request,
00673                                                         &spf_response_fallback, opts->fallback);
00674                         if (opts->debug)
00675                                 response_print("fallback query", spf_response_fallback);
00676                         if (err) {
00677                                 response_print_errors("Failed to query best-guess",
00678                                                                 spf_response_fallback, err);
00679                                 CONTINUE_ERROR;
00680                         }
00681 
00682                         /* append the result */
00683                         APPEND_RESULT(SPF_response_result(spf_response_fallback));
00684 
00685                         spf_response = SPF_response_combine(spf_response,
00686                                                         spf_response_fallback);
00687                 }
00688 
00689                 printf( "%s\n%s\n%s\n%s\n",
00690                         result,
00691                         X_OR_EMPTY(SPF_response_get_smtp_comment(spf_response)),
00692                         X_OR_EMPTY(SPF_response_get_header_comment(spf_response)),
00693                         X_OR_EMPTY(SPF_response_get_received_spf(spf_response))
00694                         );
00695 
00696                 res = SPF_response_result(spf_response);
00697 
00698                 fflush(stdout);
00699         }
00700 
00701   error:
00702         FREE(result, free);
00703         FREE_RESPONSE(spf_response);
00704         FREE_REQUEST(spf_request);
00705         FREE(spf_server, SPF_server_free);
00706 
00707         FREE(req, free);
00708         FREE(opts, free);
00709 
00710 #ifdef _WIN32
00711         SPF_win32_cleanup();
00712 #endif
00713 
00714         return res;
00715 }

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4