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 #define SPF_FREE(x) \
38  do { if (x) free(x); (x) = NULL; } while(0)
39 
40 SPF_request_t *
41 SPF_request_new(SPF_server_t *spf_server)
42 {
43  SPF_request_t *sr;
44 
45  sr = (SPF_request_t *)malloc(sizeof(SPF_request_t));
46  if (! sr)
47  return sr;
48  memset(sr, 0, sizeof(SPF_request_t));
49 
50  sr->spf_server = spf_server;
51  sr->client_ver = AF_UNSPEC;
52  sr->ipv4.s_addr = htonl(INADDR_ANY);
53  sr->ipv6 = in6addr_any;
54 
55  return sr;
56 }
57 
58 void
59 SPF_request_free(SPF_request_t *sr)
60 {
62  SPF_FREE(sr->client_dom);
63  SPF_FREE(sr->helo_dom);
64  SPF_FREE(sr->env_from);
65  SPF_FREE(sr->env_from_lp);
66  SPF_FREE(sr->env_from_dp);
67  free(sr);
68 }
69 
71 SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
72 {
73  if (sr->client_dom) {
74  free(sr->client_dom);
75  sr->client_dom = NULL;
76  }
77  sr->client_ver = AF_INET;
78  sr->ipv4 = addr;
79  return SPF_E_SUCCESS;
80 }
81 
83 SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
84 {
85  if (sr->client_dom) {
86  free(sr->client_dom);
87  sr->client_dom = NULL;
88  }
89  sr->client_ver = AF_INET6;
90  sr->ipv6 = addr;
91  return SPF_E_SUCCESS;
92 }
93 
95 SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
96 {
97  struct in_addr addr;
98  if (astr == NULL)
99  astr = "0.0.0.0";
100  if (inet_pton(AF_INET, astr, &addr) <= 0)
101  return SPF_E_INVALID_IP4;
102  return SPF_request_set_ipv4(sr, addr);
103 }
104 
106 SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
107 {
108  struct in6_addr addr;
109  if (astr == NULL)
110  astr = "::";
111  if (inet_pton(AF_INET6, astr, &addr) <= 0)
112  return SPF_E_INVALID_IP6;
113  return SPF_request_set_ipv6(sr, addr);
114 }
115 
117 SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
118 {
119  SPF_ASSERT_NOTNULL(dom);
120  SPF_FREE(sr->helo_dom);
121  sr->helo_dom = strdup(dom);
122  if (! sr->helo_dom)
123  return SPF_E_NO_MEMORY;
124  /* set cur_dom and env_from? */
125  if (sr->env_from == NULL)
126  return SPF_request_set_env_from(sr, dom);
127  return SPF_E_SUCCESS;
128 }
129 
130 const char *
131 SPF_request_get_rec_dom(SPF_request_t *sr)
132 {
133  SPF_server_t *spf_server;
134  spf_server = sr->spf_server;
135  return spf_server->rec_dom;
136 }
137 
138 int
139 SPF_request_set_env_from(SPF_request_t *sr, const char *from)
140 {
141  char *cp;
142  size_t len;
143 
144  SPF_ASSERT_NOTNULL(from);
145  SPF_FREE(sr->env_from);
146  SPF_FREE(sr->env_from_lp);
147  SPF_FREE(sr->env_from_dp);
148 
149  if (*from == '\0' && sr->helo_dom != NULL)
150  from = sr->helo_dom;
151  cp = strrchr(from, '@');
152  if (cp && (cp != from)) {
153  sr->env_from = strdup(from);
154  if (! sr->env_from)
155  return SPF_E_NO_MEMORY;
156 
157  len = cp - from;
158  sr->env_from_lp = malloc(len + 1);
159  if (!sr->env_from_lp) {
160  SPF_FREE(sr->env_from);
161  return SPF_E_NO_MEMORY;
162  }
163  strncpy(sr->env_from_lp, from, len);
164  sr->env_from_lp[len] = '\0';
165  sr->env_from_dp = strdup(cp + 1);
166  if (!sr->env_from_dp) {
167  SPF_FREE(sr->env_from);
168  SPF_FREE(sr->env_from_lp);
169  return SPF_E_NO_MEMORY;
170  }
171  }
172  else {
173  if (cp == from) from++; /* "@domain.example" */
174  len = sizeof("postmaster@") + strlen(from);
175  sr->env_from = malloc(len + 1); /* sizeof("") == 1? */
176  if (! sr->env_from)
177  return SPF_E_NO_MEMORY;
178  sprintf(sr->env_from, "postmaster@%s", from);
179  sr->env_from_lp = strdup("postmaster");
180  if (!sr->env_from_lp) {
181  SPF_FREE(sr->env_from);
182  return SPF_E_NO_MEMORY;
183  }
184  sr->env_from_dp = strdup(from);
185  if (!sr->env_from_dp) {
186  SPF_FREE(sr->env_from);
187  SPF_FREE(sr->env_from_lp);
188  return SPF_E_NO_MEMORY;
189  }
190  }
191 
192  return 0; // SPF_E_SUCCESS
193 }
194 
195 const char *
196 SPF_request_get_client_dom(SPF_request_t *sr)
197 {
198  SPF_server_t *spf_server;
199 
200  SPF_ASSERT_NOTNULL(sr);
201  spf_server = sr->spf_server;
202  SPF_ASSERT_NOTNULL(spf_server);
203 
204  if (sr->client_dom == NULL) {
205  sr->client_dom = SPF_dns_get_client_dom(spf_server->resolver,
206  sr);
207  }
208  return sr->client_dom;
209 }
210 
211 int
212 SPF_request_is_loopback(SPF_request_t *sr)
213 {
214  if (sr->client_ver == AF_INET) {
215  if ((ntohl(sr->ipv4.s_addr) & IN_CLASSA_NET) ==
216  (IN_LOOPBACKNET << 24)) {
217  return TRUE;
218  }
219  }
220  else if (sr->client_ver == AF_INET6) {
221  if (IN6_IS_ADDR_LOOPBACK(&sr->ipv6))
222  return TRUE;
223  }
224  return FALSE;
225 }
226 
227 static SPF_errcode_t
228 SPF_request_prepare(SPF_request_t *sr)
229 {
230  if (sr->use_helo)
231  sr->cur_dom = sr->helo_dom;
232  else
233  sr->cur_dom = sr->env_from_dp;
234  return SPF_E_SUCCESS;
235 }
236 
240 static SPF_errcode_t
241 SPF_request_query_record(SPF_request_t *spf_request,
242  SPF_response_t *spf_response,
243  SPF_record_t *spf_record,
244  SPF_errcode_t err)
245 {
246  if (err != SPF_E_SUCCESS) {
247  if (spf_record)
248  SPF_record_free(spf_record);
249  return err;
250  }
251  /* Now, in theory, SPF_response_errors(spf_response) == 0 */
252  if (SPF_response_errors(spf_response) > 0)
253  SPF_infof("Warning: %d errors in response, "
254  "but no error code. Evaluating.",
255  SPF_response_errors(spf_response));
256  /* If we get here, spf_record better not be NULL */
257  spf_response->spf_record_exp = spf_record;
258  err = SPF_record_interpret(spf_record,
259  spf_request, spf_response, 0);
260  SPF_record_free(spf_record);
261 
262  return err;
263 }
264 
269 SPF_request_query_mailfrom(SPF_request_t *spf_request,
270  SPF_response_t **spf_responsep)
271 {
272  SPF_server_t *spf_server;
273  SPF_record_t *spf_record;
274  SPF_errcode_t err;
275 
276  SPF_ASSERT_NOTNULL(spf_request);
277  spf_server = spf_request->spf_server;
278  SPF_ASSERT_NOTNULL(spf_server);
279 
280  *spf_responsep = SPF_response_new(spf_request);
281  if (! *spf_responsep)
282  return SPF_E_NO_MEMORY;
283 
284  /* Give localhost a free ride */
285  if (SPF_request_is_loopback(spf_request))
286  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
288 
289  SPF_request_prepare(spf_request);
290 
291  err = SPF_server_get_record(spf_server, spf_request,
292  *spf_responsep, &spf_record);
293  return SPF_request_query_record(spf_request, *spf_responsep,
294  spf_record, err);
295 }
296 
297 /* This interface isn't finalised. */
299 SPF_request_query_fallback(SPF_request_t *spf_request,
300  SPF_response_t **spf_responsep,
301  const char *record)
302 {
303  SPF_server_t *spf_server;
304  SPF_record_t *spf_record;
305  SPF_errcode_t err;
306 
307  SPF_ASSERT_NOTNULL(spf_request);
308  spf_server = spf_request->spf_server;
309  SPF_ASSERT_NOTNULL(spf_server);
310 
311  *spf_responsep = SPF_response_new(spf_request);
312  if (! *spf_responsep)
313  return SPF_E_NO_MEMORY;
314 
315  /* Give localhost a free ride */
316  if (SPF_request_is_loopback(spf_request))
317  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
319 
320  SPF_request_prepare(spf_request);
321 
322  err = SPF_record_compile(spf_server,
323  *spf_responsep, &spf_record,
324  record);
325  return SPF_request_query_record(spf_request, *spf_responsep,
326  spf_record, err);
327 }
328 
337 /* FIXME: Check the implementation of this. */
339 SPF_request_query_rcptto(SPF_request_t *spf_request,
340  SPF_response_t **spf_responsep,
341  const char *rcpt_to)
342 {
343  SPF_server_t *spf_server;
344  SPF_record_t *spf_record;
345  SPF_errcode_t err;
346  const char *rcpt_to_dom;
347  char *record;
348  size_t len;
349 
350  SPF_ASSERT_NOTNULL(spf_request);
351  spf_server = spf_request->spf_server;
352  SPF_ASSERT_NOTNULL(spf_server);
353 
354  *spf_responsep = SPF_response_new(spf_request);
355  if (! *spf_responsep)
356  return SPF_E_NO_MEMORY;
357 
358  /* Give localhost a free ride */
359  if (SPF_request_is_loopback(spf_request))
360  return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
362 
363  rcpt_to_dom = strchr(rcpt_to, '@');
364  if (rcpt_to_dom == NULL)
365  rcpt_to_dom = rcpt_to;
366  spf_request->cur_dom = rcpt_to_dom;
367 
368  len = sizeof(SPF_VER_STR) + 64 + strlen(rcpt_to_dom);
369  record = malloc(len);
370  if (! record)
371  return SPF_E_NO_MEMORY;
372  snprintf(record, len, SPF_VER_STR " mx:%s", rcpt_to_dom);
373  err = SPF_record_compile(spf_server,
374  *spf_responsep, &spf_record,
375  record);
376  free(record);
377  return SPF_request_query_record(spf_request, *spf_responsep,
378  spf_record, err);
379 }
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
Definition: spf_request.c:117
void SPF_record_free(SPF_record_t *rp)
Definition: spf_record.c:63
#define SPF_infof
Definition: spf_log.h:79
void SPF_request_free(SPF_request_t *sr)
Definition: spf_request.c:59
int SPF_request_is_loopback(SPF_request_t *sr)
Definition: spf_request.c:212
#define FALSE
Definition: spf_internal.h:24
SPF_errcode_t
Definition: spf_response.h:118
#define NULL
Definition: spf_internal.h:28
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
#define SPF_VER_STR
Definition: spf.h:35
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_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
Definition: spf_request.c:339
#define SPF_ASSERT_NOTNULL(x)
Definition: spf_log.h:118
const char * SPF_request_get_client_dom(SPF_request_t *sr)
Definition: spf_request.c:196
#define SPF_FREE(x)
Definition: spf_request.c:37
int SPF_response_errors(SPF_response_t *rp)
Definition: spf_response.c:296
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_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:95
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition: spf_request.c:41
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_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
Definition: spf_request.c:299
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:106
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
Definition: spf_request.c:139
SPF_errcode_t SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
Definition: spf_request.c:71
#define TRUE
Definition: spf_internal.h:23
char * SPF_dns_get_client_dom(SPF_dns_server_t *spf_dns_server, SPF_request_t *sr)
Definition: spf_dns.c:206
SPF_errcode_t SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
Definition: spf_request.c:83
const char * SPF_request_get_rec_dom(SPF_request_t *sr)
Definition: spf_request.c:131
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
Definition: spf_request.c:269
SPF_response_t * SPF_response_new(SPF_request_t *spf_request)
Definition: spf_response.c:37