Avoid the long whats_supported line being mixed with output from other processes
[users/jgh/exim.git] / src / src / srs.c
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
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
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     secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH);
54
55     if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
56       maxage = atoi(sbuf);
57
58     if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
59       hashlen = atoi(sbuf);
60
61     if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
62       usetimestamp = atoi(sbuf);
63
64     if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
65       usehash = atoi(sbuf);
66     }
67
68   if (srs_hashmin == -1)
69     srs_hashmin = hashlen;
70
71   /* First secret specified in secrets? */
72   co = 0;
73   list = srs_secrets;
74   if (secret == NULL || *secret == '\0')
75     if (!(secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
76       {
77       log_write(0, LOG_MAIN | LOG_PANIC,
78           "SRS Configuration Error: No secret specified");
79       return DEFER;
80       }
81
82   /* Check config */
83   if (maxage < 0 || maxage > 365)
84     {
85     log_write(0, LOG_MAIN | LOG_PANIC,
86         "SRS Configuration Error: Invalid maximum timestamp age");
87     return DEFER;
88     }
89   if (hashlen < 1 || hashlen > 20 || srs_hashmin < 1 || srs_hashmin > 20)
90     {
91     log_write(0, LOG_MAIN | LOG_PANIC,
92         "SRS Configuration Error: Invalid hash length");
93     return DEFER;
94     }
95
96   if (!(srs = srs_open(secret, Ustrlen(secret), maxage, hashlen, srs_hashmin)))
97     {
98     log_write(0, LOG_MAIN | LOG_PANIC,
99         "Failed to allocate SRS memory");
100     return DEFER;
101     }
102
103   srs_set_option(srs, SRS_OPTION_USETIMESTAMP, usetimestamp);
104   srs_set_option(srs, SRS_OPTION_USEHASH, usehash);
105
106   /* Extra secrets? */
107   while((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
108       srs_add_secret(srs, secret,
109         Ustrlen(secret) > SRS_MAX_SECRET_LENGTH ? SRS_MAX_SECRET_LENGTH :  Ustrlen(secret));
110
111   DEBUG(D_any)
112     debug_printf("SRS initialized\n");
113   }
114
115 return OK;
116 }
117
118
119 int
120 eximsrs_done()
121 {
122 if (srs) srs_close(srs);
123 srs = NULL;
124 return OK;
125 }
126
127
128 int
129 eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
130 {
131 char res[512];
132 int n;
133
134 if ((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
135   {
136   DEBUG(D_any)
137     debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
138   return DEFER;
139   }
140
141 *result = string_copy(res);
142 return OK;
143 }
144
145
146 int
147 eximsrs_reverse(uschar **result, uschar *address)
148 {
149 char res[512];
150 int n;
151
152 if ((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
153   {
154   DEBUG(D_any)
155     debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
156   if (n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
157     return DECLINE;
158   if (n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
159     return FAIL;
160   return DEFER;
161   }
162
163 *result = string_copy(res);
164 return OK;
165 }
166
167
168 int
169 eximsrs_db_set(BOOL reverse, uschar *srs_db)
170 {
171 if (reverse)
172   srs_db_reverse = (srs_db == NULL ? NULL : string_copy(srs_db));
173 else
174   srs_db_forward = (srs_db == NULL ? NULL : string_copy(srs_db));
175
176 if (srs_set_db_functions(srs, (srs_db_forward ? eximsrs_db_insert : NULL),
177                              (srs_db_reverse ? eximsrs_db_lookup : NULL)) & SRS_RESULT_FAIL)
178   return DEFER;
179
180 return OK;
181 }
182
183
184 srs_result
185 eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
186 {
187 uschar *res;
188 uschar buf[64];
189
190 if (srs_db_forward == NULL)
191   return SRS_RESULT_DBERROR;
192
193 srs_db_address = string_copyn(data, data_len);
194 if (srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
195   return SRS_RESULT_DBERROR;
196
197 srs_db_key = string_copyn(buf, 16);
198
199 if ((res = expand_string(srs_db_forward)) == NULL)
200   return SRS_RESULT_DBERROR;
201
202 if (result_len < 17)
203   return SRS_RESULT_DBERROR;
204
205 Ustrncpy(result, srs_db_key, result_len);
206
207 return SRS_RESULT_OK;
208 }
209
210
211 srs_result
212 eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
213 {
214 uschar *res;
215
216 if (srs_db_reverse == NULL)
217   return SRS_RESULT_DBERROR;
218
219 srs_db_key = string_copyn(data, data_len);
220 if ((res = expand_string(srs_db_reverse)) == NULL)
221   return SRS_RESULT_DBERROR;
222
223 if (Ustrlen(res) >= result_len)
224   return SRS_RESULT_ADDRESSTOOLONG;
225
226 strncpy(result, res, result_len);
227
228 return SRS_RESULT_OK;
229 }
230
231
232 #endif
233