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, 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 
00521         match = TRUE;
00522         for( i = 0; i < array_elem( ipv6.s6_addr ) && match; i++ )
00523         {
00524                 if ( cidr > 8 )
00525                         mask = 0xff;
00526                 else if ( cidr > 0 )
00527                         mask = (0xff << (8 - cidr)) & 0xff;
00528                 else
00529                         break;
00530                 cidr -= 8;
00531 
00532                 match = (src_ipv6.s6_addr[i] & mask) == (ipv6.s6_addr[i] & mask);
00533         }
00534 
00535         if (spf_server->debug) {
00536                 INET_NTOP(AF_INET6, &src_ipv6.s6_addr,
00537                                                         src_ip6_buf, sizeof(src_ip6_buf));
00538                 INET_NTOP(AF_INET6, &ipv6.s6_addr,
00539                                                         dst_ip6_buf, sizeof(dst_ip6_buf));
00540                 SPF_debugf( "ip_match:  %s == %s  (/%d):  %d",
00541                                 src_ip6_buf, dst_ip6_buf, cidr, match );
00542         }
00543 
00544         return match;
00545 }
00546 
00547 static int
00548 SPF_i_match_domain(SPF_server_t *spf_server,
00549                                 const char *hostname, const char *domain)
00550 {
00551         const char      *hp;
00552         int                      hlen;
00553         int                      dlen;
00554 
00555         if (spf_server->debug)
00556                 SPF_debugf( "%s ?=? %s", hostname, domain );
00557 
00558         hlen = strlen(hostname);
00559         dlen = strlen(domain);
00560 
00561         /* A host cannot be a member of a domain longer than it is. */
00562         if (dlen > hlen)
00563                 return 0;
00564 
00565         /* The two may be equal? */
00566         if (dlen == hlen)
00567                 return (strcasecmp(hostname, domain) == 0);
00568 
00569         /* The domain may match a trailing portion preceded by a dot. */
00570         hp = hostname + (hlen - dlen);
00571 
00572         if (*(hp - 1) != '.')
00573                 return 0;
00574 
00575         return (strcasecmp(hp, domain) == 0);
00576 }
00577 
00578 
00579 /*
00580  * Set cur_dom (to either sender or or helo_dom) before calling this.
00581  */
00582 
00583 SPF_errcode_t
00584 SPF_record_interpret(SPF_record_t *spf_record,
00585                         SPF_request_t *spf_request, SPF_response_t *spf_response,
00586                         int depth)
00587 {
00588         SPF_server_t    *spf_server;
00589 
00590         /* Temporaries */
00591         int                              i, j;
00592         int                              m;                     /* Mechanism iterator */
00593         SPF_mech_t              *mech;
00594         SPF_data_t              *data;
00595         SPF_data_t              *data_end;      /* XXX Replace with size_t data_len */
00596 
00597         /* Where to insert the local policy (whitelist) */
00598         SPF_mech_t              *local_policy;  /* Not the local policy */
00599         int                              found_all;             /* A crappy temporary. */
00600 
00601         char                    *buf = NULL;
00602         size_t                   buf_len = 0;
00603         ns_type                  fetch_ns_type;
00604         const char              *lookup;
00605 
00606         SPF_dns_rr_t    *rr_a;
00607         SPF_dns_rr_t    *rr_aaaa;
00608         SPF_dns_rr_t    *rr_ptr;
00609         SPF_dns_rr_t    *rr_mx;
00610 
00611         SPF_errcode_t    err;
00612 
00613         SPF_dns_server_t*resolver;
00614 
00615         /* An SPF record for subrequests - replaces c_results */
00616         SPF_record_t    *spf_record_subr;
00617 
00618         SPF_response_t  *save_spf_response;
00619         SPF_response_t  *spf_response_subr;
00620         const char              *save_cur_dom;
00621 
00622         struct in_addr  addr4;
00623         struct in6_addr addr6;
00624 
00625         int                             max_ptr;
00626         int                             max_mx;
00627         int                             max_exceeded;
00628 
00629         char                     ip4_buf[ INET_ADDRSTRLEN ];
00630         char                     ip6_buf[ INET6_ADDRSTRLEN ];
00631 
00632 
00633         /*
00634          * make sure we were passed valid data to work with
00635          */
00636         SPF_ASSERT_NOTNULL(spf_record);
00637         SPF_ASSERT_NOTNULL(spf_request);
00638         SPF_ASSERT_NOTNULL(spf_response);
00639         spf_server = spf_record->spf_server;
00640         SPF_ASSERT_NOTNULL(spf_server);
00641 
00642         SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
00643 
00644         if (depth > 20)
00645                 return DONE_PERMERR(SPF_E_RECURSIVE);
00646 
00647         if ( spf_request->client_ver != AF_INET && spf_request->client_ver != AF_INET6 )
00648                 return DONE_PERMERR(SPF_E_NOT_CONFIG);
00649 
00650         if (spf_request->cur_dom == NULL)
00651                 return DONE_PERMERR(SPF_E_NOT_CONFIG);
00652 
00653 
00654         /*
00655          * localhost always gets a free ride
00656          */
00657 
00658 #if 0
00659         /* This should have been done already before we got here. */
00660         if ( SPF_request_is_loopback( spf_request ) )
00661                 return DONE(SPF_RESULT_PASS,SPF_REASON_LOCALHOST,SPF_E_SUCCESS);
00662 #endif
00663 
00664         /*
00665          * Do some start up stuff if we haven't recursed yet
00666          */
00667 
00668         local_policy = NULL;
00669 
00670         if ( spf_request->use_local_policy ) {
00671                 /*
00672                  * find the location for the whitelist execution
00673                  *
00674                  * Philip Gladstone says:
00675                  *
00676                  * I think that the localpolicy should only be inserted if the
00677                  * final mechanism is '-all', and it should be inserted after
00678                  * the last mechanism which is not '-'.
00679                  *
00680                  * Thus for the case of 'v=spf1 +a +mx -all', this would be
00681                  * interpreted as 'v=spf1 +a +mx +localpolicy -all'. Whereas
00682                  * 'v=spf1 -all' would remain the same (no non-'-'
00683                  * mechanism). 'v=spf1 +a +mx -exists:%stuff -all' would
00684                  * become 'v=spf1 +a +mx +localpolicy -exists:%stuff -all'.
00685                  */
00686 
00687                 if ( spf_server->local_policy ) {
00688                         mech = spf_record->mech_first;
00689 
00690                         found_all = FALSE;
00691                         for(m = 0; m < spf_record->num_mech; m++)
00692                         {
00693                                 if ( mech->mech_type == MECH_ALL
00694                                          && (mech->prefix_type == PREFIX_FAIL
00695                                                  || mech->prefix_type == PREFIX_UNKNOWN
00696                                                  || mech->prefix_type == PREFIX_SOFTFAIL
00697                                                  )
00698                                         )
00699                                         found_all = TRUE;
00700 
00701                                 if ( mech->prefix_type != PREFIX_FAIL
00702                                          && mech->prefix_type != PREFIX_SOFTFAIL
00703                                         )
00704                                         local_policy = mech;
00705 
00706                                 mech = SPF_mech_next( mech );
00707                         }
00708 
00709                         if ( !found_all )
00710                                 local_policy = NULL;
00711                 }
00712 
00713         }
00714 
00715 
00716         /*
00717          * evaluate the mechanisms
00718          */
00719 
00720 #define SPF_ADD_DNS_MECH() do { spf_response->num_dns_mech++; } while(0)
00721 
00722 #define SPF_MAYBE_SKIP_CIDR() \
00723         do { \
00724                 if ( data < data_end && data->dc.parm_type == PARM_CIDR ) \
00725                         data = SPF_data_next( data ); \
00726         } while(0)
00727 
00728 #define SPF_GET_LOOKUP_DATA() \
00729         do {                                                                                            \
00730                 if ( data == data_end )                                                 \
00731                         lookup = spf_request->cur_dom;                          \
00732                 else {                                                                                  \
00733                         err = SPF_record_expand_data( spf_server,       \
00734                                                         spf_request, spf_response,      \
00735                                                         data, ((char *)data_end - (char *)data),        \
00736                                                         &buf, &buf_len );                       \
00737                         if (err == SPF_E_NO_MEMORY) {                           \
00738                                 SPF_FREE_LOOKUP_DATA();                                 \
00739                                 return DONE_TEMPERR(err);                               \
00740                         }                                                                                       \
00741                         if (err) {                                                                      \
00742                                 SPF_FREE_LOOKUP_DATA();                                 \
00743                                 return DONE_PERMERR(err);                               \
00744                         }                                                                                       \
00745                         lookup = buf;                                                           \
00746                 }                                                                                               \
00747         } while(0)
00748 #define SPF_FREE_LOOKUP_DATA() \
00749         do { if (buf != NULL) { free(buf); buf = NULL; } } while(0)
00750 
00751 
00752         resolver = spf_server->resolver;
00753 
00754         mech = spf_record->mech_first;
00755         for (m = 0; m < spf_record->num_mech; m++) {
00756 
00757                 /* This is as good a place as any. */
00758                 /* XXX Rip this out and put it into a macro which can go into inner loops. */
00759                 if (spf_response->num_dns_mech > spf_server->max_dns_mech) {
00760                         SPF_FREE_LOOKUP_DATA();
00761                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00762                 }
00763 
00764                 data = SPF_mech_data(mech);
00765                 data_end = SPF_mech_end_data(mech);
00766 
00767                 switch (mech->mech_type) {
00768                 case MECH_A:
00769                         SPF_ADD_DNS_MECH();
00770                         SPF_MAYBE_SKIP_CIDR();
00771                         SPF_GET_LOOKUP_DATA();
00772 
00773                         if (spf_request->client_ver == AF_INET)
00774                                 fetch_ns_type = ns_t_a;
00775                         else
00776                                 fetch_ns_type = ns_t_aaaa;
00777 
00778                         rr_a = SPF_dns_lookup(resolver, lookup, fetch_ns_type, TRUE);
00779 
00780                         if (spf_server->debug)
00781                                 SPF_debugf("found %d A records for %s  (herrno: %d)",
00782                                                 rr_a->num_rr, lookup, rr_a->herrno);
00783 
00784                         if (rr_a->herrno == TRY_AGAIN) {
00785                                 SPF_dns_rr_free(rr_a);
00786                                 SPF_FREE_LOOKUP_DATA();
00787                                 return DONE_TEMPERR(SPF_E_DNS_ERROR); /* REASON_MECH */
00788                         }
00789 
00790                         for (i = 0; i < rr_a->num_rr; i++) {
00791                                 /* XXX Should this be hoisted? */
00792                                 if (rr_a->rr_type != fetch_ns_type)
00793                                         continue;
00794 
00795                                 if (spf_request->client_ver == AF_INET) {
00796                                         if (SPF_i_match_ip4(spf_server, spf_request, mech, rr_a->rr[i]->a)) {
00797                                                 SPF_dns_rr_free(rr_a);
00798                                                 SPF_FREE_LOOKUP_DATA();
00799                                                 return DONE_MECH(mech->prefix_type);
00800                                         }
00801                                 }
00802                                 else {
00803                                         if (SPF_i_match_ip6(spf_server, spf_request, mech, rr_a->rr[i]->aaaa)) {
00804                                                 SPF_dns_rr_free(rr_a);
00805                                                 SPF_FREE_LOOKUP_DATA();
00806                                                 return DONE_MECH(mech->prefix_type);
00807                                         }
00808                                 }
00809                         }
00810 
00811                         SPF_dns_rr_free(rr_a);
00812                         break;
00813 
00814                 case MECH_MX:
00815                         SPF_ADD_DNS_MECH();
00816                         SPF_MAYBE_SKIP_CIDR();
00817                         SPF_GET_LOOKUP_DATA();
00818 
00819                         rr_mx = SPF_dns_lookup(resolver, lookup, ns_t_mx, TRUE);
00820 
00821                         if (spf_server->debug)
00822                                 SPF_debugf("found %d MX records for %s  (herrno: %d)",
00823                                                 rr_mx->num_rr, lookup, rr_mx->herrno);
00824 
00825                         if (rr_mx->herrno == TRY_AGAIN) {
00826                                 SPF_dns_rr_free(rr_mx);
00827                                 SPF_FREE_LOOKUP_DATA();
00828                                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
00829                         }
00830 
00831                         /* The maximum number of MX records we will inspect. */
00832                         max_mx = rr_mx->num_rr;
00833                         max_exceeded = 0;
00834                         if (max_mx > spf_server->max_dns_mx) {
00835                                 max_exceeded = 1;
00836                                 max_mx = SPF_server_get_max_dns_mx(spf_server);
00837                         }
00838 
00839                         for (j = 0; j < max_mx; j++) {
00840                                 /* XXX Should this be hoisted? */
00841                                 if (rr_mx->rr_type != ns_t_mx)
00842                                         continue;
00843 
00844                                 if (spf_request->client_ver == AF_INET)
00845                                         fetch_ns_type = ns_t_a;
00846                                 else
00847                                         fetch_ns_type = ns_t_aaaa;
00848 
00849                                 rr_a = SPF_dns_lookup(resolver, rr_mx->rr[j]->mx,
00850                                                                            fetch_ns_type, TRUE );
00851 
00852                                 if (spf_server->debug)
00853                                         SPF_debugf("%d: found %d A records for %s  (herrno: %d)",
00854                                                         j, rr_a->num_rr, rr_mx->rr[j]->mx, rr_a->herrno);
00855                                 if (rr_a->herrno == TRY_AGAIN) {
00856                                         SPF_dns_rr_free(rr_mx);
00857                                         SPF_dns_rr_free(rr_a);
00858                                         SPF_FREE_LOOKUP_DATA();
00859                                         return DONE_TEMPERR(SPF_E_DNS_ERROR);
00860                                 }
00861 
00862                                 for (i = 0; i < rr_a->num_rr; i++) {
00863                                         /* XXX Should this be hoisted? */
00864                                         if (rr_a->rr_type != fetch_ns_type)
00865                                                 continue;
00866 
00867                                         if (spf_request->client_ver == AF_INET) {
00868                                                 if (SPF_i_match_ip4(spf_server, spf_request, mech,
00869                                                                                 rr_a->rr[i]->a)) {
00870                                                         SPF_dns_rr_free(rr_mx);
00871                                                         SPF_dns_rr_free(rr_a);
00872                                                         SPF_FREE_LOOKUP_DATA();
00873                                                         return DONE(mech->prefix_type, SPF_REASON_MECH,
00874                                                                                  SPF_E_SUCCESS);
00875                                                 }
00876                                         }
00877                                         else {
00878                                                 if (SPF_i_match_ip6(spf_server, spf_request, mech,
00879                                                                                 rr_a->rr[i]->aaaa)) {
00880                                                         SPF_dns_rr_free(rr_mx);
00881                                                         SPF_dns_rr_free(rr_a);
00882                                                         SPF_FREE_LOOKUP_DATA();
00883                                                         return DONE(mech->prefix_type, SPF_REASON_MECH,
00884                                                                                  SPF_E_SUCCESS);
00885                                                 }
00886                                         }
00887                                 }
00888                                 SPF_dns_rr_free(rr_a);
00889                         }
00890 
00891                         SPF_dns_rr_free( rr_mx );
00892                         if (max_exceeded) {
00893                                 SPF_FREE_LOOKUP_DATA();
00894                                 return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00895                         }
00896                         break;
00897 
00898                 case MECH_PTR:
00899                         SPF_ADD_DNS_MECH();
00900                         SPF_GET_LOOKUP_DATA();
00901 
00902                         if (spf_request->client_ver == AF_INET) {
00903                                 rr_ptr = SPF_dns_rlookup(resolver,
00904                                                                 spf_request->ipv4, ns_t_ptr, TRUE);
00905 
00906                                 if (spf_server->debug) {
00907                                         INET_NTOP(AF_INET, &spf_request->ipv4.s_addr,
00908                                                                                 ip4_buf, sizeof(ip4_buf));
00909                                         SPF_debugf("got %d PTR records for %s (herrno: %d)",
00910                                                         rr_ptr->num_rr, ip4_buf, rr_ptr->herrno);
00911                                 }
00912 
00913                                 if (rr_ptr->herrno == TRY_AGAIN) {
00914                                         SPF_dns_rr_free(rr_ptr);
00915                                         SPF_FREE_LOOKUP_DATA();
00916                                         return DONE_TEMPERR(SPF_E_DNS_ERROR);
00917                                 }
00918 
00919 
00920                                 /* The maximum number of PTR records we will inspect. */
00921                                 max_ptr = rr_ptr->num_rr;
00922                                 max_exceeded = 0;
00923                                 if (max_ptr > spf_server->max_dns_ptr) {
00924                                         max_exceeded = 1;
00925                                         max_ptr = SPF_server_get_max_dns_ptr(spf_server);
00926                                 }
00927 
00928                                 for (i = 0; i < max_ptr; i++) {
00929                                         /* XXX MX has a 'continue' case here which should be hoisted. */
00930 
00931                                         rr_a = SPF_dns_lookup(resolver,
00932                                                         rr_ptr->rr[i]->ptr, ns_t_a, TRUE);
00933 
00934                                         if (spf_server->debug)
00935                                                 SPF_debugf( "%d:  found %d A records for %s  (herrno: %d)",
00936                                                                 i, rr_a->num_rr, rr_ptr->rr[i]->ptr, rr_a->herrno );
00937                                         if (rr_a->herrno == TRY_AGAIN) {
00938                                                 SPF_dns_rr_free(rr_ptr);
00939                                                 SPF_dns_rr_free(rr_a);
00940                                                 SPF_FREE_LOOKUP_DATA();
00941                                                 return DONE_TEMPERR( SPF_E_DNS_ERROR );
00942                                         }
00943 
00944                                         for (j = 0; j < rr_a->num_rr; j++) {
00945                                                 /* XXX MX has a 'continue' case here which should be hoisted. */
00946 
00947                                                 if (spf_server->debug) {
00948                                                         INET_NTOP(AF_INET, &rr_a->rr[j]->a.s_addr,
00949                                                                                         ip4_buf, sizeof(ip4_buf));
00950                                                         SPF_debugf("%d: %d:  found %s",
00951                                                                         i, j, ip4_buf);
00952                                                 }
00953 
00954                                                 if (rr_a->rr[j]->a.s_addr ==
00955                                                                                 spf_request->ipv4.s_addr) {
00956                                                         if (SPF_i_match_domain(spf_server,
00957                                                                                         rr_ptr->rr[i]->ptr, lookup)) {
00958                                                                 SPF_dns_rr_free(rr_ptr);
00959                                                                 SPF_dns_rr_free(rr_a);
00960                                                                 SPF_FREE_LOOKUP_DATA();
00961                                                                 return DONE_MECH(mech->prefix_type);
00962                                                         }
00963                                                 }
00964                                         }
00965                                         SPF_dns_rr_free(rr_a);
00966                                 }
00967                                 SPF_dns_rr_free(rr_ptr);
00968 
00969                                 if (max_exceeded) {
00970                                         SPF_FREE_LOOKUP_DATA();
00971                                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
00972                                 }
00973                         }
00974 
00975                         else if ( spf_request->client_ver == AF_INET6 ) {
00976                                 rr_ptr = SPF_dns_rlookup6(resolver,
00977                                                                 spf_request->ipv6, ns_t_ptr, TRUE);
00978 
00979                                 if ( spf_server->debug ) {
00980                                         INET_NTOP( AF_INET6, &spf_request->ipv6.s6_addr,
00981                                                                            ip6_buf, sizeof( ip6_buf ) );
00982                                         SPF_debugf( "found %d PTR records for %s  (herrno: %d)",
00983                                                         rr_ptr->num_rr, ip6_buf, rr_ptr->herrno );
00984                                 }
00985                                 if( rr_ptr->herrno == TRY_AGAIN ) {
00986                                         SPF_dns_rr_free(rr_ptr);
00987                                         SPF_FREE_LOOKUP_DATA();
00988                                         return DONE_TEMPERR( SPF_E_DNS_ERROR );
00989                                 }
00990 
00991 
00992                                 max_ptr = rr_ptr->num_rr;
00993                                 max_exceeded = 0;
00994                                 if (max_ptr > spf_server->max_dns_ptr) {
00995                                         max_ptr = SPF_server_get_max_dns_ptr(spf_server);
00996                                         max_exceeded = 1;
00997                                 }
00998 
00999                                 for (i = 0; i < max_ptr; i++) {
01000                                         /* XXX MX has a 'continue' case here which should be hoisted. */
01001 
01002                                         rr_aaaa = SPF_dns_lookup(resolver,
01003                                                         rr_ptr->rr[i]->ptr, ns_t_aaaa, TRUE);
01004 
01005                                         if ( spf_server->debug )
01006                                                 SPF_debugf("%d:  found %d AAAA records for %s  (herrno: %d)",
01007                                                                 i, rr_aaaa->num_rr, rr_ptr->rr[i]->ptr, rr_aaaa->herrno);
01008                                         if( rr_aaaa->herrno == TRY_AGAIN ) {
01009                                                 SPF_dns_rr_free(rr_ptr);
01010                                                 SPF_dns_rr_free(rr_aaaa);
01011                                                 SPF_FREE_LOOKUP_DATA();
01012                                                 return DONE_TEMPERR( SPF_E_DNS_ERROR );
01013                                         }
01014 
01015                                         for( j = 0; j < rr_aaaa->num_rr; j++ ) {
01016                                                 /* XXX MX has a 'continue' case here which should be hoisted. */
01017                                                 if ( spf_server->debug ) {
01018                                                         INET_NTOP(AF_INET6, &rr_aaaa->rr[j]->aaaa.s6_addr,
01019                                                                                         ip6_buf, sizeof(ip6_buf));
01020                                                         SPF_debugf( "%d: %d:  found %s",
01021                                                                         i, j, ip6_buf );
01022                                                 }
01023 
01024                                                 if (memcmp(&rr_aaaa->rr[j]->aaaa,
01025                                                                 &spf_request->ipv6,
01026                                                                 sizeof(spf_request->ipv6)) == 0) {
01027                                                         if (SPF_i_match_domain(spf_server,
01028                                                                                         rr_ptr->rr[i]->ptr, lookup)) {
01029                                                                 SPF_dns_rr_free( rr_ptr );
01030                                                                 SPF_dns_rr_free(rr_aaaa);
01031                                                                 SPF_FREE_LOOKUP_DATA();
01032                                                                 return DONE_MECH( mech->prefix_type );
01033                                                         }
01034                                                 }
01035                                         }
01036                                         SPF_dns_rr_free(rr_aaaa);
01037                                 }
01038                                 SPF_dns_rr_free(rr_ptr);
01039 
01040                                 if (max_exceeded) {
01041                                         SPF_FREE_LOOKUP_DATA();
01042                                         return DONE(SPF_RESULT_PERMERROR, SPF_REASON_NONE, SPF_E_BIG_DNS);
01043                                 }
01044                         }
01045 
01046 
01047                         break;
01048 
01049                 case MECH_INCLUDE:
01050                 case MECH_REDIRECT:
01051                         SPF_ADD_DNS_MECH();
01052 
01053                         err = SPF_record_expand_data(spf_server,
01054                                         spf_request, spf_response,
01055                                         SPF_mech_data(mech), SPF_mech_data_len(mech),
01056                                         &buf, &buf_len );
01057                         if ( err == SPF_E_NO_MEMORY ) {
01058                                 SPF_FREE_LOOKUP_DATA();
01059                                 return DONE_TEMPERR( err );
01060                         }
01061                         if ( err ) {
01062                                 SPF_FREE_LOOKUP_DATA();
01063                                 return DONE_PERMERR( err );
01064                         }
01065                         lookup = buf;
01066 
01067                         /* XXX Maintain a stack depth here. Limit at 10. */
01068                         if (strcmp(lookup, spf_request->cur_dom) == 0) {
01069                                 SPF_FREE_LOOKUP_DATA();
01070                                 return DONE_PERMERR( SPF_E_RECURSIVE );
01071                         }
01072 
01073                         /*
01074                          * get the (compiled) SPF record
01075                          */
01076 
01077                         spf_record_subr = NULL;
01078                         /* Remember to reset this. */
01079                         save_cur_dom = spf_request->cur_dom;
01080                         spf_request->cur_dom = lookup;
01081                         err = SPF_server_get_record(spf_server, spf_request,
01082                                                         spf_response, &spf_record_subr);
01083 
01084                         if ( spf_server->debug > 0 )
01085                                 SPF_debugf( "include/redirect:  got SPF record:  %s",
01086                                                 SPF_strerror( err ) );
01087 
01088                         if (err != SPF_E_SUCCESS) {
01089                                 spf_request->cur_dom = save_cur_dom;
01090                                 if (spf_record_subr)
01091                                         SPF_record_free(spf_record_subr);
01092                                 SPF_FREE_LOOKUP_DATA();
01093                                 if (err == SPF_E_DNS_ERROR)
01094                                         return DONE_TEMPERR( err );
01095                                 else
01096                                         return DONE_PERMERR( err );
01097                         }
01098 
01099                         SPF_ASSERT_NOTNULL(spf_record_subr);
01100 
01101                         /*
01102                          * If we are a redirect which is not within the scope
01103                          * of any include.
01104                          */
01105                         if (mech->mech_type == MECH_REDIRECT) {
01106                                 save_spf_response = NULL;
01107                                 if (spf_response->spf_record_exp == spf_record)
01108                                         spf_response->spf_record_exp = spf_record_subr;
01109                                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
01110                         }
01111                         else {
01112                                 save_spf_response = spf_response;
01113                                 spf_response = SPF_response_new(spf_request);
01114                                 if (! spf_response) {
01115                                         if (spf_record_subr)
01116                                                 SPF_record_free(spf_record_subr);
01117                                         SPF_FREE_LOOKUP_DATA();
01118                                         return DONE_TEMPERR(SPF_E_NO_MEMORY);
01119                                 }
01120                                 spf_response->spf_record_exp = spf_record;
01121                                 SPF_ASSERT_NOTNULL(spf_response->spf_record_exp);
01122                         }
01123                         /*
01124                          * find out whether this configuration passes
01125                          */
01126                         err = SPF_record_interpret(spf_record_subr,
01127                                                         spf_request, spf_response, depth + 1);
01128                         spf_request->cur_dom = save_cur_dom;
01129                         /* Now, if we were a redirect, the child called done()
01130                          * and used spf_record_exp. In that case, we need not
01131                          * worry that spf_record_subr is invalid after the free.
01132                          * If we were not a redirect, then spf_record_subr
01133                          * is still the record it was in the first place.
01134                          * Thus we do not need to reset it now. */
01135                         SPF_record_free(spf_record_subr);
01136                         spf_record_subr = NULL;
01137 
01138                         if ( spf_server->debug > 0 )
01139                                 SPF_debugf( "include/redirect:  executed SPF record:  %s  result: %s  reason: %s",
01140                                                 SPF_strerror( err ),
01141                                                 SPF_strresult( spf_response->result ),
01142                                                 SPF_strreason( spf_response->reason ) );
01143                         if (mech->mech_type == MECH_REDIRECT) {
01144                                 SPF_FREE_LOOKUP_DATA();
01145                                 return err;     /* One way or the other */
01146                         }
01147                         else { // if (spf_response->result != SPF_RESULT_INVALID) {
01148                                 /* Set everything up properly again. */
01149                                 spf_response_subr = spf_response;
01150                                 spf_response = save_spf_response;
01151                                 save_spf_response = NULL;
01152 
01153                                 /* Rewrite according to prefix of include */
01154                                 switch (SPF_response_result(spf_response_subr)) {
01155                                         case SPF_RESULT_PASS:
01156                                                 /* Pass */
01157                                                 SPF_FREE_LOOKUP_DATA();
01158                                                 SPF_response_free(spf_response_subr);
01159                                                 return DONE_MECH( mech->prefix_type );
01160 
01161                                         case SPF_RESULT_FAIL:
01162                                         case SPF_RESULT_SOFTFAIL:
01163                                         case SPF_RESULT_NEUTRAL:
01164                                                 /* No match */
01165                                                 SPF_response_free(spf_response_subr);
01166                                                 break;
01167 
01168                                         case SPF_RESULT_TEMPERROR:
01169                                                 /* Generate TempError */
01170                                                 err = SPF_response_errcode(spf_response_subr);
01171                                                 SPF_FREE_LOOKUP_DATA();
01172                                                 SPF_response_free(spf_response_subr);
01173                                                 return DONE_TEMPERR( err );
01174 
01175                                         case SPF_RESULT_NONE:
01176                                                 /* Generate PermError */
01177                                                 SPF_FREE_LOOKUP_DATA();
01178                                                 SPF_response_free(spf_response_subr);
01179                                                 return DONE_PERMERR(SPF_E_INCLUDE_RETURNED_NONE);
01180                                         case SPF_RESULT_PERMERROR:
01181                                         case SPF_RESULT_INVALID:
01182                                                 /* Generate PermError */
01183                                                 err = SPF_response_errcode(spf_response_subr);
01184                                                 SPF_FREE_LOOKUP_DATA();
01185                                                 SPF_response_free(spf_response_subr);
01186                                                 return DONE_PERMERR( err );
01187 
01188                                 }
01189 #if 0
01190                                 SPF_FREE_LOOKUP_DATA();
01191                                 return err;     /* The sub-interpret called done() */
01192 #endif
01193                         }
01194 
01195                         break;
01196 
01197                 case MECH_IP4:
01198                         memcpy(&addr4, SPF_mech_ip4_data(mech), sizeof(addr4));
01199                         if ( SPF_i_match_ip4( spf_server, spf_request, mech, addr4 ) ) {
01200                                 SPF_FREE_LOOKUP_DATA();
01201                                 return DONE_MECH( mech->prefix_type );
01202                         }
01203                         break;
01204 
01205                 case MECH_IP6:
01206                         memcpy(&addr6, SPF_mech_ip6_data(mech), sizeof(addr6));
01207                         if ( SPF_i_match_ip6( spf_server, spf_request, mech, addr6 ) ) {
01208                                 SPF_FREE_LOOKUP_DATA();
01209                                 return DONE_MECH( mech->prefix_type );
01210                         }
01211                         break;
01212 
01213                 case MECH_EXISTS:
01214                         SPF_ADD_DNS_MECH();
01215 
01216                         err = SPF_record_expand_data(spf_server,
01217                                                         spf_request, spf_response,
01218                                                         SPF_mech_data(mech),SPF_mech_data_len(mech),
01219                                                         &buf, &buf_len);
01220                         if (err != SPF_E_SUCCESS) {
01221                                 SPF_FREE_LOOKUP_DATA();
01222                                 return DONE_TEMPERR( err );
01223                         }
01224                         lookup = buf;
01225 
01226                         rr_a = SPF_dns_lookup(resolver, lookup, ns_t_a, FALSE );
01227 
01228                         if ( spf_server->debug )
01229                                 SPF_debugf( "found %d A records for %s  (herrno: %d)",
01230                                                 rr_a->num_rr, lookup, rr_a->herrno );
01231 
01232                         if( rr_a->herrno == TRY_AGAIN ) {
01233                                 SPF_dns_rr_free(rr_a);
01234                                 SPF_FREE_LOOKUP_DATA();
01235                                 return DONE_TEMPERR(SPF_E_DNS_ERROR);
01236                         }
01237                         if ( rr_a->num_rr > 0 ) {
01238                                 SPF_dns_rr_free(rr_a);
01239                                 SPF_FREE_LOOKUP_DATA();
01240                                 return DONE_MECH(mech->prefix_type);
01241                         }
01242 
01243                         SPF_dns_rr_free(rr_a);
01244                         break;
01245 
01246                 case MECH_ALL:
01247                         SPF_FREE_LOOKUP_DATA();
01248                         if (mech->prefix_type == PREFIX_UNKNOWN)
01249                                 return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
01250                         return DONE_MECH(mech->prefix_type);
01251                         break;
01252 
01253                 default:
01254                         SPF_FREE_LOOKUP_DATA();
01255                         return DONE_PERMERR(SPF_E_UNKNOWN_MECH);
01256                         break;
01257                 }
01258 
01259                 /*
01260                  * execute the local policy
01261                  */
01262 
01263                 if ( mech == local_policy ) {
01264                         err = SPF_record_interpret(spf_server->local_policy,
01265                                                         spf_request, spf_response, depth + 1);
01266 
01267                         if ( spf_server->debug > 0 )
01268                                 SPF_debugf( "local_policy:  executed SPF record:  %s  result: %s  reason: %s",
01269                                                         SPF_strerror( err ),
01270                                                         SPF_strresult( spf_response->result ),
01271                                                         SPF_strreason( spf_response->reason ) );
01272 
01273                         if (spf_response->result != SPF_RESULT_INVALID) {
01274                                 SPF_FREE_LOOKUP_DATA();
01275                                 return err;
01276                         }
01277                 }
01278 
01279                 mech = SPF_mech_next( mech );
01280         }
01281 
01282         SPF_FREE_LOOKUP_DATA();
01283         /* falling off the end is the same as ?all */
01284         return DONE( SPF_RESULT_NEUTRAL, SPF_REASON_DEFAULT, SPF_E_SUCCESS );
01285 }

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