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 00019 #ifdef STDC_HEADERS 00020 # include <stdio.h> /* stdin / stdout */ 00021 # include <stdlib.h> /* malloc / free */ 00022 # include <ctype.h> /* isupper / tolower */ 00023 #endif 00024 00025 #ifdef HAVE_INTTYPES_H 00026 #include <inttypes.h> 00027 #endif 00028 00029 #ifdef HAVE_NETDB_H 00030 #include <netdb.h> 00031 #endif 00032 00033 #ifdef HAVE_UNISTD_H 00034 #include <unistd.h> 00035 #endif 00036 00037 #ifdef HAVE_STRING_H 00038 # include <string.h> /* strstr / strdup */ 00039 #else 00040 # ifdef HAVE_STRINGS_H 00041 # include <strings.h> /* strstr / strdup */ 00042 # endif 00043 #endif 00044 00045 #ifdef HAVE_NETDB_H 00046 # include <netdb.h> 00047 #endif 00048 00049 #ifndef HOST_NAME_MAX 00050 #define HOST_NAME_MAX 255 00051 #endif 00052 00053 00054 #include "spf.h" 00055 #include "spf_response.h" 00056 #include "spf_record.h" 00057 #include "spf_server.h" 00058 #include "spf_dns.h" 00059 #include "spf_dns_resolv.h" 00060 #include "spf_dns_cache.h" 00061 #include "spf_dns_zone.h" 00062 #include "spf_internal.h" 00063 #include "spf_dns_internal.h" 00064 00065 00066 __attribute__((warn_unused_result)) 00067 static SPF_errcode_t 00068 SPF_server_set_rec_dom_ghbn(SPF_server_t *sp) 00069 { 00070 sp->rec_dom = malloc(HOST_NAME_MAX); 00071 if (! sp->rec_dom) 00072 return SPF_E_NO_MEMORY; 00073 #ifdef _WIN32 00074 gethostnameFQDN(sp->rec_dom, HOST_NAME_MAX); 00075 return 0; /* XXX FIXME? */ 00076 #else 00077 if (gethostname(sp->rec_dom, HOST_NAME_MAX) < 0) 00078 /* XXX Error using strerror. */ 00079 return SPF_E_INTERNAL_ERROR; 00080 #endif 00081 return SPF_E_SUCCESS; 00082 } 00083 00084 static void 00085 SPF_server_new_common_pre(SPF_server_t *sp, int debug) 00086 { 00087 SPF_errcode_t err; 00088 00089 memset(sp, 0, sizeof(SPF_server_t)); 00090 00091 sp->max_dns_mech = SPF_MAX_DNS_MECH; 00092 sp->max_dns_ptr = SPF_MAX_DNS_PTR; 00093 sp->max_dns_mx = SPF_MAX_DNS_MX; 00094 sp->debug = debug; 00095 00096 err = SPF_server_set_rec_dom_ghbn(sp); 00097 if (err != SPF_E_SUCCESS) 00098 SPF_error("Failed to set rec_dom using gethostname()"); 00099 } 00100 00101 static void 00102 SPF_server_new_common_post(SPF_server_t *sp) 00103 { 00104 SPF_response_t *spf_response; 00105 SPF_errcode_t err; 00106 00107 spf_response = NULL; 00108 err = SPF_server_set_explanation(sp, SPF_DEFAULT_EXP, 00109 &spf_response); 00110 if (err != SPF_E_SUCCESS) 00111 SPF_errorf("Error code %d compiling default explanation", err); 00112 if (spf_response) { 00113 /* XXX Print the errors?! */ 00114 if (SPF_response_messages(spf_response) > 0) 00115 SPF_error("Response errors compiling default explanation"); 00116 SPF_response_free(spf_response); 00117 } 00118 00119 spf_response = NULL; 00120 err = SPF_server_set_localpolicy(sp, "", 0, &spf_response); 00121 if (err != SPF_E_SUCCESS) 00122 SPF_errorf("Error code %d compiling default whitelist", err); 00123 if (spf_response) { 00124 /* XXX Print the errors?! */ 00125 if (SPF_response_messages(spf_response) > 0) 00126 SPF_error("Response errors compiling default whitelist"); 00127 SPF_response_free(spf_response); 00128 } 00129 } 00130 00131 SPF_server_t * 00132 SPF_server_new(SPF_server_dnstype_t dnstype, int debug) 00133 { 00134 SPF_dns_server_t *dc_r; 00135 SPF_dns_server_t *dc_c; 00136 SPF_dns_server_t *dc_z; 00137 SPF_server_t *sp; 00138 00139 sp = (SPF_server_t *)malloc(sizeof(SPF_server_t)); 00140 if (! sp) 00141 return sp; 00142 SPF_server_new_common_pre(sp, debug); 00143 sp->destroy_resolver = 1; 00144 00145 switch (dnstype) { 00146 case SPF_DNS_RESOLV: 00147 dc_r = SPF_dns_resolv_new(NULL, NULL, debug); 00148 if (dc_r == NULL) 00149 SPF_error("Failed to create DNS resolver"); 00150 sp->resolver = dc_r; 00151 break; 00152 00153 case SPF_DNS_CACHE: 00154 dc_r = SPF_dns_resolv_new(NULL, NULL, debug); 00155 if (dc_r == NULL) 00156 SPF_error("Failed to create DNS resolver"); 00157 dc_c = SPF_dns_cache_new(dc_r, NULL, debug, 8); 00158 if (dc_c == NULL) 00159 SPF_error("Failed to create DNS cache"); 00160 sp->resolver = dc_c; 00161 break; 00162 00163 case SPF_DNS_ZONE: 00164 dc_z = SPF_dns_zone_new(NULL, NULL, debug); 00165 if (dc_z == NULL) 00166 SPF_error("Failed to create DNS zone"); 00167 sp->resolver = dc_z; 00168 break; 00169 00170 default: 00171 SPF_errorf("Unknown DNS type %d", dnstype); 00172 } 00173 00174 SPF_server_new_common_post(sp); 00175 00176 return sp; 00177 } 00178 00179 SPF_server_t * 00180 SPF_server_new_dns(SPF_dns_server_t *dns, int debug) 00181 { 00182 SPF_server_t *sp; 00183 00184 sp = (SPF_server_t *)malloc(sizeof(SPF_server_t)); 00185 if (! sp) 00186 return sp; 00187 SPF_server_new_common_pre(sp, debug); 00188 sp->destroy_resolver = 0; 00189 sp->resolver = dns; 00190 SPF_server_new_common_post(sp); 00191 return sp; 00192 } 00193 00199 void 00200 SPF_server_free(SPF_server_t *sp) 00201 { 00202 if (sp->resolver && sp->destroy_resolver) 00203 SPF_dns_free(sp->resolver); 00204 if (sp->local_policy) 00205 SPF_record_free(sp->local_policy); 00206 if (sp->explanation) 00207 SPF_macro_free(sp->explanation); 00208 if (sp->rec_dom) 00209 free(sp->rec_dom); 00210 /* XXX TODO: Free other parts of the structure. */ 00211 free(sp); 00212 } 00213 00214 SPF_errcode_t 00215 SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom) 00216 { 00217 if (sp->rec_dom) 00218 free(sp->rec_dom); 00219 if (dom == NULL) 00220 return SPF_server_set_rec_dom_ghbn(sp); 00221 sp->rec_dom = strdup(dom); 00222 if (! sp->rec_dom) 00223 return SPF_E_NO_MEMORY; 00224 return SPF_E_SUCCESS; 00225 } 00226 00227 SPF_errcode_t 00228 SPF_server_set_sanitize(SPF_server_t *sp, int sanitize) 00229 { 00230 sp->sanitize = sanitize; 00231 return SPF_E_SUCCESS; 00232 } 00233 00234 SPF_errcode_t 00235 SPF_server_set_explanation(SPF_server_t *sp, const char *exp, 00236 SPF_response_t **spf_responsep) 00237 { 00238 SPF_macro_t *spf_macro = NULL; 00239 SPF_errcode_t err; 00240 00241 SPF_ASSERT_NOTNULL(exp); 00242 00243 /* This is a hackish way to get the errors. */ 00244 if (! *spf_responsep) { 00245 *spf_responsep = SPF_response_new(NULL); 00246 if (! *spf_responsep) 00247 return SPF_E_NO_MEMORY; 00248 } 00249 00250 err = SPF_record_compile_macro(sp, *spf_responsep, &spf_macro, exp); 00251 if (err == SPF_E_SUCCESS) { 00252 if (sp->explanation) 00253 SPF_macro_free(sp->explanation); 00254 sp->explanation = spf_macro; 00255 } 00256 else { 00257 SPF_response_add_error(*spf_responsep, err, 00258 "Failed to compile explanation '%s'", exp); 00259 if (spf_macro) 00260 SPF_macro_free(spf_macro); 00261 } 00262 00263 return err; 00264 } 00265 00266 SPF_errcode_t 00267 SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy, 00268 int use_default_whitelist, 00269 SPF_response_t **spf_responsep) 00270 { 00271 SPF_record_t *spf_record = NULL; 00272 SPF_errcode_t err; 00273 char *record; 00274 size_t len; 00275 00276 SPF_ASSERT_NOTNULL(policy); 00277 00278 /* This is a hackish way to get the errors. */ 00279 if (! *spf_responsep) { 00280 *spf_responsep = SPF_response_new(NULL); 00281 if (! *spf_responsep) 00282 return SPF_E_NO_MEMORY; 00283 } 00284 00285 len = sizeof(SPF_VER_STR) + strlen(policy) + 20; 00286 if (use_default_whitelist) 00287 len += sizeof(SPF_DEFAULT_WHITELIST); 00288 record = malloc(len); 00289 if (! record) 00290 return SPF_E_NO_MEMORY; 00291 if (use_default_whitelist) 00292 snprintf(record, len, "%s %s %s", 00293 SPF_VER_STR, policy, SPF_DEFAULT_WHITELIST); 00294 else 00295 snprintf(record, len, "%s %s", SPF_VER_STR, policy); 00296 00297 err = SPF_record_compile(sp, *spf_responsep, &spf_record, record); 00298 if (err == SPF_E_SUCCESS) { 00299 if (sp->local_policy) 00300 SPF_record_free(sp->local_policy); 00301 sp->local_policy = spf_record; 00302 } 00303 else { 00304 SPF_response_add_error(*spf_responsep, err, 00305 "Failed to compile local policy '%s'", policy); 00306 if (spf_record) 00307 SPF_record_free(spf_record); 00308 } 00309 00310 free(record); 00311 00312 return err; 00313 } 00314 00315 SPF_errcode_t 00316 SPF_server_get_record(SPF_server_t *spf_server, 00317 SPF_request_t *spf_request, 00318 SPF_response_t *spf_response, 00319 SPF_record_t **spf_recordp) 00320 { 00321 SPF_dns_server_t *resolver; 00322 SPF_dns_rr_t *rr_txt; 00323 SPF_errcode_t err; 00324 SPF_dns_stat_t herrno; 00325 const char *domain; 00326 ns_type rr_type; 00327 int num_found; 00328 int idx_found; 00329 int i; 00330 00331 00332 SPF_ASSERT_NOTNULL(spf_server); 00333 SPF_ASSERT_NOTNULL(spf_request); 00334 SPF_ASSERT_NOTNULL(spf_server->resolver); 00335 SPF_ASSERT_NOTNULL(spf_recordp); 00336 00337 domain = spf_request->cur_dom; 00338 SPF_ASSERT_NOTNULL(domain); 00339 00340 *spf_recordp = NULL; 00341 00342 resolver = spf_server->resolver; 00343 00344 if (resolver->get_spf) 00345 return resolver->get_spf(spf_server, spf_request, 00346 spf_response, spf_recordp); 00347 00348 /* I am VERY, VERY sorry about the gotos. Shevek. */ 00349 rr_type = ns_t_spf; 00350 retry: 00351 rr_txt = SPF_dns_lookup(resolver, domain, rr_type, TRUE); 00352 00353 switch (rr_txt->herrno) { 00354 case HOST_NOT_FOUND: 00355 if (spf_server->debug > 0) 00356 SPF_debugf("get_record(%s): HOST_NOT_FOUND", domain); 00357 SPF_dns_rr_free(rr_txt); 00358 if (rr_type == ns_t_spf) { 00359 rr_type = ns_t_txt; 00360 goto retry; 00361 } 00362 spf_response->result = SPF_RESULT_NONE; 00363 spf_response->reason = SPF_REASON_FAILURE; 00364 return SPF_response_add_error(spf_response, SPF_E_NOT_SPF, 00365 "Host '%s' not found.", domain); 00366 // break; 00367 00368 case NO_DATA: 00369 if (spf_server->debug > 0) 00370 SPF_debugf("get_record(%s): NO_DATA", domain); 00371 SPF_dns_rr_free(rr_txt); 00372 if (rr_type == ns_t_spf) { 00373 rr_type = ns_t_txt; 00374 goto retry; 00375 } 00376 spf_response->result = SPF_RESULT_NONE; 00377 spf_response->reason = SPF_REASON_FAILURE; 00378 return SPF_response_add_error(spf_response, SPF_E_NOT_SPF, 00379 "No DNS data for '%s'.", domain); 00380 // break; 00381 00382 case TRY_AGAIN: 00383 if (spf_server->debug > 0) 00384 SPF_debugf("get_record(%s): TRY_AGAIN", domain); 00385 SPF_dns_rr_free(rr_txt); 00386 return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR, 00387 "Temporary DNS failure for '%s'.", domain); 00388 // break; 00389 00390 case NO_RECOVERY: 00391 if (spf_server->debug > 0) 00392 SPF_debugf("get_record(%s): NO_RECOERY", domain); 00393 SPF_dns_rr_free(rr_txt); 00394 return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR, 00395 "Unrecoverable DNS failure for '%s'.", domain); 00396 // break; 00397 00398 case NETDB_SUCCESS: 00399 if (spf_server->debug > 0) 00400 SPF_debugf("get_record(%s): NETDB_SUCCESS", domain); 00401 break; 00402 00403 default: 00404 if (spf_server->debug > 0) 00405 SPF_debugf("get_record(%s): UNKNOWN_ERROR", domain); 00406 herrno = rr_txt->herrno; // Avoid use-after-free 00407 SPF_dns_rr_free(rr_txt); 00408 return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR, 00409 "Unknown DNS failure for '%s': %d.", 00410 domain, herrno); 00411 // break; 00412 } 00413 00414 if (rr_txt->num_rr == 0) { 00415 SPF_dns_rr_free(rr_txt); 00416 if (rr_type == ns_t_spf) { 00417 rr_type = ns_t_txt; 00418 goto retry; 00419 } 00420 return SPF_response_add_error(spf_response, SPF_E_NOT_SPF, 00421 "No TXT records returned from DNS lookup for '%s'", 00422 domain); 00423 } 00424 00425 /* Actually, this could never be used uninitialised anyway. */ 00426 idx_found = 0; 00427 00428 /* check for multiple SPF records */ 00429 num_found = 0; 00430 for (i = 0; i < rr_txt->num_rr; i++) { 00431 /* 00432 if (spf_server->debug > 1) 00433 SPF_debugf("Comparing '%s' with '%s'", 00434 SPF_VER_STR " ", rr_txt->rr[i]->txt); 00435 */ 00436 if (strncasecmp(rr_txt->rr[i]->txt, 00437 SPF_VER_STR, sizeof(SPF_VER_STR) - 1) == 0) { 00438 char e = rr_txt->rr[i]->txt[sizeof(SPF_VER_STR) - 1]; 00439 if (e == ' ' || e == '\0') { 00440 if (spf_server->debug > 0) 00441 SPF_debugf("found SPF record: %s", rr_txt->rr[i]->txt); 00442 num_found++; 00443 idx_found = i; 00444 } 00445 } 00446 } 00447 00448 if (num_found == 0) { 00449 SPF_dns_rr_free(rr_txt); 00450 if (rr_type == ns_t_spf) { 00451 rr_type = ns_t_txt; 00452 goto retry; 00453 } 00454 spf_response->result = SPF_RESULT_NONE; 00455 spf_response->reason = SPF_REASON_FAILURE; 00456 return SPF_response_add_error(spf_response, SPF_E_NOT_SPF, 00457 "No SPF records for '%s'", domain); 00458 } 00459 if (num_found > 1) { 00460 SPF_dns_rr_free(rr_txt); 00461 // rfc4408 requires permerror here. 00462 /* XXX This could be refactored with SPF_i_done. */ 00463 spf_response->result = SPF_RESULT_PERMERROR; 00464 spf_response->reason = SPF_REASON_FAILURE; 00465 return SPF_response_add_error(spf_response, SPF_E_MULTIPLE_RECORDS, 00466 "Multiple SPF records for '%s'", domain); 00467 } 00468 00469 /* try to compile the SPF record */ 00470 err = SPF_record_compile(spf_server, 00471 spf_response, spf_recordp, 00472 rr_txt->rr[idx_found]->txt ); 00473 SPF_dns_rr_free(rr_txt); 00474 00475 /* FIXME: support multiple versions */ 00476 if (err != SPF_E_SUCCESS) 00477 return SPF_response_add_error(spf_response, SPF_E_NOT_SPF, 00478 "Failed to compile SPF record for '%s'", domain); 00479 00480 return SPF_E_SUCCESS; 00481 } 00482 00488 #define SPF_ACCESS_INT(f) \ 00489 SPF_errcode_t SPF_server_set_ ## f(SPF_server_t *s, int n) { \ 00490 s->f = n; return SPF_E_SUCCESS; \ 00491 } \ 00492 int SPF_server_get_ ## f(SPF_server_t *s) { \ 00493 return s->f; \ 00494 } 00495 00501 SPF_ACCESS_INT(max_dns_mech); 00502 SPF_ACCESS_INT(max_dns_ptr); 00503 SPF_ACCESS_INT(max_dns_mx);