1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
4
5 /* SRS - Sender rewriting scheme support
6 (C)2004 Miles Wilton <miles@mirtol.com>
7 Copyright (c) The Exim Maintainers 2016
8
9 SRS Support Version: 1.0a
10
11 License: GPL */
12
13 #include "exim.h"
14 #ifdef EXPERIMENTAL_SRS_ALT
15
16 #include <srs_alt.h>
17 #include "srs.h"
18
19 srs_t *srs = NULL;
20 uschar *srs_db_forward = NULL;
21 uschar *srs_db_reverse = NULL;
22
23
24 /* srs_init just initialises libsrs and creates (if necessary)
25 an srs object to use for all srs calls in this instance */
26
27 int
eximsrs_init()28 eximsrs_init()
29 {
30 const uschar *list = srs_config;
31 uschar secret_buf[SRS_MAX_SECRET_LENGTH];
32 uschar *secret = NULL;
33 uschar sbuf[4];
34 uschar *sbufp;
35
36 /* Check if this instance of Exim has not initialized SRS */
37 if (srs == NULL)
38 {
39 int co = 0;
40 int hashlen, maxage;
41 BOOL usetimestamp, usehash;
42
43 /* Copy config vars */
44 hashlen = srs_hashlength;
45 maxage = srs_maxage;
46 usetimestamp = srs_usetimestamp;
47 usehash = srs_usehash;
48
49 /* Pass srs_config var (overrides new config vars) */
50 co = 0;
51 if (srs_config != NULL)
52 {
53 /* looks like list not expanded, so cannot be tainted */
54 secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH);
55
56 if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
57 maxage = atoi(sbuf);
58
59 if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
60 hashlen = atoi(sbuf);
61
62 if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
63 usetimestamp = atoi(sbuf);
64
65 if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
66 usehash = atoi(sbuf);
67 }
68
69 if (srs_hashmin == -1)
70 srs_hashmin = hashlen;
71
72 /* First secret specified in secrets? */
73 co = 0;
74 list = srs_secrets;
75 if (secret == NULL || *secret == '\0')
76 /* looks like list not expanded so cannot be tainted */
77 if (!(secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
78 {
79 log_write(0, LOG_MAIN | LOG_PANIC,
80 "SRS Configuration Error: No secret specified");
81 return DEFER;
82 }
83
84 /* Check config */
85 if (maxage < 0 || maxage > 365)
86 {
87 log_write(0, LOG_MAIN | LOG_PANIC,
88 "SRS Configuration Error: Invalid maximum timestamp age");
89 return DEFER;
90 }
91 if (hashlen < 1 || hashlen > 20 || srs_hashmin < 1 || srs_hashmin > 20)
92 {
93 log_write(0, LOG_MAIN | LOG_PANIC,
94 "SRS Configuration Error: Invalid hash length");
95 return DEFER;
96 }
97
98 if (!(srs = srs_open(secret, Ustrlen(secret), maxage, hashlen, srs_hashmin)))
99 {
100 log_write(0, LOG_MAIN | LOG_PANIC,
101 "Failed to allocate SRS memory");
102 return DEFER;
103 }
104
105 srs_set_option(srs, SRS_OPTION_USETIMESTAMP, usetimestamp);
106 srs_set_option(srs, SRS_OPTION_USEHASH, usehash);
107
108 /* Extra secrets? */
109 /* looks like list not expanded so cannot be tainted */
110 while((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
111 srs_add_secret(srs, secret,
112 Ustrlen(secret) > SRS_MAX_SECRET_LENGTH ? SRS_MAX_SECRET_LENGTH : Ustrlen(secret));
113
114 DEBUG(D_any)
115 debug_printf("SRS initialized\n");
116 }
117
118 return OK;
119 }
120
121
122 int
eximsrs_done()123 eximsrs_done()
124 {
125 if (srs) srs_close(srs);
126 srs = NULL;
127 return OK;
128 }
129
130
131 int
eximsrs_forward(uschar ** result,uschar * orig_sender,uschar * domain)132 eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
133 {
134 char res[512];
135 int n;
136
137 if ((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
138 {
139 DEBUG(D_any)
140 debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
141 return DEFER;
142 }
143
144 *result = string_copy(res);
145 return OK;
146 }
147
148
149 int
eximsrs_reverse(uschar ** result,uschar * address)150 eximsrs_reverse(uschar **result, uschar *address)
151 {
152 char res[512];
153 int n;
154
155 if ((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
156 {
157 DEBUG(D_any)
158 debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
159 if (n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
160 return DECLINE;
161 if (n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
162 return FAIL;
163 return DEFER;
164 }
165
166 *result = string_copy(res);
167 return OK;
168 }
169
170
171 int
eximsrs_db_set(BOOL reverse,uschar * srs_db)172 eximsrs_db_set(BOOL reverse, uschar *srs_db)
173 {
174 if (reverse)
175 srs_db_reverse = (srs_db == NULL ? NULL : string_copy(srs_db));
176 else
177 srs_db_forward = (srs_db == NULL ? NULL : string_copy(srs_db));
178
179 if (srs_set_db_functions(srs, (srs_db_forward ? eximsrs_db_insert : NULL),
180 (srs_db_reverse ? eximsrs_db_lookup : NULL)) & SRS_RESULT_FAIL)
181 return DEFER;
182
183 return OK;
184 }
185
186
187 srs_result
eximsrs_db_insert(srs_t * srs,char * data,uint data_len,char * result,uint result_len)188 eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
189 {
190 uschar *res;
191 uschar buf[64];
192
193 if (srs_db_forward == NULL)
194 return SRS_RESULT_DBERROR;
195
196 srs_db_address = string_copyn(data, data_len);
197 if (srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
198 return SRS_RESULT_DBERROR;
199
200 srs_db_key = string_copyn(buf, 16);
201
202 if ((res = expand_string(srs_db_forward)) == NULL)
203 return SRS_RESULT_DBERROR;
204
205 if (result_len < 17)
206 return SRS_RESULT_DBERROR;
207
208 Ustrncpy(result, srs_db_key, result_len);
209
210 return SRS_RESULT_OK;
211 }
212
213
214 srs_result
eximsrs_db_lookup(srs_t * srs,char * data,uint data_len,char * result,uint result_len)215 eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
216 {
217 uschar *res;
218
219 if (srs_db_reverse == NULL)
220 return SRS_RESULT_DBERROR;
221
222 srs_db_key = string_copyn(data, data_len);
223 if ((res = expand_string(srs_db_reverse)) == NULL)
224 return SRS_RESULT_DBERROR;
225
226 if (Ustrlen(res) >= result_len)
227 return SRS_RESULT_ADDRESSTOOLONG;
228
229 strncpy(result, res, result_len);
230
231 return SRS_RESULT_OK;
232 }
233
234
235 #endif
236
237