"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/libspf2/spf_interpret.c" (28 Jan 2012, 33183 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 "spf_interpret.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * This program is free software; you can redistribute it and/or modify
    3  * it under the terms of either:
    4  *
    5  *   a) The GNU Lesser General Public License as published by the Free
    6  *    Software Foundation; either version 2.1, or (at your option) any
    7  *    later version,
    8  *
    9  *   OR
   10  *
   11  *   b) The two-clause BSD license.
   12  *
   13  * These licenses can be found with the distribution in the file LICENSES
   14  */
   15 
   16 #include "spf_sys_config.h"
   17 
   18 #ifdef STDC_HEADERS
   19 # include <stdio.h>     /* stdin / stdout */
   20 # include <stdlib.h>       /* malloc / free */
   21 #endif
   22 
   23 #ifdef HAVE_STRING_H
   24 # include <string.h>       /* strstr / strdup */
   25 #else
   26 # ifdef HAVE_STRINGS_H
   27 #  include <strings.h>     /* strstr / strdup */
   28 # endif
   29 #endif
   30 
   31 #ifdef HAVE_NETDB_H
   32 #include <netdb.h>
   33 #endif
   34 
   35 #include <ctype.h>
   36 
   37 #include "spf.h"
   38 #include "spf_dns.h"
   39 #include "spf_internal.h"
   40 #include "spf_dns_internal.h"
   41 #include "spf_server.h"
   42 
   43 static SPF_errcode_t
   44 SPF_i_set_explanation(SPF_response_t *spf_response)
   45 {
   46     SPF_server_t    *spf_server;
   47     SPF_request_t   *spf_request;
   48     SPF_record_t    *spf_record;
   49     SPF_errcode_t    err;
   50     char            *buf;
   51     size_t           buflen;
   52 
   53     SPF_ASSERT_NOTNULL(spf_response);
   54     spf_request = spf_response->spf_request;
   55     SPF_ASSERT_NOTNULL(spf_request);
   56     spf_server = spf_request->spf_server;
   57     SPF_ASSERT_NOTNULL(spf_server);
   58 
   59     spf_record = spf_response->spf_record_exp;
   60     SPF_ASSERT_NOTNULL(spf_record);
   61 
   62     if (spf_response->explanation)
   63         free(spf_response->explanation);
   64     spf_response->explanation = NULL;
   65 
   66     buflen = SPF_SMTP_COMMENT_SIZE + 1;
   67     buf = malloc(buflen);
   68     if (buf == NULL)
   69         return SPF_E_NO_MEMORY;
   70     memset(buf, '\0', buflen);
   71 
   72     err = SPF_request_get_exp(spf_server, spf_request,
   73                     spf_response, spf_record, &buf, &buflen);
   74     if (err != SPF_E_SUCCESS) {
   75         free(buf);
   76         return err;
   77     }
   78 
   79     spf_response->explanation = buf;
   80 
   81     return SPF_E_SUCCESS;
   82 }
   83 
   84 static SPF_errcode_t
   85 SPF_i_set_smtp_comment(SPF_response_t *spf_response)
   86 {
   87     SPF_server_t    *spf_server;
   88     SPF_request_t   *spf_request;
   89     SPF_errcode_t    err;
   90     char             buf[SPF_SMTP_COMMENT_SIZE];
   91 
   92     SPF_ASSERT_NOTNULL(spf_response);
   93     spf_request = spf_response->spf_request;
   94     SPF_ASSERT_NOTNULL(spf_request);
   95     spf_server = spf_request->spf_server;
   96     SPF_ASSERT_NOTNULL(spf_server);
   97 
   98     if (spf_response->smtp_comment)
   99         free(spf_response->smtp_comment);
  100     spf_response->smtp_comment = NULL;
  101 
  102     /* smtp_comment = exp= + <why string> */
  103     switch (spf_response->result) {
  104         case SPF_RESULT_FAIL:
  105         case SPF_RESULT_SOFTFAIL:
  106         case SPF_RESULT_NEUTRAL:
  107         case SPF_RESULT_NONE:
  108 
  109             err = SPF_i_set_explanation(spf_response);
  110             if (err != SPF_E_SUCCESS)
  111                 return err;
  112 
  113             memset(buf, '\0', sizeof(buf));
  114             snprintf(buf, SPF_SMTP_COMMENT_SIZE, "%s : Reason: %s",
  115                     spf_response->explanation,
  116                     SPF_strreason(spf_response->reason));
  117             buf[SPF_SMTP_COMMENT_SIZE - 1] = '\0';
  118 
  119             /* It doesn't really hurt much if this fails. */
  120             spf_response->smtp_comment = strdup(buf);
  121             if (! spf_response->smtp_comment)
  122                 return SPF_E_NO_MEMORY;
  123 
  124             break;
  125         case SPF_RESULT_INVALID:
  126         case SPF_RESULT_PASS:
  127         case SPF_RESULT_TEMPERROR:
  128         case SPF_RESULT_PERMERROR:
  129         default:
  130             break;
  131     }
  132 
  133     return SPF_E_SUCCESS;
  134 }
  135 
  136 static SPF_errcode_t
  137 SPF_i_set_header_comment(SPF_response_t *spf_response)
  138 {
  139     SPF_server_t    *spf_server;
  140     SPF_request_t   *spf_request;
  141     char            *spf_source;
  142 
  143     size_t           len;
  144 
  145     char             ip4_buf[ INET_ADDRSTRLEN ];
  146     char             ip6_buf[ INET6_ADDRSTRLEN ];
  147     const char      *ip;
  148 
  149     char            *buf;
  150     char            *sender_dom;
  151     char            *p, *p_end;
  152 
  153     SPF_ASSERT_NOTNULL(spf_response);
  154     spf_request = spf_response->spf_request;
  155     SPF_ASSERT_NOTNULL(spf_request);
  156     spf_server = spf_request->spf_server;
  157     SPF_ASSERT_NOTNULL(spf_server);
  158 
  159     if (spf_response->header_comment)
  160         free(spf_response->header_comment);
  161     spf_response->header_comment = NULL;
  162 
  163     /* Is this cur_dom? */
  164     sender_dom = spf_request->env_from_dp;
  165     if (sender_dom == NULL)
  166         sender_dom = spf_request->helo_dom;
  167 
  168     if ( spf_response->reason == SPF_REASON_LOCAL_POLICY ) {
  169         spf_source = strdup( "local policy" );
  170     }
  171     else if ( spf_response->reason == SPF_REASON_2MX ) {
  172         if ( spf_request->rcpt_to_dom == NULL  || spf_request->rcpt_to_dom[0] == '\0' )
  173             SPF_error( "RCPT TO domain is NULL" );
  174 
  175         spf_source = strdup( spf_request->rcpt_to_dom );
  176     }
  177     else if ( sender_dom == NULL ) {
  178         spf_source = strdup( "unknown domain" );
  179     }
  180     else {
  181         len = strlen( sender_dom ) + sizeof( "domain of " );
  182         spf_source = malloc( len );
  183         if ( spf_source )
  184             snprintf( spf_source, len, "domain of %s", sender_dom );
  185     }
  186 
  187     if ( spf_source == NULL )
  188         return SPF_E_INTERNAL_ERROR;
  189 
  190     ip = NULL;
  191     if ( spf_request->client_ver == AF_INET ) {
  192         ip = inet_ntop( AF_INET, &spf_request->ipv4,
  193                         ip4_buf, sizeof( ip4_buf ) );
  194     }
  195     else if (spf_request->client_ver == AF_INET6 ) {
  196         ip = inet_ntop( AF_INET6, &spf_request->ipv6,
  197                         ip6_buf, sizeof( ip6_buf ) );
  198     }
  199     if ( ip == NULL )
  200         ip = "(unknown ip address)";
  201 
  202     len = strlen( SPF_request_get_rec_dom(spf_request) ) + strlen( spf_source ) + strlen( ip ) + 80;
  203     buf = malloc( len );
  204     if ( buf == NULL ) {
  205         free( spf_source );
  206         return SPF_E_INTERNAL_ERROR;
  207     }
  208 
  209     p = buf;
  210     p_end = p + len;
  211 
  212     /* create the stock header comment */
  213     p += snprintf( p, p_end - p, "%s: ",  SPF_request_get_rec_dom(spf_request) );
  214 
  215     switch(spf_response->result)
  216     {
  217     case SPF_RESULT_PASS:
  218         if ( spf_response->reason == SPF_REASON_LOCALHOST )
  219             snprintf( p, p_end - p, "localhost is always allowed." );
  220         else if ( spf_response->reason == SPF_REASON_2MX )
  221             snprintf( p, p_end - p, "message received from %s which is an MX secondary for %s.",
  222                       ip, spf_source );
  223         else
  224             snprintf( p, p_end - p, "%s designates %s as permitted sender",
  225                       spf_source, ip );
  226         break;
  227 
  228     case SPF_RESULT_FAIL:
  229         snprintf( p, p_end - p, "%s does not designate %s as permitted sender",
  230                   spf_source, ip );
  231         break;
  232 
  233     case SPF_RESULT_SOFTFAIL:
  234         snprintf( p, p_end - p, "transitioning %s does not designate %s as permitted sender",
  235                   spf_source, ip );
  236         break;
  237 
  238     case SPF_RESULT_PERMERROR:
  239         snprintf(p, p_end - p, "error in processing during lookup of %s: %s",
  240                       spf_source, SPF_strerror(spf_response->err));
  241         break;
  242 
  243     case SPF_RESULT_NEUTRAL:
  244         snprintf(p, p_end - p, "%s is neither permitted nor denied by %s",
  245                 ip, spf_source);
  246         break;
  247     case SPF_RESULT_NONE:
  248         snprintf(p, p_end - p, "%s does not provide an SPF record",
  249                 spf_source);
  250         break;
  251 
  252     case SPF_RESULT_TEMPERROR:
  253         snprintf(p, p_end - p, "encountered temporary error during SPF processing of %s",
  254                 spf_source );
  255         break;
  256 
  257 
  258     default:
  259         snprintf( p, p_end - p, "error: unknown SPF result %d encountered while checking %s for %s",
  260                   spf_response->result, ip, spf_source );
  261         break;
  262     }
  263 
  264     if (spf_source)
  265         free(spf_source);
  266 
  267     spf_response->header_comment = SPF_sanitize(spf_server, buf);
  268 
  269     return SPF_E_SUCCESS;
  270 }
  271 
  272 static SPF_errcode_t
  273 SPF_i_set_received_spf(SPF_response_t *spf_response)
  274 {
  275     SPF_server_t    *spf_server;
  276     SPF_request_t   *spf_request;
  277     char             ip4_buf[ INET_ADDRSTRLEN ];
  278     char             ip6_buf[ INET6_ADDRSTRLEN ];
  279     const char      *ip;
  280 
  281     char            *buf;
  282     size_t           buflen = SPF_RECEIVED_SPF_SIZE;
  283     char            *buf_value;
  284     
  285     char            *p, *p_end;
  286 
  287     SPF_ASSERT_NOTNULL(spf_response);
  288     spf_request = spf_response->spf_request;
  289     SPF_ASSERT_NOTNULL(spf_request);
  290     spf_server = spf_request->spf_server;
  291     SPF_ASSERT_NOTNULL(spf_server);
  292 
  293     if (spf_response->received_spf)
  294         free(spf_response->received_spf);
  295     spf_response->received_spf = NULL;
  296 
  297     buf = malloc( buflen );
  298     if ( buf == NULL )
  299         return SPF_E_INTERNAL_ERROR;
  300     
  301     p = buf;
  302     p_end = p + buflen;
  303 
  304     /* create the stock Received-SPF: header */
  305 
  306     p += snprintf( p, p_end - p, "Received-SPF: ");
  307     buf_value = p;
  308 
  309     do {    /* A prop for a structured goto called 'break' */
  310         p += snprintf( p, p_end - p, "%s (%s)",
  311                        SPF_strresult( spf_response->result ),
  312                        spf_response->header_comment );
  313         if ( p_end - p <= 0 ) break;
  314 
  315         
  316         
  317         /* add in the optional ip address keyword */
  318         ip = NULL;
  319         if ( spf_request->client_ver == AF_INET ) {
  320             ip = inet_ntop( AF_INET, &spf_request->ipv4,
  321                             ip4_buf, sizeof( ip4_buf ) );
  322         }
  323         else if (spf_request->client_ver == AF_INET6 ) {
  324             ip = inet_ntop( AF_INET6, &spf_request->ipv6,
  325                             ip6_buf, sizeof( ip6_buf ) );
  326         }
  327 
  328         if ( ip != NULL ) {
  329             p += snprintf( p, p_end - p, " client-ip=%s;", ip );
  330             if ( p_end - p <= 0 ) break;
  331         }
  332         
  333 
  334         /* add in the optional envelope-from keyword */
  335         if ( spf_request->env_from != NULL ) {
  336             p += snprintf( p, p_end - p, " envelope-from=%s;", spf_request->env_from );
  337             if ( p_end - p <= 0 ) break;
  338         }
  339         
  340 
  341         /* add in the optional helo domain keyword */
  342         if ( spf_request->helo_dom != NULL ) {
  343             p += snprintf( p, p_end - p, " helo=%s;", spf_request->helo_dom );
  344             if ( p_end - p <= 0 ) break;
  345         }
  346         
  347 
  348         /* FIXME: Add in full compiler errors. */
  349 #if 0
  350         /* add in the optional compiler error keyword */
  351         if ( output.err_msg != NULL ) {
  352             p += snprintf( p, p_end - p, " problem=%s;", output.err_msg );
  353             if ( p_end - p <= 0 ) break;
  354         }
  355         else if ( c_results.err_msg != NULL ) {
  356             p += snprintf( p, p_end - p, " problem=%s;", c_results.err_msg );
  357             if ( p_end - p <= 0 ) break;
  358         }
  359 #endif
  360 
  361         /* FIXME  should the explanation string be included in the header? */
  362 
  363         /* FIXME  should the header be reformated to include line breaks? */
  364     } while(0);
  365 
  366     spf_response->received_spf = SPF_sanitize(spf_server, buf);
  367     spf_response->received_spf_value = buf_value;
  368 
  369     return SPF_E_SUCCESS;
  370 }
  371 
  372 
  373 
  374 #define DONE(result,reason,err) SPF_i_done(spf_response, result, reason, err)
  375 #define DONE_TEMPERR(err) DONE(SPF_RESULT_TEMPERROR,SPF_REASON_NONE,err)
  376 #define DONE_PERMERR(err) DONE(SPF_RESULT_PERMERROR,SPF_REASON_NONE,err)
  377 #define DONE_MECH(result) DONE(result, SPF_REASON_MECH, SPF_E_SUCCESS)
  378 
  379 /**
  380  * This must be called with EITHER
  381  * spf_response->spf_record_exp != NULL
  382  *   OR
  383  * result in { SPF_RESULT_PASS SPF_RESULT_INVALID
  384  *      SPF_RESULT_TEMPERROR SPF_RESULT_PERMERROR }
  385  * or the library will abort when it tries to generate an explanation.
  386  */
  387 SPF_errcode_t
  388 SPF_i_done(SPF_response_t *spf_response,
  389     SPF_result_t result, SPF_reason_t reason, SPF_errcode_t err)
  390 {
  391     SPF_request_t   *spf_request;
  392     SPF_server_t    *spf_server;
  393 
  394     SPF_ASSERT_NOTNULL(spf_response);
  395     spf_request = spf_response->spf_request;
  396     SPF_ASSERT_NOTNULL(spf_request);
  397     spf_server = spf_request->spf_server;
  398     SPF_ASSERT_NOTNULL(spf_server);
  399 
  400     spf_response->result = result;
  401     spf_response->reason = reason;
  402     spf_response->err = err;
  403 
  404     SPF_i_set_smtp_comment(spf_response);
  405     SPF_i_set_header_comment(spf_response);
  406     SPF_i_set_received_spf(spf_response);
  407 
  408     return err;
  409 }
  410 
  411 /*
  412  * FIXME: Everything before this line could go into a separate file.
  413  */
  414 
  415 
  416 
  417 
  418 #define INET_NTOP(af, src, dst, cnt) do { \
  419     if (inet_ntop(af, src, dst, cnt) == NULL) \
  420         snprintf(dst, cnt, "ip-error" ); \
  421             } while(0)
  422 
  423 static int
  424 SPF_i_mech_cidr(SPF_request_t *spf_request, SPF_mech_t *mech)
  425 {
  426     SPF_data_t              *data;
  427 
  428     SPF_ASSERT_NOTNULL(mech);
  429 
  430     switch( mech->mech_type )
  431     {
  432     case MECH_IP4:
  433     case MECH_IP6:
  434         return mech->mech_len;
  435         break;
  436 
  437     case MECH_A:
  438     case MECH_MX:
  439         data = SPF_mech_data( mech );
  440         /* XXX this was <= but I think that was wrong. */
  441         if ( data < SPF_mech_end_data( mech )
  442              && data->dc.parm_type == PARM_CIDR )
  443         {
  444             if ( spf_request->client_ver == AF_INET )
  445                 return data->dc.ipv4;
  446             else if ( spf_request->client_ver == AF_INET6 )
  447                 return data->dc.ipv6;
  448         }
  449         break;
  450     }
  451 
  452     return 0;
  453 }
  454 
  455 
  456 
  457 static int
  458 SPF_i_match_ip4(SPF_server_t *spf_server,
  459             SPF_request_t *spf_request,
  460             SPF_mech_t *mech,
  461             struct in_addr ipv4 )
  462 {
  463     char        src_ip4_buf[ INET_ADDRSTRLEN ];
  464     char        dst_ip4_buf[ INET_ADDRSTRLEN ];
  465     char        mask_ip4_buf[ INET_ADDRSTRLEN ];
  466 
  467     struct in_addr      src_ipv4;
  468     int             cidr, mask;
  469 
  470 
  471     if ( spf_request->client_ver != AF_INET )
  472         return FALSE;
  473 
  474     src_ipv4 = spf_request->ipv4;
  475 
  476     cidr = SPF_i_mech_cidr( spf_request, mech );
  477     if ( cidr == 0 )
  478         cidr = 32;
  479     mask = 0xffffffff << (32 - cidr);
  480     mask = htonl(mask);
  481 
  482     if (spf_server->debug) {
  483         INET_NTOP(AF_INET, &src_ipv4.s_addr,
  484                         src_ip4_buf, sizeof(src_ip4_buf));
  485         INET_NTOP(AF_INET, &ipv4.s_addr,
  486                         dst_ip4_buf, sizeof(dst_ip4_buf));
  487         INET_NTOP(AF_INET, &mask,
  488                         mask_ip4_buf, sizeof(mask_ip4_buf));
  489         SPF_debugf( "ip_match:  %s == %s  (/%d %s):  %d",
  490                 src_ip4_buf, dst_ip4_buf, cidr, mask_ip4_buf,
  491                 (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask));
  492     }
  493 
  494     return (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask);
  495 }
  496 
  497 
  498 static int
  499 SPF_i_match_ip6(SPF_server_t *spf_server,
  500             SPF_request_t *spf_request,
  501             SPF_mech_t *mech,
  502             struct in6_addr ipv6 )
  503 {
  504     char        src_ip6_buf[ INET6_ADDRSTRLEN ];
  505     char        dst_ip6_buf[ INET6_ADDRSTRLEN ];
  506 
  507     struct in6_addr     src_ipv6;
  508     int             cidr, cidr_save, mask;
  509     int             i;
  510     int             match;
  511 
  512     if ( spf_request->client_ver != AF_INET6 )
  513         return FALSE;
  514 
  515     src_ipv6 = spf_request->ipv6;
  516 
  517     cidr = SPF_i_mech_cidr(spf_request, mech);
  518     if ( cidr == 0 )
  519         cidr = 128;
  520     cidr_save = cidr;
  521 
  522     match = TRUE;
  523     for( i = 0; i < array_elem( ipv6.s6_addr ) && match; i++ )
  524     {
  525         if ( cidr > 8 )
  526             mask = 0xff;
  527         else if ( cidr > 0 )
  528             mask = (0xff << (8 - cidr)) & 0xff;
  529         else
  530             break;
  531         cidr -= 8;
  532 
  533         match = (src_ipv6.s6_addr[i] & mask) == (ipv6.s6_addr[i] & mask);
  534     }
  535 
  536     if (spf_server->debug) {
  537         INET_NTOP(AF_INET6, &src_ipv6.s6_addr,
  538                             src_ip6_buf, sizeof(src_ip6_buf));
  539         INET_NTOP(AF_INET6, &ipv6.s6_addr,
  540                             dst_ip6_buf, sizeof(dst_ip6_buf));
  541         SPF_debugf( "ip_match:  %s == %s  (/%d):  %d",
  542                 src_ip6_buf, dst_ip6_buf, cidr_save, match );
  543     }
  544 
  545     return match;
  546 }
  547 
  548 static int
  549 SPF_i_match_domain(SPF_server_t *spf_server,
  550                 const char *hostname, const char *domain)
  551 {
  552     const char  *hp;
  553     size_t       hlen;
  554     size_t       dlen;
  555 
  556     if (spf_server->debug)
  557         SPF_debugf( "%s ?=? %s", hostname, domain );
  558 
  559     hlen = strlen(hostname);
  560     dlen = strlen(domain);
  561 
  562     /* A host cannot be a member of a domain longer than it is. */
  563     if (dlen > hlen)
  564         return 0;
  565 
  566     /* The two may be equal? */
  567     if (dlen == hlen)
  568         return (strcasecmp(hostname, domain) == 0);
  569 
  570     /* The domain may match a trailing portion preceded by a dot. */
  571     hp = hostname + (hlen - dlen);
  572 
  573     if (*(hp - 1) != '.')
  574         return 0;
  575 
  576     return (strcasecmp(hp, domain) == 0);
  577 }
  578 
  579 
  580 /*
  581  * Set cur_dom (to either sender or or helo_dom) before calling this.
  582  */
  583 
  584 SPF_errcode_t
  585 SPF_record_interpret(SPF_record_t *spf_record,
  586             SPF_request_t *spf_request, SPF_response_t *spf_response,
  587             int depth)
  588 {
  589     SPF_server_t    *spf_server;
  590 
  591     /* Temporaries */
  592     int              i, j;
  593     int              m;         /* Mechanism iterator */
  594     SPF_mech_t      *mech;
  595     SPF_data_t      *data;
  596     SPF_data_t      *data_end;  /* XXX Replace with size_t data_len */
  597 
  598     /* Where to insert the local policy (whitelist) */
  599     SPF_mech_t      *local_policy;  /* Not the local policy */
  600     int              found_all;     /* A crappy temporary. */
  601 
  602     char            *buf = NULL;
  603     size_t           buf_len = 0;
  604     ns_type          fetch_ns_type;
  605     const char      *lookup;
  606 
  607     SPF_dns_rr_t    *rr_a;
  608     SPF_dns_rr_t    *rr_aaaa;
  609     SPF_dns_rr_t    *rr_ptr;
  610     SPF_dns_rr_t    *rr_mx;
  611 
  612     SPF_errcode_t    err;
  613 
  614     SPF_dns_server_t*resolver;
  615 
  616     /* An SPF record for subrequests - replaces c_results */
  617     SPF_record_t    *spf_record_subr;
  618 
  619     SPF_response_t  *save_spf_response;
  620     SPF_response_t  *spf_response_subr;
  621     const char      *save_cur_dom;
  622 
  623     struct in_addr  addr4;
  624     struct in6_addr addr6;
  625 
  626     int             max_ptr;
  627     int             max_mx;
  628     int             max_exceeded;
  629 
  630     char             ip4_buf[ INET_ADDRSTRLEN ];
  631     char             ip6_buf[ INET6_ADDRSTRLEN ];
  632 
  633 
  634     /*
  635      * make sure we were passed valid data to work with
  636      */
  637     SPF_ASSERT_NOTNULL(spf_record);
  638     SPF_ASSERT_NOTNULL(spf_request);
  639     SPF_ASSERT_NOTNULL(spf_response);
  640     spf_server = spf_record->spf_server;
  641     SPF_ASSERT_NOTNULL(spf_server);
  642 
  643     SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
  644 
  645     if (depth > 20)
  646         return DONE_PERMERR(SPF_E_RECURSIVE);
  647 
  648     if ( spf_request->client_ver != AF_INET && spf_request->client_ver != AF_INET6 )
  649         return DONE_PERMERR(SPF_E_NOT_CONFIG);
  650 
  651     if (spf_request->cur_dom == NULL)
  652         return DONE_PERMERR(SPF_E_NOT_CONFIG);
  653 
  654 
  655     /*
  656      * localhost always gets a free ride
  657      */
  658 
  659 #if 0
  660     /* This should have been done already before we got here. */
  661     if ( SPF_request_is_loopback( spf_request ) )
  662         return DONE(SPF_RESULT_PASS,SPF_REASON_LOCALHOST,SPF_E_SUCCESS);
  663 #endif
  664 
  665     /*
  666      * Do some start up stuff if we haven't recursed yet
  667      */
  668 
  669     local_policy = NULL;
  670 
  671     if ( spf_request->use_local_policy ) {
  672         /*
  673          * find the location for the whitelist execution
  674          *
  675          * Philip Gladstone says:
  676          *
  677          * I think that the localpolicy should only be inserted if the
  678          * final mechanism is '-all', and it should be inserted after
  679          * the last mechanism which is not '-'.
  680          *
  681          * Thus for the case of 'v=spf1 +a +mx -all', this would be
  682          * interpreted as 'v=spf1 +a +mx +localpolicy -all'. Whereas
  683          * 'v=spf1 -all' would remain the same (no non-'-'
  684          * mechanism). 'v=spf1 +a +mx -exists:%stuff -all' would
  685          * become 'v=spf1 +a +mx +localpolicy -exists:%stuff -all'.
  686          */
  687 
  688         if ( spf_server->local_policy ) {
  689             mech = spf_record->mech_first;
  690 
  691             found_all = FALSE;
  692             for(m = 0; m < spf_record->num_mech; m++)
  693             {
  694                 if ( mech->mech_type == MECH_ALL
  695                      && (mech->prefix_type == PREFIX_FAIL
  696                          || mech->prefix_type == PREFIX_UNKNOWN
  697                          || mech->prefix_type == PREFIX_SOFTFAIL
  698                          )
  699                     )
  700                     found_all = TRUE;
  701 
  702                 if ( mech->prefix_type != PREFIX_FAIL
  703                      && mech->prefix_type != PREFIX_SOFTFAIL
  704                     )
  705                     local_policy = mech;
  706 
  707                 mech = SPF_mech_next( mech );
  708             }
  709 
  710             if ( !found_all )
  711                 local_policy = NULL;
  712         }
  713 
  714     }
  715 
  716 
  717     /*
  718      * evaluate the mechanisms
  719      */
  720 
  721 #define SPF_ADD_DNS_MECH() do { spf_response->num_dns_mech++; } while(0)
  722 
  723 #define SPF_MAYBE_SKIP_CIDR() \
  724     do { \
  725         if ( data < data_end && data->dc.parm_type == PARM_CIDR ) \
  726             data = SPF_data_next( data ); \
  727     } while(0)
  728 
  729 #define SPF_GET_LOOKUP_DATA() \
  730     do {                                                \
  731         if ( data == data_end )                         \
  732             lookup = spf_request->cur_dom;              \
  733         else {                                          \
  734             err = SPF_record_expand_data( spf_server,   \
  735                             spf_request, spf_response,  \
  736                             data, ((char *)data_end - (char *)data),    \
  737                             &buf, &buf_len );           \
  738             if (err == SPF_E_NO_MEMORY) {               \
  739                 SPF_FREE_LOOKUP_DATA();                 \
  740                 return DONE_TEMPERR(err);               \
  741             }                                           \
  742             if (err) {                                  \
  743                 SPF_FREE_LOOKUP_DATA();                 \
  744                 return DONE_PERMERR(err);               \
  745             }                                           \
  746             lookup = buf;                               \
  747         }                                               \
  748     } while(0)
  749 #define SPF_FREE_LOOKUP_DATA() \
  750     do { if (buf != NULL) { free(buf); buf = NULL; } } while(0)
  751 
  752 
  753     resolver = spf_server->resolver;
  754 
  755     mech = spf_record->mech_first;
  756     for (m = 0; m < spf_record->num_mech; m++) {
  757 
  758         /* This is as good a place as any. */
  759         /* XXX Rip this out and put it into a macro which can go into inner loops. */
  760         if (spf_response->num_dns_mech > spf_server->max_dns_mech) {
  761             SPF_FREE_LOOKUP_DATA();
  762             return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
  763         }
  764 
  765         data = SPF_mech_data(mech);
  766         data_end = SPF_mech_end_data(mech);
  767 
  768         switch (mech->mech_type) {
  769         case MECH_A:
  770             SPF_ADD_DNS_MECH();
  771             SPF_MAYBE_SKIP_CIDR();
  772             SPF_GET_LOOKUP_DATA();
  773 
  774             if (spf_request->client_ver == AF_INET)
  775                 fetch_ns_type = ns_t_a;
  776             else
  777                 fetch_ns_type = ns_t_aaaa;
  778 
  779             rr_a = SPF_dns_lookup(resolver, lookup, fetch_ns_type, TRUE);
  780 
  781             if (spf_server->debug)
  782                 SPF_debugf("found %d A records for %s  (herrno: %d)",
  783                         rr_a->num_rr, lookup, rr_a->herrno);
  784 
  785             if (rr_a->herrno == TRY_AGAIN) {
  786                 SPF_dns_rr_free(rr_a);
  787                 SPF_FREE_LOOKUP_DATA();
  788                 return DONE_TEMPERR(SPF_E_DNS_ERROR); /* REASON_MECH */
  789             }
  790 
  791             for (i = 0; i < rr_a->num_rr; i++) {
  792                 /* XXX Should this be hoisted? */
  793                 if (rr_a->rr_type != fetch_ns_type)
  794                     continue;
  795 
  796                 if (spf_request->client_ver == AF_INET) {
  797                     if (SPF_i_match_ip4(spf_server, spf_request, mech, rr_a->rr[i]->a)) {
  798                         SPF_dns_rr_free(rr_a);
  799                         SPF_FREE_LOOKUP_DATA();
  800                         return DONE_MECH(mech->prefix_type);
  801                     }
  802                 }
  803                 else {
  804                     if (SPF_i_match_ip6(spf_server, spf_request, mech, rr_a->rr[i]->aaaa)) {
  805                         SPF_dns_rr_free(rr_a);
  806                         SPF_FREE_LOOKUP_DATA();
  807                         return DONE_MECH(mech->prefix_type);
  808                     }
  809                 }
  810             }
  811 
  812             SPF_dns_rr_free(rr_a);
  813             break;
  814 
  815         case MECH_MX:
  816             SPF_ADD_DNS_MECH();
  817             SPF_MAYBE_SKIP_CIDR();
  818             SPF_GET_LOOKUP_DATA();
  819 
  820             rr_mx = SPF_dns_lookup(resolver, lookup, ns_t_mx, TRUE);
  821 
  822             if (spf_server->debug)
  823                 SPF_debugf("found %d MX records for %s  (herrno: %d)",
  824                         rr_mx->num_rr, lookup, rr_mx->herrno);
  825 
  826             if (rr_mx->herrno == TRY_AGAIN) {
  827                 SPF_dns_rr_free(rr_mx);
  828                 SPF_FREE_LOOKUP_DATA();
  829                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
  830             }
  831 
  832             /* The maximum number of MX records we will inspect. */
  833             max_mx = rr_mx->num_rr;
  834             max_exceeded = 0;
  835             if (max_mx > spf_server->max_dns_mx) {
  836                 max_exceeded = 1;
  837                 max_mx = SPF_server_get_max_dns_mx(spf_server);
  838             }
  839 
  840             for (j = 0; j < max_mx; j++) {
  841                 /* XXX Should this be hoisted? */
  842                 if (rr_mx->rr_type != ns_t_mx)
  843                     continue;
  844 
  845                 if (spf_request->client_ver == AF_INET)
  846                     fetch_ns_type = ns_t_a;
  847                 else
  848                     fetch_ns_type = ns_t_aaaa;
  849 
  850                 rr_a = SPF_dns_lookup(resolver, rr_mx->rr[j]->mx,
  851                                        fetch_ns_type, TRUE );
  852 
  853                 if (spf_server->debug)
  854                     SPF_debugf("%d: found %d A records for %s  (herrno: %d)",
  855                             j, rr_a->num_rr, rr_mx->rr[j]->mx, rr_a->herrno);
  856                 if (rr_a->herrno == TRY_AGAIN) {
  857                     SPF_dns_rr_free(rr_mx);
  858                     SPF_dns_rr_free(rr_a);
  859                     SPF_FREE_LOOKUP_DATA();
  860                     return DONE_TEMPERR(SPF_E_DNS_ERROR);
  861                 }
  862 
  863                 for (i = 0; i < rr_a->num_rr; i++) {
  864                     /* XXX Should this be hoisted? */
  865                     if (rr_a->rr_type != fetch_ns_type)
  866                         continue;
  867 
  868                     if (spf_request->client_ver == AF_INET) {
  869                         if (SPF_i_match_ip4(spf_server, spf_request, mech,
  870                                         rr_a->rr[i]->a)) {
  871                             SPF_dns_rr_free(rr_mx);
  872                             SPF_dns_rr_free(rr_a);
  873                             SPF_FREE_LOOKUP_DATA();
  874                             return DONE(mech->prefix_type, SPF_REASON_MECH,
  875                                          SPF_E_SUCCESS);
  876                         }
  877                     }
  878                     else {
  879                         if (SPF_i_match_ip6(spf_server, spf_request, mech,
  880                                         rr_a->rr[i]->aaaa)) {
  881                             SPF_dns_rr_free(rr_mx);
  882                             SPF_dns_rr_free(rr_a);
  883                             SPF_FREE_LOOKUP_DATA();
  884                             return DONE(mech->prefix_type, SPF_REASON_MECH,
  885                                          SPF_E_SUCCESS);
  886                         }
  887                     }
  888                 }
  889                 SPF_dns_rr_free(rr_a);
  890             }
  891 
  892             SPF_dns_rr_free( rr_mx );
  893             if (max_exceeded) {
  894                 SPF_FREE_LOOKUP_DATA();
  895                 return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
  896             }
  897             break;
  898 
  899         case MECH_PTR:
  900             SPF_ADD_DNS_MECH();
  901             SPF_GET_LOOKUP_DATA();
  902 
  903             if (spf_request->client_ver == AF_INET) {
  904                 rr_ptr = SPF_dns_rlookup(resolver,
  905                                 spf_request->ipv4, ns_t_ptr, TRUE);
  906 
  907                 if (spf_server->debug) {
  908                     INET_NTOP(AF_INET, &spf_request->ipv4.s_addr,
  909                                         ip4_buf, sizeof(ip4_buf));
  910                     SPF_debugf("got %d PTR records for %s (herrno: %d)",
  911                             rr_ptr->num_rr, ip4_buf, rr_ptr->herrno);
  912                 }
  913 
  914                 if (rr_ptr->herrno == TRY_AGAIN) {
  915                     SPF_dns_rr_free(rr_ptr);
  916                     SPF_FREE_LOOKUP_DATA();
  917                     return DONE_TEMPERR(SPF_E_DNS_ERROR);
  918                 }
  919 
  920 
  921                 /* The maximum number of PTR records we will inspect. */
  922                 max_ptr = rr_ptr->num_rr;
  923                 max_exceeded = 0;
  924                 if (max_ptr > spf_server->max_dns_ptr) {
  925                     max_exceeded = 1;
  926                     max_ptr = SPF_server_get_max_dns_ptr(spf_server);
  927                 }
  928 
  929                 for (i = 0; i < max_ptr; i++) {
  930                     /* XXX MX has a 'continue' case here which should be hoisted. */
  931 
  932                     rr_a = SPF_dns_lookup(resolver,
  933                             rr_ptr->rr[i]->ptr, ns_t_a, TRUE);
  934 
  935                     if (spf_server->debug)
  936                         SPF_debugf( "%d:  found %d A records for %s  (herrno: %d)",
  937                                 i, rr_a->num_rr, rr_ptr->rr[i]->ptr, rr_a->herrno );
  938                     if (rr_a->herrno == TRY_AGAIN) {
  939                         SPF_dns_rr_free(rr_ptr);
  940                         SPF_dns_rr_free(rr_a);
  941                         SPF_FREE_LOOKUP_DATA();
  942                         return DONE_TEMPERR( SPF_E_DNS_ERROR );
  943                     }
  944 
  945                     for (j = 0; j < rr_a->num_rr; j++) {
  946                         /* XXX MX has a 'continue' case here which should be hoisted. */
  947 
  948                         if (spf_server->debug) {
  949                             INET_NTOP(AF_INET, &rr_a->rr[j]->a.s_addr,
  950                                             ip4_buf, sizeof(ip4_buf));
  951                             SPF_debugf("%d: %d:  found %s",
  952                                     i, j, ip4_buf);
  953                         }
  954 
  955                         if (rr_a->rr[j]->a.s_addr ==
  956                                         spf_request->ipv4.s_addr) {
  957                             if (SPF_i_match_domain(spf_server,
  958                                             rr_ptr->rr[i]->ptr, lookup)) {
  959                                 SPF_dns_rr_free(rr_ptr);
  960                                 SPF_dns_rr_free(rr_a);
  961                                 SPF_FREE_LOOKUP_DATA();
  962                                 return DONE_MECH(mech->prefix_type);
  963                             }
  964                         }
  965                     }
  966                     SPF_dns_rr_free(rr_a);
  967                 }
  968                 SPF_dns_rr_free(rr_ptr);
  969 
  970                 if (max_exceeded) {
  971                     SPF_FREE_LOOKUP_DATA();
  972                     return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
  973                 }
  974             }
  975 
  976             else if ( spf_request->client_ver == AF_INET6 ) {
  977                 rr_ptr = SPF_dns_rlookup6(resolver,
  978                                 spf_request->ipv6, ns_t_ptr, TRUE);
  979 
  980                 if ( spf_server->debug ) {
  981                     INET_NTOP( AF_INET6, &spf_request->ipv6.s6_addr,
  982                                        ip6_buf, sizeof( ip6_buf ) );
  983                     SPF_debugf( "found %d PTR records for %s  (herrno: %d)",
  984                             rr_ptr->num_rr, ip6_buf, rr_ptr->herrno );
  985                 }
  986                 if( rr_ptr->herrno == TRY_AGAIN ) {
  987                     SPF_dns_rr_free(rr_ptr);
  988                     SPF_FREE_LOOKUP_DATA();
  989                     return DONE_TEMPERR( SPF_E_DNS_ERROR );
  990                 }
  991 
  992 
  993                 max_ptr = rr_ptr->num_rr;
  994                 max_exceeded = 0;
  995                 if (max_ptr > spf_server->max_dns_ptr) {
  996                     max_ptr = SPF_server_get_max_dns_ptr(spf_server);
  997                     max_exceeded = 1;
  998                 }
  999 
 1000                 for (i = 0; i < max_ptr; i++) {
 1001                     /* XXX MX has a 'continue' case here which should be hoisted. */
 1002 
 1003                     rr_aaaa = SPF_dns_lookup(resolver,
 1004                             rr_ptr->rr[i]->ptr, ns_t_aaaa, TRUE);
 1005 
 1006                     if ( spf_server->debug )
 1007                         SPF_debugf("%d:  found %d AAAA records for %s  (herrno: %d)",
 1008                                 i, rr_aaaa->num_rr, rr_ptr->rr[i]->ptr, rr_aaaa->herrno);
 1009                     if( rr_aaaa->herrno == TRY_AGAIN ) {
 1010                         SPF_dns_rr_free(rr_ptr);
 1011                         SPF_dns_rr_free(rr_aaaa);
 1012                         SPF_FREE_LOOKUP_DATA();
 1013                         return DONE_TEMPERR( SPF_E_DNS_ERROR );
 1014                     }
 1015 
 1016                     for( j = 0; j < rr_aaaa->num_rr; j++ ) {
 1017                         /* XXX MX has a 'continue' case here which should be hoisted. */
 1018                         if ( spf_server->debug ) {
 1019                             INET_NTOP(AF_INET6, &rr_aaaa->rr[j]->aaaa.s6_addr,
 1020                                             ip6_buf, sizeof(ip6_buf));
 1021                             SPF_debugf( "%d: %d:  found %s",
 1022                                     i, j, ip6_buf );
 1023                         }
 1024 
 1025                         if (memcmp(&rr_aaaa->rr[j]->aaaa,
 1026                                 &spf_request->ipv6,
 1027                                 sizeof(spf_request->ipv6)) == 0) {
 1028                             if (SPF_i_match_domain(spf_server,
 1029                                             rr_ptr->rr[i]->ptr, lookup)) {
 1030                                 SPF_dns_rr_free( rr_ptr );
 1031                                 SPF_dns_rr_free(rr_aaaa);
 1032                                 SPF_FREE_LOOKUP_DATA();
 1033                                 return DONE_MECH( mech->prefix_type );
 1034                             }
 1035                         }
 1036                     }
 1037                     SPF_dns_rr_free(rr_aaaa);
 1038                 }
 1039                 SPF_dns_rr_free(rr_ptr);
 1040 
 1041                 if (max_exceeded) {
 1042                     SPF_FREE_LOOKUP_DATA();
 1043                     return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
 1044                 }
 1045             }
 1046 
 1047 
 1048             break;
 1049 
 1050         case MECH_INCLUDE:
 1051         case MECH_REDIRECT:
 1052             SPF_ADD_DNS_MECH();
 1053 
 1054             err = SPF_record_expand_data(spf_server,
 1055                     spf_request, spf_response,
 1056                     SPF_mech_data(mech), SPF_mech_data_len(mech),
 1057                     &buf, &buf_len );
 1058             if ( err == SPF_E_NO_MEMORY ) {
 1059                 SPF_FREE_LOOKUP_DATA();
 1060                 return DONE_TEMPERR( err );
 1061             }
 1062             if ( err ) {
 1063                 SPF_FREE_LOOKUP_DATA();
 1064                 return DONE_PERMERR( err );
 1065             }
 1066             lookup = buf;
 1067 
 1068             /* XXX Maintain a stack depth here. Limit at 10. */
 1069             if (strcmp(lookup, spf_request->cur_dom) == 0) {
 1070                 SPF_FREE_LOOKUP_DATA();
 1071                 return DONE_PERMERR( SPF_E_RECURSIVE );
 1072             }
 1073 
 1074             /*
 1075              * get the (compiled) SPF record
 1076              */
 1077 
 1078             spf_record_subr = NULL;
 1079             /* Remember to reset this. */
 1080             save_cur_dom = spf_request->cur_dom;
 1081             spf_request->cur_dom = lookup;
 1082             err = SPF_server_get_record(spf_server, spf_request,
 1083                             spf_response, &spf_record_subr);
 1084 
 1085             if ( spf_server->debug > 0 )
 1086                 SPF_debugf( "include/redirect:  got SPF record:  %s",
 1087                         SPF_strerror( err ) );
 1088 
 1089             if (err != SPF_E_SUCCESS) {
 1090                 spf_request->cur_dom = save_cur_dom;
 1091                 if (spf_record_subr)
 1092                     SPF_record_free(spf_record_subr);
 1093                 SPF_FREE_LOOKUP_DATA();
 1094                 if (err == SPF_E_DNS_ERROR)
 1095                     return DONE_TEMPERR( err );
 1096                 else
 1097                     return DONE_PERMERR( err );
 1098             }
 1099 
 1100             SPF_ASSERT_NOTNULL(spf_record_subr);
 1101 
 1102             /*
 1103              * If we are a redirect which is not within the scope
 1104              * of any include.
 1105              */
 1106             if (mech->mech_type == MECH_REDIRECT) {
 1107                 save_spf_response = NULL;
 1108                 if (spf_response->spf_record_exp == spf_record)
 1109                     spf_response->spf_record_exp = spf_record_subr;
 1110                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
 1111             }
 1112             else {
 1113                 save_spf_response = spf_response;
 1114                 spf_response = SPF_response_new(spf_request);
 1115                 if (! spf_response) {
 1116                     if (spf_record_subr)
 1117                         SPF_record_free(spf_record_subr);
 1118                     SPF_FREE_LOOKUP_DATA();
 1119                     return DONE_TEMPERR(SPF_E_NO_MEMORY);
 1120                 }
 1121                 spf_response->spf_record_exp = spf_record;
 1122                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
 1123             }
 1124             /*
 1125              * find out whether this configuration passes
 1126              */
 1127             err = SPF_record_interpret(spf_record_subr,
 1128                             spf_request, spf_response, depth + 1);
 1129             spf_request->cur_dom = save_cur_dom;
 1130             /* Now, if we were a redirect, the child called done()
 1131              * and used spf_record_exp. In that case, we need not
 1132              * worry that spf_record_subr is invalid after the free.
 1133              * If we were not a redirect, then spf_record_subr
 1134              * is still the record it was in the first place.
 1135              * Thus we do not need to reset it now. */
 1136             SPF_record_free(spf_record_subr);
 1137             spf_record_subr = NULL;
 1138 
 1139             if ( spf_server->debug > 0 )
 1140                 SPF_debugf( "include/redirect:  executed SPF record:  %s  result: %s  reason: %s",
 1141                         SPF_strerror( err ),
 1142                         SPF_strresult( spf_response->result ),
 1143                         SPF_strreason( spf_response->reason ) );
 1144             if (mech->mech_type == MECH_REDIRECT) {
 1145                 SPF_FREE_LOOKUP_DATA();
 1146                 return err; /* One way or the other */
 1147             }
 1148             else { // if (spf_response->result != SPF_RESULT_INVALID) {
 1149                 /* Set everything up properly again. */
 1150                 spf_response_subr = spf_response;
 1151                 spf_response = save_spf_response;
 1152                 save_spf_response = NULL;
 1153 
 1154                 /* Rewrite according to prefix of include */
 1155                 switch (SPF_response_result(spf_response_subr)) {
 1156                     case SPF_RESULT_PASS:
 1157                         /* Pass */
 1158                         SPF_FREE_LOOKUP_DATA();
 1159                         SPF_response_free(spf_response_subr);
 1160                         return DONE_MECH( mech->prefix_type );
 1161 
 1162                     case SPF_RESULT_FAIL:
 1163                     case SPF_RESULT_SOFTFAIL:
 1164                     case SPF_RESULT_NEUTRAL:
 1165                         /* No match */
 1166                         SPF_response_free(spf_response_subr);
 1167                         break;
 1168 
 1169                     case SPF_RESULT_TEMPERROR:
 1170                         /* Generate TempError */
 1171                         err = SPF_response_errcode(spf_response_subr);
 1172                         SPF_FREE_LOOKUP_DATA();
 1173                         SPF_response_free(spf_response_subr);
 1174                         return DONE_TEMPERR( err );
 1175 
 1176                     case SPF_RESULT_NONE:
 1177                         /* Generate PermError */
 1178                         SPF_FREE_LOOKUP_DATA();
 1179                         SPF_response_free(spf_response_subr);
 1180                         return DONE_PERMERR(SPF_E_INCLUDE_RETURNED_NONE);
 1181                     case SPF_RESULT_PERMERROR:
 1182                     case SPF_RESULT_INVALID:
 1183                         /* Generate PermError */
 1184                         err = SPF_response_errcode(spf_response_subr);
 1185                         SPF_FREE_LOOKUP_DATA();
 1186                         SPF_response_free(spf_response_subr);
 1187                         return DONE_PERMERR( err );
 1188 
 1189                 }
 1190 #if 0
 1191                 SPF_FREE_LOOKUP_DATA();
 1192                 return err; /* The sub-interpret called done() */
 1193 #endif
 1194             }
 1195 
 1196             break;
 1197 
 1198         case MECH_IP4:
 1199             memcpy(&addr4, SPF_mech_ip4_data(mech), sizeof(addr4));
 1200             if ( SPF_i_match_ip4( spf_server, spf_request, mech, addr4 ) ) {
 1201                 SPF_FREE_LOOKUP_DATA();
 1202                 return DONE_MECH( mech->prefix_type );
 1203             }
 1204             break;
 1205 
 1206         case MECH_IP6:
 1207             memcpy(&addr6, SPF_mech_ip6_data(mech), sizeof(addr6));
 1208             if ( SPF_i_match_ip6( spf_server, spf_request, mech, addr6 ) ) {
 1209                 SPF_FREE_LOOKUP_DATA();
 1210                 return DONE_MECH( mech->prefix_type );
 1211             }
 1212             break;
 1213 
 1214         case MECH_EXISTS:
 1215             SPF_ADD_DNS_MECH();
 1216 
 1217             err = SPF_record_expand_data(spf_server,
 1218                             spf_request, spf_response,
 1219                             SPF_mech_data(mech),SPF_mech_data_len(mech),
 1220                             &buf, &buf_len);
 1221             if (err != SPF_E_SUCCESS) {
 1222                 SPF_FREE_LOOKUP_DATA();
 1223                 return DONE_TEMPERR( err );
 1224             }
 1225             lookup = buf;
 1226 
 1227             rr_a = SPF_dns_lookup(resolver, lookup, ns_t_a, FALSE );
 1228 
 1229             if ( spf_server->debug )
 1230                 SPF_debugf( "found %d A records for %s  (herrno: %d)",
 1231                         rr_a->num_rr, lookup, rr_a->herrno );
 1232 
 1233             if( rr_a->herrno == TRY_AGAIN ) {
 1234                 SPF_dns_rr_free(rr_a);
 1235                 SPF_FREE_LOOKUP_DATA();
 1236                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
 1237             }
 1238             if ( rr_a->num_rr > 0 ) {
 1239                 SPF_dns_rr_free(rr_a);
 1240                 SPF_FREE_LOOKUP_DATA();
 1241                 return DONE_MECH(mech->prefix_type);
 1242             }
 1243 
 1244             SPF_dns_rr_free(rr_a);
 1245             break;
 1246 
 1247         case MECH_ALL:
 1248             SPF_FREE_LOOKUP_DATA();
 1249             if (mech->prefix_type == PREFIX_UNKNOWN)
 1250                 return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
 1251             return DONE_MECH(mech->prefix_type);
 1252             break;
 1253 
 1254         default:
 1255             SPF_FREE_LOOKUP_DATA();
 1256             return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
 1257             break;
 1258         }
 1259 
 1260         /*
 1261          * execute the local policy
 1262          */
 1263 
 1264         if ( mech == local_policy ) {
 1265             err = SPF_record_interpret(spf_server->local_policy,
 1266                             spf_request, spf_response, depth + 1);
 1267 
 1268             if ( spf_server->debug > 0 )
 1269                 SPF_debugf( "local_policy:  executed SPF record:  %s  result: %s  reason: %s",
 1270                             SPF_strerror( err ),
 1271                             SPF_strresult( spf_response->result ),
 1272                             SPF_strreason( spf_response->reason ) );
 1273 
 1274             if (spf_response->result != SPF_RESULT_INVALID) {
 1275                 SPF_FREE_LOOKUP_DATA();
 1276                 return err;
 1277             }
 1278         }
 1279 
 1280         mech = SPF_mech_next( mech );
 1281     }
 1282 
 1283     SPF_FREE_LOOKUP_DATA();
 1284     /* falling off the end is the same as ?all */
 1285     return DONE( SPF_RESULT_NEUTRAL, SPF_REASON_DEFAULT, SPF_E_SUCCESS );
 1286 }