1 /*
2 **  Copyright (c) 2012-2015, 2018, 2021, The Trusted Domain Project.
3 **    All rights reserved.
4 */
5 
6 #ifndef OPENDMARC_INTERNAL_H
7 #define OPENDMARC_INTERNAL_H
8 
9 #if HAVE_CONFIG_H
10 # include "build-config.h"
11 #endif
12 
13 # if HAVE_CTYPE_H
14 #	include <ctype.h>
15 # endif
16 # if HAVE_ERRNO_H
17 #	include <errno.h>
18 # endif
19 # if HAVE_POLL_H
20 #	include <poll.h>
21 # endif
22 # if HAVE_FCNTL_H
23 #	include <fcntl.h>
24 # endif
25 # ifdef sun
26 #	include <libgen.h>
27 # endif
28 # if HAVE_MEMORY_H
29 #	include <memory.h>
30 # endif
31 # if HAVE_STDIO_H
32 #	 include <stdio.h>
33 # endif
34 # if HAVE_STDLIB_H
35 #	include <stdlib.h>
36 # endif
37 # if HAVE_STRING_H
38 #	include <string.h>
39 # endif
40 # if HAVE_SYS_SOCKET_H
41 #	include <sys/socket.h>
42 # endif
43 # if HAVE_SYS_STAT_H
44 #	include <sys/stat.h>
45 # endif
46 # if HAVE_SYS_TYPES_H
47 #	include <sys/types.h>
48 # endif
49 # if HAVE_SYSEXITS_H
50 #	include <sysexits.h>
51 # endif
52 # if HAVE_SYSLOG_H
53 #	include <syslog.h>
54 # endif
55 # if TM_IN_SYS_TIME
56 #	include <sys/time.h>
57 # else
58 #	include <time.h>
59 # endif
60 # if TIME_WITH_SYS_TIME && TM_IN_SYS_TIME
61 #	include <time.h>
62 # endif
63 # if HAVE_UNISTD_H
64 #	include <unistd.h>
65 # endif
66 # if HAVE_NETDB_H
67 #	include <netdb.h>
68 # endif
69 # if HAVE_NETINET_IN_H
70 #	include <netinet/in.h>
71 # endif
72 # if HAVE_SYS_PARAM_H
73 #	include <sys/param.h>
74 # endif
75 # if HAVE_ARPA_INET_H
76 #	include <arpa/inet.h>
77 # endif
78 # if HAVE_ARPA_NAMESER_H
79 #	include <arpa/nameser.h>
80 # endif
81 # if HAVE_ARPA_NAMESER_COMPAT_H
82 #	include <arpa/nameser_compat.h>
83 # endif
84 # if HAVE_RESOLV_H
85 #	include <resolv.h>
86 # endif
87 # if HAVE_SIGNAL_H
88 #	include <signal.h>
89 # endif
90 # if HAVE_PTHREAD_H || HAVE_PTHREAD
91 #	include <pthread.h>
92 # endif
93 
94 # ifndef UNDEFINED
95 #       define UNDEFINED	(-1)
96 # endif
97 # ifndef TRUE
98 #       define TRUE		(1)
99 # endif
100 # ifndef FALSE
101 #       define FALSE		(0)
102 # endif
103 # ifndef MAYBE
104 #       define MAYBE		(2)
105 # endif
106 # define bool int
107 
108 #ifndef NETDB_INTERNAL
109 # define NETDB_INTERNAL (-1)
110 #endif
111 
112 #ifndef NETDB_SUCCESS
113 # define NETDB_SUCCESS (0)
114 #endif
115 
116 /*
117 ** Beware that some Linux versions incorrectly define
118 ** MAXHOSTNAMELEN as 64, but DNS lookups require a length
119 ** of 255. So we don't use MAXHOSTNAMELEN here. Instead
120 ** we use our own MAXDNSHOSTNAME.
121 */
122 #define MAXDNSHOSTNAME 256
123 
124 /*
125 ** Maximum number of DNS retries when resolving CNAMES, etc.
126 */
127 
128 #define	DNS_MAX_RETRIES 6
129 
130 /*****************************************************************************
131 ** DMARC_POLICY_T -- The opaque context for the library.
132 ** 	Memory needs to be allocated and freed.
133 *****************************************************************************/
134 
135 typedef struct dmarc_policy_t {
136 	/*
137 	 * Supplied information
138 	 */
139 	u_char *	ip_addr;		/* Input: connected IPV4 or IPV6 address */
140 	int 		ip_type;		/* Input: IPv4 or IPv6 */
141 	u_char * 	spf_domain;		/* Input: Domain used to verify SPF */
142 	int 	 	spf_origin;		/* Input: was domain MAIL From: or HELO for SPF check */
143 	int		spf_outcome;		/* Input: What was the outcome of the SPF check */
144 	u_char *	spf_human_outcome;	/* Input: What was the outcome of the SPF check in human readable form */
145 	int		dkim_final;		/* This is the best record found */
146 	u_char * 	dkim_domain;		/* Input: The d= domain */
147 	u_char *	dkim_selector;		/* Input: The s= selector */
148 	int		dkim_outcome;		/* Input: What was the outcome of the DKIM check */
149 	u_char *	dkim_human_outcome;	/* Input: What was the outcome of the DKIM check in human readable form */
150 
151 	/*
152 	 * Computed outcomes
153 	 */
154 	int		dkim_alignment;
155 	int		spf_alignment;
156 
157 	/*
158 	 * Computed Organizational domain, if subdomain lacked a record.
159 	 */
160 	u_char *	from_domain;		/* Input: From: header domain */
161 	u_char *	organizational_domain;
162 
163 	/*
164 	 * Found in the _dmarc record or supplied to us.
165 	 */
166 	int		h_error;	/* Zero if found, else DNS error */
167 	int		adkim;
168 	int		aspf;
169 	int		p;
170 	int		sp;
171 	int		pct;
172 	int		rf;
173 	uint32_t	ri;
174 	int		rua_cnt;
175 	u_char **	rua_list;
176 	int		ruf_cnt;
177 	u_char **	ruf_list;
178 	int		fo;
179 } DMARC_POLICY_T;
180 #ifndef OPENDMARC_POLICY_C
181 # define OPENDMARC_POLICY_C 1
182 #endif /* ! OPENDMARC_POLICY_C */
183 
184 
185 /* dmarc_dns.c */
186 char * dmarc_dns_get_record(char *domain, int *reply, char *got_txtbuf, size_t got_txtlen);
187 
188 /* opendmarc_hash.c */
189 typedef struct entry_bucket {
190 	struct entry_bucket *previous;
191 	struct entry_bucket *next;
192 	char  *key;
193 	void  *data;
194 	time_t timestamp;
195 } OPENDMARC_HASH_BUCKET;
196 
197 typedef struct {
198 	OPENDMARC_HASH_BUCKET   *bucket;
199 # if HAVE_PTHREAD_H || HAVE_PTHREAD
200 	pthread_mutex_t  mutex;
201 # endif
202 } OPENDMARC_HASH_SHELF;
203 
204 #define	OPENDMARC_MIN_SHELVES_LG2	4
205 #define	OPENDMARC_MIN_SHELVES	(1 << OPENDMARC_MIN_SHELVES_LG2)
206 
207 /*
208  * max * sizeof internal_entry must fit into size_t.
209  * assumes internal_entry is <= 32 (2^5) bytes.
210  */
211 #define	OPENDMARC_MAX_SHELVES_LG2	(sizeof (size_t) * 8 - 1 - 5)
212 #define	OPENDMARC_MAX_SHELVES	((size_t)1 << OPENDMARC_MAX_SHELVES_LG2)
213 
214 typedef struct {
215 	OPENDMARC_HASH_SHELF *table;
216 	size_t         tablesize;
217 	void (*freefunct)(void *);
218 } OPENDMARC_HASH_CTX;
219 
220 #define OPENDMARC_DEFAULT_HASH_TABLESIZE	(2048)
221 
222 OPENDMARC_HASH_CTX *	opendmarc_hash_init(size_t tablesize);
223 OPENDMARC_HASH_CTX *	opendmarc_hash_shutdown(OPENDMARC_HASH_CTX *hctx);
224 void			opendmarc_hash_set_callback(OPENDMARC_HASH_CTX *hctx, void (*callback)(void *));
225 void *      		opendmarc_hash_lookup(OPENDMARC_HASH_CTX *hctx, char *string, void *data, size_t datalen);
226 int           		opendmarc_hash_drop(OPENDMARC_HASH_CTX *hctx, char *string);
227 int           		opendmarc_hash_expire(OPENDMARC_HASH_CTX *hctx, time_t age);
228 
229 /* opendmarc_tld.c */
230 int 			opendmarc_tld_read_file(char *path_fname, char *commentstring, char *drop, char *except);
231 int 			opendmarc_get_tld(u_char *domain, u_char *tld, size_t tld_len);
232 int                     opendmarc_reverse_domain(u_char *domain, u_char *buf, size_t buflen);
233 void 			opendmarc_tld_shutdown(void);
234 
235 /* opendmarc_util.c */
236 u_char ** opendmarc_util_pushargv(u_char *str, u_char **ary, int *cnt);
237 u_char ** opendmarc_util_clearargv(u_char **ary);
238 u_char ** opendmarc_util_dupe_argv(u_char **ary);
239 u_char *  opendmarc_util_cleanup(u_char *str, u_char *buf, size_t buflen);
240 u_char *  opendmarc_util_finddomain(u_char *raw, u_char *buf, size_t buflen);
241 char **   opendmarc_util_freenargv(char **ary, int *num);
242 char **   opendmarc_util_pushnargv(char *str, char **ary, int *num);
243 char *    opendmarc_util_ultoa(unsigned long val, char *buffer, size_t bufferlen);
244 
245 /* opendmarc_policy.c */
246 void opendmarc_policy_library_dns_hook(int *nscountp, struct sockaddr_in *nsaddr_list);
247 
248 #if WITH_SPF
249 
250 #if HAVE_SPF2_H
251 #include "spf.h"
252 typedef struct spf_context_struct {
253 	SPF_server_t *		spf_server;
254 	SPF_request_t *		spf_request;
255 	SPF_response_t *	spf_response;
256 	SPF_result_t		spf_result;
257 	char    		mailfrom_addr[512];
258 	char			mailfrom_domain[256];
259 	char    		helo_domain[256];
260 } SPF_CTX_T;
261 int opendmarc_spf2_test(char *ip_address, char *mail_from_domain, char *helo_domain, char *spf_record, int softfail_okay_flag, char *human_readable, size_t human_readable_len, int *used_mfrom);
262 
263 #else /* not HAVE_SPF2_H */
264 
265 /* opendmarc_spf.c and opendmarc_spf_dns.c */
266 #define MAX_SPF_RECURSION (10)
267 typedef struct spf_context_struct {
268         int     nlines;
269 	char *  lines[MAX_SPF_RECURSION+2];
270 	int     status;
271 	int     in_token;
272 	char    mailfrom_addr[512];
273 	char    helo_domain[256];
274 	char    mailfrom_domain[256];
275 	char    validated_domain[256];
276 	char    ip_address[32];
277 	char    spf_record[BUFSIZ *2];
278 	char ** iplist;
279 	int     ipcount;
280 	char    exp_buf[512];
281 	int     did_get_exp;
282 } SPF_CTX_T;
283 int		opendmarc_spf_test(char *ip_address, char *mail_from_domain, char *helo_domain, char *spf_record, int softfail_okay_flag, char *human_readable, size_t human_readable_len, int *used_mfrom);
284 char ** 	opendmarc_spf_dns_lookup_a(char *domain, char **ary, int *cnt);
285 char ** 	opendmarc_spf_dns_lookup_mx(char *domain, char **ary, int *cnt);
286 char ** 	opendmarc_spf_dns_lookup_mx_domain(char *domain, char **ary, int *cnt);
287 char ** 	opendmarc_spf_dns_lookup_ptr(char *ip, char **ary, int *cnt);
288 int     	opendmarc_spf_dns_cidr_address(char *addr, u_long *hi, u_long *lo);
289 int     	opendmarc_spf_dns_does_domain_exist(char *domain, int *reply);
290 char *  	opendmarc_spf_dns_get_record(char *domain, int *reply, char *txt, size_t txtlen, char *cname, size_t cnamelen, int spfcheck);
291 int     	opendmarc_spf_dns_does_domain_exist(char *domain, int *reply);
292 char *  	opendmarc_spf_dns_get_record(char *domain, int *reply, char *txt, size_t txtlen, char *cname, size_t cnamelen, int spfcheck);
293 int 		opendmarc_spf_ipv6_cidr_check(char *ipv6_str, char *cidr_string);
294 int 		opendmarc_spf_cidr_address(uint32_t ip, char *cidr_addr);
295 SPF_CTX_T *     opendmarc_spf_alloc_ctx();
296 SPF_CTX_T *     opendmarc_spf_free_ctx(SPF_CTX_T *spfctx);
297 int             opendmarc_spf_status_to_pass(int status, int none_pass);
298 int             opendmarc_spf_specify_mailfrom(SPF_CTX_T *spfctx, char *mailfrom, size_t mailfrom_len, int *use_domain);
299 int             opendmarc_spf_specify_helo_domain(SPF_CTX_T *spfctx, char *helo_domain, size_t helo_domain_len);
300 int             opendmarc_spf_specify_ip_address(SPF_CTX_T *spfctx, char *ip_address, size_t ip_address_len);
301 int             opendmarc_spf_specify_record(SPF_CTX_T *spfctx, char *spf_record, size_t spf_record_length);
302 int             opendmarc_spf_parse(SPF_CTX_T *spfctx, int dns_count, char *xbuf, size_t xbuf_len);
303 const char *    opendmarc_spf_status_to_msg(SPF_CTX_T *spfctx, int status);
304 #endif /* HAVE_SPF2_H */
305 
306 #endif /* WITH_SPF */
307 
308 #endif /* OPENDMARC_INTERNAL_H */
309