00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "spf_sys_config.h"
00017
00018 #ifdef STDC_HEADERS
00019 # include <stdio.h>
00020 # include <stdlib.h>
00021 #endif
00022
00023 #ifdef HAVE_STRING_H
00024 # include <string.h>
00025 #else
00026 # ifdef HAVE_STRINGS_H
00027 # include <strings.h>
00028 # endif
00029 #endif
00030
00031
00032 #include "spf.h"
00033 #include "spf_dns.h"
00034 #include "spf_request.h"
00035 #include "spf_internal.h"
00036
00037 #include <idn2.h>
00038
00039 #define SPF_FREE(x) \
00040 do { if (x) free(x); (x) = NULL; } while(0)
00041
00042 SPF_request_t *
00043 SPF_request_new(SPF_server_t *spf_server)
00044 {
00045 SPF_request_t *sr;
00046
00047 sr = (SPF_request_t *)malloc(sizeof(SPF_request_t));
00048 if (! sr)
00049 return sr;
00050 memset(sr, 0, sizeof(SPF_request_t));
00051
00052 sr->spf_server = spf_server;
00053 sr->client_ver = AF_UNSPEC;
00054 sr->ipv4.s_addr = htonl(INADDR_ANY);
00055 sr->ipv6 = in6addr_any;
00056
00057 return sr;
00058 }
00059
00060 void
00061 SPF_request_free(SPF_request_t *sr)
00062 {
00063 SPF_ASSERT_NOTNULL(sr);
00064 SPF_FREE(sr->client_dom);
00065 SPF_FREE(sr->helo_dom);
00066 SPF_FREE(sr->env_from);
00067 SPF_FREE(sr->env_from_lp);
00068 SPF_FREE(sr->env_from_dp);
00069 free(sr);
00070 }
00071
00072 SPF_errcode_t
00073 SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
00074 {
00075 if (sr->client_dom) {
00076 free(sr->client_dom);
00077 sr->client_dom = NULL;
00078 }
00079 sr->client_ver = AF_INET;
00080 sr->ipv4 = addr;
00081 return SPF_E_SUCCESS;
00082 }
00083
00084 SPF_errcode_t
00085 SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
00086 {
00087 if (sr->client_dom) {
00088 free(sr->client_dom);
00089 sr->client_dom = NULL;
00090 }
00091 sr->client_ver = AF_INET6;
00092 sr->ipv6 = addr;
00093 return SPF_E_SUCCESS;
00094 }
00095
00096 SPF_errcode_t
00097 SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
00098 {
00099 struct in_addr addr;
00100 if (astr == NULL)
00101 astr = "0.0.0.0";
00102 if (inet_pton(AF_INET, astr, &addr) <= 0)
00103 return SPF_E_INVALID_IP4;
00104 return SPF_request_set_ipv4(sr, addr);
00105 }
00106
00107 SPF_errcode_t
00108 SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
00109 {
00110 struct in6_addr addr;
00111 if (astr == NULL)
00112 astr = "::";
00113 if (inet_pton(AF_INET6, astr, &addr) <= 0)
00114 return SPF_E_INVALID_IP6;
00115 return SPF_request_set_ipv6(sr, addr);
00116 }
00117
00118
00119 static int
00120 is_eai(const char *dom)
00121 {
00122 char *s = (char *)dom;
00123
00124 while(*s)
00125 if(*s++ & 0x80) return 1;
00126 return 0;
00127 }
00128
00129 SPF_errcode_t
00130 SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
00131 {
00132 SPF_ASSERT_NOTNULL(dom);
00133 SPF_FREE(sr->helo_dom);
00134 if(is_eai(dom)) {
00135 int i;
00136 char *adom;
00137
00138 i = idn2_to_ascii_8z(dom, &adom, 0);
00139 if(i == IDN2_OK) {
00140 sr->helo_dom = adom;
00141 } else {
00142 sr->helo_dom = 0;
00143 return SPF_E_INVALID_CHAR;
00144 }
00145 } else
00146 sr->helo_dom = strdup(dom);
00147 if (! sr->helo_dom)
00148 return SPF_E_NO_MEMORY;
00149
00150 if (sr->env_from == NULL)
00151 return SPF_request_set_env_from(sr, sr->helo_dom);
00152 return SPF_E_SUCCESS;
00153 }
00154
00155 const char *
00156 SPF_request_get_rec_dom(SPF_request_t *sr)
00157 {
00158 SPF_server_t *spf_server;
00159 spf_server = sr->spf_server;
00160 return spf_server->rec_dom;
00161 }
00162
00163 int
00164 SPF_request_set_env_from(SPF_request_t *sr, const char *from)
00165 {
00166 char *cp;
00167 size_t len;
00168
00169 SPF_ASSERT_NOTNULL(from);
00170 SPF_FREE(sr->env_from);
00171 SPF_FREE(sr->env_from_lp);
00172 SPF_FREE(sr->env_from_dp);
00173
00174 if (*from == '\0' && sr->helo_dom != NULL)
00175 from = sr->helo_dom;
00176 cp = strrchr(from, '@');
00177 if (cp && (cp != from)) {
00178 sr->env_from = strdup(from);
00179 if (! sr->env_from)
00180 return SPF_E_NO_MEMORY;
00181
00182 len = cp - from;
00183 sr->env_from_lp = malloc(len + 1);
00184 if (!sr->env_from_lp) {
00185 SPF_FREE(sr->env_from);
00186 return SPF_E_NO_MEMORY;
00187 }
00188 strncpy(sr->env_from_lp, from, len);
00189 sr->env_from_lp[len] = '\0';
00190 if(is_eai(cp+1)) {
00191 int i;
00192 char *adom;
00193
00194 i = idn2_to_ascii_8z(cp+1, &adom, 0);
00195 if(i == IDN2_OK) {
00196 sr->env_from_dp = adom;
00197 } else {
00198 SPF_FREE(sr->env_from);
00199 SPF_FREE(sr->env_from_lp);
00200 return SPF_E_INVALID_CHAR;
00201 }
00202 } else
00203 sr->env_from_dp = strdup(cp + 1);
00204 if (!sr->env_from_dp) {
00205 SPF_FREE(sr->env_from);
00206 SPF_FREE(sr->env_from_lp);
00207 return SPF_E_NO_MEMORY;
00208 }
00209 }
00210 else {
00211 if (cp == from) from++;
00212 if(is_eai(from)) {
00213 int i;
00214 char *adom;
00215
00216 i = idn2_to_ascii_8z(cp+1, &adom, 0);
00217 if(i == IDN2_OK) {
00218 from = adom;
00219 } else
00220 return SPF_E_INVALID_CHAR;
00221 }
00222 len = sizeof("postmaster@") + strlen(from);
00223 sr->env_from = malloc(len + 1);
00224 if (! sr->env_from)
00225 return SPF_E_NO_MEMORY;
00226 sprintf(sr->env_from, "postmaster@%s", from);
00227 sr->env_from_lp = strdup("postmaster");
00228 if (!sr->env_from_lp) {
00229 SPF_FREE(sr->env_from);
00230 return SPF_E_NO_MEMORY;
00231 }
00232 sr->env_from_dp = strdup(from);
00233 if (!sr->env_from_dp) {
00234 SPF_FREE(sr->env_from);
00235 SPF_FREE(sr->env_from_lp);
00236 return SPF_E_NO_MEMORY;
00237 }
00238 }
00239
00240 return 0;
00241 }
00242
00243 const char *
00244 SPF_request_get_client_dom(SPF_request_t *sr)
00245 {
00246 SPF_server_t *spf_server;
00247
00248 SPF_ASSERT_NOTNULL(sr);
00249 spf_server = sr->spf_server;
00250 SPF_ASSERT_NOTNULL(spf_server);
00251
00252 if (sr->client_dom == NULL) {
00253 sr->client_dom = SPF_dns_get_client_dom(spf_server->resolver,
00254 sr);
00255 }
00256 return sr->client_dom;
00257 }
00258
00259 int
00260 SPF_request_is_loopback(SPF_request_t *sr)
00261 {
00262 if (sr->client_ver == AF_INET) {
00263 if ((ntohl(sr->ipv4.s_addr) & IN_CLASSA_NET) ==
00264 (IN_LOOPBACKNET << 24)) {
00265 return TRUE;
00266 }
00267 }
00268 else if (sr->client_ver == AF_INET6) {
00269 if (IN6_IS_ADDR_LOOPBACK(&sr->ipv6))
00270 return TRUE;
00271 }
00272 return FALSE;
00273 }
00274
00275 static SPF_errcode_t
00276 SPF_request_prepare(SPF_request_t *sr)
00277 {
00278 if (sr->use_helo)
00279 sr->cur_dom = sr->helo_dom;
00280 else
00281 sr->cur_dom = sr->env_from_dp;
00282 return SPF_E_SUCCESS;
00283 }
00284
00288 static SPF_errcode_t
00289 SPF_request_query_record(SPF_request_t *spf_request,
00290 SPF_response_t *spf_response,
00291 SPF_record_t *spf_record,
00292 SPF_errcode_t err)
00293 {
00294 if (err != SPF_E_SUCCESS) {
00295 if (spf_record)
00296 SPF_record_free(spf_record);
00297 SPF_i_done(spf_response, spf_response->result, spf_response->reason, spf_response->err);
00298 return err;
00299 }
00300
00301 if (SPF_response_errors(spf_response) > 0)
00302 SPF_infof("Warning: %d errors in response, "
00303 "but no error code. Evaluating.",
00304 SPF_response_errors(spf_response));
00305
00306 spf_response->spf_record_exp = spf_record;
00307 err = SPF_record_interpret(spf_record,
00308 spf_request, spf_response, 0);
00309 SPF_record_free(spf_record);
00310 spf_response->spf_record_exp = NULL;
00311
00312 return err;
00313 }
00314
00318 SPF_errcode_t
00319 SPF_request_query_mailfrom(SPF_request_t *spf_request,
00320 SPF_response_t **spf_responsep)
00321 {
00322 SPF_server_t *spf_server;
00323 SPF_record_t *spf_record;
00324 SPF_errcode_t err;
00325
00326 SPF_ASSERT_NOTNULL(spf_request);
00327 spf_server = spf_request->spf_server;
00328 SPF_ASSERT_NOTNULL(spf_server);
00329
00330 *spf_responsep = SPF_response_new(spf_request);
00331 if (! *spf_responsep)
00332 return SPF_E_NO_MEMORY;
00333
00334
00335 if (SPF_request_is_loopback(spf_request))
00336 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00337 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00338
00339 SPF_request_prepare(spf_request);
00340
00341 err = SPF_server_get_record(spf_server, spf_request,
00342 *spf_responsep, &spf_record);
00343 return SPF_request_query_record(spf_request, *spf_responsep,
00344 spf_record, err);
00345 }
00346
00347
00348 SPF_errcode_t
00349 SPF_request_query_fallback(SPF_request_t *spf_request,
00350 SPF_response_t **spf_responsep,
00351 const char *record)
00352 {
00353 SPF_server_t *spf_server;
00354 SPF_record_t *spf_record;
00355 SPF_errcode_t err;
00356
00357 SPF_ASSERT_NOTNULL(spf_request);
00358 spf_server = spf_request->spf_server;
00359 SPF_ASSERT_NOTNULL(spf_server);
00360
00361 *spf_responsep = SPF_response_new(spf_request);
00362 if (! *spf_responsep)
00363 return SPF_E_NO_MEMORY;
00364
00365
00366 if (SPF_request_is_loopback(spf_request))
00367 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00368 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00369
00370 SPF_request_prepare(spf_request);
00371
00372 err = SPF_record_compile(spf_server,
00373 *spf_responsep, &spf_record,
00374 record);
00375 return SPF_request_query_record(spf_request, *spf_responsep,
00376 spf_record, err);
00377 }
00378
00387
00388 SPF_errcode_t
00389 SPF_request_query_rcptto(SPF_request_t *spf_request,
00390 SPF_response_t **spf_responsep,
00391 const char *rcpt_to)
00392 {
00393 SPF_server_t *spf_server;
00394 SPF_record_t *spf_record;
00395 SPF_errcode_t err;
00396 const char *rcpt_to_dom;
00397 char *record;
00398 char *eai_dom = NULL;
00399 size_t len;
00400
00401 SPF_ASSERT_NOTNULL(spf_request);
00402 spf_server = spf_request->spf_server;
00403 SPF_ASSERT_NOTNULL(spf_server);
00404
00405 *spf_responsep = SPF_response_new(spf_request);
00406 if (! *spf_responsep)
00407 return SPF_E_NO_MEMORY;
00408
00409
00410 if (SPF_request_is_loopback(spf_request))
00411 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
00412 SPF_REASON_LOCALHOST, SPF_E_SUCCESS);
00413
00414 rcpt_to_dom = strchr(rcpt_to, '@');
00415 if (rcpt_to_dom == NULL)
00416 rcpt_to_dom = rcpt_to;
00417 else
00418 rcpt_to_dom++;
00419 if(is_eai(rcpt_to_dom)) {
00420 int i;
00421
00422 i = idn2_to_ascii_8z(rcpt_to_dom, &eai_dom, 0);
00423 if(i == IDN2_OK) {
00424 spf_request->cur_dom = eai_dom;
00425 } else
00426 return SPF_E_INVALID_CHAR;
00427 } else
00428 spf_request->cur_dom = rcpt_to_dom;
00429
00430 len = sizeof(SPF_VER_STR) + 64 + strlen(rcpt_to_dom);
00431 record = malloc(len);
00432 if (! record)
00433 return SPF_E_NO_MEMORY;
00434 snprintf(record, len, SPF_VER_STR " mx:%s", rcpt_to_dom);
00435 err = SPF_record_compile(spf_server,
00436 *spf_responsep, &spf_record,
00437 record);
00438 free(record);
00439 if(eai_dom) free(eai_dom);
00440 return SPF_request_query_record(spf_request, *spf_responsep,
00441 spf_record, err);
00442 }