s/qmail 4.2.29a
Next generation secure email transport
Loading...
Searching...
No Matches
fastforward.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "readclose.h"
5#include "stralloc.h"
6#include "buffer.h"
7#include "strset.h"
8#include "getoptb.h"
9#include "exit.h"
10#include "logmsg.h"
11#include "env.h"
12#include "sig.h"
13#include "qmail.h"
14#include "fmt.h"
15#include "case.h"
16#include "alloc.h"
17#include "seek.h"
18#include "wait.h"
19#include "byte.h"
20#include "str.h"
21#include "open.h"
22#include "cdbread.h"
23
24#define WHO "fastforward"
25
26static void usage()
27{
28 logmsg(WHO,100,USAGE,"fastforward [ -nNpP ] data.cdb");
29}
30static void nomem()
31{
32 logmsg(WHO,111,FATAL,"out of memory");
33}
34
35static void print(char *s)
36{
37 char ch;
38 while ((ch = *s++)) {
39 buffer_put(buffer_2,&ch,1);
40 }
41}
42
43static void printsafe(char *s)
44{
45 char ch;
46 while ((ch = *s++)) {
47 if (ch < 32) ch = '_';
48 buffer_put(buffer_2,&ch,1);
49 }
50}
51
52struct qmail qq;
53char qp[FMT_ULONG];
54char qqbuf[1];
55
56ssize_t qqwrite(int fd,char *buf,int len)
57{
58 qmail_put(&qq,buf,len);
59 return len;
60}
61
62buffer bufq = BUFFER_INIT(qqwrite,-1,qqbuf,sizeof(qqbuf));
63
64char messbuf[4096];
65buffer mess = BUFFER_INIT(read,0,messbuf,sizeof(messbuf));
66
69
70char *dtline;
71stralloc sender = {0};
72stralloc programs = {0};
73stralloc forward = {0};
74
76stralloc todo = {0};
77
78stralloc mailinglist = {0};
79
80void dofile(char *fn)
81{
82 int fd;
83 struct stat st;
84 int i;
85 int j;
86
87 if (!stralloc_copys(&mailinglist,"")) nomem();
88
89 fd = open_read(fn);
90 if (fd == -1)
91 logmsg(WHO,111,FATAL,B("unable to read: ",fn));
92 if (fstat(fd,&st) == -1)
93 logmsg(WHO,111,FATAL,B("unable to read: ",fn));
94 if ((st.st_mode & 0444) != 0444)
95 logmsg(WHO,111,FATAL,B(fn," is not world-readable"));
96 if (readclose_append(fd,&mailinglist,1024) == -1)
97 logmsg(WHO,111,FATAL,B("unable to read: ",fn));
98
99 i = 0;
100 for (j = 0; j < mailinglist.len; ++j)
101 if (!mailinglist.s[j]) {
102 if ((mailinglist.s[i] == '.') || (mailinglist.s[i] == '/')) {
103 if (!stralloc_cats(&todo,mailinglist.s + i)) nomem();
104 if (!stralloc_0(&todo)) nomem();
105 }
106 else if ((mailinglist.s[i] == '&') && (j - i < 900)) {
107 if (!stralloc_cats(&todo,mailinglist.s + i)) nomem();
108 if (!stralloc_0(&todo)) nomem();
109 }
110 i = j + 1;
111 }
112}
113
114char *fncdb;
116stralloc key = {0};
117uint32 dlen;
118stralloc data = {0};
119struct cdb cdb;
120
122{
123 logmsg(WHO,111,FATAL,B("unable to read: ",fncdb));
124}
125
126int findtarget(int flagwild,char *prepend,char *addr)
127{
128 int r;
129 int at;
130
131 if (!stralloc_copys(&key,prepend)) nomem();
132 if (!stralloc_cats(&key,addr)) nomem();
133 case_lowerb(key.s,key.len);
134
135 r = cdb_find(&cdb,key.s,key.len);
136 if (r == -1) cdbreaderror();
137 if (r) return 1;
138
139 if (!flagwild) return 0;
140 at = str_rchr(addr,'@');
141 if (!addr[at]) return 0;
142
143 if (!stralloc_copys(&key,prepend)) nomem();
144 if (!stralloc_cats(&key,addr + at)) nomem();
145 case_lowerb(key.s,key.len);
146
147 r = cdb_find(&cdb,key.s,key.len);
148 if (r == -1) cdbreaderror();
149 if (r) return 1;
150
151 if (!stralloc_copys(&key,prepend)) nomem();
152 if (!stralloc_catb(&key,addr,at + 1)) nomem();
153 case_lowerb(key.s,key.len);
154
155 r = cdb_find(&cdb,key.s,key.len);
156 if (r == -1) cdbreaderror();
157 if (r) return 1;
158
159 return 0;
160}
161
162int gettarget(int flagwild,char *prepend,char *addr)
163{
164 if (!findtarget(flagwild,prepend,addr)) return 0;
165 dlen = cdb_datalen(&cdb);
166 if (!stralloc_ready(&data,(unsigned int) dlen)) nomem();
167 data.len = dlen;
168 if (cdb_read(&cdb,data.s,data.len,cdb_datapos(&cdb)) == -1)
169 cdbreaderror();
170
171 return 1;
172}
173
174void doprogram(char *arg)
175{
176 char *args[5];
177 int child;
178 int wstat;
179
180 if (!flagdeliver) {
181 print("run ");
182 printsafe(arg);
183 print("\n");
184 buffer_flush(buffer_2);
185 return;
186 }
187
188 if (*arg == '!') {
189 args[0] = "preline";
190 args[1] = "sh";
191 args[2] = "-c";
192 args[3] = arg + 1;
193 args[4] = 0;
194 }
195 else {
196 args[0] = "sh";
197 args[1] = "-c";
198 args[2] = arg + 1;
199 args[3] = 0;
200 }
201
202 switch (child = vfork()) {
203 case -1:
204 logmsg(WHO,111,FATAL,"unable to fork: ");
205 case 0:
206 sig_pipedefault();
207 execvp(*args,args);
208 logmsg(WHO,111,FATAL,B("unable to run: ",arg));
209 }
210
211 wait_pid(&wstat,child);
212 if (wait_crashed(wstat))
213 logmsg(WHO,111,FATAL,B("child crashed in: ",arg));
214
215 switch (wait_exitcode(wstat)) {
216 case 64: case 65: case 70: case 76: case 77: case 78: case 112:
217 case 100: _exit(100);
218 case 0: break;
219 default: _exit(111);
220 }
221
222 if (seek_begin(0) == -1)
223 logmsg(WHO,111,FATAL,"unable to rewind input: ");
224}
225
226void dodata()
227{
228 int i;
229 int j;
230 i = 0;
231
232 for (j = 0; j < data.len; ++j)
233 if (!data.s[j]) {
234 if ((data.s[i] == '|') || (data.s[i] == '!'))
235 doprogram(data.s + i);
236 else if ((data.s[i] == '.') || (data.s[i] == '/')) {
237 if (!stralloc_cats(&todo,data.s + i)) nomem();
238 if (!stralloc_0(&todo)) nomem();
239 }
240 else if ((data.s[i] == '&') && (j - i < 900)) {
241 if (!stralloc_cats(&todo,data.s + i)) nomem();
242 if (!stralloc_0(&todo)) nomem();
243 }
244 i = j + 1;
245 }
246}
247
248void dorecip(char *addr)
249{
250
251 if (!findtarget(0,"?",addr))
252 if (gettarget(0,":",addr)) {
253 dodata();
254 return;
255 }
256 if (!stralloc_cats(&forward,addr)) nomem();
257 if (!stralloc_0(&forward)) nomem();
258}
259
260void doorigrecip(char *addr)
261{
262 if (sender.len)
263 if ((sender.len != 4) || byte_diff(sender.s,4,"#@[]"))
264 if (gettarget(1,"?",addr))
265 if (!stralloc_copy(&sender,&data)) nomem();
266 if (!gettarget(1,":",addr))
267 if (flagpassthrough)
268 _exit(0);
269 else
270 logmsg(WHO,100,ERROR,"Sorry, no mailbox here by that name. (#5.1.1)");
271 dodata();
272}
273
274stralloc recipient = {0};
276
277int main(int argc,char **argv)
278{
279 int opt;
280 char *x;
281 int i;
282
283 sig_pipeignore();
284
285 dtline = env_get("DTLINE");
286 if (!dtline) dtline = "";
287
288 x = env_get("SENDER");
289 if (!x) x = "original envelope sender";
290 if (!stralloc_copys(&sender,x)) nomem();
291
292 if (!stralloc_copys(&forward,"")) nomem();
293 if (!strset_init(&done)) nomem();
294
295 while ((opt = getopt(argc,argv,"nNpPdD")) != opteof)
296 switch (opt) {
297 case 'n': flagdeliver = 0; break;
298 case 'N': flagdeliver = 1; break;
299 case 'p': flagpassthrough = 1; break;
300 case 'P': flagpassthrough = 0; break;
301 case 'd': flagdefault = 1; break;
302 case 'D': flagdefault = 0; break;
303 default: usage();
304 }
305 argv += optind;
306
307 fncdb = *argv;
308 if (!fncdb) usage();
309 fdcdb = open_read(fncdb);
310 if (fdcdb == -1) cdbreaderror();
311 cdb_init(&cdb,fdcdb);
312
313 if (flagdefault) {
314 x = env_get("DEFAULT");
315 if (!x) x = env_get("EXT");
316 if (!x) logmsg(WHO,100,FATAL,"$DEFAULT or $EXT must be set");
317 if (!stralloc_copys(&recipient,x)) nomem();
318 if (!stralloc_cats(&recipient,"@")) nomem();
319 x = env_get("HOST");
320 if (!x) logmsg(WHO,100,FATAL,"$HOST must be set");
321 if (!stralloc_cats(&recipient,x)) nomem();
322 if (!stralloc_0(&recipient)) nomem();
323 x = recipient.s;
324 }
325 else {
326 x = env_get("RECIPIENT");
327 if (!x) logmsg(WHO,100,FATAL,"$RECIPIENT must be set");
328 }
329 if (!strset_add(&done,x)) nomem();
330 doorigrecip(x);
331
332 while (todo.len) {
333 i = todo.len - 1;
334 while ((i > 0) && todo.s[i - 1]) --i;
335 todo.len = i;
336
337 if (strset_in(&done,todo.s + i)) continue;
338
339 x = alloc(str_len(todo.s + i) + 1);
340 if (!x) nomem();
341 str_copy(x,todo.s + i);
342 if (!strset_add(&done,x)) nomem();
343
344 x = todo.s + i;
345 if (*x == 0)
346 continue;
347 else if ((*x == '.') || (*x == '/'))
348 dofile(x);
349 else
350 dorecip(x + 1);
351 }
352
353 if (!forward.len) {
354 if (!flagdeliver) {
355 print("no forwarding\n");
356 buffer_flush(buffer_2);
357 }
358 _exit(flagpassthrough ? 99 : 0);
359 }
360
361 if (!stralloc_0(&sender)) nomem();
362
363 if (!flagdeliver) {
364 print("from <");
365 printsafe(sender.s);
366 print(">\n");
367 while (forward.len) {
368 i = forward.len - 1;
369 while ((i > 0) && forward.s[i - 1]) --i;
370 forward.len = i;
371 print("to <");
372 printsafe(forward.s + i);
373 print(">\n");
374 }
375 buffer_flush(buffer_2);
376 _exit(flagpassthrough ? 99 : 0);
377 }
378
379 if (qmail_open(&qq) == -1)
380 logmsg(WHO,111,FATAL,"unable to fork: ");
382 if (buffer_copy(&bufq,&mess) != 0)
383 logmsg(WHO,111,FATAL,"unable to read message: ");
384 buffer_flush(&bufq);
385 qp[fmt_ulong(qp,qmail_qp(&qq))] = 0;
386
387 qmail_from(&qq,sender.s);
388
389 while (forward.len) {
390 i = forward.len - 1;
391 while ((i > 0) && forward.s[i - 1]) --i;
392 forward.len = i;
393 qmail_to(&qq,forward.s + i);
394 }
395
396 x = qmail_close(&qq);
397 if (*x) logmsg(WHO,*x == 'D' ? 100 : 111,FATAL,x + 1);
398 logmsg(WHO,flagpassthrough ? 99 : 0,LOG,B("qp ",qp));
399}
int main()
Definition: chkshsgr.c:6
void nomem()
Definition: columnt.c:16
int stralloc_copys(stralloc *, char const *)
void _exit()
stralloc key
Definition: fastforward.c:116
char qp[FMT_ULONG]
Definition: fastforward.c:53
void dodata()
Definition: fastforward.c:226
int gettarget(int flagwild, char *prepend, char *addr)
Definition: fastforward.c:162
int flagdefault
Definition: fastforward.c:275
void dofile(char *fn)
Definition: fastforward.c:80
ssize_t qqwrite(int fd, char *buf, int len)
Definition: fastforward.c:56
strset done
Definition: fastforward.c:75
stralloc todo
Definition: fastforward.c:76
int fdcdb
Definition: fastforward.c:115
stralloc forward
Definition: fastforward.c:73
stralloc sender
Definition: fastforward.c:71
char * dtline
Definition: fastforward.c:70
void cdbreaderror()
Definition: fastforward.c:121
stralloc recipient
Definition: fastforward.c:274
buffer bufq
Definition: fastforward.c:62
stralloc mailinglist
Definition: fastforward.c:78
stralloc data
Definition: fastforward.c:118
void doprogram(char *arg)
Definition: fastforward.c:174
int flagdeliver
Definition: fastforward.c:67
int findtarget(int flagwild, char *prepend, char *addr)
Definition: fastforward.c:126
char qqbuf[1]
Definition: fastforward.c:54
void dorecip(char *addr)
Definition: fastforward.c:248
stralloc programs
Definition: fastforward.c:72
int flagpassthrough
Definition: fastforward.c:68
buffer mess
Definition: fastforward.c:65
char * fncdb
Definition: fastforward.c:114
#define WHO
Definition: fastforward.c:24
char messbuf[4096]
Definition: fastforward.c:64
struct cdb cdb
Definition: fastforward.c:119
uint32 dlen
Definition: fastforward.c:117
void doorigrecip(char *addr)
Definition: fastforward.c:260
struct qmail qq
Definition: fastforward.c:52
char buf[100+FMT_ULONG]
Definition: hier.c:10
int fd
stralloc fn
Definition: qmail-qmaint.c:483
int j
Definition: qmail-send.c:920
stralloc addr
Definition: qmail-smtpd.c:521
void qmail_to(struct qmail *, char *)
Definition: qmail.c:83
void qmail_from(struct qmail *, char *)
Definition: qmail.c:73
void qmail_put(struct qmail *, char *, int)
Definition: qmail.c:63
char * qmail_close(struct qmail *)
Definition: qmail.c:90
unsigned long qmail_qp(struct qmail *)
Definition: qmail.c:53
void qmail_puts(struct qmail *, char *)
Definition: qmail.c:68
int qmail_open(struct qmail *)
Definition: qmail.c:21
int strset_add(strset *, char *)
Definition: strset.c:61
int strset_init(strset *)
Definition: strset.c:20
char * strset_in(strset *, char *)
Definition: strset.c:40
Definition: qmail.h:6
Definition: strset.h:14