Drain socket to get clean TCP FINs
[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 eximsrs_init()
28 {
29   const uschar *list = srs_config;
30   uschar secret_buf[SRS_MAX_SECRET_LENGTH];
31   uschar *secret = NULL;
32   uschar sbuf[4];
33   uschar *sbufp;
34
35   /* Check if this instance of Exim has not initialized SRS */
36   if(srs == NULL)
37   {
38     int co = 0;
39     int hashlen, maxage;
40     BOOL usetimestamp, usehash;
41
42     /* Copy config vars */
43     hashlen = srs_hashlength;
44     maxage = srs_maxage;
45     usetimestamp = srs_usetimestamp;
46     usehash = srs_usehash;
47
48     /* Pass srs_config var (overrides new config vars) */
49     co = 0;
50     if(srs_config != NULL)
51     {
52       secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH);
53
54       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
55         maxage = atoi(sbuf);
56
57       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
58         hashlen = atoi(sbuf);
59
60       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
61         usetimestamp = atoi(sbuf);
62
63       if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
64         usehash = atoi(sbuf);
65     }
66
67     if(srs_hashmin == -1)
68       srs_hashmin = hashlen;
69
70     /* First secret specified in secrets? */
71     co = 0;
72     list = srs_secrets;
73     if(secret == NULL || *secret == '\0')
74     {
75       if((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)) == NULL)
76       {
77         log_write(0, LOG_MAIN | LOG_PANIC,
78             "SRS Configuration Error: No secret specified");
79         return DEFER;
80       }
81     }
82
83     /* Check config */
84     if(maxage < 0 || maxage > 365)
85     {
86       log_write(0, LOG_MAIN | LOG_PANIC,
87           "SRS Configuration Error: Invalid maximum timestamp age");
88       return DEFER;
89     }
90     if(hashlen < 1 || hashlen > 20 || srs_hashmin < 1 || srs_hashmin > 20)
91     {
92       log_write(0, LOG_MAIN | LOG_PANIC,
93           "SRS Configuration Error: Invalid hash length");
94       return DEFER;
95     }
96
97     if((srs = srs_open(secret, Ustrlen(secret), maxage, hashlen, srs_hashmin)) == NULL)
98     {
99       log_write(0, LOG_MAIN | LOG_PANIC,
100           "Failed to allocate SRS memory");
101       return DEFER;
102     }
103
104     srs_set_option(srs, SRS_OPTION_USETIMESTAMP, usetimestamp);
105     srs_set_option(srs, SRS_OPTION_USEHASH, usehash);
106
107     /* Extra secrets? */
108     while((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)) != NULL)
109         srs_add_secret(srs, secret, (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 eximsrs_done()
120 {
121   if(srs != NULL)
122     srs_close(srs);
123
124   srs = NULL;
125
126   return OK;
127 }
128
129
130 int eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
131 {
132   char res[512];
133   int n;
134
135   if((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
136   {
137     DEBUG(D_any)
138       debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
139     return DEFER;
140   }
141
142   *result = string_copy(res);
143   return OK;
144 }
145
146
147 int 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 eximsrs_db_set(BOOL reverse, uschar *srs_db)
169 {
170   if(reverse)
171     srs_db_reverse = (srs_db == NULL ? NULL : string_copy(srs_db));
172   else
173     srs_db_forward = (srs_db == NULL ? NULL : string_copy(srs_db));
174
175   if(srs_set_db_functions(srs, (srs_db_forward ? eximsrs_db_insert : NULL),
176                                (srs_db_reverse ? eximsrs_db_lookup : NULL)) & SRS_RESULT_FAIL)
177     return DEFER;
178
179   return OK;
180 }
181
182
183 srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
184 {
185   uschar *res;
186   uschar buf[64];
187
188   if(srs_db_forward == NULL)
189     return SRS_RESULT_DBERROR;
190
191   srs_db_address = string_copyn(data, data_len);
192   if(srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
193     return SRS_RESULT_DBERROR;
194
195   srs_db_key = string_copyn(buf, 16);
196
197   if((res = expand_string(srs_db_forward)) == NULL)
198     return SRS_RESULT_DBERROR;
199
200   if(result_len < 17)
201     return SRS_RESULT_DBERROR;
202
203   Ustrncpy(result, srs_db_key, result_len);
204
205   return SRS_RESULT_OK;
206 }
207
208
209 srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
210 {
211   uschar *res;
212
213   if(srs_db_reverse == NULL)
214     return SRS_RESULT_DBERROR;
215
216   srs_db_key = string_copyn(data, data_len);
217   if((res = expand_string(srs_db_reverse)) == NULL)
218     return SRS_RESULT_DBERROR;
219
220   if(Ustrlen(res) >= result_len)
221     return SRS_RESULT_ADDRESSTOOLONG;
222
223   strncpy(result, res, result_len);
224
225   return SRS_RESULT_OK;
226 }
227
228
229 #endif
230