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