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 #ifndef INC_SPF_RESPONSE
17 #define INC_SPF_RESPONSE
18 
19 /**
20  * @file
21  *
22  * Results from an SPF check
23  *
24  * The results of the SPF check (as defined by the official SPF spec)
25  *
26  * To quote from doc/draft-mengwong-spf-00.txt Section 3:
27  *
28  *     3. SPF Record Evaluation
29  *
30  *        An SPF client evaluates an SPF record and produces one of seven
31  *        results:
32  *
33  *          None: The domain does not publish SPF data.
34  *
35  *          Neutral (?): The SPF client MUST proceed as if a domain did not
36  *          publish SPF data.  This result occurs if the domain explicitly
37  *          specifies a "?" value, or if processing "falls off the end" of
38  *          the SPF record.
39  *
40  *          Pass (+): the message meets the publishing domain's definition of
41  *          legitimacy.  MTAs proceed to apply local policy and MAY accept or
42  *          reject the message accordingly.
43  *
44  *          Fail (-): the message does not meet a domain's definition of
45  *          legitimacy.  MTAs MAY reject the message using a permanent
46  *          failure reply code.  (Code 550 is RECOMMENDED.  See RFC2821
47  *          section 7.1.)
48  *
49  *          Softfail (~): the message does not meet a domain's strict
50  *          definition of legitimacy, but the domain cannot confidently state
51  *          that the message is a forgery.  MTAs SHOULD accept the message
52  *          but MAY subject it to a higher transaction cost, deeper scrutiny,
53  *          or an unfavourable score.
54  *
55  *        There are two error conditions, one temporary and one permanent.
56  *
57  *          Error: indicates an error during lookup; an MTA MAY reject the
58  *          message using a transient failure code, such as 450.
59  *
60  *          Unknown: indicates incomplete processing: an MTA MUST proceed as
61  *          if a domain did not publish SPF data.
62  *
63  *        When SPF-aware SMTP receivers accept a message, they SHOULD prepend a
64  *        Received-SPF header.  See section 6.
65  *
66  *        SPF clients MUST use the algorithm described in this section
67  *        or its functional equivalent.
68  *
69  *        If an SPF client encounters a syntax error in an
70  *        SPF record, it must terminate processing and return a result
71  *        of "unknown".
72  *
73  *
74  * note: SPF_RESULT_* values are constrained by the internal PREFIX_* values
75  */
76 
77 
78 typedef
79 enum SPF_result_enum {
80 	SPF_RESULT_INVALID = 0,		/**< We should never return this. */
81 	SPF_RESULT_NEUTRAL,
82 	SPF_RESULT_PASS,
83 	SPF_RESULT_FAIL,
84 	SPF_RESULT_SOFTFAIL,
85 
86 	SPF_RESULT_NONE,
87 	SPF_RESULT_TEMPERROR,
88 	SPF_RESULT_PERMERROR
89 } SPF_result_t;
90 
91 /**
92  * The reason that the result was returned
93  *
94  * This is what triggered the SPF result.  Usually, it is a mechanism in the
95  * SPF record that causes the result, but if it was something else, the
96  * calling program will often want to take a different action or issue
97  * a different message.
98  */
99 typedef
100 enum SPF_reason_enum {
101 	SPF_REASON_NONE			= 0
102 ,	SPF_REASON_FAILURE
103 ,	SPF_REASON_LOCALHOST	/**< localhost always gets a free ride */
104 ,	SPF_REASON_LOCAL_POLICY	/**< local policy caused the match */
105 ,	SPF_REASON_MECH			/**< mechanism caused the match	*/
106 ,	SPF_REASON_DEFAULT		/**< ran off the end of the rec	*/
107 ,	SPF_REASON_2MX			/**< sent from a secondary MX	*/
108 } SPF_reason_t;
109 
110 /**
111  * error codes returned by various SPF functions.  (including SPF_compile()
112  * and SPF_id2str(), spf_result(), etc.).
113  *
114  * The function SPF_strerror() will return a longer explanation of these
115  * errors.
116  */
117 
118 typedef
119 enum SPF_errcode_t {
120 	SPF_E_SUCCESS	 = 0	/**< No errors			*/
121 ,	SPF_E_NO_MEMORY			/**< Out of memory		*/
122 ,	SPF_E_NOT_SPF			/**< Could not find a valid SPF record */
123 ,	SPF_E_SYNTAX			/**< Syntax error			*/
124 ,	SPF_E_MOD_W_PREF		/**< Modifiers can not have prefixes */
125 ,	SPF_E_INVALID_CHAR		/**< Invalid character found	*/
126 ,	SPF_E_UNKNOWN_MECH		/**< Unknown mechanism found	*/
127 ,	SPF_E_INVALID_OPT		/**< Invalid option found		*/
128 ,	SPF_E_INVALID_CIDR		/**< Invalid CIDR length		*/
129 ,	SPF_E_MISSING_OPT		/**< Required option is missing	*/
130 ,	SPF_E_INTERNAL_ERROR	/**< Internal programming error	*/
131 ,	SPF_E_INVALID_ESC		/**< Invalid %-escape character	*/
132 ,	SPF_E_INVALID_VAR		/**< Invalid macro variable	*/
133 ,	SPF_E_BIG_SUBDOM		/**< Subdomain truncation depth too large */
134 ,	SPF_E_INVALID_DELIM		/**< Invalid delimiter character	*/
135 ,	SPF_E_BIG_STRING		/**< Option string too long	*/
136 ,	SPF_E_BIG_MECH			/**< Too many mechanisms		*/
137 ,	SPF_E_BIG_MOD			/**< Too many modifiers		*/
138 ,	SPF_E_BIG_DNS			/**< Mechanisms used too many DNS lookups */
139 ,	SPF_E_INVALID_IP4		/**< Invalid IPv4 address literal	*/
140 ,	SPF_E_INVALID_IP6		/**< Invalid IPv6 address literal	*/
141 ,	SPF_E_INVALID_PREFIX	/**< Invalid mechanism prefix	*/
142 ,	SPF_E_RESULT_UNKNOWN	/**< SPF result is \"unknown\"	*/
143 ,	SPF_E_UNINIT_VAR		/**< Uninitialized variable	*/
144 ,	SPF_E_MOD_NOT_FOUND		/**< Modifier not found		*/
145 ,	SPF_E_NOT_CONFIG		/**< Not configured		*/
146 ,	SPF_E_DNS_ERROR			/**< DNS lookup failure		*/
147 ,	SPF_E_BAD_HOST_IP		/**< Invalid hostname (an IP address?) */
148 ,	SPF_E_BAD_HOST_TLD		/**< Hostname has a missing or invalid TLD */
149 ,	SPF_E_MECH_AFTER_ALL	/**< Mechanisms found after the \"all:\"
150 								mechanism will be ignored */
151 ,	SPF_E_INCLUDE_RETURNED_NONE	/**< If an include recursive query returns none it's a perm error */
152 ,	SPF_E_RECURSIVE			/**< Recursive include */
153 ,	SPF_E_MULTIPLE_RECORDS	/**< Multiple SPF or TXT records found */
154 } SPF_errcode_t;
155 
156 typedef
157 struct SPF_error_struct
158 {
159 	SPF_errcode_t	 code;
160 	char			*message;
161 	char			 is_error;
162 } SPF_error_t;
163 
164 typedef struct SPF_response_struct SPF_response_t;
165 
166 #include "spf.h"
167 #include "spf_request.h"
168 
169 struct SPF_response_struct {
170 	/* Structure variables */
171 	SPF_request_t	*spf_request;
172 	SPF_record_t	*spf_record_exp;
173 
174 	/* The answer itself. */
175 	SPF_result_t	 result;
176 	SPF_reason_t	 reason;
177 	SPF_errcode_t	 err;
178 
179 	char			*received_spf;
180 	char			*received_spf_value;
181 	char			*header_comment;
182 	char			*smtp_comment;
183 	char			*explanation;
184 
185 	/* The errors */
186 	SPF_error_t		*errors;
187 	unsigned short	 errors_size;		/**< Allocated */
188 	unsigned short	 errors_length;		/**< Used */
189 	unsigned short	 num_errors;		/**< Excluding warnings */
190 
191 	/* Stuff which lets us get there. */
192 	int				 num_dns_mech;
193 };
194 
195 
196 SPF_response_t	*SPF_response_new(SPF_request_t *spf_request);
197 void			 SPF_response_free(SPF_response_t *rp);
198 SPF_response_t	*SPF_response_combine(SPF_response_t *main,
199 					SPF_response_t *r2mx);
200 
201 	/* Query functions for elements of the result */
202 SPF_result_t	 SPF_response_result(SPF_response_t *rp);
203 SPF_reason_t	 SPF_response_reason(SPF_response_t *rp);
204 SPF_errcode_t	 SPF_response_errcode(SPF_response_t *rp);
205 const char		*SPF_response_get_received_spf(SPF_response_t *rp);
206 const char		*SPF_response_get_received_spf_value(SPF_response_t*rp);
207 const char		*SPF_response_get_header_comment(SPF_response_t *rp);
208 const char		*SPF_response_get_smtp_comment(SPF_response_t *rp);
209 const char		*SPF_response_get_explanation(SPF_response_t *rp);
210 
211 	/** How many warnings were generated? */
212 int				 SPF_response_messages(SPF_response_t *rp);
213 	/** How many errors were generated? */
214 int				 SPF_response_errors(SPF_response_t *rp);
215 	/** Errors + warnings */
216 int				 SPF_response_warnings(SPF_response_t *rp);
217 	/** Returns an individual message */
218 SPF_error_t		*SPF_response_message(SPF_response_t *rp, int idx);
219 
220 SPF_errcode_t	 SPF_error_code(SPF_error_t *err);
221 const char *	 SPF_error_message(SPF_error_t *err);
222 char			 SPF_error_errorp(SPF_error_t *err);
223 
224 	/** Internal functions for adding errors. */
225 
226 SPF_errcode_t	 SPF_response_add_error_ptr(SPF_response_t *rp,
227 					SPF_errcode_t code,
228 					const char *text, const char *tptr,
229 					const char *format, ...);
230 SPF_errcode_t	 SPF_response_add_error_idx(SPF_response_t *rp,
231 					SPF_errcode_t code,
232 					const char *text, int idx,
233 					const char *format, ...);
234 SPF_errcode_t	 SPF_response_add_error(SPF_response_t *rp,
235 					SPF_errcode_t code,
236 					const char *format, ...);
237 SPF_errcode_t	 SPF_response_add_warn_ptr(SPF_response_t *rp,
238 					SPF_errcode_t code,
239 					const char *text, const char *tptr,
240 					const char *format, ...);
241 SPF_errcode_t	 SPF_response_add_warn_idx(SPF_response_t *rp,
242 					SPF_errcode_t code,
243 					const char *text, int idx,
244 					const char *format, ...);
245 SPF_errcode_t	 SPF_response_add_warn(SPF_response_t *rp,
246 					SPF_errcode_t code,
247 					const char *format, ...);
248 
249 #endif
250