libspf2  1.2.10
spf_server.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of either:
4  *
5  * a) The GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 2.1, or (at your option) any
7  * later version,
8  *
9  * OR
10  *
11  * b) The two-clause BSD license.
12  *
13  * These licenses can be found with the distribution in the file LICENSES
14  */
15 
16 #include "spf_sys_config.h"
17 
18 
19 #ifdef STDC_HEADERS
20 # include <stdio.h> /* stdin / stdout */
21 # include <stdlib.h> /* malloc / free */
22 # include <ctype.h> /* isupper / tolower */
23 #endif
24 
25 #ifdef HAVE_INTTYPES_H
26 #include <inttypes.h>
27 #endif
28 
29 #ifdef HAVE_NETDB_H
30 #include <netdb.h>
31 #endif
32 
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 
37 #ifdef HAVE_STRING_H
38 # include <string.h> /* strstr / strdup */
39 #else
40 # ifdef HAVE_STRINGS_H
41 # include <strings.h> /* strstr / strdup */
42 # endif
43 #endif
44 
45 #ifdef HAVE_NETDB_H
46 # include <netdb.h>
47 #endif
48 
49 #ifndef HOST_NAME_MAX
50 #define HOST_NAME_MAX 255
51 #endif
52 
53 
54 #include "spf.h"
55 #include "spf_response.h"
56 #include "spf_record.h"
57 #include "spf_server.h"
58 #include "spf_dns.h"
59 #include "spf_dns_resolv.h"
60 #include "spf_dns_cache.h"
61 #include "spf_dns_zone.h"
62 #include "spf_internal.h"
63 #include "spf_dns_internal.h"
64 
65 
66 __attribute__((warn_unused_result))
67 static SPF_errcode_t
68 SPF_server_set_rec_dom_ghbn(SPF_server_t *sp)
69 {
70  sp->rec_dom = malloc(HOST_NAME_MAX);
71  if (! sp->rec_dom)
72  return SPF_E_NO_MEMORY;
73 #ifdef _WIN32
74  gethostnameFQDN(sp->rec_dom, HOST_NAME_MAX);
75  return 0; /* XXX FIXME? */
76 #else
77  if (gethostname(sp->rec_dom, HOST_NAME_MAX) < 0)
78  /* XXX Error using strerror. */
79  return SPF_E_INTERNAL_ERROR;
80 #endif
81  return SPF_E_SUCCESS;
82 }
83 
84 static void
85 SPF_server_new_common_pre(SPF_server_t *sp, int debug)
86 {
87  SPF_errcode_t err;
88 
89  memset(sp, 0, sizeof(SPF_server_t));
90 
91  sp->max_dns_mech = SPF_MAX_DNS_MECH;
92  sp->max_dns_ptr = SPF_MAX_DNS_PTR;
93  sp->max_dns_mx = SPF_MAX_DNS_MX;
94  sp->debug = debug;
95 
96  err = SPF_server_set_rec_dom_ghbn(sp);
97  if (err != SPF_E_SUCCESS)
98  SPF_error("Failed to set rec_dom using gethostname()");
99 }
100 
101 static void
102 SPF_server_new_common_post(SPF_server_t *sp)
103 {
104  SPF_response_t *spf_response;
105  SPF_errcode_t err;
106 
107  spf_response = NULL;
109  &spf_response);
110  if (err != SPF_E_SUCCESS)
111  SPF_errorf("Error code %d compiling default explanation", err);
112  if (spf_response) {
113  /* XXX Print the errors?! */
114  if (SPF_response_messages(spf_response) > 0)
115  SPF_error("Response errors compiling default explanation");
116  SPF_response_free(spf_response);
117  }
118 
119  spf_response = NULL;
120  err = SPF_server_set_localpolicy(sp, "", 0, &spf_response);
121  if (err != SPF_E_SUCCESS)
122  SPF_errorf("Error code %d compiling default whitelist", err);
123  if (spf_response) {
124  /* XXX Print the errors?! */
125  if (SPF_response_messages(spf_response) > 0)
126  SPF_error("Response errors compiling default whitelist");
127  SPF_response_free(spf_response);
128  }
129 }
130 
131 SPF_server_t *
133 {
134  SPF_dns_server_t *dc_r;
135  SPF_dns_server_t *dc_c;
136  SPF_dns_server_t *dc_z;
137  SPF_server_t *sp;
138 
139  sp = (SPF_server_t *)malloc(sizeof(SPF_server_t));
140  if (! sp)
141  return sp;
142  SPF_server_new_common_pre(sp, debug);
143  sp->destroy_resolver = 1;
144 
145  switch (dnstype) {
146  case SPF_DNS_RESOLV:
147  dc_r = SPF_dns_resolv_new(NULL, NULL, debug);
148  if (dc_r == NULL)
149  SPF_error("Failed to create DNS resolver");
150  sp->resolver = dc_r;
151  break;
152 
153  case SPF_DNS_CACHE:
154  dc_r = SPF_dns_resolv_new(NULL, NULL, debug);
155  if (dc_r == NULL)
156  SPF_error("Failed to create DNS resolver");
157  dc_c = SPF_dns_cache_new(dc_r, NULL, debug, 8);
158  if (dc_c == NULL)
159  SPF_error("Failed to create DNS cache");
160  sp->resolver = dc_c;
161  break;
162 
163  case SPF_DNS_ZONE:
164  dc_z = SPF_dns_zone_new(NULL, NULL, debug);
165  if (dc_z == NULL)
166  SPF_error("Failed to create DNS zone");
167  sp->resolver = dc_z;
168  break;
169 
170  default:
171  SPF_errorf("Unknown DNS type %d", dnstype);
172  }
173 
174  SPF_server_new_common_post(sp);
175 
176  return sp;
177 }
178 
179 SPF_server_t *
180 SPF_server_new_dns(SPF_dns_server_t *dns, int debug)
181 {
182  SPF_server_t *sp;
183 
184  sp = (SPF_server_t *)malloc(sizeof(SPF_server_t));
185  if (! sp)
186  return sp;
187  SPF_server_new_common_pre(sp, debug);
188  sp->destroy_resolver = 0;
189  sp->resolver = dns;
190  SPF_server_new_common_post(sp);
191  return sp;
192 }
193 
199 void
200 SPF_server_free(SPF_server_t *sp)
201 {
202  if (sp->resolver && sp->destroy_resolver)
203  SPF_dns_free(sp->resolver);
204  if (sp->local_policy)
205  SPF_record_free(sp->local_policy);
206  if (sp->explanation)
207  SPF_macro_free(sp->explanation);
208  if (sp->rec_dom)
209  free(sp->rec_dom);
210  /* XXX TODO: Free other parts of the structure. */
211  free(sp);
212 }
213 
215 SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
216 {
217  if (sp->rec_dom)
218  free(sp->rec_dom);
219  if (dom == NULL)
220  return SPF_server_set_rec_dom_ghbn(sp);
221  sp->rec_dom = strdup(dom);
222  if (! sp->rec_dom)
223  return SPF_E_NO_MEMORY;
224  return SPF_E_SUCCESS;
225 }
226 
228 SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
229 {
230  sp->sanitize = sanitize;
231  return SPF_E_SUCCESS;
232 }
233 
235 SPF_server_set_explanation(SPF_server_t *sp, const char *exp,
236  SPF_response_t **spf_responsep)
237 {
238  SPF_macro_t *spf_macro = NULL;
239  SPF_errcode_t err;
240 
241  SPF_ASSERT_NOTNULL(exp);
242 
243  /* This is a hackish way to get the errors. */
244  if (! *spf_responsep) {
245  *spf_responsep = SPF_response_new(NULL);
246  if (! *spf_responsep)
247  return SPF_E_NO_MEMORY;
248  }
249 
250  err = SPF_record_compile_macro(sp, *spf_responsep, &spf_macro, exp);
251  if (err == SPF_E_SUCCESS) {
252  if (sp->explanation)
253  SPF_macro_free(sp->explanation);
254  sp->explanation = spf_macro;
255  }
256  else {
257  SPF_response_add_error(*spf_responsep, err,
258  "Failed to compile explanation '%s'", exp);
259  if (spf_macro)
260  SPF_macro_free(spf_macro);
261  }
262 
263  return err;
264 }
265 
267 SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy,
268  int use_default_whitelist,
269  SPF_response_t **spf_responsep)
270 {
271  SPF_record_t *spf_record = NULL;
272  SPF_errcode_t err;
273  char *record;
274  size_t len;
275 
276  SPF_ASSERT_NOTNULL(policy);
277 
278  /* This is a hackish way to get the errors. */
279  if (! *spf_responsep) {
280  *spf_responsep = SPF_response_new(NULL);
281  if (! *spf_responsep)
282  return SPF_E_NO_MEMORY;
283  }
284 
285  len = sizeof(SPF_VER_STR) + strlen(policy) + 20;
286  if (use_default_whitelist)
287  len += sizeof(SPF_DEFAULT_WHITELIST);
288  record = malloc(len);
289  if (! record)
290  return SPF_E_NO_MEMORY;
291  if (use_default_whitelist)
292  snprintf(record, len, "%s %s %s",
294  else
295  snprintf(record, len, "%s %s", SPF_VER_STR, policy);
296 
297  err = SPF_record_compile(sp, *spf_responsep, &spf_record, record);
298  if (err == SPF_E_SUCCESS) {
299  if (sp->local_policy)
300  SPF_record_free(sp->local_policy);
301  sp->local_policy = spf_record;
302  }
303  else {
304  SPF_response_add_error(*spf_responsep, err,
305  "Failed to compile local policy '%s'", policy);
306  if (spf_record)
307  SPF_record_free(spf_record);
308  }
309 
310  free(record);
311 
312  return err;
313 }
314 
316 SPF_server_get_record(SPF_server_t *spf_server,
317  SPF_request_t *spf_request,
318  SPF_response_t *spf_response,
319  SPF_record_t **spf_recordp)
320 {
321  SPF_dns_server_t *resolver;
322  SPF_dns_rr_t *rr_txt;
323  SPF_errcode_t err;
324  SPF_dns_stat_t herrno;
325  const char *domain;
326  ns_type rr_type;
327  int num_found;
328  int idx_found;
329  int i;
330 
331 
332  SPF_ASSERT_NOTNULL(spf_server);
333  SPF_ASSERT_NOTNULL(spf_request);
334  SPF_ASSERT_NOTNULL(spf_server->resolver);
335  SPF_ASSERT_NOTNULL(spf_recordp);
336 
337  domain = spf_request->cur_dom;
338  SPF_ASSERT_NOTNULL(domain);
339 
340  *spf_recordp = NULL;
341 
342  resolver = spf_server->resolver;
343 
344  if (resolver->get_spf)
345  return resolver->get_spf(spf_server, spf_request,
346  spf_response, spf_recordp);
347 
348  /* I am VERY, VERY sorry about the gotos. Shevek. */
349  rr_type = ns_t_spf;
350 retry:
351  rr_txt = SPF_dns_lookup(resolver, domain, rr_type, TRUE);
352 
353  switch (rr_txt->herrno) {
354  case HOST_NOT_FOUND:
355  if (spf_server->debug > 0)
356  SPF_debugf("get_record(%s): HOST_NOT_FOUND", domain);
357  SPF_dns_rr_free(rr_txt);
358  if (rr_type == ns_t_spf) {
359  rr_type = ns_t_txt;
360  goto retry;
361  }
362  spf_response->result = SPF_RESULT_NONE;
363  spf_response->reason = SPF_REASON_FAILURE;
364  return SPF_response_add_error(spf_response, SPF_E_NOT_SPF,
365  "Host '%s' not found.", domain);
366  // break;
367 
368  case NO_DATA:
369  if (spf_server->debug > 0)
370  SPF_debugf("get_record(%s): NO_DATA", domain);
371  SPF_dns_rr_free(rr_txt);
372  if (rr_type == ns_t_spf) {
373  rr_type = ns_t_txt;
374  goto retry;
375  }
376  spf_response->result = SPF_RESULT_NONE;
377  spf_response->reason = SPF_REASON_FAILURE;
378  return SPF_response_add_error(spf_response, SPF_E_NOT_SPF,
379  "No DNS data for '%s'.", domain);
380  // break;
381 
382  case TRY_AGAIN:
383  if (spf_server->debug > 0)
384  SPF_debugf("get_record(%s): TRY_AGAIN", domain);
385  SPF_dns_rr_free(rr_txt);
386  if (rr_type == ns_t_spf) {
387  rr_type = ns_t_txt;
388  goto retry;
389  }
390  spf_response->result = SPF_RESULT_TEMPERROR;
391  spf_response->reason = SPF_REASON_FAILURE;
392  return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR,
393  "Temporary DNS failure for '%s'.", domain);
394  // break;
395 
396  case NO_RECOVERY:
397  if (spf_server->debug > 0)
398  SPF_debugf("get_record(%s): NO_RECOVERY", domain);
399  SPF_dns_rr_free(rr_txt);
400  if (rr_type == ns_t_spf) {
401  rr_type = ns_t_txt;
402  goto retry;
403  }
404  spf_response->result = SPF_RESULT_PERMERROR;
405  spf_response->reason = SPF_REASON_FAILURE;
406  return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR,
407  "Unrecoverable DNS failure for '%s'.", domain);
408  // break;
409 
410  case NETDB_SUCCESS:
411  if (spf_server->debug > 0)
412  SPF_debugf("get_record(%s): NETDB_SUCCESS", domain);
413  break;
414 
415  default:
416  if (spf_server->debug > 0)
417  SPF_debugf("get_record(%s): UNKNOWN_ERROR", domain);
418  herrno = rr_txt->herrno; // Avoid use-after-free
419  SPF_dns_rr_free(rr_txt);
420  if (rr_type == ns_t_spf) {
421  rr_type = ns_t_txt;
422  goto retry;
423  }
424  return SPF_response_add_error(spf_response, SPF_E_DNS_ERROR,
425  "Unknown DNS failure for '%s': %d.",
426  domain, herrno);
427  // break;
428  }
429 
430  if (rr_txt->num_rr == 0) {
431  SPF_dns_rr_free(rr_txt);
432  if (rr_type == ns_t_spf) {
433  rr_type = ns_t_txt;
434  goto retry;
435  }
436  return SPF_response_add_error(spf_response, SPF_E_NOT_SPF,
437  "No TXT records returned from DNS lookup for '%s'",
438  domain);
439  }
440 
441  /* Actually, this could never be used uninitialised anyway. */
442  idx_found = 0;
443 
444  /* check for multiple SPF records */
445  num_found = 0;
446  for (i = 0; i < rr_txt->num_rr; i++) {
447  /*
448  if (spf_server->debug > 1)
449  SPF_debugf("Comparing '%s' with '%s'",
450  SPF_VER_STR " ", rr_txt->rr[i]->txt);
451  */
452  if (strncasecmp(rr_txt->rr[i]->txt,
453  SPF_VER_STR, sizeof(SPF_VER_STR) - 1) == 0) {
454  char e = rr_txt->rr[i]->txt[sizeof(SPF_VER_STR) - 1];
455  if (e == ' ' || e == '\0') {
456  if (spf_server->debug > 0)
457  SPF_debugf("found SPF record: %s", rr_txt->rr[i]->txt);
458  num_found++;
459  idx_found = i;
460  }
461  }
462  }
463 
464  if (num_found == 0) {
465  SPF_dns_rr_free(rr_txt);
466  if (rr_type == ns_t_spf) {
467  rr_type = ns_t_txt;
468  goto retry;
469  }
470  spf_response->result = SPF_RESULT_NONE;
471  spf_response->reason = SPF_REASON_FAILURE;
472  return SPF_response_add_error(spf_response, SPF_E_NOT_SPF,
473  "No SPF records for '%s'", domain);
474  }
475  if (num_found > 1) {
476  SPF_dns_rr_free(rr_txt);
477  // rfc4408 requires permerror here.
478  /* XXX This could be refactored with SPF_i_done. */
479  spf_response->result = SPF_RESULT_PERMERROR;
480  spf_response->reason = SPF_REASON_FAILURE;
481  return SPF_response_add_error(spf_response, SPF_E_MULTIPLE_RECORDS,
482  "Multiple SPF records for '%s'", domain);
483  }
484 
485  /* try to compile the SPF record */
486  err = SPF_record_compile(spf_server,
487  spf_response, spf_recordp,
488  rr_txt->rr[idx_found]->txt );
489  SPF_dns_rr_free(rr_txt);
490 
491  /* FIXME: support multiple versions */
492  if (err != SPF_E_SUCCESS)
493  return SPF_response_add_error(spf_response, SPF_E_NOT_SPF,
494  "Failed to compile SPF record for '%s'", domain);
495 
496  return SPF_E_SUCCESS;
497 }
498 
504 #define SPF_ACCESS_INT(f) \
505  SPF_errcode_t SPF_server_set_ ## f(SPF_server_t *s, int n) { \
506  s->f = n; return SPF_E_SUCCESS; \
507  } \
508  int SPF_server_get_ ## f(SPF_server_t *s) { \
509  return s->f; \
510  }
511 
517 SPF_ACCESS_INT(max_dns_mech);
518 SPF_ACCESS_INT(max_dns_ptr);
519 SPF_ACCESS_INT(max_dns_mx);
#define SPF_VER_STR
Definition: spf.h:35
#define SPF_DEFAULT_WHITELIST
Definition: spf.h:63
#define SPF_DEFAULT_EXP
Definition: spf.h:67
#define ns_t_spf
Definition: spf_dns.h:89
#define NO_DATA
Definition: spf_dns.h:106
#define NO_RECOVERY
Definition: spf_dns.h:105
#define HOST_NOT_FOUND
Definition: spf_dns.h:103
#define NETDB_SUCCESS
Definition: spf_dns.h:102
void SPF_dns_free(SPF_dns_server_t *spf_dns_server)
Definition: spf_dns.c:116
int SPF_dns_stat_t
Definition: spf_dns.h:108
#define TRY_AGAIN
Definition: spf_dns.h:104
SPF_dns_rr_t * SPF_dns_lookup(SPF_dns_server_t *spf_dns_server, const char *domain, ns_type rr_type, int should_cache)
Definition: spf_dns.c:133
SPF_dns_server_t * SPF_dns_cache_new(SPF_dns_server_t *layer_below, const char *name, int debug, int cache_bits)
SPF_dns_server_t * SPF_dns_resolv_new(SPF_dns_server_t *layer_below, const char *name, int debug)
void SPF_dns_rr_free(SPF_dns_rr_t *spfrr)
Definition: spf_dns_rr.c:114
A local DNS zone layer.
SPF_dns_server_t * SPF_dns_zone_new(SPF_dns_server_t *layer_below, const char *name, int debug)
Definition: spf_dns_zone.c:337
#define NULL
Definition: spf_internal.h:28
#define SPF_MAX_DNS_MECH
Definition: spf_internal.h:55
#define SPF_MAX_DNS_MX
Definition: spf_internal.h:69
#define TRUE
Definition: spf_internal.h:23
#define SPF_MAX_DNS_PTR
Definition: spf_internal.h:62
#define SPF_errorf
Definition: spf_log.h:77
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
#define SPF_error(errmsg)
Definition: spf_log.h:40
#define SPF_debugf
Definition: spf_log.h:80
void SPF_macro_free(SPF_macro_t *mac)
Definition: spf_record.c:73
SPF_errcode_t SPF_record_compile(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_record_t **spf_recordp, const char *record)
Definition: spf_compile.c:1180
void SPF_record_free(SPF_record_t *rp)
Definition: spf_record.c:63
SPF_errcode_t SPF_record_compile_macro(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_macro_t **spf_macrop, const char *record)
Definition: spf_compile.c:1499
@ SPF_RESULT_PERMERROR
Definition: spf_response.h:88
@ SPF_RESULT_NONE
Definition: spf_response.h:86
@ SPF_RESULT_TEMPERROR
Definition: spf_response.h:87
SPF_errcode_t SPF_response_add_error(SPF_response_t *rp, SPF_errcode_t code, const char *format,...)
Definition: spf_response.c:256
SPF_response_t * SPF_response_new(SPF_request_t *spf_request)
Definition: spf_response.c:37
void SPF_response_free(SPF_response_t *rp)
Definition: spf_response.c:53
int SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
@ SPF_REASON_FAILURE
Definition: spf_response.h:102
SPF_errcode_t
Definition: spf_response.h:119
@ SPF_E_DNS_ERROR
Definition: spf_response.h:146
@ SPF_E_INTERNAL_ERROR
Definition: spf_response.h:130
@ SPF_E_NO_MEMORY
Definition: spf_response.h:121
@ SPF_E_NOT_SPF
Definition: spf_response.h:122
@ SPF_E_SUCCESS
Definition: spf_response.h:120
@ SPF_E_MULTIPLE_RECORDS
Definition: spf_response.h:153
SPF_server_dnstype_t
Definition: spf_server.h:72
@ SPF_DNS_RESOLV
Definition: spf_server.h:73
@ SPF_DNS_CACHE
Definition: spf_server.h:73
@ SPF_DNS_ZONE
Definition: spf_server.h:73
ns_type
Definition: arpa_nameser.h:300
@ ns_t_txt
Definition: arpa_nameser.h:317
int strncasecmp(const char *s1, const char *s2, size_t n)
Definition: strncasecmp.c:11
#define debug
#define SPF_ACCESS_INT(f)
Definition: spf_server.c:504
__attribute__((warn_unused_result))
Definition: spf_server.c:66
SPF_server_t * SPF_server_new_dns(SPF_dns_server_t *dns, int debug)
Definition: spf_server.c:180
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
Definition: spf_server.c:235
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
Definition: spf_server.c:132
void SPF_server_free(SPF_server_t *sp)
Definition: spf_server.c:200
SPF_errcode_t SPF_server_get_record(SPF_server_t *spf_server, SPF_request_t *spf_request, SPF_response_t *spf_response, SPF_record_t **spf_recordp)
Definition: spf_server.c:316
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
Definition: spf_server.c:228
SPF_errcode_t SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy, int use_default_whitelist, SPF_response_t **spf_responsep)
Definition: spf_server.c:267
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
Definition: spf_server.c:215
#define HOST_NAME_MAX
Definition: spf_server.c:50
SPF_dns_rr_data_t ** rr
Definition: spf_dns_rr.h:60
SPF_dns_stat_t herrno
Definition: spf_dns_rr.h:66