69f35bf999dd5ee973d7e9d453d3d3fe65a53237
[users/jgh/exim.git] / src / src / srs.c
1 /* $Cambridge: exim/src/src/srs.c,v 1.8 2005/06/27 18:10:30 tom Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* SRS - Sender rewriting scheme support
8   (C)2004 Miles Wilton <miles@mirtol.com>
9
10   SRS Support Version: 1.0a
11
12   License: GPL */
13
14 #include "exim.h"
15 #ifdef EXPERIMENTAL_SRS
16
17 #include <srs_alt.h>
18 #include "srs.h"
19
20 srs_t    *srs                   = NULL;
21 uschar   *srs_db_forward        = NULL;
22 uschar   *srs_db_reverse        = NULL;
23
24
25 /* srs_init just initialises libsrs and creates (if necessary)
26    an srs object to use for all srs calls in this instance */
27
28 int eximsrs_init()
29 {
30   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))) != NULL)
56         maxage = atoi(sbuf);
57
58       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
59         hashlen = atoi(sbuf);
60
61       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
62         usetimestamp = atoi(sbuf);
63
64       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
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     {
76       if((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)) == NULL)
77       {
78         log_write(0, LOG_MAIN | LOG_PANIC,
79             "SRS Configuration Error: No secret specified");
80         return DEFER;
81       }
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)) == NULL)
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     while((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)) != NULL)
110         srs_add_secret(srs, secret, (Ustrlen(secret) > SRS_MAX_SECRET_LENGTH) ? SRS_MAX_SECRET_LENGTH :  Ustrlen(secret));
111
112     DEBUG(D_any)
113       debug_printf("SRS initialized\n");
114   }
115
116   return OK;
117 }
118
119
120 int eximsrs_done()
121 {
122   if(srs != NULL)
123     srs_close(srs);
124
125   srs = NULL;
126
127   return OK;
128 }
129
130
131 int eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
132 {
133   char res[512];
134   int n;
135
136   if((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
137   {
138     DEBUG(D_any)
139       debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
140     return DEFER;
141   }
142
143   *result = string_copy(res);
144   return OK;
145 }
146
147
148 int eximsrs_reverse(uschar **result, uschar *address)
149 {
150   char res[512];
151   int n;
152
153   if((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
154   {
155     DEBUG(D_any)
156       debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
157     if(n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
158       return DECLINE;
159     if(n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
160       return FAIL;
161     return DEFER;
162   }
163
164   *result = string_copy(res);
165   return OK;
166 }
167
168
169 int 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 eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
185 {
186   uschar *res;
187   uschar buf[64];
188
189   if(srs_db_forward == NULL)
190     return SRS_RESULT_DBERROR;
191
192   srs_db_address = string_copyn(data, data_len);
193   if(srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
194     return SRS_RESULT_DBERROR;
195
196   srs_db_key = string_copyn(buf, 16);
197
198   if((res = expand_string(srs_db_forward)) == NULL)
199     return SRS_RESULT_DBERROR;
200
201   if(result_len < 17)
202     return SRS_RESULT_DBERROR;
203
204   Ustrncpy(result, srs_db_key, result_len);
205
206   return SRS_RESULT_OK;
207 }
208
209
210 srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
211 {
212   uschar *res;
213
214   if(srs_db_reverse == NULL)
215     return SRS_RESULT_DBERROR;
216
217   srs_db_key = string_copyn(data, data_len);
218   if((res = expand_string(srs_db_reverse)) == NULL)
219     return SRS_RESULT_DBERROR;
220
221   if(Ustrlen(res) >= result_len)
222     return SRS_RESULT_ADDRESSTOOLONG;
223
224   strncpy(result, res, result_len);
225
226   return SRS_RESULT_OK;
227 }
228
229
230 #endif
231