DKIM: document proper Ed25519 key-generation methods; remove helper program
[exim.git] / src / src / spf.c
CommitLineData
8523533c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
8e669ac1 4
8523533c 5/* Experimental SPF support.
5a66c31b 6 Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2014
80fea873 7 License: GPL
f9ba5e22 8 Copyright (c) The Exim Maintainers 2015 - 2018
80fea873 9*/
8e669ac1 10
8523533c
TK
11/* Code for calling spf checks via libspf-alt. Called from acl.c. */
12
13#include "exim.h"
7952eef9 14#ifdef SUPPORT_SPF
8523533c 15
6d06cf48
TK
16/* must be kept in numeric order */
17static spf_result_id spf_result_id_list[] = {
f2ed27cf
JH
18 /* name value */
19 { US"invalid", 0},
20 { US"neutral", 1 },
21 { US"pass", 2 },
22 { US"fail", 3 },
23 { US"softfail", 4 },
24 { US"none", 5 },
25 { US"err_temp", 6 }, /* Deprecated Apr 2014 */
26 { US"err_perm", 7 }, /* Deprecated Apr 2014 */
27 { US"temperror", 6 }, /* RFC 4408 defined */
28 { US"permerror", 7 } /* RFC 4408 defined */
6d06cf48
TK
29};
30
384152a6
TK
31SPF_server_t *spf_server = NULL;
32SPF_request_t *spf_request = NULL;
33SPF_response_t *spf_response = NULL;
34SPF_response_t *spf_response_2mx = NULL;
8523533c 35
eb52e2cb 36
8523533c
TK
37/* spf_init sets up a context that can be re-used for several
38 messages on the same SMTP connection (that come from the
eb52e2cb 39 same host with the same HELO string)
8e669ac1 40
eb52e2cb 41Return: Boolean success */
8e669ac1 42
eb52e2cb
JH
43BOOL
44spf_init(uschar *spf_helo_domain, uschar *spf_remote_addr)
45{
46spf_server = SPF_server_new(SPF_DNS_CACHE, 0);
8e669ac1 47
eb52e2cb
JH
48if (!spf_server)
49 {
50 DEBUG(D_receive) debug_printf("spf: SPF_server_new() failed.\n");
51 return FALSE;
8523533c
TK
52 }
53
eb52e2cb
JH
54if (SPF_server_set_rec_dom(spf_server, CS primary_hostname))
55 {
56 DEBUG(D_receive) debug_printf("spf: SPF_server_set_rec_dom(\"%s\") failed.\n",
57 primary_hostname);
58 spf_server = NULL;
59 return FALSE;
7b3a77e5
TK
60 }
61
eb52e2cb
JH
62spf_request = SPF_request_new(spf_server);
63
64if ( SPF_request_set_ipv4_str(spf_request, CS spf_remote_addr)
65 && SPF_request_set_ipv6_str(spf_request, CS spf_remote_addr)
66 )
67 {
68 DEBUG(D_receive)
69 debug_printf("spf: SPF_request_set_ipv4_str() and "
70 "SPF_request_set_ipv6_str() failed [%s]\n", spf_remote_addr);
71 spf_server = NULL;
72 spf_request = NULL;
73 return FALSE;
8523533c
TK
74 }
75
eb52e2cb
JH
76if (SPF_request_set_helo_dom(spf_request, CS spf_helo_domain))
77 {
78 DEBUG(D_receive) debug_printf("spf: SPF_set_helo_dom(\"%s\") failed.\n",
79 spf_helo_domain);
80 spf_server = NULL;
81 spf_request = NULL;
82 return FALSE;
8523533c 83 }
8e669ac1 84
eb52e2cb 85return TRUE;
8523533c
TK
86}
87
88
89/* spf_process adds the envelope sender address to the existing
90 context (if any), retrieves the result, sets up expansion
eb52e2cb 91 strings and evaluates the condition outcome.
f9ba5e22 92
eb52e2cb
JH
93Return: OK/FAIL */
94
95int
96spf_process(const uschar **listptr, uschar *spf_envelope_sender, int action)
97{
98int sep = 0;
99const uschar *list = *listptr;
100uschar *spf_result_id;
101int rc = SPF_RESULT_PERMERROR;
102
103if (!(spf_server && spf_request))
104 /* no global context, assume temp error and skip to evaluation */
105 rc = SPF_RESULT_PERMERROR;
106
107else if (SPF_request_set_env_from(spf_request, CS spf_envelope_sender))
108 /* Invalid sender address. This should be a real rare occurence */
109 rc = SPF_RESULT_PERMERROR;
110
111else
112 {
8523533c 113 /* get SPF result */
65a7d8c3 114 if (action == SPF_PROCESS_FALLBACK)
87e9d061 115 {
7156b1ef 116 SPF_request_query_fallback(spf_request, &spf_response, CS spf_guess);
87e9d061
JH
117 spf_result_guessed = TRUE;
118 }
65a7d8c3
NM
119 else
120 SPF_request_query_mailfrom(spf_request, &spf_response);
8523533c
TK
121
122 /* set up expansion items */
5903c6ff
JH
123 spf_header_comment = US SPF_response_get_header_comment(spf_response);
124 spf_received = US SPF_response_get_received_spf(spf_response);
125 spf_result = US SPF_strresult(SPF_response_result(spf_response));
126 spf_smtp_comment = US SPF_response_get_smtp_comment(spf_response);
8523533c 127
384152a6 128 rc = SPF_response_result(spf_response);
eb52e2cb
JH
129 }
130
131/* We got a result. Now see if we should return OK or FAIL for it */
132DEBUG(D_acl) debug_printf("SPF result is %s (%d)\n", SPF_strresult(rc), rc);
133
134if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none")))
135 return spf_process(listptr, spf_envelope_sender, SPF_PROCESS_FALLBACK);
136
137while ((spf_result_id = string_nextinlist(&list, &sep, NULL, 0)))
138 {
139 BOOL negate, result;
140
141 if ((negate = spf_result_id[0] == '!'))
142 spf_result_id++;
143
144 result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name) == 0;
145 if (negate != result) return OK;
146 }
8523533c 147
eb52e2cb
JH
148/* no match */
149return FAIL;
8523533c
TK
150}
151
dfbcb5ac
JH
152
153
154gstring *
155authres_spf(gstring * g)
156{
87e9d061 157uschar * s;
dfbcb5ac
JH
158if (!spf_result) return g;
159
87e9d061
JH
160g = string_append(g, 2, US";\n\tspf=", spf_result);
161if (spf_result_guessed)
162 g = string_cat(g, US" (best guess record for domain)");
163
164s = expand_string(US"$sender_address_domain");
165return s && *s
166 ? string_append(g, 2, US" smtp.mailfrom=", s)
167 : string_cat(g, US" smtp.mailfrom=<>");
dfbcb5ac
JH
168}
169
170
8523533c 171#endif