libspf2 1.2.10
|
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 }