4fac22604a0d4885eb5e97c7e865249bc1c7ed03
[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
8   SRS Support Version: 1.0a
9
10   License: GPL */
11
12 #include "exim.h"
13 #ifdef EXPERIMENTAL_SRS
14
15 #include <srs_alt.h>
16 #include "srs.h"
17
18 srs_t    *srs                   = NULL;
19 uschar   *srs_db_forward        = NULL;
20 uschar   *srs_db_reverse        = NULL;
21
22
23 /* srs_init just initialises libsrs and creates (if necessary)
24    an srs object to use for all srs calls in this instance */
25
26 int eximsrs_init()
27 {
28   const uschar *list = srs_config;
29   uschar secret_buf[SRS_MAX_SECRET_LENGTH];
30   uschar *secret = NULL;
31   uschar sbuf[4];
32   uschar *sbufp;
33
34   /* Check if this instance of Exim has not initialized SRS */
35   if(srs == NULL)
36   {
37     int co = 0;
38     int hashlen, maxage;
39     BOOL usetimestamp, usehash;
40
41     /* Copy config vars */
42     hashlen = srs_hashlength;
43     maxage = srs_maxage;
44     usetimestamp = srs_usetimestamp;
45     usehash = srs_usehash;
46
47     /* Pass srs_config var (overrides new config vars) */
48     co = 0;
49     if(srs_config != NULL)
50     {
51       secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH);
52
53       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
54         maxage = atoi(sbuf);
55
56       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
57         hashlen = atoi(sbuf);
58
59       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
60         usetimestamp = atoi(sbuf);
61
62       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
63         usehash = atoi(sbuf);
64     }
65
66     if(srs_hashmin == -1)
67       srs_hashmin = hashlen;
68
69     /* First secret specified in secrets? */
70     co = 0;
71     list = srs_secrets;
72     if(secret == NULL || *secret == '\0')
73     {
74       if((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)) == NULL)
75       {
76         log_write(0, LOG_MAIN | LOG_PANIC,
77             "SRS Configuration Error: No secret specified");
78         return DEFER;
79       }
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)) == NULL)
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)) != NULL)
108         srs_add_secret(srs, secret, (Ustrlen(secret) > SRS_MAX_SECRET_LENGTH) ? SRS_MAX_SECRET_LENGTH :  Ustrlen(secret));
109
110     DEBUG(D_any)
111       debug_printf("SRS initialized\n");
112   }
113
114   return OK;
115 }
116
117
118 int eximsrs_done()
119 {
120   if(srs != NULL)
121     srs_close(srs);
122
123   srs = NULL;
124
125   return OK;
126 }
127
128
129 int 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 eximsrs_reverse(uschar **result, uschar *address)
147 {
148   char res[512];
149   int n;
150
151   if((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
152   {
153     DEBUG(D_any)
154       debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
155     if(n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
156       return DECLINE;
157     if(n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
158       return FAIL;
159     return DEFER;
160   }
161
162   *result = string_copy(res);
163   return OK;
164 }
165
166
167 int eximsrs_db_set(BOOL reverse, uschar *srs_db)
168 {
169   if(reverse)
170     srs_db_reverse = (srs_db == NULL ? NULL : string_copy(srs_db));
171   else
172     srs_db_forward = (srs_db == NULL ? NULL : string_copy(srs_db));
173
174   if(srs_set_db_functions(srs, (srs_db_forward ? eximsrs_db_insert : NULL),
175                                (srs_db_reverse ? eximsrs_db_lookup : NULL)) & SRS_RESULT_FAIL)
176     return DEFER;
177
178   return OK;
179 }
180
181
182 srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
183 {
184   uschar *res;
185   uschar buf[64];
186
187   if(srs_db_forward == NULL)
188     return SRS_RESULT_DBERROR;
189
190   srs_db_address = string_copyn(data, data_len);
191   if(srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
192     return SRS_RESULT_DBERROR;
193
194   srs_db_key = string_copyn(buf, 16);
195
196   if((res = expand_string(srs_db_forward)) == NULL)
197     return SRS_RESULT_DBERROR;
198
199   if(result_len < 17)
200     return SRS_RESULT_DBERROR;
201
202   Ustrncpy(result, srs_db_key, result_len);
203
204   return SRS_RESULT_OK;
205 }
206
207
208 srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
209 {
210   uschar *res;
211
212   if(srs_db_reverse == NULL)
213     return SRS_RESULT_DBERROR;
214
215   srs_db_key = string_copyn(data, data_len);
216   if((res = expand_string(srs_db_reverse)) == NULL)
217     return SRS_RESULT_DBERROR;
218
219   if(Ustrlen(res) >= result_len)
220     return SRS_RESULT_ADDRESSTOOLONG;
221
222   strncpy(result, res, result_len);
223
224   return SRS_RESULT_OK;
225 }
226
227
228 #endif
229