s/qmail 4.4.12
Next generation secure email transport
Loading...
Searching...
No Matches
srsq.c
Go to the documentation of this file.
1
13#include <time.h> /* time */
14#include <sys/time.h> /* timeval / timezone struct */
15#include "str.h"
16#include "sha1.h"
17#include "byte.h"
18#include "case.h"
19#include "stralloc.h"
20#include "srsq.h"
21#include "uint_t.h"
22
23static const char *srs_separators = "=-+";
24
25stralloc secret = {0};
26stralloc sendhost = {0};
27stralloc senduser = {0};
28
29const char *srs_errorstr(int code)
30{
31 X(0,"")
32 /* Simple errors */
33 X(SRS_SUCCESS,"Success")
34 X(SRS_ENOTSRSADDRESS,"Not an SRS address.")
35 X(SRS_ENOSENDERATSIGN,"No at sign in sender address")
36
37 /* Config errors */
38 X(SRS_ENOSECRETS,"No secrets in SRS configuration.")
39 X(SRS_ESEPARATORINVALID,"Invalid separator suggested.")
40
41 /* Run time errors */
42 X(SRS_EOUTOFMEMORY,"Out of memory.")
43
44 /* Syntax errors */
45 X(SRS_ENOSRS0HOST,"No host in SRS0 address.")
46 X(SRS_ENOSRS0USER,"No user in SRS0 address.")
47 X(SRS_ENOSRS0HASH,"No hash in SRS0 address.")
48 X(SRS_ENOSRS0STAMP,"No timestamp in SRS0 address.")
49 X(SRS_ENOSRS1HOST,"No host in SRS1 address.")
50 X(SRS_ENOSRS1USER,"No user in SRS1 address.")
51 X(SRS_ENOSRS1HASH,"No hash in SRS1 address.")
52 X(SRS_EBADTIMESTAMPCHAR,"Bad base32 character in timestamp.")
53 X(SRS_EHASHTOOSHORT,"Hash too short in SRS address.")
54
55 /* SRS errors */
56 X(SRS_ETIMESTAMPOUTOFDATE,"Time stamp out of date.")
57 X(SRS_EHASHINVALID,"Hash invalid in SRS address.")
58
59 return "Unknown SRS error.";
60}
61
63{
64 if (!stralloc_copys(&srs->secrets,"")) return SRS_EOUTOFMEMORY;
65 srs->numsecrets = 0;
66 srs->separator = '=';
67 srs->maxage = 21;
68 srs->hashlen = 4;
70 srs->noforward = 0;
71 srs->noreverse = 0;
73
74 return SRS_SUCCESS;
75}
76
77/* Don't mess with these unless you know what you're doing well
78 * enough to rewrite the timestamp functions. These are based on
79 * a 2 character timestamp.
80 * Changing these in the wild is probably a bad idea. */
81#define SRS_TIME_PRECISION (60*60*24) /* One day */
82#define SRS_TIME_BASEBITS 5 /* 2^5 = 32 = strlen(CHARS) */
83
84/* This had better be a real variable since we do arithmethic with it. */
85const char *SRS_TIME_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
86#define SRS_TIME_SIZE 2
87#define SRS_TIME_SLOTS (1 << (SRS_TIME_BASEBITS << (SRS_TIME_SIZE - 1)))
88
89int srs_create_timestamp(char *buf,time_t now) // ok
90{
92 buf[1] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
94 buf[0] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
95 buf[2] = '\0';
96 return SRS_SUCCESS;
97}
98
99/* Keep backward compatiblity */
100
102{
103 char *sp = 0;
104 char ch;
105 int off;
106 time_t now;
107 time_t then;
108
109 /* We had better go around this loop exactly twice! */
110 then = 0;
111 case_uppers(stamp);
112 for (sp = stamp; *sp; sp++) {
113 ch = *sp;
114 off = str_chr(SRS_TIME_BASECHARS,ch); // original: off = bp - SRS_TIME_BASECHARS;
115 if (off == str_len(sp))
117 then = (then << SRS_TIME_BASEBITS) | off;
118 }
119
120 time(&now);
122 while (now < then)
124
125 if (now <= then + srs->maxage) return SRS_SUCCESS;
127}
128
129const char *SRS_HASH_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
130 "abcdefghijklmnopqrstuvwxyz"
131 "0123456789+/";
132
133int srs_create_hash(srs_ctx *srs,char *hash,const char *secret,char *one,char *two,char *three)
134{
136 int i, j;
137 char srshash[SHA1_DIGESTSIZE + 1];
138 unsigned char *hp = 0;
139 char *bp;
140
141 if (!secret) return SRS_ENOSECRETS;
142
143 sha1_init(&ctx);
144 sha1_update(&ctx,(uint8 *)secret,str_len(secret));
145
146 if (one && *one) {
147 case_lowers(one);
148 sha1_update(&ctx,(uint8 *)one,str_len(one));
149 }
150 if (two && *two) {
151 case_lowers(two);
152 sha1_update(&ctx,(uint8 *)two,str_len(two));
153 }
154 if (three && *three) {
155 case_lowers(three);
156 sha1_update(&ctx,(uint8 *)three,str_len(three));
157 }
158
159 sha1_final((uint8 *)srshash,&ctx); /* args inverted */
160 srshash[SHA1_DIGESTSIZE] = '\0';
161
162 /* A little base64 encoding. Just a little. */
163
164 hp = (unsigned char *)srshash;
165 bp = hash;
166 for (i = j = 0; i < srs->hashlen; i++) {
167 switch (i & 0x03) {
168 default: /* NOTREACHED */
169 case 0:
170 j = (*hp >> 2); break;
171 case 1:
172 j = ((*hp & 0x03) << 4) | ((*(hp + 1) & 0xF0) >> 4); hp++; break;
173 case 2:
174 j = ((*hp & 0x0F) << 2) | ((*(hp + 1) & 0xC0) >> 6); hp++; break;
175 case 3:
176 j = (*hp++ & 0x3F); break;
177 }
178 *bp++ = SRS_HASH_BASECHARS[j];
179 }
180 *bp = '\0';
181 hash[srs->hashlen - 1] = '\0'; // off-by-one error in srs2.c
182
183 return SRS_SUCCESS;
184}
185
186int srs_check_hash(srs_ctx *srs,const char *hash,char *one,char *two,char *three)
187{
188 int i, j;
189 char srshash[SRS_HASHLEN + 1];
190
191 for (i = j = 0; j < srs->numsecrets; i++) {
192 if (!stralloc_copys(&secret,srs->secrets.s + i)) return SRS_EOUTOFMEMORY;
193 i += secret.len;
194 if (*(srs->secrets.s + i) == '\0') j++;
195 if (!stralloc_0(&secret)) return SRS_EOUTOFMEMORY;
196
197 srs_create_hash(srs,srshash,secret.s,one,two,three);
198 if (!str_diffn(hash,srshash,SRS_HASHLEN)) return SRS_SUCCESS;
199 }
200
201 return SRS_EHASHINVALID;
202}
203
204int srs_make_shortcut(srs_ctx *srs,stralloc *srsaddr,char *sendhost,char *senduser,const char *aliashost)
205{
206 char hash[SRS_HASHLEN + 1];
207 char *srshash = hash; // very ugly
208 char srsstamp[SRS_TIME_SIZE + 1];
209 int j, r;
210
211 /* This never happens if we get called from guarded() */
212
213 if (!case_diffb(senduser,4,SRS0TAG) && str_chr(srs_separators,senduser[4]) < 3) {
214 sendhost = senduser + 5;
215 if (*sendhost == '\0') return SRS_ENOSRS0HOST;
216 j = str_chr(sendhost,SRSDEL);
217 senduser = sendhost + j + 1;
218 if ((senduser == NULL) || (*senduser == '\0')) return SRS_ENOSRS0USER;
219 }
220
221 r = srs_create_timestamp(srsstamp,time(NULL));
222 if (r != SRS_SUCCESS) return r;
223
224 r = srs_create_hash(srs,srshash,srsstamp,sendhost,senduser,0);
225 if (r != SRS_SUCCESS) return r;
226
227 if (!stralloc_copys(srsaddr,SRS0TAG)) return SRS_EOUTOFMEMORY;
228 if (!stralloc_catb(srsaddr,&srs->separator,1)) return SRS_EOUTOFMEMORY;
229 if (!stralloc_cats(srsaddr,srshash)) return SRS_EOUTOFMEMORY;
230 if (!stralloc_cats(srsaddr,SRSSEP)) return SRS_EOUTOFMEMORY;
231 if (!stralloc_cats(srsaddr,srsstamp)) return SRS_EOUTOFMEMORY;
232 if (!stralloc_cats(srsaddr,SRSSEP)) return SRS_EOUTOFMEMORY;
233 if (!stralloc_cats(srsaddr,sendhost)) return SRS_EOUTOFMEMORY;
234 if (!stralloc_cats(srsaddr,SRSSEP)) return SRS_EOUTOFMEMORY;
235 if (!stralloc_cats(srsaddr,senduser)) return SRS_EOUTOFMEMORY;
236 if (!stralloc_cats(srsaddr,"@")) return SRS_EOUTOFMEMORY;
237 if (!stralloc_cats(srsaddr,aliashost)) return SRS_EOUTOFMEMORY;
238 if (!stralloc_0(srsaddr)) return SRS_EOUTOFMEMORY;
239
240 return SRS_SUCCESS;
241}
242
243int srs_make_guarded(srs_ctx *srs,stralloc *srsaddr,char *sendhost,
244 char *senduser,const char *aliashost)
245{
246 char *srshost = 0;
247 char *srsuser = 0;
248 char *srshash = 0;
249 int j = 0;
250 int r;
251
252 if (!case_diffb(senduser,4,SRS1TAG) && str_chr(srs_separators,senduser[4]) < 3) {
253 srshash = senduser + 5;
254 if (*srshash == '\0') return SRS_ENOSRS1HASH;
255 if (j == str_chr(srshash,SRSDEL)) return SRS_ENOSRS1HOST;
256 srshost = srshash + j + 1;
257 j = str_chr(srshost,SRSDEL);
258 if (j == str_len(srshost)) return SRS_ENOSRS1USER;
259 srshost[j] = '\0';
260 srsuser = srshost + j + 1;
261 r = srs_create_hash(srs,srshash,0,srshost,srsuser,0);
262 if (r != SRS_SUCCESS) return r;
263 } else if (!case_diffb(senduser,4,SRS0TAG) && str_chr(srs_separators,senduser[4]) < 3) {
264 srsuser = senduser + 4;
266 r = srs_create_hash(srs,srshash,0,srshost,srsuser,0);
267 if (r != SRS_SUCCESS) return r;
268 } else
269 return srs_make_shortcut(srs,srsaddr,sendhost,senduser,aliashost);
270
271 /* make guarded address */
272
273 if (!stralloc_copys(srsaddr,SRS1TAG)) return SRS_EOUTOFMEMORY;
274 if (!stralloc_catb(srsaddr,&srs->separator,1)) return SRS_EOUTOFMEMORY;
275 if (!stralloc_cats(srsaddr,srshash)) return SRS_EOUTOFMEMORY;
276 if (!stralloc_cats(srsaddr,SRSSEP)) return SRS_EOUTOFMEMORY;
277 if (!stralloc_cats(srsaddr,srshost)) return SRS_EOUTOFMEMORY;
278 if (!stralloc_cats(srsaddr,SRSSEP)) return SRS_EOUTOFMEMORY;
279 if (!stralloc_cats(srsaddr,srsuser)) return SRS_EOUTOFMEMORY;
280 if (!stralloc_cats(srsaddr,"@")) return SRS_EOUTOFMEMORY;
281 if (!stralloc_cats(srsaddr,aliashost)) return SRS_EOUTOFMEMORY;
282 if (!stralloc_0(srsaddr)) return SRS_EOUTOFMEMORY;
283
284 return SRS_SUCCESS;
285}
286
287int srs_parse_shortcut(srs_ctx *srs,stralloc *srsaddr,char *senduser)
288{
289 char *srshash = 0;
290 char *srsstamp = 0;
291 char *srshost = 0;
292 char *srsuser = 0;
293 int j, r;
294
295 if (!case_diffb(senduser,4,SRS0TAG)) {
296 srshash = senduser + 5;
297 j = str_chr(srshash,SRSDEL);
298 if (j == str_len(srshash)) return SRS_ENOSRS0STAMP;
299 srshash[j] = '\0';
300 srsstamp = srshash + j + 1;
301 j = str_chr(srsstamp,SRSDEL);
302 if (j == str_len(srsstamp)) return SRS_ENOSRS0HOST;
303 srsstamp[j] = '\0';
304 srshost = srsstamp + j + 1;
305 j = str_chr(srshost,SRSDEL);
306 if (j == str_len(srshost)) return SRS_ENOSRS0USER;
307 srshost[j] = '\0';
308 srsuser = srshost + j + 1;
309 r = srs_check_timestamp(srs,srsstamp);
310 if (r != SRS_SUCCESS) return r;
311 r = srs_check_hash(srs,srshash,srsstamp,srshost,srsuser);
312 if (r != SRS_SUCCESS) return r;
313
314 if (!stralloc_copys(srsaddr,srsuser)) return SRS_EOUTOFMEMORY;
315 if (!stralloc_cats(srsaddr,"@")) return SRS_EOUTOFMEMORY;
316 if (!stralloc_cats(srsaddr,srshost)) return SRS_EOUTOFMEMORY;
317 if (!stralloc_0(srsaddr)) return SRS_EOUTOFMEMORY;
318 return SRS_SUCCESS;
319 }
320
321 return SRS_ENOTSRSADDRESS;
322}
323
324int srs_reverse(srs_ctx *srs,stralloc *srsaddr,char *inaddr)
325{
326 char *srshash;
327 char *srshost = 0;
328 char *srsuser = 0;
329 int j, r;
330
331 if (!SRS_IS_SRS_ADDRESS(inaddr)) return SRS_ENOTSRSADDRESS;
332 if (srs->noreverse) return SRS_ENOTREWRITTEN;
333
334 j = str_chr(inaddr,'@');
335 if (j < str_len(inaddr)) inaddr[j] = '\0'; // only local part relevant
336
337 if (!case_diffb(inaddr,4,SRS1TAG)) {
338 srshash = inaddr + 5;
339 j = str_chr(srshash,SRSDEL);
340 if (j != 3) return SRS_ENOSRS1HASH;
341 srshash[j] = '\0';
342 srshost = srshash + j + 1; // rewritten-domain-part
343 if (j == str_len(srshost)) return SRS_ENOSRS1HOST;
344 j = str_chr(srshost,SRSDEL);
345 if (j == str_len(srshost)) return SRS_ENOSRS1USER;
346 srsuser = srshost + j + 1; // =orig-local-part.....
347
348 r = srs_check_hash(srs,srshash,srshost,srsuser,0);
349 if (r != SRS_SUCCESS) return r;
350
351 if (!stralloc_copys(srsaddr,inaddr)) return SRS_EOUTOFMEMORY;
352 if (!stralloc_cats(srsaddr,"@")) return SRS_EOUTOFMEMORY;
353 if (!stralloc_cats(srsaddr,srshost)) return SRS_EOUTOFMEMORY;
354 return SRS_SUCCESS;
355 }
356 else
357 return srs_parse_shortcut(srs,srsaddr,srsuser);
358}
359
360int srs_forward(srs_ctx *srs,stralloc *srsaddr,const char *sender,const char *alias)
361{
362 int at;
363
364 if (srs->noforward) return SRS_ENOTREWRITTEN;
365
366 /* This is allowed to be a plain domain */
367
368 at = str_chr(alias,'@');
369 if (at < str_len(alias)) {
370 if (!stralloc_copys(&sendhost,alias + at + 1)) return SRS_EOUTOFMEMORY;
371 if (!stralloc_0(&sendhost)) return SRS_EOUTOFMEMORY;
372 } else return SRS_ENOSENDERATSIGN;
373
374 if (!srs->alwaysrewrite) {
375 if (case_equals(sendhost.s,alias)) {
376 if (!stralloc_copys(srsaddr,sendhost.s)) return SRS_EOUTOFMEMORY;
377 if (!stralloc_0(srsaddr)) return SRS_EOUTOFMEMORY;
378 return SRS_SUCCESS;
379 }
380 }
381
382 at = str_chr(sender,'@');
383 if (at < str_len(sender)) {
384 if (!stralloc_copyb(&senduser,sender,at)) return SRS_EOUTOFMEMORY;
385 }
386 if (!stralloc_copys(&sendhost,sender + at + 1)) return SRS_EOUTOFMEMORY;
387 if (!stralloc_0(&senduser)) return SRS_EOUTOFMEMORY;
388 if (!stralloc_0(&sendhost)) return SRS_EOUTOFMEMORY;
389
390 return srs_make_guarded(srs,srsaddr,sendhost.s,senduser.s,alias);
391}
int stralloc_copys(stralloc *, char const *)
stralloc sender
Definition: fastforward.c:71
char buf[100+FMT_ULONG]
Definition: hier.c:11
datetime_sec now()
Definition: now.c:5
stralloc hash
Definition: qmail-dksign.c:234
buffer bp
Definition: qmail-ldapam.c:51
unsigned long code
Definition: qmail-remote.c:605
SSL_CTX * ctx
Definition: qmail-remote.c:108
int j
Definition: qmail-send.c:926
void sha1_final(uint8_t hash[SHA1_DIGESTSIZE], sha1_ctx *context)
Definition: sha1.c:146
void sha1_init(sha1_ctx *context)
Definition: sha1.c:111
#define SHA1_DIGESTSIZE
Definition: sha1.h:16
void sha1_update(sha1_ctx *context, const uint8_t *data, uint32_t len)
Definition: sha1.c:124
char stamp[FMT_ULONG+FMT_ULONG+3]
Definition: splogger.c:16
stralloc srshost
Definition: srsforward.c:30
srs_ctx srs
Definition: srsforward.c:33
stralloc sendhost
Definition: srsq.c:26
#define SRS_TIME_SLOTS
Definition: srsq.c:87
int srs_create_timestamp(char *buf, time_t now)
Definition: srsq.c:89
#define SRS_TIME_PRECISION
Definition: srsq.c:81
stralloc secret
Definition: srsq.c:25
int srs_create_hash(srs_ctx *srs, char *hash, const char *secret, char *one, char *two, char *three)
Definition: srsq.c:133
int srs_parse_shortcut(srs_ctx *srs, stralloc *srsaddr, char *senduser)
Definition: srsq.c:287
int srs_reverse(srs_ctx *srs, stralloc *srsaddr, char *inaddr)
Definition: srsq.c:324
int srs_check_timestamp(srs_ctx *srs, char *stamp)
Definition: srsq.c:101
#define SRS_TIME_SIZE
Definition: srsq.c:86
int srs_forward(srs_ctx *srs, stralloc *srsaddr, const char *sender, const char *alias)
Definition: srsq.c:360
int srs_init(srs_ctx *srs)
Definition: srsq.c:62
int srs_make_guarded(srs_ctx *srs, stralloc *srsaddr, char *sendhost, char *senduser, const char *aliashost)
Definition: srsq.c:243
const char * SRS_TIME_BASECHARS
Definition: srsq.c:85
int srs_check_hash(srs_ctx *srs, const char *hash, char *one, char *two, char *three)
Definition: srsq.c:186
stralloc senduser
Definition: srsq.c:27
int srs_make_shortcut(srs_ctx *srs, stralloc *srsaddr, char *sendhost, char *senduser, const char *aliashost)
Definition: srsq.c:204
const char * srs_errorstr(int code)
Definition: srsq.c:29
#define SRS_TIME_BASEBITS
Definition: srsq.c:82
const char * SRS_HASH_BASECHARS
Definition: srsq.c:129
#define SRS_ETIMESTAMPOUTOFDATE
Definition: srsq.h:48
#define SRS_EOUTOFMEMORY
Definition: srsq.h:36
#define SRS_ENOSRS1USER
Definition: srsq.h:43
#define SRS_ENOSENDERATSIGN
Definition: srsq.h:31
#define SRS0TAG
Definition: srsq.h:15
#define SRS_ENOSRS1HASH
Definition: srsq.h:44
#define SRS_ENOSRS1HOST
Definition: srsq.h:42
#define SRSSEP
Definition: srsq.h:14
#define SRS_ENOSRS0USER
Definition: srsq.h:39
#define SRS_ENOSRS0HASH
Definition: srsq.h:40
#define SRS_EHASHINVALID
Definition: srsq.h:49
#define X(e, s)
Definition: srsq.h:61
#define SRSDEL
Definition: srsq.h:13
#define SRS_EHASHTOOSHORT
Definition: srsq.h:46
#define SRS1TAG
Definition: srsq.h:16
#define SRS_ENOSECRETS
Definition: srsq.h:33
#define SRS_ESEPARATORINVALID
Definition: srsq.h:34
#define SRS_HASHLEN
Definition: srsq.h:17
#define SRS_ENOSRS0HOST
Definition: srsq.h:38
#define SRS_ENOTREWRITTEN
Definition: srsq.h:30
#define SRS_SUCCESS
Definition: srsq.h:28
#define SRS_IS_SRS_ADDRESS(x)
Definition: srsq.h:55
#define SRS_EBADTIMESTAMPCHAR
Definition: srsq.h:45
#define SRS_ENOTSRSADDRESS
Definition: srsq.h:29
#define SRS_ENOSRS0STAMP
Definition: srsq.h:41
Definition: sha1.h:19
Definition: srsq.h:65
stralloc nonrewrite
Definition: srsq.h:80
int hashlen
Definition: srsq.h:73
int alwaysrewrite
Definition: srsq.h:77
int hashmin
Definition: srsq.h:74
char separator
Definition: srsq.h:69
int noreverse
Definition: srsq.h:79
int maxage
Definition: srsq.h:72
int noforward
Definition: srsq.h:78
stralloc secrets
Definition: srsq.h:67
int numsecrets
Definition: srsq.h:68