libspf2  1.2.10
spf_request.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 #ifdef STDC_HEADERS
19 # include <stdio.h> /* stdin / stdout */
20 # include <stdlib.h> /* malloc / free */
21 #endif
22 
23 #ifdef HAVE_STRING_H
24 # include <string.h> /* strstr / strdup */
25 #else
26 # ifdef HAVE_STRINGS_H
27 # include <strings.h> /* strstr / strdup */
28 # endif
29 #endif
30 
31 
32 #include "spf.h"
33 #include "spf_dns.h"
34 #include "spf_request.h"
35 #include "spf_internal.h"
36 
37 #include <idn2.h>
38 
39 #define SPF_FREE(x) \
40  do { if (x) free(x); (x) = NULL; } while(0)
41 
42 SPF_request_t *
43 SPF_request_new(SPF_server_t *spf_server)
44 {
45  SPF_request_t *sr;
46 
47  sr = (SPF_request_t *)malloc(sizeof(SPF_request_t));
48  if (! sr)
49  return sr;
50  memset(sr, 0, sizeof(SPF_request_t));
51 
52  sr->spf_server = spf_server;
53  sr->client_ver = AF_UNSPEC;
54  sr->ipv4.s_addr = htonl(INADDR_ANY);
55  sr->ipv6 = in6addr_any;
56 
57  return sr;
58 }
59 
60 void
61 SPF_request_free(SPF_request_t *sr)
62 {
64  SPF_FREE(sr->client_dom);
65  SPF_FREE(sr->helo_dom);
66  SPF_FREE(sr->env_from);
67  SPF_FREE(sr->env_from_lp);
68  SPF_FREE(sr->env_from_dp);
69  free(sr);
70 }
71 
73 SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
74 {
75  if (sr->client_dom) {
76  free(sr->client_dom);
77  sr->client_dom = NULL;
78  }
79  sr->client_ver = AF_INET;
80  sr->ipv4 = addr;
81  return SPF_E_SUCCESS;
82 }
83 
85 SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
86 {
87  if (sr->client_dom) {
88  free(sr->client_dom);
89  sr->client_dom = NULL;
90  }
91  sr->client_ver = AF_INET6;
92  sr->ipv6 = addr;
93  return SPF_E_SUCCESS;
94 }
95 
97 SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
98 {
99  struct in_addr addr;
100  if (astr == NULL)
101  astr = "0.0.0.0";
102  if (inet_pton(AF_INET, astr, &addr) <= 0)
103  return SPF_E_INVALID_IP4;
104  return SPF_request_set_ipv4(sr, addr);
105 }
106 
108 SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
109 {
110  struct in6_addr addr;
111  if (astr == NULL)
112  astr = "::";
113  if (inet_pton(AF_INET6, astr, &addr) <= 0)
114  return SPF_E_INVALID_IP6;
115  return SPF_request_set_ipv6(sr, addr);
116 }
117 
118 /* is a string an EAI address with UTF-8 ? */
119 static int
120  is_eai(const char *dom)
121 {
122  char *s = (char *)dom;
123 
124  while(*s)
125  if(*s++ & 0x80) return 1;
126  return 0;
127 }
128 
130 SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
131 {
132  SPF_ASSERT_NOTNULL(dom);
133  SPF_FREE(sr->helo_dom);
134  if(is_eai(dom)) { /* turn U-labels in helo into A-labels */
135  int i;
136  char *adom;
137 
138  i = idn2_to_ascii_8z(dom, &adom, 0);
139  if(i == IDN2_OK) {
140  sr->helo_dom = adom;
141  } else {
142  sr->helo_dom = 0;
143  return SPF_E_INVALID_CHAR;
144  }
145  } else
146  sr->helo_dom = strdup(dom);
147  if (! sr->helo_dom)
148  return SPF_E_NO_MEMORY;
149  /* set cur_dom and env_from? */
150  if (sr->env_from == NULL)
151  return SPF_request_set_env_from(sr, sr->helo_dom);
152  return SPF_E_SUCCESS;
153 }
154 
155 const char *
156 SPF_request_get_rec_dom(SPF_request_t *sr)
157 {
158  SPF_server_t *spf_server;
159  spf_server = sr->spf_server;
160  return spf_server->rec_dom;
161 }
162 
163 int
164 SPF_request_set_env_from(SPF_request_t *sr, const char *from)
165 {
166  char *cp;
167  size_t len;
168 
169  SPF_ASSERT_NOTNULL(from);
170  SPF_FREE(sr->env_from);
171  SPF_FREE(sr->env_from_lp);
172  SPF_FREE(sr->env_from_dp);
173 
174  if (*from == '\0' && sr->helo_dom != NULL)
175  from = sr->helo_dom;
176  cp = strrchr(from, '@');
177  if (cp && (cp != from)) {
178  sr->env_from = strdup(from);
179  if (! sr->env_from)
180  return SPF_E_NO_MEMORY;
181 
182  len = cp - from;
183  sr->env_from_lp = malloc(len + 1);
184  if (!sr->env_from_lp) {
185  SPF_FREE(sr->env_from);
186  return SPF_E_NO_MEMORY;
187  }
188  strncpy(sr->env_from_lp, from, len);
189  sr->env_from_lp[len] = '\0';
190  if(is_eai(cp+1)) {
191  int i;
192  char *adom;
193 
194  i = idn2_to_ascii_8z(cp+1, &adom, 0);
195  if(i == IDN2_OK) {
196  sr->env_from_dp = adom;
197  } else {
198  SPF_FREE(sr->env_from);
199  SPF_FREE(sr->env_from_lp);
200  return SPF_E_INVALID_CHAR;
201  }
202  } else
203  sr->env_from_dp = strdup(cp + 1);
204  if (!sr->env_from_dp) {
205  SPF_FREE(sr->env_from);
206  SPF_FREE(sr->env_from_lp);
207  return SPF_E_NO_MEMORY;
208  }
209  }
210  else {
211  if (cp == from) from++; /* "@domain.example" */
212  if(is_eai(from)) {
213  int i;
214  char *adom;
215 
216  i = idn2_to_ascii_8z(cp+1, &adom, 0);
217  if(i == IDN2_OK) {
218  from = adom;
219  } else
220  return SPF_E_INVALID_CHAR;
221  }
222  len = sizeof("postmaster@") + strlen(from);
223  sr->env_from = malloc(len + 1); /* sizeof("") == 1? */
224  if (! sr->env_from)
225  return SPF_E_NO_MEMORY;
226  sprintf(sr->env_from, "postmaster@%s", from);
227  sr->env_from_lp = strdup("postmaster");
228  if (!sr->env_from_lp) {
229  SPF_FREE(sr->env_from);
230  return SPF_E_NO_MEMORY;
231  }
232  sr->env_from_dp = strdup(from);
233  if (!sr->env_from_dp) {
234  SPF_FREE(sr->env_from);
235  SPF_FREE(sr->env_from_lp);
236  return SPF_E_NO_MEMORY;
237  }
238  }
239 
240  return 0; // SPF_E_SUCCESS
241 }
242 
243 const char *
244 SPF_request_get_client_dom(SPF_request_t *sr)
245 {
246  SPF_server_t *spf_server;
247 
248  SPF_ASSERT_NOTNULL(sr);
249  spf_server = sr->spf_server;
250  SPF_ASSERT_NOTNULL(spf_server);
251 
252  if (sr->client_dom == NULL) {
253  sr->client_dom = SPF_dns_get_client_dom(spf_server->resolver,
254  sr);
255  }
256  return sr->client_dom;
257 }
258 
259 int
260 SPF_request_is_loopback(SPF_request_t *sr)
261 {
262  if (sr->client_ver == AF_INET) {
263  if ((ntohl(sr->ipv4.s_addr) & IN_CLASSA_NET) ==
264  (IN_LOOPBACKNET << 24)) {
265  return TRUE;
266  }
267  }
268  else if (sr->client_ver == AF_INET6) {
269  if (IN6_IS_ADDR_LOOPBACK(&sr->ipv6))
270  return TRUE;
271  }
272  return FALSE;
273 }
274 
275 static SPF_errcode_t
276 SPF_request_prepare(SPF_request_t *sr)
277 {
278  if (sr->use_helo)
279  sr->cur_dom = sr->helo_dom;
280  else
281  sr->cur_dom = sr->env_from_dp;
282  return SPF_E_SUCCESS;
283 }
284 
288 static SPF_errcode_t
289 SPF_request_query_record(SPF_request_t *spf_request,
290  SPF_response_t *spf_response,
291  SPF_record_t *spf_record,
292  SPF_errcode_t err)
293 {
294  if (err != SPF_E_SUCCESS) {
295  if (spf_record)
296  SPF_record_free(spf_record);
297  SPF_i_done(spf_response, spf_response->result, spf_response->reason, spf_response->err);
298  return err;
299  }
300  /* Now, in theory, SPF_response_errors(spf_response) == 0 */
301  if (SPF_response_errors(spf_response) > 0)
302  SPF_infof("Warning: %d errors in response, "
303  "but no error code. Evaluating.",
304  SPF_response_errors(spf_response));
305  /* If we get here, spf_record better not be NULL */
306  spf_response->spf_record_exp = spf_record;
307  err = SPF_record_interpret(spf_record,
308  spf_request, spf_response, 0);
309  SPF_record_free(spf_record);
310  spf_response->spf_record_exp = NULL;
311 
312  return err;
313 }
314 
319 SPF_request_query_mailfrom(SPF_request_t *spf_request,
320  SPF_response_t **spf_responsep)
321 {
322  SPF_server_t *spf_server;
323  SPF_record_t *spf_record;
324  SPF_errcode_t err;
325 
326  SPF_ASSERT_NOTNULL(spf_request);
327  spf_server = spf_request->spf_server;
328  SPF_ASSERT_NOTNULL(spf_server);
329 
330  *spf_responsep = SPF_response_new(spf_request);
331  if (! *spf_responsep)
332  return SPF_E_NO_MEMORY;
333 
334  /* Give localhost a free ride */
335  if (SPF_request_is_loopback(spf_request))
336  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
338 
339  SPF_request_prepare(spf_request);
340 
341  err = SPF_server_get_record(spf_server, spf_request,
342  *spf_responsep, &spf_record);
343  return SPF_request_query_record(spf_request, *spf_responsep,
344  spf_record, err);
345 }
346 
347 /* This interface isn't finalised. */
349 SPF_request_query_fallback(SPF_request_t *spf_request,
350  SPF_response_t **spf_responsep,
351  const char *record)
352 {
353  SPF_server_t *spf_server;
354  SPF_record_t *spf_record;
355  SPF_errcode_t err;
356 
357  SPF_ASSERT_NOTNULL(spf_request);
358  spf_server = spf_request->spf_server;
359  SPF_ASSERT_NOTNULL(spf_server);
360 
361  *spf_responsep = SPF_response_new(spf_request);
362  if (! *spf_responsep)
363  return SPF_E_NO_MEMORY;
364 
365  /* Give localhost a free ride */
366  if (SPF_request_is_loopback(spf_request))
367  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
369 
370  SPF_request_prepare(spf_request);
371 
372  err = SPF_record_compile(spf_server,
373  *spf_responsep, &spf_record,
374  record);
375  return SPF_request_query_record(spf_request, *spf_responsep,
376  spf_record, err);
377 }
378 
387 /* FIXME: Check the implementation of this. */
389 SPF_request_query_rcptto(SPF_request_t *spf_request,
390  SPF_response_t **spf_responsep,
391  const char *rcpt_to)
392 {
393  SPF_server_t *spf_server;
394  SPF_record_t *spf_record;
395  SPF_errcode_t err;
396  const char *rcpt_to_dom;
397  char *record;
398  char *eai_dom = NULL;
399  size_t len;
400 
401  SPF_ASSERT_NOTNULL(spf_request);
402  spf_server = spf_request->spf_server;
403  SPF_ASSERT_NOTNULL(spf_server);
404 
405  *spf_responsep = SPF_response_new(spf_request);
406  if (! *spf_responsep)
407  return SPF_E_NO_MEMORY;
408 
409  /* Give localhost a free ride */
410  if (SPF_request_is_loopback(spf_request))
411  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
413 
414  rcpt_to_dom = strchr(rcpt_to, '@');
415  if (rcpt_to_dom == NULL)
416  rcpt_to_dom = rcpt_to;
417  else
418  rcpt_to_dom++;
419  if(is_eai(rcpt_to_dom)) {
420  int i;
421 
422  i = idn2_to_ascii_8z(rcpt_to_dom, &eai_dom, 0);
423  if(i == IDN2_OK) {
424  spf_request->cur_dom = eai_dom;
425  } else
426  return SPF_E_INVALID_CHAR;
427  } else
428  spf_request->cur_dom = rcpt_to_dom;
429 
430  len = sizeof(SPF_VER_STR) + 64 + strlen(rcpt_to_dom);
431  record = malloc(len);
432  if (! record)
433  return SPF_E_NO_MEMORY;
434  snprintf(record, len, SPF_VER_STR " mx:%s", rcpt_to_dom);
435  err = SPF_record_compile(spf_server,
436  *spf_responsep, &spf_record,
437  record);
438  free(record);
439  if(eai_dom) free(eai_dom);
440  return SPF_request_query_record(spf_request, *spf_responsep,
441  spf_record, err);
442 }
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
SPF_response_t * SPF_response_new(SPF_request_t *spf_request)
Definition: spf_response.c:37
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:108
#define TRUE
Definition: spf_internal.h:23
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
SPF_errcode_t SPF_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
Definition: spf_request.c:349
SPF_errcode_t SPF_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
Definition: spf_request.c:389
char * SPF_dns_get_client_dom(SPF_dns_server_t *spf_dns_server, SPF_request_t *sr)
Definition: spf_dns.c:206
#define SPF_FREE(x)
Definition: spf_request.c:39
size_t len
Definition: memcmp.c:10
SPF_errcode_t
Definition: spf_response.h:118
const char * SPF_request_get_client_dom(SPF_request_t *sr)
Definition: spf_request.c:244
void SPF_record_free(SPF_record_t *rp)
Definition: spf_record.c:63
int SPF_request_is_loopback(SPF_request_t *sr)
Definition: spf_request.c:260
#define NULL
Definition: spf_internal.h:28
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
Definition: spf_request.c:130
#define SPF_infof
Definition: spf_log.h:79
const char * SPF_request_get_rec_dom(SPF_request_t *sr)
Definition: spf_request.c:156
SPF_errcode_t SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
Definition: spf_request.c:73
#define FALSE
Definition: spf_internal.h:24
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
Definition: spf_request.c:319
SPF_errcode_t SPF_record_interpret(SPF_record_t *spf_record, SPF_request_t *spf_request, SPF_response_t *spf_response, int depth)
SPF_errcode_t SPF_i_done(SPF_response_t *spf_response, SPF_result_t result, SPF_reason_t reason, SPF_errcode_t err)
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
void SPF_request_free(SPF_request_t *sr)
Definition: spf_request.c:61
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:97
SPF_errcode_t SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
Definition: spf_request.c:85
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition: spf_request.c:43
int SPF_response_errors(SPF_response_t *rp)
Definition: spf_response.c:296
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
Definition: spf_request.c:164
#define SPF_VER_STR
Definition: spf.h:35