libspf2 1.2.11
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
40SPF_request_t *
41SPF_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
58void
59SPF_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
71SPF_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
83SPF_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
95SPF_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
106SPF_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
117SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
118{
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
130const char *
131SPF_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
138int
139SPF_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
195const char *
197{
198 SPF_server_t *spf_server;
199
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
211int
212SPF_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
227static SPF_errcode_t
228SPF_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
240static SPF_errcode_t
241SPF_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 SPF_i_done(spf_response, spf_response->result, spf_response->reason, spf_response->err);
250 return err;
251 }
252 /* Now, in theory, SPF_response_errors(spf_response) == 0 */
253 if (SPF_response_errors(spf_response) > 0)
254 SPF_infof("Warning: %d errors in response, "
255 "but no error code. Evaluating.",
256 SPF_response_errors(spf_response));
257 /* If we get here, spf_record better not be NULL */
258 spf_response->spf_record_exp = spf_record;
259 err = SPF_record_interpret(spf_record,
260 spf_request, spf_response, 0);
261 SPF_record_free(spf_record);
262
263 return err;
264}
265
270SPF_request_query_mailfrom(SPF_request_t *spf_request,
271 SPF_response_t **spf_responsep)
272{
273 SPF_server_t *spf_server;
274 SPF_record_t *spf_record;
275 SPF_errcode_t err;
276
277 SPF_ASSERT_NOTNULL(spf_request);
278 spf_server = spf_request->spf_server;
279 SPF_ASSERT_NOTNULL(spf_server);
280
281 *spf_responsep = SPF_response_new(spf_request);
282 if (! *spf_responsep)
283 return SPF_E_NO_MEMORY;
284
285 /* Give localhost a free ride */
286 if (SPF_request_is_loopback(spf_request))
287 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
289
290 SPF_request_prepare(spf_request);
291
292 err = SPF_server_get_record(spf_server, spf_request,
293 *spf_responsep, &spf_record);
294 return SPF_request_query_record(spf_request, *spf_responsep,
295 spf_record, err);
296}
297
298/* This interface isn't finalised. */
300SPF_request_query_fallback(SPF_request_t *spf_request,
301 SPF_response_t **spf_responsep,
302 const char *record)
303{
304 SPF_server_t *spf_server;
305 SPF_record_t *spf_record;
306 SPF_errcode_t err;
307
308 SPF_ASSERT_NOTNULL(spf_request);
309 spf_server = spf_request->spf_server;
310 SPF_ASSERT_NOTNULL(spf_server);
311
312 *spf_responsep = SPF_response_new(spf_request);
313 if (! *spf_responsep)
314 return SPF_E_NO_MEMORY;
315
316 /* Give localhost a free ride */
317 if (SPF_request_is_loopback(spf_request))
318 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
320
321 SPF_request_prepare(spf_request);
322
323 err = SPF_record_compile(spf_server,
324 *spf_responsep, &spf_record,
325 record);
326 return SPF_request_query_record(spf_request, *spf_responsep,
327 spf_record, err);
328}
329
338/* FIXME: Check the implementation of this. */
340SPF_request_query_rcptto(SPF_request_t *spf_request,
341 SPF_response_t **spf_responsep,
342 const char *rcpt_to)
343{
344 SPF_server_t *spf_server;
345 SPF_record_t *spf_record;
346 SPF_errcode_t err;
347 const char *rcpt_to_dom;
348 char *record;
349 size_t len;
350
351 SPF_ASSERT_NOTNULL(spf_request);
352 spf_server = spf_request->spf_server;
353 SPF_ASSERT_NOTNULL(spf_server);
354
355 *spf_responsep = SPF_response_new(spf_request);
356 if (! *spf_responsep)
357 return SPF_E_NO_MEMORY;
358
359 /* Give localhost a free ride */
360 if (SPF_request_is_loopback(spf_request))
361 return SPF_i_done(*spf_responsep, SPF_RESULT_PASS,
363
364 rcpt_to_dom = strchr(rcpt_to, '@');
365 if (rcpt_to_dom == NULL)
366 rcpt_to_dom = rcpt_to;
367 else
368 rcpt_to_dom++;
369 spf_request->cur_dom = rcpt_to_dom;
370
371 len = sizeof(SPF_VER_STR) + 64 + strlen(rcpt_to_dom);
372 record = malloc(len);
373 if (! record)
374 return SPF_E_NO_MEMORY;
375 snprintf(record, len, SPF_VER_STR " mx:%s", rcpt_to_dom);
376 err = SPF_record_compile(spf_server,
377 *spf_responsep, &spf_record,
378 record);
379 free(record);
380 return SPF_request_query_record(spf_request, *spf_responsep,
381 spf_record, err);
382}
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
char * SPF_dns_get_client_dom(SPF_dns_server_t *spf_dns_server, SPF_request_t *sr)
Definition spf_dns.c:206
@ SPF_RESULT_PASS
SPF_response_t * SPF_response_new(SPF_request_t *spf_request)
@ SPF_REASON_LOCALHOST
SPF_errcode_t
@ SPF_E_INVALID_IP6
@ SPF_E_NO_MEMORY
@ SPF_E_INVALID_IP4
@ SPF_E_SUCCESS
int SPF_response_errors(SPF_response_t *rp)
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_record_compile(SPF_server_t *spf_server, SPF_response_t *spf_response, SPF_record_t **spf_recordp, const char *record)
void SPF_record_free(SPF_record_t *rp)
Definition spf_record.c:63
#define SPF_VER_STR
Definition spf.h:35
#define SPF_infof
Definition spf_log.h:79
#define SPF_ASSERT_NOTNULL(x)
Definition spf_log.h:118
#define NULL
#define TRUE
#define FALSE
SPF_errcode_t SPF_i_done(SPF_response_t *spf_response, SPF_result_t result, SPF_reason_t reason, SPF_errcode_t err)
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition spf_request.c:41
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
SPF_errcode_t SPF_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
SPF_errcode_t SPF_request_set_ipv4(SPF_request_t *sr, struct in_addr addr)
Definition spf_request.c:71
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition spf_request.c:95
#define SPF_FREE(x)
Definition spf_request.c:37
const char * SPF_request_get_client_dom(SPF_request_t *sr)
const char * SPF_request_get_rec_dom(SPF_request_t *sr)
int SPF_request_is_loopback(SPF_request_t *sr)
void SPF_request_free(SPF_request_t *sr)
Definition spf_request.c:59
SPF_errcode_t SPF_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
SPF_errcode_t SPF_request_set_ipv6(SPF_request_t *sr, struct in6_addr addr)
Definition spf_request.c:83