3bc2421b458c87e80997d6b849b3469564073526
14 #include "readwrite.h"
18 #include "subscribe.h"
21 #define FATAL "ezmlm-return: fatal: "
22 void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); }
23 void die_nomem() { strerr_die2x(111,FATAL
,"out of memory"); }
26 strerr_die2x(100,FATAL
,"I do not accept messages at this address (#5.1.1)");
30 strerr_die1x(0,"ezmlm-return: info: trash address");
38 char strnum
[FMT_ULONG
];
40 char hashcopy
[COOKIE
];
41 unsigned long cookiedate
;
42 stralloc fndate
= {0};
43 stralloc fndatenew
= {0};
44 stralloc fnhash
= {0};
45 stralloc fnhashnew
= {0};
47 stralloc quoted
= {0};
51 { strerr_die4sys(111,FATAL
,"unable to write ",fnhashnew
.s
,": "); }
53 { strerr_die4sys(111,FATAL
,"unable to write ",fndatenew
.s
,": "); }
55 { strerr_die2sys(111,FATAL
,"unable to read input: "); }
57 void dowit(addr
,when
,bounce
)
64 if (!issub(addr
)) return;
66 if (!stralloc_copys(&fndate
,"bounce/w")) die_nomem();
67 if (!stralloc_catb(&fndate
,strnum
,fmt_ulong(strnum
,when
))) die_nomem();
68 if (!stralloc_cats(&fndate
,".")) die_nomem();
69 if (!stralloc_catb(&fndate
,strnum
,fmt_ulong(strnum
,(unsigned long) getpid()))) die_nomem();
70 if (!stralloc_0(&fndate
)) die_nomem();
71 if (!stralloc_copy(&fndatenew
,&fndate
)) die_nomem();
74 fd
= open_trunc(fndatenew
.s
);
75 if (fd
== -1) die_datenew();
76 substdio_fdbuf(&ssout
,write
,fd
,outbuf
,sizeof(outbuf
));
77 if (substdio_puts(&ssout
,addr
) == -1) die_datenew();
78 if (substdio_put(&ssout
,"",1) == -1) die_datenew();
79 if (substdio_puts(&ssout
,"Return-Path: <") == -1) die_datenew();
80 if (!quote2("ed
,sender
)) die_nomem();
81 if (substdio_put(&ssout
,quoted
.s
,quoted
.len
) == -1) die_datenew();
82 if (substdio_puts(&ssout
,">\n") == -1) die_datenew();
83 if (substdio_put(&ssout
,bounce
->s
,bounce
->len
) == -1) die_datenew();
84 if (substdio_flush(&ssout
) == -1) die_datenew();
85 if (fsync(fd
) == -1) die_datenew();
86 if (close(fd
) == -1) die_datenew(); /* NFS stupidity */
88 if (rename(fndatenew
.s
,fndate
.s
) == -1)
89 strerr_die6sys(111,FATAL
,"unable to rename ",fndatenew
.s
," to ",fndate
.s
,": ");
92 void doit(addr
,msgnum
,when
,bounce
)
101 if (!issub(addr
)) return;
103 if (!stralloc_copys(&fndate
,"bounce/d")) die_nomem();
104 if (!stralloc_catb(&fndate
,strnum
,fmt_ulong(strnum
,when
))) die_nomem();
105 if (!stralloc_cats(&fndate
,".")) die_nomem();
106 if (!stralloc_catb(&fndate
,strnum
,fmt_ulong(strnum
,(unsigned long) getpid()))) die_nomem();
107 if (!stralloc_0(&fndate
)) die_nomem();
108 if (!stralloc_copy(&fndatenew
,&fndate
)) die_nomem();
109 fndatenew
.s
[7] = 'D';
111 fd
= open_trunc(fndatenew
.s
);
112 if (fd
== -1) die_datenew();
113 substdio_fdbuf(&ssout
,write
,fd
,outbuf
,sizeof(outbuf
));
114 if (substdio_puts(&ssout
,addr
) == -1) die_datenew();
115 if (substdio_put(&ssout
,"",1) == -1) die_datenew();
116 if (substdio_puts(&ssout
,"Return-Path: <") == -1) die_datenew();
117 if (!quote2("ed
,sender
)) die_nomem();
118 if (substdio_put(&ssout
,quoted
.s
,quoted
.len
) == -1) die_datenew();
119 if (substdio_puts(&ssout
,">\n") == -1) die_datenew();
120 if (substdio_put(&ssout
,bounce
->s
,bounce
->len
) == -1) die_datenew();
121 if (substdio_flush(&ssout
) == -1) die_datenew();
122 if (fsync(fd
) == -1) die_datenew();
123 if (close(fd
) == -1) die_datenew(); /* NFS stupidity */
125 cookie(hash
,"",0,"",addr
,"");
126 if (!stralloc_copys(&fnhash
,"bounce/h")) die_nomem();
127 if (!stralloc_catb(&fnhash
,hash
,COOKIE
)) die_nomem();
128 if (!stralloc_0(&fnhash
)) die_nomem();
129 if (!stralloc_copy(&fnhashnew
,&fnhash
)) die_nomem();
130 fnhashnew
.s
[7] = 'H';
132 fdnew
= open_trunc(fnhashnew
.s
);
133 if (fdnew
== -1) die_hashnew();
134 substdio_fdbuf(&ssout
,write
,fdnew
,outbuf
,sizeof(outbuf
));
136 fd
= open_read(fnhash
.s
);
138 if (errno
!= error_noent
)
139 strerr_die4sys(111,FATAL
,"unable to read ",fnhash
.s
,": ");
140 if (rename(fndatenew
.s
,fndate
.s
) == -1)
141 strerr_die6sys(111,FATAL
,"unable to rename ",fndatenew
.s
," to ",fndate
.s
,": ");
144 substdio_fdbuf(&ssin
,read
,fd
,inbuf
,sizeof(inbuf
));
145 switch(substdio_copy(&ssout
,&ssin
)) {
146 case -2: die_msgin();
147 case -3: die_hashnew();
150 if (unlink(fndatenew
.s
) == -1)
151 strerr_die4sys(111,FATAL
,"unable to unlink ",fndatenew
.s
,": ");
153 if (substdio_puts(&ssout
," ") == -1) die_hashnew();
154 if (substdio_put(&ssout
,strnum
,fmt_ulong(strnum
,msgnum
)) == -1) die_hashnew();
155 if (substdio_puts(&ssout
,"\n") == -1) die_hashnew();
156 if (substdio_flush(&ssout
) == -1) die_hashnew();
157 if (fsync(fdnew
) == -1) die_hashnew();
158 if (close(fdnew
) == -1) die_hashnew(); /* NFS stupidity */
160 if (rename(fnhashnew
.s
,fnhash
.s
) == -1)
161 strerr_die6sys(111,FATAL
,"unable to rename ",fnhashnew
.s
," to ",fnhash
.s
,": ");
164 stralloc bounce
= {0};
166 stralloc header
= {0};
167 stralloc intro
= {0};
168 stralloc failure
= {0};
169 stralloc paragraph
= {0};
174 stralloc inhost
= {0};
175 stralloc outhost
= {0};
176 stralloc inlocal
= {0};
177 stralloc outlocal
= {0};
190 unsigned long msgnum
;
191 unsigned long cookiedate
;
199 when
= (unsigned long) now();
202 if (!dir
) die_usage();
204 sender
= env_get("SENDER");
205 if (!sender
) strerr_die2x(100,FATAL
,"SENDER not set");
206 local
= env_get("LOCAL");
207 if (!local
) strerr_die2x(100,FATAL
,"LOCAL not set");
208 host
= env_get("HOST");
209 if (!host
) strerr_die2x(100,FATAL
,"HOST not set");
211 if (chdir(dir
) == -1)
212 strerr_die4sys(111,FATAL
,"unable to switch to ",dir
,": ");
214 switch(slurp("key",&key
,32)) {
216 strerr_die4sys(111,FATAL
,"unable to read ",dir
,"/key: ");
218 strerr_die3x(100,FATAL
,dir
,"/key does not exist");
220 getconf_line(&inhost
,"inhost",1,FATAL
,dir
);
221 getconf_line(&inlocal
,"inlocal",1,FATAL
,dir
);
222 getconf_line(&outhost
,"outhost",1,FATAL
,dir
);
223 getconf_line(&outlocal
,"outlocal",1,FATAL
,dir
);
225 if (inhost
.len
!= str_len(host
)) die_badaddr();
226 if (case_diffb(inhost
.s
,inhost
.len
,host
)) die_badaddr();
227 if (inlocal
.len
> str_len(local
)) die_badaddr();
228 if (case_diffb(inlocal
.s
,inlocal
.len
,local
)) die_badaddr();
230 action
= local
+ inlocal
.len
;
232 if (!str_start(action
,"-return-")) die_badaddr();
235 if (!*action
) die_trash();
237 if (str_start(action
,"probe-")) {
239 action
+= scan_ulong(action
,&cookiedate
);
240 if (now() - cookiedate
> 3000000) die_trash();
241 if (*action
++ != '.') die_trash();
242 i
= str_chr(action
,'-');
243 if (i
!= COOKIE
) die_trash();
244 byte_copy(hashcopy
,COOKIE
,action
);
246 if (*action
++ != '-') die_trash();
247 i
= str_rchr(action
,'=');
248 if (!stralloc_copyb(&line
,action
,i
)) die_nomem();
250 if (!stralloc_cats(&line
,"@")) die_nomem();
251 if (!stralloc_cats(&line
,action
+ i
+ 1)) die_nomem();
253 if (!stralloc_0(&line
)) die_nomem();
254 strnum
[fmt_ulong(strnum
,cookiedate
)] = 0;
255 cookie(hash
,key
.s
,key
.len
,strnum
,line
.s
,"P");
256 if (byte_diff(hash
,COOKIE
,hashcopy
)) die_trash();
258 if (subscribe(line
.s
,0) == 1) log("-probe",line
.s
);
262 fdlock
= open_append("lockbounce");
264 strerr_die4sys(111,FATAL
,"unable to open ",dir
,"/lockbounce: ");
265 if (lock_ex(fdlock
) == -1)
266 strerr_die4sys(111,FATAL
,"unable to lock ",dir
,"/lockbounce: ");
268 if (str_start(action
,"warn-")) {
270 action
+= scan_ulong(action
,&cookiedate
);
271 if (now() - cookiedate
> 3000000) die_trash();
272 if (*action
++ != '.') die_trash();
273 i
= str_chr(action
,'-');
274 if (i
!= COOKIE
) die_trash();
275 byte_copy(hashcopy
,COOKIE
,action
);
277 if (*action
++ != '-') die_trash();
278 i
= str_rchr(action
,'=');
279 if (!stralloc_copyb(&line
,action
,i
)) die_nomem();
281 if (!stralloc_cats(&line
,"@")) die_nomem();
282 if (!stralloc_cats(&line
,action
+ i
+ 1)) die_nomem();
284 if (!stralloc_0(&line
)) die_nomem();
285 strnum
[fmt_ulong(strnum
,cookiedate
)] = 0;
286 cookie(hash
,key
.s
,key
.len
,strnum
,line
.s
,"W");
287 if (byte_diff(hash
,COOKIE
,hashcopy
)) die_trash();
289 if (slurpclose(0,&bounce
,1024) == -1) die_msgin();
290 dowit(line
.s
,when
,&bounce
);
294 action
+= scan_ulong(action
,&msgnum
);
295 if (*action
!= '-') die_badaddr();
299 if (slurpclose(0,&bounce
,1024) == -1) die_msgin();
301 i
= str_rchr(action
,'=');
302 if (!stralloc_copyb(&line
,action
,i
)) die_nomem();
304 if (!stralloc_cats(&line
,"@")) die_nomem();
305 if (!stralloc_cats(&line
,action
+ i
+ 1)) die_nomem();
307 if (!stralloc_0(&line
)) die_nomem();
308 doit(line
.s
,msgnum
,when
,&bounce
);
312 /* pre-VERP bounce, in QSBMF format */
314 substdio_fdbuf(&ssmsgin
,read
,0,msginbuf
,sizeof(msginbuf
));
320 if (!stralloc_copys(¶graph
,"")) die_nomem();
322 if (getln(&ssmsgin
,&line
,&match
,'\n') == -1) die_msgin();
323 if (!match
) die_trash();
324 if (!stralloc_cat(¶graph
,&line
)) die_nomem();
325 if (line
.len
<= 1) break;
328 if (!flaghaveheader
) {
329 if (!stralloc_copy(&header
,¶graph
)) die_nomem();
334 if (!flaghaveintro
) {
335 if (paragraph
.len
< 15) die_trash();
336 if (str_diffn(paragraph
.s
,"Hi. This is the",15)) die_trash();
337 if (!stralloc_copy(&intro
,¶graph
)) die_nomem();
342 if (paragraph
.s
[0] == '-')
345 if (paragraph
.s
[0] == '<') {
346 if (!stralloc_copy(&failure
,¶graph
)) die_nomem();
348 if (!stralloc_copy(&bounce
,&header
)) die_nomem();
349 if (!stralloc_cat(&bounce
,&intro
)) die_nomem();
350 if (!stralloc_cat(&bounce
,&failure
)) die_nomem();
352 i
= byte_chr(failure
.s
,failure
.len
,'\n');
353 if (i
< 3) die_trash();
355 if (!stralloc_copyb(&line
,failure
.s
+ 1,i
- 3)) die_nomem();
356 if (byte_chr(line
.s
,line
.len
,'\0') == line
.len
) {
357 if (!stralloc_0(&line
)) die_nomem();
358 doit(line
.s
,msgnum
,when
,&bounce
);