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_response.h"
35
36 SPF_response_t *
SPF_response_new(SPF_request_t * spf_request)37 SPF_response_new(SPF_request_t *spf_request)
38 {
39 SPF_response_t *rp;
40
41 rp = (SPF_response_t *)malloc(sizeof(SPF_response_t));
42 if (! rp)
43 return rp;
44 memset(rp, 0, sizeof(SPF_response_t));
45
46 rp->spf_request = spf_request;
47 rp->result = SPF_RESULT_INVALID;
48
49 return rp;
50 }
51
52 void
SPF_response_free(SPF_response_t * rp)53 SPF_response_free(SPF_response_t *rp)
54 {
55 int i;
56
57 if (rp->received_spf)
58 free(rp->received_spf);
59 /* Don't free received_spf_value - it points into received_spf */
60 if (rp->header_comment)
61 free(rp->header_comment);
62 if (rp->smtp_comment)
63 free(rp->smtp_comment);
64 if (rp->explanation)
65 free(rp->explanation);
66
67 if (rp->errors) {
68 for (i = 0; i < rp->errors_length; i++) {
69 free(rp->errors[i].message);
70 }
71 free(rp->errors);
72 }
73
74 free(rp);
75 }
76
77 static SPF_response_t *
SPF_response_choose(SPF_response_t * yes,SPF_response_t * no)78 SPF_response_choose(SPF_response_t *yes, SPF_response_t *no)
79 {
80 SPF_response_free(no);
81 return yes;
82 }
83
84 /*
85 * This is rather a guess-and-fiddle routine which tries to pick
86 * the best of both worlds. It doesn't currently deal with error
87 * messages at all.
88 */
89 SPF_response_t *
SPF_response_combine(SPF_response_t * main,SPF_response_t * r2mx)90 SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
91 {
92 switch (SPF_response_result(main)) {
93 case SPF_RESULT_INVALID:
94 /* If the main failed entirely, use the secondary */
95 return SPF_response_choose(r2mx, main);
96
97 case SPF_RESULT_PASS:
98 /* If the main passed, use main */
99 return SPF_response_choose(main, r2mx);
100
101 case SPF_RESULT_NEUTRAL:
102 /* If the main is neutral: */
103 switch (SPF_response_result(r2mx)) {
104 case SPF_RESULT_PASS:
105 /* Use the secondary if it passed */
106 return SPF_response_choose(r2mx, main);
107 default:
108 /* Otherwise just use the main */
109 return SPF_response_choose(main, r2mx);
110 }
111
112 case SPF_RESULT_FAIL:
113 /* If the main failed, use the secondary */
114 return SPF_response_choose(r2mx, main);
115
116 case SPF_RESULT_TEMPERROR:
117 case SPF_RESULT_PERMERROR:
118 case SPF_RESULT_SOFTFAIL:
119 default:
120 /* If the main is peculiar, including softfail: */
121 switch (SPF_response_result(r2mx)) {
122 case SPF_RESULT_PASS:
123 case SPF_RESULT_NEUTRAL:
124 case SPF_RESULT_SOFTFAIL:
125 /* Use the secondary if it didn't fail */
126 return SPF_response_choose(r2mx, main);
127 default:
128 /* Otherwise just use the main */
129 return SPF_response_choose(main, r2mx);
130 }
131 }
132 }
133
134 SPF_result_t
SPF_response_result(SPF_response_t * rp)135 SPF_response_result(SPF_response_t *rp)
136 {
137 if (rp == NULL)
138 return SPF_RESULT_NONE;
139
140 return rp->result;
141 }
142
143 SPF_reason_t
SPF_response_reason(SPF_response_t * rp)144 SPF_response_reason(SPF_response_t *rp)
145 {
146 return rp->reason;
147 }
148
149 SPF_errcode_t
SPF_response_errcode(SPF_response_t * rp)150 SPF_response_errcode(SPF_response_t *rp)
151 {
152 return rp->err;
153 }
154
155 const char *
SPF_response_get_received_spf(SPF_response_t * rp)156 SPF_response_get_received_spf(SPF_response_t *rp)
157 {
158 return rp->received_spf;
159 }
160
161 const char *
SPF_response_get_received_spf_value(SPF_response_t * rp)162 SPF_response_get_received_spf_value(SPF_response_t *rp)
163 {
164 return rp->received_spf_value;
165 }
166
167 const char *
SPF_response_get_header_comment(SPF_response_t * rp)168 SPF_response_get_header_comment(SPF_response_t *rp)
169 {
170 return rp->header_comment;
171 }
172
173 const char *
SPF_response_get_smtp_comment(SPF_response_t * rp)174 SPF_response_get_smtp_comment(SPF_response_t *rp)
175 {
176 return rp->smtp_comment;
177 }
178
179 const char *
SPF_response_get_explanation(SPF_response_t * rp)180 SPF_response_get_explanation(SPF_response_t *rp)
181 {
182 return rp->explanation;
183 }
184
185 /* Error manipulation functions */
186
187 #define SPF_ERRMSGSIZE 4096
188
189 static SPF_errcode_t
SPF_response_add_error_v(SPF_response_t * rp,SPF_errcode_t code,int is_error,const char * text,int idx,const char * format,va_list ap)190 SPF_response_add_error_v(SPF_response_t *rp,
191 SPF_errcode_t code, int is_error,
192 const char *text, int idx,
193 const char *format, va_list ap)
194 {
195 SPF_error_t *tmp;
196 char buf[SPF_ERRMSGSIZE];
197 int size;
198
199 /* TODO: Use text and idx */
200
201 if (!format)
202 format = SPF_strerror(code);
203 size = vsnprintf(buf, sizeof(buf), format, ap);
204 if (text != NULL) {
205 snprintf(&buf[size], sizeof(buf) - size,
206 " near '%.12s'", &text[idx]);
207 }
208 buf[SPF_ERRMSGSIZE - 1] = '\0';
209
210 if (rp->errors_length == rp->errors_size) {
211 size = rp->errors_size + (rp->errors_size / 4) + 4;
212 tmp = (SPF_error_t *)realloc(rp->errors, size * sizeof(SPF_error_t));
213 if (! tmp) {
214 SPF_error("Failed to allocate memory for extra response error");
215 return code;
216 }
217 rp->errors = tmp;
218 rp->errors_size = size;
219 }
220
221 rp->errors[rp->errors_length].code = code;
222 rp->errors[rp->errors_length].is_error = is_error;
223 /* If we are a memory error, this might fail. */
224 rp->errors[rp->errors_length].message = strdup(buf);
225 rp->errors_length++;
226
227 return code;
228 }
229
230 #define SPF_ADD_ERROR(_ise, _txt, _ix) \
231 va_list ap; va_start(ap, format); \
232 SPF_response_add_error_v(rp, code, _ise, _txt, _ix, format, ap); \
233 rp->num_errors++; \
234 va_end(ap); return code;
235 #define SPF_ADD_WARN(_ise, _txt, _ix) \
236 va_list ap; va_start(ap, format); \
237 SPF_response_add_error_v(rp, code, _ise, _txt, _ix, format, ap); \
238 va_end(ap); return code;
239
240 SPF_errcode_t
SPF_response_add_error_ptr(SPF_response_t * rp,SPF_errcode_t code,const char * text,const char * tptr,const char * format,...)241 SPF_response_add_error_ptr(SPF_response_t *rp,
242 SPF_errcode_t code,
243 const char *text, const char *tptr,
244 const char *format, ...)
245 {
246 SPF_ADD_ERROR(1, text ? text : tptr, text ? (tptr - text) : 0);
247 }
248
249 SPF_errcode_t
SPF_response_add_error_idx(SPF_response_t * rp,SPF_errcode_t code,const char * text,int idx,const char * format,...)250 SPF_response_add_error_idx(SPF_response_t *rp,
251 SPF_errcode_t code,
252 const char *text, int idx,
253 const char *format, ...)
254 {
255 SPF_ADD_ERROR(1, text, idx);
256 }
257
258 SPF_errcode_t
SPF_response_add_error(SPF_response_t * rp,SPF_errcode_t code,const char * format,...)259 SPF_response_add_error(SPF_response_t *rp,
260 SPF_errcode_t code,
261 const char *format, ...)
262 {
263 SPF_ADD_ERROR(1, NULL, 0);
264 }
265
266 SPF_errcode_t
SPF_response_add_warn_ptr(SPF_response_t * rp,SPF_errcode_t code,const char * text,const char * tptr,const char * format,...)267 SPF_response_add_warn_ptr(SPF_response_t *rp,
268 SPF_errcode_t code,
269 const char *text, const char *tptr,
270 const char *format, ...)
271 {
272 SPF_ADD_WARN(0, text ? text : tptr, text ? (tptr - text) : 0);
273 }
274
275 SPF_errcode_t
SPF_response_add_warn_idx(SPF_response_t * rp,SPF_errcode_t code,const char * text,int idx,const char * format,...)276 SPF_response_add_warn_idx(SPF_response_t *rp,
277 SPF_errcode_t code,
278 const char *text, int idx,
279 const char *format, ...)
280 {
281 SPF_ADD_WARN(0, text, idx);
282 }
283
284 SPF_errcode_t
SPF_response_add_warn(SPF_response_t * rp,SPF_errcode_t code,const char * format,...)285 SPF_response_add_warn(SPF_response_t *rp,
286 SPF_errcode_t code,
287 const char *format, ...)
288 {
289 SPF_ADD_WARN(0, NULL, 0);
290 }
291
292 int
SPF_response_messages(SPF_response_t * rp)293 SPF_response_messages(SPF_response_t *rp)
294 {
295 return rp->errors_length;
296 }
297
298 int
SPF_response_errors(SPF_response_t * rp)299 SPF_response_errors(SPF_response_t *rp)
300 {
301 return rp->num_errors;
302 }
303
304 int
SPF_response_warnings(SPF_response_t * rp)305 SPF_response_warnings(SPF_response_t *rp)
306 {
307 return rp->errors_length - rp->num_errors;
308 }
309
310 SPF_error_t *
SPF_response_message(SPF_response_t * rp,int idx)311 SPF_response_message(SPF_response_t *rp, int idx)
312 {
313 return &rp->errors[idx];
314 }
315
316 SPF_errcode_t
SPF_error_code(SPF_error_t * err)317 SPF_error_code(SPF_error_t *err)
318 {
319 return err->code;
320 }
321
322 const char *
SPF_error_message(SPF_error_t * err)323 SPF_error_message(SPF_error_t *err)
324 {
325 return err->message;
326 }
327
328 char
SPF_error_errorp(SPF_error_t * err)329 SPF_error_errorp(SPF_error_t *err)
330 {
331 return err->is_error;
332 }
333