spf_interpret.c

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of either:
00004  *
00005  *   a) The GNU Lesser General Public License as published by the Free
00006  *        Software Foundation; either version 2.1, or (at your option) any
00007  *        later version,
00008  *
00009  *   OR
00010  *
00011  *   b) The two-clause BSD license.
00012  *
00013  * These licenses can be found with the distribution in the file LICENSES
00014  */
00015 
00016 #include "spf_sys_config.h"
00017 
00018 #ifdef STDC_HEADERS
00019 # include <stdio.h>             /* stdin / stdout */
00020 # include <stdlib.h>       /* malloc / free */
00021 #endif
00022 
00023 #ifdef HAVE_STRING_H
00024 # include <string.h>       /* strstr / strdup */
00025 #else
00026 # ifdef HAVE_STRINGS_H
00027 #  include <strings.h>     /* strstr / strdup */
00028 # endif
00029 #endif
00030 
00031 #ifdef HAVE_NETDB_H
00032 #include <netdb.h>
00033 #endif
00034 
00035 #include <ctype.h>
00036 
00037 #include "spf.h"
00038 #include "spf_dns.h"
00039 #include "spf_internal.h"
00040 #include "spf_dns_internal.h"
00041 #include "spf_server.h"
00042 
00043 static SPF_errcode_t
00044 SPF_i_set_explanation(SPF_response_t *spf_response)
00045 {
00046         SPF_server_t    *spf_server;
00047         SPF_request_t   *spf_request;
00048         SPF_record_t    *spf_record;
00049         SPF_errcode_t    err;
00050         char                    *buf;
00051         size_t                   buflen;
00052 
00053         SPF_ASSERT_NOTNULL(spf_response);
00054         spf_request = spf_response->spf_request;
00055         SPF_ASSERT_NOTNULL(spf_request);
00056         spf_server = spf_request->spf_server;
00057         SPF_ASSERT_NOTNULL(spf_server);
00058 
00059         spf_record = spf_response->spf_record_exp;
00060         SPF_ASSERT_NOTNULL(spf_record);
00061 
00062         if (spf_response->explanation)
00063                 free(spf_response->explanation);
00064         spf_response->explanation = NULL;
00065 
00066         buflen = SPF_SMTP_COMMENT_SIZE + 1;
00067         buf = malloc(buflen);
00068         if (buf == NULL)
00069                 return SPF_E_NO_MEMORY;
00070         memset(buf, '\0', buflen);
00071 
00072         err = SPF_request_get_exp(spf_server, spf_request,
00073                                         spf_response, spf_record, &buf, &buflen);
00074         if (err != SPF_E_SUCCESS) {
00075                 free(buf);
00076                 return err;
00077         }
00078 
00079         spf_response->explanation = buf;
00080 
00081         return SPF_E_SUCCESS;
00082 }
00083 
00084 static SPF_errcode_t
00085 SPF_i_set_smtp_comment(SPF_response_t *spf_response)
00086 {
00087         SPF_server_t    *spf_server;
00088         SPF_request_t   *spf_request;
00089         SPF_errcode_t    err;
00090         char                     buf[SPF_SMTP_COMMENT_SIZE];
00091 
00092         SPF_ASSERT_NOTNULL(spf_response);
00093         spf_request = spf_response->spf_request;
00094         SPF_ASSERT_NOTNULL(spf_request);
00095         spf_server = spf_request->spf_server;
00096         SPF_ASSERT_NOTNULL(spf_server);
00097 
00098         if (spf_response->smtp_comment)
00099                 free(spf_response->smtp_comment);
00100         spf_response->smtp_comment = NULL;
00101 
00102         /* smtp_comment = exp= + <why string> */
00103         switch (spf_response->result) {
00104                 case SPF_RESULT_FAIL:
00105                 case SPF_RESULT_SOFTFAIL:
00106                 case SPF_RESULT_NEUTRAL:
00107                 case SPF_RESULT_NONE:
00108 
00109                         err = SPF_i_set_explanation(spf_response);
00110                         if (err != SPF_E_SUCCESS)
00111                                 return err;
00112 
00113                         memset(buf, '\0', sizeof(buf));
00114                         snprintf(buf, SPF_SMTP_COMMENT_SIZE, "%s : Reason: %s",
00115                                         spf_response->explanation,
00116                                         SPF_strreason(spf_response->reason));
00117                         buf[SPF_SMTP_COMMENT_SIZE - 1] = '\0';
00118 
00119                         /* It doesn't really hurt much if this fails. */
00120                         spf_response->smtp_comment = strdup(buf);
00121                         if (! spf_response->smtp_comment)
00122                                 return SPF_E_NO_MEMORY;
00123 
00124                         break;
00125                 case SPF_RESULT_INVALID:
00126                 case SPF_RESULT_PASS:
00127                 case SPF_RESULT_TEMPERROR:
00128                 case SPF_RESULT_PERMERROR:
00129                 default:
00130                         break;
00131         }
00132 
00133         return SPF_E_SUCCESS;
00134 }
00135 
00136 static SPF_errcode_t
00137 SPF_i_set_header_comment(SPF_response_t *spf_response)
00138 {
00139         SPF_server_t    *spf_server;
00140         SPF_request_t   *spf_request;
00141         char                    *spf_source;
00142 
00143         size_t                   len;
00144 
00145         char                     ip4_buf[ INET_ADDRSTRLEN ];
00146         char                     ip6_buf[ INET6_ADDRSTRLEN ];
00147         const char              *ip;
00148 
00149         char                    *buf;
00150         char                    *sender_dom;
00151         char                    *p, *p_end;
00152 
00153         SPF_ASSERT_NOTNULL(spf_response);
00154         spf_request = spf_response->spf_request;
00155         SPF_ASSERT_NOTNULL(spf_request);
00156         spf_server = spf_request->spf_server;
00157         SPF_ASSERT_NOTNULL(spf_server);
00158 
00159         if (spf_response->header_comment)
00160                 free(spf_response->header_comment);
00161         spf_response->header_comment = NULL;
00162 
00163         /* Is this cur_dom? */
00164         sender_dom = spf_request->env_from_dp;
00165         if (sender_dom == NULL)
00166                 sender_dom = spf_request->helo_dom;
00167 
00168         if ( spf_response->reason == SPF_REASON_LOCAL_POLICY ) {
00169                 spf_source = strdup( "local policy" );
00170         }
00171         else if ( spf_response->reason == SPF_REASON_2MX ) {
00172                 if ( spf_request->rcpt_to_dom == NULL  || spf_request->rcpt_to_dom[0] == '\0' )
00173                         SPF_error( "RCPT TO domain is NULL" );
00174 
00175                 spf_source = strdup( spf_request->rcpt_to_dom );
00176         }
00177         else if ( sender_dom == NULL ) {
00178                 spf_source = strdup( "unknown domain" );
00179         }
00180         else {
00181                 len = strlen( sender_dom ) + sizeof( "domain of " );
00182                 spf_source = malloc( len );
00183                 if ( spf_source )
00184                         snprintf( spf_source, len, "domain of %s", sender_dom );
00185         }
00186 
00187         if ( spf_source == NULL )
00188                 return SPF_E_INTERNAL_ERROR;
00189 
00190         ip = NULL;
00191         if ( spf_request->client_ver == AF_INET ) {
00192                 ip = inet_ntop( AF_INET, &spf_request->ipv4,
00193                                                 ip4_buf, sizeof( ip4_buf ) );
00194         }
00195         else if (spf_request->client_ver == AF_INET6 ) {
00196                 ip = inet_ntop( AF_INET6, &spf_request->ipv6,
00197                                                 ip6_buf, sizeof( ip6_buf ) );
00198         }
00199         if ( ip == NULL )
00200                 ip = "(unknown ip address)";
00201 
00202         len = strlen( SPF_request_get_rec_dom(spf_request) ) + strlen( spf_source ) + strlen( ip ) + 80;
00203         buf = malloc( len );
00204         if ( buf == NULL ) {
00205                 free( spf_source );
00206                 return SPF_E_INTERNAL_ERROR;
00207         }
00208 
00209         p = buf;
00210         p_end = p + len;
00211 
00212         /* create the stock header comment */
00213         p += snprintf( p, p_end - p, "%s: ",  SPF_request_get_rec_dom(spf_request) );
00214 
00215         switch(spf_response->result)
00216         {
00217         case SPF_RESULT_PASS:
00218                 if ( spf_response->reason == SPF_REASON_LOCALHOST )
00219                         snprintf( p, p_end - p, "localhost is always allowed." );
00220                 else if ( spf_response->reason == SPF_REASON_2MX )
00221                         snprintf( p, p_end - p, "message received from %s which is an MX secondary for %s.",
00222                                           ip, spf_source );
00223                 else
00224                         snprintf( p, p_end - p, "%s designates %s as permitted sender",
00225                                           spf_source, ip );
00226                 break;
00227 
00228         case SPF_RESULT_FAIL:
00229                 snprintf( p, p_end - p, "%s does not designate %s as permitted sender",
00230                                   spf_source, ip );
00231                 break;
00232 
00233         case SPF_RESULT_SOFTFAIL:
00234                 snprintf( p, p_end - p, "transitioning %s does not designate %s as permitted sender",
00235                                   spf_source, ip );
00236                 break;
00237 
00238         case SPF_RESULT_PERMERROR:
00239                 snprintf(p, p_end - p, "error in processing during lookup of %s: %s",
00240                                           spf_source, SPF_strerror(spf_response->err));
00241                 break;
00242 
00243         case SPF_RESULT_NEUTRAL:
00244                 snprintf(p, p_end - p, "%s is neither permitted nor denied by %s",
00245                                 ip, spf_source);
00246                 break;
00247         case SPF_RESULT_NONE:
00248                 snprintf(p, p_end - p, "%s does not provide an SPF record",
00249                                 spf_source);
00250                 break;
00251 
00252         case SPF_RESULT_TEMPERROR:
00253                 snprintf(p, p_end - p, "encountered temporary error during SPF processing of %s",
00254                                 spf_source );
00255                 break;
00256 
00257 
00258         default:
00259                 snprintf( p, p_end - p, "error: unknown SPF result %d encountered while checking %s for %s",
00260                                   spf_response->result, ip, spf_source );
00261                 break;
00262         }
00263 
00264         if (spf_source)
00265                 free(spf_source);
00266 
00267         spf_response->header_comment = SPF_sanitize(spf_server, buf);
00268 
00269         return SPF_E_SUCCESS;
00270 }
00271 
00272 static SPF_errcode_t
00273 SPF_i_set_received_spf(SPF_response_t *spf_response)
00274 {
00275         SPF_server_t    *spf_server;
00276         SPF_request_t   *spf_request;
00277         char                     ip4_buf[ INET_ADDRSTRLEN ];
00278         char                     ip6_buf[ INET6_ADDRSTRLEN ];
00279         const char              *ip;
00280 
00281         char                    *buf;
00282         size_t                   buflen = SPF_RECEIVED_SPF_SIZE;
00283         char                    *buf_value;
00284         
00285         char                    *p, *p_end;
00286 
00287         SPF_ASSERT_NOTNULL(spf_response);
00288         spf_request = spf_response->spf_request;
00289         SPF_ASSERT_NOTNULL(spf_request);
00290         spf_server = spf_request->spf_server;
00291         SPF_ASSERT_NOTNULL(spf_server);
00292 
00293         if (spf_response->received_spf)
00294                 free(spf_response->received_spf);
00295         spf_response->received_spf = NULL;
00296 
00297         buf = malloc( buflen );
00298         if ( buf == NULL )
00299                 return SPF_E_INTERNAL_ERROR;
00300         
00301         p = buf;
00302         p_end = p + buflen;
00303 
00304         /* create the stock Received-SPF: header */
00305 
00306         p += snprintf( p, p_end - p, "Received-SPF: ");
00307         buf_value = p;
00308 
00309         do {    /* A prop for a structured goto called 'break' */
00310                 p += snprintf( p, p_end - p, "%s (%s)",
00311                                            SPF_strresult( spf_response->result ),
00312                                            spf_response->header_comment );
00313                 if ( p_end - p <= 0 ) break;
00314 
00315                 
00316                 
00317                 /* add in the optional ip address keyword */
00318                 ip = NULL;
00319                 if ( spf_request->client_ver == AF_INET ) {
00320                         ip = inet_ntop( AF_INET, &spf_request->ipv4,
00321                                                         ip4_buf, sizeof( ip4_buf ) );
00322                 }
00323                 else if (spf_request->client_ver == AF_INET6 ) {
00324                         ip = inet_ntop( AF_INET6, &spf_request->ipv6,
00325                                                         ip6_buf, sizeof( ip6_buf ) );
00326                 }
00327 
00328                 if ( ip != NULL ) {
00329                         p += snprintf( p, p_end - p, " client-ip=%s;", ip );
00330                         if ( p_end - p <= 0 ) break;
00331                 }
00332                 
00333 
00334                 /* add in the optional envelope-from keyword */
00335                 if ( spf_request->env_from != NULL ) {
00336                         p += snprintf( p, p_end - p, " envelope-from=%s;", spf_request->env_from );
00337                         if ( p_end - p <= 0 ) break;
00338                 }
00339                 
00340 
00341                 /* add in the optional helo domain keyword */
00342                 if ( spf_request->helo_dom != NULL ) {
00343                         p += snprintf( p, p_end - p, " helo=%s;", spf_request->helo_dom );
00344                         if ( p_end - p <= 0 ) break;
00345                 }
00346                 
00347 
00348                 /* FIXME: Add in full compiler errors. */
00349 #if 0
00350                 /* add in the optional compiler error keyword */
00351                 if ( output.err_msg != NULL ) {
00352                         p += snprintf( p, p_end - p, " problem=%s;", output.err_msg );
00353                         if ( p_end - p <= 0 ) break;
00354                 }
00355                 else if ( c_results.err_msg != NULL ) {
00356                         p += snprintf( p, p_end - p, " problem=%s;", c_results.err_msg );
00357                         if ( p_end - p <= 0 ) break;
00358                 }
00359 #endif
00360 
00361                 /* FIXME  should the explanation string be included in the header? */
00362 
00363                 /* FIXME  should the header be reformated to include line breaks? */
00364         } while(0);
00365 
00366         spf_response->received_spf = SPF_sanitize(spf_server, buf);
00367         spf_response->received_spf_value = buf_value;
00368 
00369         return SPF_E_SUCCESS;
00370 }
00371 
00372 
00373 
00374 #define DONE(result,reason,err) SPF_i_done(spf_response, result, reason, err)
00375 #define DONE_TEMPERR(err) DONE(SPF_RESULT_TEMPERROR,SPF_REASON_NONE,err)
00376 #define DONE_PERMERR(err) DONE(SPF_RESULT_PERMERROR,SPF_REASON_NONE,err)
00377 #define DONE_MECH(result) DONE(result, SPF_REASON_MECH, SPF_E_SUCCESS)
00378 
00387 SPF_errcode_t
00388 SPF_i_done(SPF_response_t *spf_response,
00389         SPF_result_t result, SPF_reason_t reason, SPF_errcode_t err)
00390 {
00391         SPF_request_t   *spf_request;
00392         SPF_server_t    *spf_server;
00393 
00394         SPF_ASSERT_NOTNULL(spf_response);
00395         spf_request = spf_response->spf_request;
00396         SPF_ASSERT_NOTNULL(spf_request);
00397         spf_server = spf_request->spf_server;
00398         SPF_ASSERT_NOTNULL(spf_server);
00399 
00400         spf_response->result = result;
00401         spf_response->reason = reason;
00402         spf_response->err = err;
00403 
00404         SPF_i_set_smtp_comment(spf_response);
00405         SPF_i_set_header_comment(spf_response);
00406         SPF_i_set_received_spf(spf_response);
00407 
00408         return err;
00409 }
00410 
00411 /*
00412  * FIXME: Everything before this line could go into a separate file.
00413  */
00414 
00415 
00416 
00417 
00418 #define INET_NTOP(af, src, dst, cnt) do { \
00419         if (inet_ntop(af, src, dst, cnt) == NULL) \
00420                 snprintf(dst, cnt, "ip-error" ); \
00421                         } while(0)
00422 
00423 static int
00424 SPF_i_mech_cidr(SPF_request_t *spf_request, SPF_mech_t *mech)
00425 {
00426         SPF_data_t                              *data;
00427 
00428         SPF_ASSERT_NOTNULL(mech);
00429 
00430         switch( mech->mech_type )
00431         {
00432         case MECH_IP4:
00433         case MECH_IP6:
00434                 return mech->mech_len;
00435                 break;
00436 
00437         case MECH_A:
00438         case MECH_MX:
00439                 data = SPF_mech_data( mech );
00440                 /* XXX this was <= but I think that was wrong. */
00441                 if ( data < SPF_mech_end_data( mech )
00442                          && data->dc.parm_type == PARM_CIDR )
00443                 {
00444                         if ( spf_request->client_ver == AF_INET )
00445                                 return data->dc.ipv4;
00446                         else if ( spf_request->client_ver == AF_INET6 )
00447                                 return data->dc.ipv6;
00448                 }
00449                 break;
00450         }
00451 
00452         return 0;
00453 }
00454 
00455 
00456 
00457 static int
00458 SPF_i_match_ip4(SPF_server_t *spf_server,
00459                         SPF_request_t *spf_request,
00460                         SPF_mech_t *mech,
00461                         struct in_addr ipv4 )
00462 {
00463         char            src_ip4_buf[ INET_ADDRSTRLEN ];
00464         char            dst_ip4_buf[ INET_ADDRSTRLEN ];
00465         char            mask_ip4_buf[ INET_ADDRSTRLEN ];
00466 
00467         struct in_addr          src_ipv4;
00468         int                             cidr, mask;
00469 
00470 
00471         if ( spf_request->client_ver != AF_INET )
00472                 return FALSE;
00473 
00474         src_ipv4 = spf_request->ipv4;
00475 
00476         cidr = SPF_i_mech_cidr( spf_request, mech );
00477         if ( cidr == 0 )
00478                 cidr = 32;
00479         mask = 0xffffffff << (32 - cidr);
00480         mask = htonl(mask);
00481 
00482         if (spf_server->debug) {
00483                 INET_NTOP(AF_INET, &src_ipv4.s_addr,
00484                                                 src_ip4_buf, sizeof(src_ip4_buf));
00485                 INET_NTOP(AF_INET, &ipv4.s_addr,
00486                                                 dst_ip4_buf, sizeof(dst_ip4_buf));
00487                 INET_NTOP(AF_INET, &mask,
00488                                                 mask_ip4_buf, sizeof(mask_ip4_buf));
00489                 SPF_debugf( "ip_match:  %s == %s  (/%d %s):  %d",
00490                                 src_ip4_buf, dst_ip4_buf, cidr, mask_ip4_buf,
00491                                 (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask));
00492         }
00493 
00494         return (src_ipv4.s_addr & mask) == (ipv4.s_addr & mask);
00495 }
00496 
00497 
00498 static int
00499 SPF_i_match_ip6(SPF_server_t *spf_server,
00500                         SPF_request_t *spf_request,
00501                         SPF_mech_t *mech,
00502                         struct in6_addr ipv6 )
00503 {
00504         char            src_ip6_buf[ INET6_ADDRSTRLEN ];
00505         char            dst_ip6_buf[ INET6_ADDRSTRLEN ];
00506 
00507         struct in6_addr         src_ipv6;
00508         int                             cidr, cidr_save, mask;
00509         int                             i;
00510         int                             match;
00511 
00512         if ( spf_request->client_ver != AF_INET6 )
00513                 return FALSE;
00514 
00515         src_ipv6 = spf_request->ipv6;
00516 
00517         cidr = SPF_i_mech_cidr(spf_request, mech);
00518         if ( cidr == 0 )
00519                 cidr = 128;
00520         cidr_save = cidr;
00521 
00522         match = TRUE;
00523         for( i = 0; i < array_elem( ipv6.s6_addr ) && match; i++ )
00524         {
00525                 if ( cidr > 8 )
00526                         mask = 0xff;
00527                 else if ( cidr > 0 )
00528                         mask = (0xff << (8 - cidr)) & 0xff;
00529                 else
00530                         break;
00531                 cidr -= 8;
00532 
00533                 match = (src_ipv6.s6_addr[i] & mask) == (ipv6.s6_addr[i] & mask);
00534         }
00535 
00536         if (spf_server->debug) {
00537                 INET_NTOP(AF_INET6, &src_ipv6.s6_addr,
00538                                                         src_ip6_buf, sizeof(src_ip6_buf));
00539                 INET_NTOP(AF_INET6, &ipv6.s6_addr,
00540                                                         dst_ip6_buf, sizeof(dst_ip6_buf));
00541                 SPF_debugf( "ip_match:  %s == %s  (/%d):  %d",
00542                                 src_ip6_buf, dst_ip6_buf, cidr_save, match );
00543         }
00544 
00545         return match;
00546 }
00547 
00548 static int
00549 SPF_i_match_domain(SPF_server_t *spf_server,
00550                                 const char *hostname, const char *domain)
00551 {
00552         const char      *hp;
00553         size_t           hlen;
00554         size_t           dlen;
00555 
00556         if (spf_server->debug)
00557                 SPF_debugf( "%s ?=? %s", hostname, domain );
00558 
00559         hlen = strlen(hostname);
00560         dlen = strlen(domain);
00561 
00562         /* A host cannot be a member of a domain longer than it is. */
00563         if (dlen > hlen)
00564                 return 0;
00565 
00566         /* The two may be equal? */
00567         if (dlen == hlen)
00568                 return (strcasecmp(hostname, domain) == 0);
00569 
00570         /* The domain may match a trailing portion preceded by a dot. */
00571         hp = hostname + (hlen - dlen);
00572 
00573         if (*(hp - 1) != '.')
00574                 return 0;
00575 
00576         return (strcasecmp(hp, domain) == 0);
00577 }
00578 
00579 
00580 /*
00581  * Set cur_dom (to either sender or or helo_dom) before calling this.
00582  */
00583 
00584 SPF_errcode_t
00585 SPF_record_interpret(SPF_record_t *spf_record,
00586                         SPF_request_t *spf_request, SPF_response_t *spf_response,
00587                         int depth)
00588 {
00589         SPF_server_t    *spf_server;
00590 
00591         /* Temporaries */
00592         int                              i, j;
00593         int                              m;                     /* Mechanism iterator */
00594         SPF_mech_t              *mech;
00595         SPF_data_t              *data;
00596         SPF_data_t              *data_end;      /* XXX Replace with size_t data_len */
00597 
00598         /* Where to insert the local policy (whitelist) */
00599         SPF_mech_t              *local_policy;  /* Not the local policy */
00600         int                              found_all;             /* A crappy temporary. */
00601 
00602         char                    *buf = NULL;
00603         size_t                   buf_len = 0;
00604         ns_type                  fetch_ns_type;
00605         const char              *lookup;
00606 
00607         SPF_dns_rr_t    *rr_a;
00608         SPF_dns_rr_t    *rr_aaaa;
00609         SPF_dns_rr_t    *rr_ptr;
00610         SPF_dns_rr_t    *rr_mx;
00611 
00612         SPF_errcode_t    err;
00613 
00614         SPF_dns_server_t*resolver;
00615 
00616         /* An SPF record for subrequests - replaces c_results */
00617         SPF_record_t    *spf_record_subr;
00618 
00619         SPF_response_t  *save_spf_response;
00620         SPF_response_t  *spf_response_subr;
00621         const char              *save_cur_dom;
00622 
00623         struct in_addr  addr4;
00624         struct in6_addr addr6;
00625 
00626         int                             max_ptr;
00627         int                             max_mx;
00628         int                             max_exceeded;
00629 
00630         char                     ip4_buf[ INET_ADDRSTRLEN ];
00631         char                     ip6_buf[ INET6_ADDRSTRLEN ];
00632 
00633 
00634         /*
00635          * make sure we were passed valid data to work with
00636          */
00637         SPF_ASSERT_NOTNULL(spf_record);
00638         SPF_ASSERT_NOTNULL(spf_request);
00639         SPF_ASSERT_NOTNULL(spf_response);
00640         spf_server = spf_record->spf_server;
00641         SPF_ASSERT_NOTNULL(spf_server);
00642 
00643         SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
00644 
00645         if (depth > 20)
00646                 return DONE_PERMERR(SPF_E_RECURSIVE);
00647 
00648         if ( spf_request->client_ver != AF_INET && spf_request->client_ver != AF_INET6 )
00649                 return DONE_PERMERR(SPF_E_NOT_CONFIG);
00650 
00651         if (spf_request->cur_dom == NULL)
00652                 return DONE_PERMERR(SPF_E_NOT_CONFIG);
00653 
00654 
00655         /*
00656          * localhost always gets a free ride
00657          */
00658 
00659 #if 0
00660         /* This should have been done already before we got here. */
00661         if ( SPF_request_is_loopback( spf_request ) )
00662                 return DONE(SPF_RESULT_PASS,SPF_REASON_LOCALHOST,SPF_E_SUCCESS);
00663 #endif
00664 
00665         /*
00666          * Do some start up stuff if we haven't recursed yet
00667          */
00668 
00669         local_policy = NULL;
00670 
00671         if ( spf_request->use_local_policy ) {
00672                 /*
00673                  * find the location for the whitelist execution
00674                  *
00675                  * Philip Gladstone says:
00676                  *
00677                  * I think that the localpolicy should only be inserted if the
00678                  * final mechanism is '-all', and it should be inserted after
00679                  * the last mechanism which is not '-'.
00680                  *
00681                  * Thus for the case of 'v=spf1 +a +mx -all', this would be
00682                  * interpreted as 'v=spf1 +a +mx +localpolicy -all'. Whereas
00683                  * 'v=spf1 -all' would remain the same (no non-'-'
00684                  * mechanism). 'v=spf1 +a +mx -exists:%stuff -all' would
00685                  * become 'v=spf1 +a +mx +localpolicy -exists:%stuff -all'.
00686                  */
00687 
00688                 if ( spf_server->local_policy ) {
00689                         mech = spf_record->mech_first;
00690 
00691                         found_all = FALSE;
00692                         for(m = 0; m < spf_record->num_mech; m++)
00693                         {
00694                                 if ( mech->mech_type == MECH_ALL
00695                                          && (mech->prefix_type == PREFIX_FAIL
00696                                                  || mech->prefix_type == PREFIX_UNKNOWN
00697                                                  || mech->prefix_type == PREFIX_SOFTFAIL
00698                                                  )
00699                                         )
00700                                         found_all = TRUE;
00701 
00702                                 if ( mech->prefix_type != PREFIX_FAIL
00703                                          && mech->prefix_type != PREFIX_SOFTFAIL
00704                                         )
00705                                         local_policy = mech;
00706 
00707                                 mech = SPF_mech_next( mech );
00708                         }
00709 
00710                         if ( !found_all )
00711                                 local_policy = NULL;
00712                 }
00713 
00714         }
00715 
00716 
00717         /*
00718          * evaluate the mechanisms
00719          */
00720 
00721 #define SPF_ADD_DNS_MECH() do { spf_response->num_dns_mech++; } while(0)
00722 
00723 #define SPF_MAYBE_SKIP_CIDR() \
00724         do { \
00725                 if ( data < data_end && data->dc.parm_type == PARM_CIDR ) \
00726                         data = SPF_data_next( data ); \
00727         } while(0)
00728 
00729 #define SPF_GET_LOOKUP_DATA() \
00730         do {                                                                                            \
00731                 if ( data == data_end )                                                 \
00732                         lookup = spf_request->cur_dom;                          \
00733                 else {                                                                                  \
00734                         err = SPF_record_expand_data( spf_server,       \
00735                                                         spf_request, spf_response,      \
00736                                                         data, ((char *)data_end - (char *)data),        \
00737                                                         &buf, &buf_len );                       \
00738                         if (err == SPF_E_NO_MEMORY) {                           \
00739                                 SPF_FREE_LOOKUP_DATA();                                 \
00740                                 return DONE_TEMPERR(err);                               \
00741                         }                                                                                       \
00742                         if (err) {                                                                      \
00743                                 SPF_FREE_LOOKUP_DATA();                                 \
00744                                 return DONE_PERMERR(err);                               \
00745                         }                                                                                       \
00746                         lookup = buf;                                                           \
00747                 }                                                                                               \
00748         } while(0)
00749 #define SPF_FREE_LOOKUP_DATA() \
00750         do { if (buf != NULL) { free(buf); buf = NULL; } } while(0)
00751 
00752 
00753         resolver = spf_server->resolver;
00754 
00755         mech = spf_record->mech_first;
00756         for (m = 0; m < spf_record->num_mech; m++) {
00757 
00758                 /* This is as good a place as any. */
00759                 /* XXX Rip this out and put it into a macro which can go into inner loops. */
00760                 if (spf_response->num_dns_mech > spf_server->max_dns_mech) {
00761                         SPF_FREE_LOOKUP_DATA();
00762                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00763                 }
00764 
00765                 data = SPF_mech_data(mech);
00766                 data_end = SPF_mech_end_data(mech);
00767 
00768                 switch (mech->mech_type) {
00769                 case MECH_A:
00770                         SPF_ADD_DNS_MECH();
00771                         SPF_MAYBE_SKIP_CIDR();
00772                         SPF_GET_LOOKUP_DATA();
00773 
00774                         if (spf_request->client_ver == AF_INET)
00775                                 fetch_ns_type = ns_t_a;
00776                         else
00777                                 fetch_ns_type = ns_t_aaaa;
00778 
00779                         rr_a = SPF_dns_lookup(resolver, lookup, fetch_ns_type, TRUE);
00780 
00781                         if (spf_server->debug)
00782                                 SPF_debugf("found %d A records for %s  (herrno: %d)",
00783                                                 rr_a->num_rr, lookup, rr_a->herrno);
00784 
00785                         if (rr_a->herrno == TRY_AGAIN) {
00786                                 SPF_dns_rr_free(rr_a);
00787                                 SPF_FREE_LOOKUP_DATA();
00788                                 return DONE_TEMPERR(SPF_E_DNS_ERROR); /* REASON_MECH */
00789                         }
00790 
00791                         for (i = 0; i < rr_a->num_rr; i++) {
00792                                 /* XXX Should this be hoisted? */
00793                                 if (rr_a->rr_type != fetch_ns_type)
00794                                         continue;
00795 
00796                                 if (spf_request->client_ver == AF_INET) {
00797                                         if (SPF_i_match_ip4(spf_server, spf_request, mech, rr_a->rr[i]->a)) {
00798                                                 SPF_dns_rr_free(rr_a);
00799                                                 SPF_FREE_LOOKUP_DATA();
00800                                                 return DONE_MECH(mech->prefix_type);
00801                                         }
00802                                 }
00803                                 else {
00804                                         if (SPF_i_match_ip6(spf_server, spf_request, mech, rr_a->rr[i]->aaaa)) {
00805                                                 SPF_dns_rr_free(rr_a);
00806                                                 SPF_FREE_LOOKUP_DATA();
00807                                                 return DONE_MECH(mech->prefix_type);
00808                                         }
00809                                 }
00810                         }
00811 
00812                         SPF_dns_rr_free(rr_a);
00813                         break;
00814 
00815                 case MECH_MX:
00816                         SPF_ADD_DNS_MECH();
00817                         SPF_MAYBE_SKIP_CIDR();
00818                         SPF_GET_LOOKUP_DATA();
00819 
00820                         rr_mx = SPF_dns_lookup(resolver, lookup, ns_t_mx, TRUE);
00821 
00822                         if (spf_server->debug)
00823                                 SPF_debugf("found %d MX records for %s  (herrno: %d)",
00824                                                 rr_mx->num_rr, lookup, rr_mx->herrno);
00825 
00826                         if (rr_mx->herrno == TRY_AGAIN) {
00827                                 SPF_dns_rr_free(rr_mx);
00828                                 SPF_FREE_LOOKUP_DATA();
00829                                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
00830                         }
00831 
00832                         /* The maximum number of MX records we will inspect. */
00833                         max_mx = rr_mx->num_rr;
00834                         max_exceeded = 0;
00835                         if (max_mx > spf_server->max_dns_mx) {
00836                                 max_exceeded = 1;
00837                                 max_mx = SPF_server_get_max_dns_mx(spf_server);
00838                         }
00839 
00840                         for (j = 0; j < max_mx; j++) {
00841                                 /* XXX Should this be hoisted? */
00842                                 if (rr_mx->rr_type != ns_t_mx)
00843                                         continue;
00844 
00845                                 if (spf_request->client_ver == AF_INET)
00846                                         fetch_ns_type = ns_t_a;
00847                                 else
00848                                         fetch_ns_type = ns_t_aaaa;
00849 
00850                                 rr_a = SPF_dns_lookup(resolver, rr_mx->rr[j]->mx,
00851                                                                            fetch_ns_type, TRUE );
00852 
00853                                 if (spf_server->debug)
00854                                         SPF_debugf("%d: found %d A records for %s  (herrno: %d)",
00855                                                         j, rr_a->num_rr, rr_mx->rr[j]->mx, rr_a->herrno);
00856                                 if (rr_a->herrno == TRY_AGAIN) {
00857                                         SPF_dns_rr_free(rr_mx);
00858                                         SPF_dns_rr_free(rr_a);
00859                                         SPF_FREE_LOOKUP_DATA();
00860                                         return DONE_TEMPERR(SPF_E_DNS_ERROR);
00861                                 }
00862 
00863                                 for (i = 0; i < rr_a->num_rr; i++) {
00864                                         /* XXX Should this be hoisted? */
00865                                         if (rr_a->rr_type != fetch_ns_type)
00866                                                 continue;
00867 
00868                                         if (spf_request->client_ver == AF_INET) {
00869                                                 if (SPF_i_match_ip4(spf_server, spf_request, mech,
00870                                                                                 rr_a->rr[i]->a)) {
00871                                                         SPF_dns_rr_free(rr_mx);
00872                                                         SPF_dns_rr_free(rr_a);
00873                                                         SPF_FREE_LOOKUP_DATA();
00874                                                         return DONE(mech->prefix_type, SPF_REASON_MECH,
00875                                                                                  SPF_E_SUCCESS);
00876                                                 }
00877                                         }
00878                                         else {
00879                                                 if (SPF_i_match_ip6(spf_server, spf_request, mech,
00880                                                                                 rr_a->rr[i]->aaaa)) {
00881                                                         SPF_dns_rr_free(rr_mx);
00882                                                         SPF_dns_rr_free(rr_a);
00883                                                         SPF_FREE_LOOKUP_DATA();
00884                                                         return DONE(mech->prefix_type, SPF_REASON_MECH,
00885                                                                                  SPF_E_SUCCESS);
00886                                                 }
00887                                         }
00888                                 }
00889                                 SPF_dns_rr_free(rr_a);
00890                         }
00891 
00892                         SPF_dns_rr_free( rr_mx );
00893                         if (max_exceeded) {
00894                                 SPF_FREE_LOOKUP_DATA();
00895                                 return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00896                         }
00897                         break;
00898 
00899                 case MECH_PTR:
00900                         SPF_ADD_DNS_MECH();
00901                         SPF_GET_LOOKUP_DATA();
00902 
00903                         if (spf_request->client_ver == AF_INET) {
00904                                 rr_ptr = SPF_dns_rlookup(resolver,
00905                                                                 spf_request->ipv4, ns_t_ptr, TRUE);
00906 
00907                                 if (spf_server->debug) {
00908                                         INET_NTOP(AF_INET, &spf_request->ipv4.s_addr,
00909                                                                                 ip4_buf, sizeof(ip4_buf));
00910                                         SPF_debugf("got %d PTR records for %s (herrno: %d)",
00911                                                         rr_ptr->num_rr, ip4_buf, rr_ptr->herrno);
00912                                 }
00913 
00914                                 if (rr_ptr->herrno == TRY_AGAIN) {
00915                                         SPF_dns_rr_free(rr_ptr);
00916                                         SPF_FREE_LOOKUP_DATA();
00917                                         return DONE_TEMPERR(SPF_E_DNS_ERROR);
00918                                 }
00919 
00920 
00921                                 /* The maximum number of PTR records we will inspect. */
00922                                 max_ptr = rr_ptr->num_rr;
00923                                 max_exceeded = 0;
00924                                 if (max_ptr > spf_server->max_dns_ptr) {
00925                                         max_exceeded = 1;
00926                                         max_ptr = SPF_server_get_max_dns_ptr(spf_server);
00927                                 }
00928 
00929                                 for (i = 0; i < max_ptr; i++) {
00930                                         /* XXX MX has a 'continue' case here which should be hoisted. */
00931 
00932                                         rr_a = SPF_dns_lookup(resolver,
00933                                                         rr_ptr->rr[i]->ptr, ns_t_a, TRUE);
00934 
00935                                         if (spf_server->debug)
00936                                                 SPF_debugf( "%d:  found %d A records for %s  (herrno: %d)",
00937                                                                 i, rr_a->num_rr, rr_ptr->rr[i]->ptr, rr_a->herrno );
00938                                         if (rr_a->herrno == TRY_AGAIN) {
00939                                                 SPF_dns_rr_free(rr_ptr);
00940                                                 SPF_dns_rr_free(rr_a);
00941                                                 SPF_FREE_LOOKUP_DATA();
00942                                                 return DONE_TEMPERR( SPF_E_DNS_ERROR );
00943                                         }
00944 
00945                                         for (j = 0; j < rr_a->num_rr; j++) {
00946                                                 /* XXX MX has a 'continue' case here which should be hoisted. */
00947 
00948                                                 if (spf_server->debug) {
00949                                                         INET_NTOP(AF_INET, &rr_a->rr[j]->a.s_addr,
00950                                                                                         ip4_buf, sizeof(ip4_buf));
00951                                                         SPF_debugf("%d: %d:  found %s",
00952                                                                         i, j, ip4_buf);
00953                                                 }
00954 
00955                                                 if (rr_a->rr[j]->a.s_addr ==
00956                                                                                 spf_request->ipv4.s_addr) {
00957                                                         if (SPF_i_match_domain(spf_server,
00958                                                                                         rr_ptr->rr[i]->ptr, lookup)) {
00959                                                                 SPF_dns_rr_free(rr_ptr);
00960                                                                 SPF_dns_rr_free(rr_a);
00961                                                                 SPF_FREE_LOOKUP_DATA();
00962                                                                 return DONE_MECH(mech->prefix_type);
00963                                                         }
00964                                                 }
00965                                         }
00966                                         SPF_dns_rr_free(rr_a);
00967                                 }
00968                                 SPF_dns_rr_free(rr_ptr);
00969 
00970                                 if (max_exceeded) {
00971                                         SPF_FREE_LOOKUP_DATA();
00972                                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00973                                 }
00974                         }
00975 
00976                         else if ( spf_request->client_ver == AF_INET6 ) {
00977                                 rr_ptr = SPF_dns_rlookup6(resolver,
00978                                                                 spf_request->ipv6, ns_t_ptr, TRUE);
00979 
00980                                 if ( spf_server->debug ) {
00981                                         INET_NTOP( AF_INET6, &spf_request->ipv6.s6_addr,
00982                                                                            ip6_buf, sizeof( ip6_buf ) );
00983                                         SPF_debugf( "found %d PTR records for %s  (herrno: %d)",
00984                                                         rr_ptr->num_rr, ip6_buf, rr_ptr->herrno );
00985                                 }
00986                                 if( rr_ptr->herrno == TRY_AGAIN ) {
00987                                         SPF_dns_rr_free(rr_ptr);
00988                                         SPF_FREE_LOOKUP_DATA();
00989                                         return DONE_TEMPERR( SPF_E_DNS_ERROR );
00990                                 }
00991 
00992 
00993                                 max_ptr = rr_ptr->num_rr;
00994                                 max_exceeded = 0;
00995                                 if (max_ptr > spf_server->max_dns_ptr) {
00996                                         max_ptr = SPF_server_get_max_dns_ptr(spf_server);
00997                                         max_exceeded = 1;
00998                                 }
00999 
01000                                 for (i = 0; i < max_ptr; i++) {
01001                                         /* XXX MX has a 'continue' case here which should be hoisted. */
01002 
01003                                         rr_aaaa = SPF_dns_lookup(resolver,
01004                                                         rr_ptr->rr[i]->ptr, ns_t_aaaa, TRUE);
01005 
01006                                         if ( spf_server->debug )
01007                                                 SPF_debugf("%d:  found %d AAAA records for %s  (herrno: %d)",
01008                                                                 i, rr_aaaa->num_rr, rr_ptr->rr[i]->ptr, rr_aaaa->herrno);
01009                                         if( rr_aaaa->herrno == TRY_AGAIN ) {
01010                                                 SPF_dns_rr_free(rr_ptr);
01011                                                 SPF_dns_rr_free(rr_aaaa);
01012                                                 SPF_FREE_LOOKUP_DATA();
01013                                                 return DONE_TEMPERR( SPF_E_DNS_ERROR );
01014                                         }
01015 
01016                                         for( j = 0; j < rr_aaaa->num_rr; j++ ) {
01017                                                 /* XXX MX has a 'continue' case here which should be hoisted. */
01018                                                 if ( spf_server->debug ) {
01019                                                         INET_NTOP(AF_INET6, &rr_aaaa->rr[j]->aaaa.s6_addr,
01020                                                                                         ip6_buf, sizeof(ip6_buf));
01021                                                         SPF_debugf( "%d: %d:  found %s",
01022                                                                         i, j, ip6_buf );
01023                                                 }
01024 
01025                                                 if (memcmp(&rr_aaaa->rr[j]->aaaa,
01026                                                                 &spf_request->ipv6,
01027                                                                 sizeof(spf_request->ipv6)) == 0) {
01028                                                         if (SPF_i_match_domain(spf_server,
01029                                                                                         rr_ptr->rr[i]->ptr, lookup)) {
01030                                                                 SPF_dns_rr_free( rr_ptr );
01031                                                                 SPF_dns_rr_free(rr_aaaa);
01032                                                                 SPF_FREE_LOOKUP_DATA();
01033                                                                 return DONE_MECH( mech->prefix_type );
01034                                                         }
01035                                                 }
01036                                         }
01037                                         SPF_dns_rr_free(rr_aaaa);
01038                                 }
01039                                 SPF_dns_rr_free(rr_ptr);
01040 
01041                                 if (max_exceeded) {
01042                                         SPF_FREE_LOOKUP_DATA();
01043                                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
01044                                 }
01045                         }
01046 
01047 
01048                         break;
01049 
01050                 case MECH_INCLUDE:
01051                 case MECH_REDIRECT:
01052                         SPF_ADD_DNS_MECH();
01053 
01054                         err = SPF_record_expand_data(spf_server,
01055                                         spf_request, spf_response,
01056                                         SPF_mech_data(mech), SPF_mech_data_len(mech),
01057                                         &buf, &buf_len );
01058                         if ( err == SPF_E_NO_MEMORY ) {
01059                                 SPF_FREE_LOOKUP_DATA();
01060                                 return DONE_TEMPERR( err );
01061                         }
01062                         if ( err ) {
01063                                 SPF_FREE_LOOKUP_DATA();
01064                                 return DONE_PERMERR( err );
01065                         }
01066                         lookup = buf;
01067 
01068                         /* XXX Maintain a stack depth here. Limit at 10. */
01069                         if (strcmp(lookup, spf_request->cur_dom) == 0) {
01070                                 SPF_FREE_LOOKUP_DATA();
01071                                 return DONE_PERMERR( SPF_E_RECURSIVE );
01072                         }
01073 
01074                         /*
01075                          * get the (compiled) SPF record
01076                          */
01077 
01078                         spf_record_subr = NULL;
01079                         /* Remember to reset this. */
01080                         save_cur_dom = spf_request->cur_dom;
01081                         spf_request->cur_dom = lookup;
01082                         err = SPF_server_get_record(spf_server, spf_request,
01083                                                         spf_response, &spf_record_subr);
01084 
01085                         if ( spf_server->debug > 0 )
01086                                 SPF_debugf( "include/redirect:  got SPF record:  %s",
01087                                                 SPF_strerror( err ) );
01088 
01089                         if (err != SPF_E_SUCCESS) {
01090                                 spf_request->cur_dom = save_cur_dom;
01091                                 if (spf_record_subr)
01092                                         SPF_record_free(spf_record_subr);
01093                                 SPF_FREE_LOOKUP_DATA();
01094                                 if (err == SPF_E_DNS_ERROR)
01095                                         return DONE_TEMPERR( err );
01096                                 else
01097                                         return DONE_PERMERR( err );
01098                         }
01099 
01100                         SPF_ASSERT_NOTNULL(spf_record_subr);
01101 
01102                         /*
01103                          * If we are a redirect which is not within the scope
01104                          * of any include.
01105                          */
01106                         if (mech->mech_type == MECH_REDIRECT) {
01107                                 save_spf_response = NULL;
01108                                 if (spf_response->spf_record_exp == spf_record)
01109                                         spf_response->spf_record_exp = spf_record_subr;
01110                                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
01111                         }
01112                         else {
01113                                 save_spf_response = spf_response;
01114                                 spf_response = SPF_response_new(spf_request);
01115                                 if (! spf_response) {
01116                                         if (spf_record_subr)
01117                                                 SPF_record_free(spf_record_subr);
01118                                         SPF_FREE_LOOKUP_DATA();
01119                                         return DONE_TEMPERR(SPF_E_NO_MEMORY);
01120                                 }
01121                                 spf_response->spf_record_exp = spf_record;
01122                                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
01123                         }
01124                         /*
01125                          * find out whether this configuration passes
01126                          */
01127                         err = SPF_record_interpret(spf_record_subr,
01128                                                         spf_request, spf_response, depth + 1);
01129                         spf_request->cur_dom = save_cur_dom;
01130                         /* Now, if we were a redirect, the child called done()
01131                          * and used spf_record_exp. In that case, we need not
01132                          * worry that spf_record_subr is invalid after the free.
01133                          * If we were not a redirect, then spf_record_subr
01134                          * is still the record it was in the first place.
01135                          * Thus we do not need to reset it now. */
01136                         SPF_record_free(spf_record_subr);
01137                         spf_record_subr = NULL;
01138 
01139                         if ( spf_server->debug > 0 )
01140                                 SPF_debugf( "include/redirect:  executed SPF record:  %s  result: %s  reason: %s",
01141                                                 SPF_strerror( err ),
01142                                                 SPF_strresult( spf_response->result ),
01143                                                 SPF_strreason( spf_response->reason ) );
01144                         if (mech->mech_type == MECH_REDIRECT) {
01145                                 SPF_FREE_LOOKUP_DATA();
01146                                 return err;     /* One way or the other */
01147                         }
01148                         else { // if (spf_response->result != SPF_RESULT_INVALID) {
01149                                 /* Set everything up properly again. */
01150                                 spf_response_subr = spf_response;
01151                                 spf_response = save_spf_response;
01152                                 save_spf_response = NULL;
01153 
01154                                 /* Rewrite according to prefix of include */
01155                                 switch (SPF_response_result(spf_response_subr)) {
01156                                         case SPF_RESULT_PASS:
01157                                                 /* Pass */
01158                                                 SPF_FREE_LOOKUP_DATA();
01159                                                 SPF_response_free(spf_response_subr);
01160                                                 return DONE_MECH( mech->prefix_type );
01161 
01162                                         case SPF_RESULT_FAIL:
01163                                         case SPF_RESULT_SOFTFAIL:
01164                                         case SPF_RESULT_NEUTRAL:
01165                                                 /* No match */
01166                                                 SPF_response_free(spf_response_subr);
01167                                                 break;
01168 
01169                                         case SPF_RESULT_TEMPERROR:
01170                                                 /* Generate TempError */
01171                                                 err = SPF_response_errcode(spf_response_subr);
01172                                                 SPF_FREE_LOOKUP_DATA();
01173                                                 SPF_response_free(spf_response_subr);
01174                                                 return DONE_TEMPERR( err );
01175 
01176                                         case SPF_RESULT_NONE:
01177                                                 /* Generate PermError */
01178                                                 SPF_FREE_LOOKUP_DATA();
01179                                                 SPF_response_free(spf_response_subr);
01180                                                 return DONE_PERMERR(SPF_E_INCLUDE_RETURNED_NONE);
01181                                         case SPF_RESULT_PERMERROR:
01182                                         case SPF_RESULT_INVALID:
01183                                                 /* Generate PermError */
01184                                                 err = SPF_response_errcode(spf_response_subr);
01185                                                 SPF_FREE_LOOKUP_DATA();
01186                                                 SPF_response_free(spf_response_subr);
01187                                                 return DONE_PERMERR( err );
01188 
01189                                 }
01190 #if 0
01191                                 SPF_FREE_LOOKUP_DATA();
01192                                 return err;     /* The sub-interpret called done() */
01193 #endif
01194                         }
01195 
01196                         break;
01197 
01198                 case MECH_IP4:
01199                         memcpy(&addr4, SPF_mech_ip4_data(mech), sizeof(addr4));
01200                         if ( SPF_i_match_ip4( spf_server, spf_request, mech, addr4 ) ) {
01201                                 SPF_FREE_LOOKUP_DATA();
01202                                 return DONE_MECH( mech->prefix_type );
01203                         }
01204                         break;
01205 
01206                 case MECH_IP6:
01207                         memcpy(&addr6, SPF_mech_ip6_data(mech), sizeof(addr6));
01208                         if ( SPF_i_match_ip6( spf_server, spf_request, mech, addr6 ) ) {
01209                                 SPF_FREE_LOOKUP_DATA();
01210                                 return DONE_MECH( mech->prefix_type );
01211                         }
01212                         break;
01213 
01214                 case MECH_EXISTS:
01215                         SPF_ADD_DNS_MECH();
01216 
01217                         err = SPF_record_expand_data(spf_server,
01218                                                         spf_request, spf_response,
01219                                                         SPF_mech_data(mech),SPF_mech_data_len(mech),
01220                                                         &buf, &buf_len);
01221                         if (err != SPF_E_SUCCESS) {
01222                                 SPF_FREE_LOOKUP_DATA();
01223                                 return DONE_TEMPERR( err );
01224                         }
01225                         lookup = buf;
01226 
01227                         rr_a = SPF_dns_lookup(resolver, lookup, ns_t_a, FALSE );
01228 
01229                         if ( spf_server->debug )
01230                                 SPF_debugf( "found %d A records for %s  (herrno: %d)",
01231                                                 rr_a->num_rr, lookup, rr_a->herrno );
01232 
01233                         if( rr_a->herrno == TRY_AGAIN ) {
01234                                 SPF_dns_rr_free(rr_a);
01235                                 SPF_FREE_LOOKUP_DATA();
01236                                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
01237                         }
01238                         if ( rr_a->num_rr > 0 ) {
01239                                 SPF_dns_rr_free(rr_a);
01240                                 SPF_FREE_LOOKUP_DATA();
01241                                 return DONE_MECH(mech->prefix_type);
01242                         }
01243 
01244                         SPF_dns_rr_free(rr_a);
01245                         break;
01246 
01247                 case MECH_ALL:
01248                         SPF_FREE_LOOKUP_DATA();
01249                         if (mech->prefix_type == PREFIX_UNKNOWN)
01250                                 return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
01251                         return DONE_MECH(mech->prefix_type);
01252                         break;
01253 
01254                 default:
01255                         SPF_FREE_LOOKUP_DATA();
01256                         return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
01257                         break;
01258                 }
01259 
01260                 /*
01261                  * execute the local policy
01262                  */
01263 
01264                 if ( mech == local_policy ) {
01265                         err = SPF_record_interpret(spf_server->local_policy,
01266                                                         spf_request, spf_response, depth + 1);
01267 
01268                         if ( spf_server->debug > 0 )
01269                                 SPF_debugf( "local_policy:  executed SPF record:  %s  result: %s  reason: %s",
01270                                                         SPF_strerror( err ),
01271                                                         SPF_strresult( spf_response->result ),
01272                                                         SPF_strreason( spf_response->reason ) );
01273 
01274                         if (spf_response->result != SPF_RESULT_INVALID) {
01275                                 SPF_FREE_LOOKUP_DATA();
01276                                 return err;
01277                         }
01278                 }
01279 
01280                 mech = SPF_mech_next( mech );
01281         }
01282 
01283         SPF_FREE_LOOKUP_DATA();
01284         /* falling off the end is the same as ?all */
01285         return DONE( SPF_RESULT_NEUTRAL, SPF_REASON_DEFAULT, SPF_E_SUCCESS );
01286 }

Generated on Sun May 29 13:27:09 2016 for libspf2 by  doxygen 1.4.6