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 <stdlib.h> /* malloc / free */ 00020 # include <stdio.h> /* stdin / stdout */ 00021 #endif 00022 00023 #ifdef HAVE_NETDB_H 00024 #include <netdb.h> 00025 #endif 00026 00027 #ifdef HAVE_STRING_H 00028 # include <string.h> /* strstr / strdup */ 00029 #else 00030 # ifdef HAVE_STRINGS_H 00031 # include <strings.h> /* strstr / strdup */ 00032 # endif 00033 #endif 00034 00035 00036 #include "spf.h" 00037 #include "spf_dns.h" 00038 #include "spf_internal.h" 00039 #include "spf_dns_internal.h" 00040 00041 00042 /* This never happens. We get SPF_DEFAULT_EXP instead. 00043 * This is a panic response which must not contain macros. */ 00044 #define SPF_LAME_EXP "SPF failure: no explanation available" 00045 00046 static SPF_errcode_t 00047 SPF_server_get_default_explanation(SPF_server_t *spf_server, 00048 SPF_request_t *spf_request, 00049 SPF_response_t *spf_response, 00050 char **bufp, size_t *buflenp) 00051 { 00052 SPF_errcode_t err; 00053 SPF_macro_t *spf_macro; 00054 00055 spf_macro = spf_server->explanation; 00056 if (spf_macro != NULL) { 00057 err = SPF_record_expand_data(spf_server, 00058 spf_request, spf_response, 00059 SPF_macro_data(spf_macro), spf_macro->macro_len, 00060 bufp, buflenp); 00061 return err; 00062 } 00063 else { 00064 size_t len = sizeof(SPF_LAME_EXP) + 1; 00065 if (*buflenp < len) { 00066 char *tmp = realloc(*bufp, len); 00067 if (tmp == NULL) 00068 return SPF_E_NO_MEMORY; 00069 *bufp = tmp; 00070 *buflenp = len; 00071 } 00072 strcpy(*bufp, SPF_LAME_EXP); 00073 return SPF_E_SUCCESS; 00074 } 00075 } 00076 00077 #define RETURN_DEFAULT_EXP() do { \ 00078 return SPF_server_get_default_explanation(spf_server, \ 00079 spf_request, spf_response, bufp, buflenp); \ 00080 } while(0) 00081 00082 SPF_errcode_t 00083 SPF_request_get_exp(SPF_server_t *spf_server, 00084 SPF_request_t *spf_request, 00085 SPF_response_t *spf_response, 00086 SPF_record_t *spf_record, 00087 char **bufp, size_t *buflenp) 00088 { 00089 SPF_macro_t *spf_macro; 00090 SPF_dns_server_t *resolver; 00091 SPF_dns_rr_t *rr_txt; 00092 SPF_errcode_t err; 00093 const char *domain; 00094 00095 00096 /* 00097 * There are lots of places to look for the explanation message, 00098 * some require DNS lookups, some don't. 00099 */ 00100 00101 SPF_ASSERT_NOTNULL(spf_server); 00102 SPF_ASSERT_NOTNULL(spf_request); 00103 SPF_ASSERT_NOTNULL(spf_response); 00104 SPF_ASSERT_NOTNULL(spf_record); 00105 SPF_ASSERT_NOTNULL(bufp); 00106 SPF_ASSERT_NOTNULL(buflenp); 00107 00108 domain = spf_request->cur_dom; 00109 00110 if ( domain == NULL ) 00111 return SPF_response_add_warn(spf_response, SPF_E_NOT_CONFIG, 00112 "Could not identify current domain for explanation"); 00113 00114 /* 00115 * start looking... check spfid for exp-text= 00116 */ 00117 00118 err = SPF_record_find_mod_value(spf_server, spf_request, 00119 spf_response, spf_record, 00120 SPF_EXP_MOD_NAME, bufp, buflenp); 00121 if (err == SPF_E_SUCCESS) 00122 return err; 00123 00124 00125 /* 00126 * still looking... check the spfid for exp= 00127 */ 00128 00129 err = SPF_record_find_mod_value(spf_server, spf_request, 00130 spf_response, spf_record, 00131 "exp", bufp, buflenp ); 00132 if (err != SPF_E_SUCCESS) { 00133 /* 00134 * still looking... try to return default exp from spfcid 00135 */ 00136 RETURN_DEFAULT_EXP(); 00137 } 00138 00139 if (*bufp == NULL || (*bufp)[0] == '\0') { 00140 /* 00141 * still looking... try to return default exp from spfcid 00142 */ 00143 SPF_response_add_warn(spf_response, SPF_E_NOT_SPF, 00144 "Explanation is blank!"); 00145 RETURN_DEFAULT_EXP(); 00146 } 00147 00148 00149 /* 00150 * still looking... try doing a DNS lookup on the exp= name 00151 */ 00152 00153 resolver = spf_server->resolver; 00154 00155 if (resolver->get_exp) 00156 return resolver->get_exp(spf_server, *bufp, bufp, buflenp); 00157 00158 rr_txt = SPF_dns_lookup(resolver, *bufp, ns_t_txt, TRUE); 00159 if (rr_txt == NULL) { 00160 SPF_dns_rr_free(rr_txt); 00161 RETURN_DEFAULT_EXP(); 00162 } 00163 00164 switch (rr_txt->herrno) { 00165 case HOST_NOT_FOUND: 00166 case NO_DATA: 00167 SPF_dns_rr_free(rr_txt); 00168 RETURN_DEFAULT_EXP(); 00169 break; 00170 00171 case TRY_AGAIN: 00172 SPF_dns_rr_free(rr_txt); 00173 RETURN_DEFAULT_EXP(); 00174 break; 00175 00176 case NETDB_SUCCESS: 00177 break; 00178 00179 default: 00180 SPF_warning("Unknown DNS lookup error code"); 00181 SPF_dns_rr_free(rr_txt); 00182 RETURN_DEFAULT_EXP(); 00183 break; 00184 } 00185 00186 if (rr_txt->num_rr == 0) { 00187 SPF_response_add_warn(spf_response, SPF_E_NOT_SPF, 00188 "No TXT records returned from DNS lookup"); 00189 RETURN_DEFAULT_EXP(); 00190 } 00191 00192 00193 /* 00194 * still looking... try compiling this TXT record 00195 */ 00196 00197 /* FIXME we are supposed to concatenate the TXT records */ 00198 00199 /* FIXME: If this generates any errors, demote them to warnings. */ 00200 spf_macro = NULL; 00201 err = SPF_record_compile_macro(spf_server, spf_response, &spf_macro, 00202 rr_txt->rr[0]->txt); 00203 if (err != SPF_E_SUCCESS) { 00204 if (spf_macro) 00205 SPF_macro_free(spf_macro); 00206 SPF_dns_rr_free(rr_txt); 00207 RETURN_DEFAULT_EXP(); 00208 } 00209 00210 err = SPF_record_expand_data(spf_server, 00211 spf_request, spf_response, 00212 SPF_macro_data(spf_macro), spf_macro->macro_len, 00213 bufp, buflenp); 00214 SPF_macro_free(spf_macro); 00215 SPF_dns_rr_free(rr_txt); 00216 00217 return err; 00218 }