|
0
|
1 |
#include <sys/types.h>
|
|
|
2 |
#include <sys/stat.h>
|
|
|
3 |
#include "sig.h"
|
|
|
4 |
#include "wait.h"
|
|
|
5 |
#include "substdio.h"
|
|
|
6 |
#include "byte.h"
|
|
|
7 |
#include "str.h"
|
|
|
8 |
#include "stralloc.h"
|
|
|
9 |
#include "select.h"
|
|
|
10 |
#include "exit.h"
|
|
|
11 |
#include "coe.h"
|
|
|
12 |
#include "open.h"
|
|
|
13 |
#include "error.h"
|
|
|
14 |
#include "auto_qmail.h"
|
|
|
15 |
#include "auto_uids.h"
|
|
|
16 |
#include "auto_spawn.h"
|
|
|
17 |
|
|
|
18 |
extern int truncreport;
|
|
|
19 |
extern int spawn();
|
|
|
20 |
extern void report();
|
|
|
21 |
extern void initialize();
|
|
|
22 |
|
|
|
23 |
struct delivery
|
|
|
24 |
{
|
|
|
25 |
int used;
|
|
|
26 |
int fdin; /* pipe input */
|
|
|
27 |
int pid; /* zero if child is dead */
|
|
|
28 |
int wstat; /* if !pid: status of child */
|
|
|
29 |
int fdout; /* pipe output, -1 if !pid; delays eof until after death */
|
|
|
30 |
stralloc output;
|
|
|
31 |
}
|
|
|
32 |
;
|
|
|
33 |
|
|
|
34 |
struct delivery *d;
|
|
|
35 |
|
|
|
36 |
void sigchld()
|
|
|
37 |
{
|
|
|
38 |
int wstat;
|
|
|
39 |
int pid;
|
|
|
40 |
int i;
|
|
|
41 |
while ((pid = wait_nohang(&wstat)) > 0)
|
|
|
42 |
for (i = 0;i < auto_spawn;++i) if (d[i].used)
|
|
|
43 |
if (d[i].pid == pid)
|
|
|
44 |
{
|
|
|
45 |
close(d[i].fdout); d[i].fdout = -1;
|
|
|
46 |
d[i].wstat = wstat; d[i].pid = 0;
|
|
|
47 |
}
|
|
|
48 |
}
|
|
|
49 |
|
|
|
50 |
int flagwriting = 1;
|
|
|
51 |
|
|
|
52 |
int okwrite(fd,buf,n) int fd; char *buf; int n;
|
|
|
53 |
{
|
|
|
54 |
int w;
|
|
|
55 |
if (!flagwriting) return n;
|
|
|
56 |
w = write(fd,buf,n);
|
|
|
57 |
if (w != -1) return w;
|
|
|
58 |
if (errno == error_intr) return -1;
|
|
|
59 |
flagwriting = 0; close(fd);
|
|
|
60 |
return n;
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
int flagreading = 1;
|
|
|
64 |
char outbuf[1024]; substdio ssout;
|
|
|
65 |
|
|
|
66 |
int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */
|
|
|
67 |
int flagabort = 0; /* if 1, everything except delnum is garbage */
|
|
|
68 |
int delnum;
|
|
|
69 |
stralloc messid = {0};
|
|
|
70 |
stralloc sender = {0};
|
|
|
71 |
stralloc recip = {0};
|
|
|
72 |
|
|
|
73 |
void err(s) char *s;
|
|
|
74 |
{
|
|
|
75 |
char ch; ch = delnum; substdio_put(&ssout,&ch,1);
|
|
|
76 |
substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1);
|
|
|
77 |
}
|
|
|
78 |
|
|
|
79 |
void docmd()
|
|
|
80 |
{
|
|
|
81 |
int f;
|
|
|
82 |
int i;
|
|
|
83 |
int j;
|
|
|
84 |
int fdmess;
|
|
|
85 |
int pi[2];
|
|
|
86 |
struct stat st;
|
|
|
87 |
|
|
|
88 |
if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
|
|
|
89 |
if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; }
|
|
|
90 |
if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; }
|
|
|
91 |
if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; }
|
|
|
92 |
for (i = 0;i < messid.len;++i)
|
|
|
93 |
if (messid.s[i])
|
|
|
94 |
if (!i || (messid.s[i] != '/'))
|
|
|
95 |
if ((unsigned char) (messid.s[i] - '0') > 9)
|
|
|
96 |
{ err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; }
|
|
|
97 |
if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; }
|
|
|
98 |
if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; }
|
|
|
99 |
|
|
|
100 |
if (!stralloc_copys(&d[delnum].output,""))
|
|
|
101 |
{ err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
|
|
|
102 |
|
|
|
103 |
j = byte_rchr(recip.s,recip.len,'@');
|
|
|
104 |
if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; }
|
|
|
105 |
|
|
|
106 |
fdmess = open_read(messid.s);
|
|
|
107 |
if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; }
|
|
|
108 |
|
|
|
109 |
if (fstat(fdmess,&st) == -1)
|
|
|
110 |
{ close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; }
|
|
|
111 |
if ((st.st_mode & S_IFMT) != S_IFREG)
|
|
|
112 |
{ close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; }
|
|
|
113 |
if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */
|
|
|
114 |
/* your security is already toast at this point. damage control... */
|
|
|
115 |
{ close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; }
|
|
|
116 |
|
|
|
117 |
if (pipe(pi) == -1)
|
|
|
118 |
{ close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; }
|
|
|
119 |
|
|
|
120 |
coe(pi[0]);
|
|
|
121 |
|
|
|
122 |
f = spawn(fdmess,pi[1],sender.s,recip.s,j);
|
|
|
123 |
close(fdmess);
|
|
|
124 |
if (f == -1)
|
|
|
125 |
{ close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; }
|
|
|
126 |
|
|
|
127 |
d[delnum].fdin = pi[0];
|
|
|
128 |
d[delnum].fdout = pi[1]; coe(pi[1]);
|
|
|
129 |
d[delnum].pid = f;
|
|
|
130 |
d[delnum].used = 1;
|
|
|
131 |
}
|
|
|
132 |
|
|
|
133 |
char cmdbuf[1024];
|
|
|
134 |
|
|
|
135 |
void getcmd()
|
|
|
136 |
{
|
|
|
137 |
int i;
|
|
|
138 |
int r;
|
|
|
139 |
char ch;
|
|
|
140 |
|
|
|
141 |
r = read(0,cmdbuf,sizeof(cmdbuf));
|
|
|
142 |
if (r == 0)
|
|
|
143 |
{ flagreading = 0; return; }
|
|
|
144 |
if (r == -1)
|
|
|
145 |
{
|
|
|
146 |
if (errno != error_intr)
|
|
|
147 |
flagreading = 0;
|
|
|
148 |
return;
|
|
|
149 |
}
|
|
|
150 |
|
|
|
151 |
for (i = 0;i < r;++i)
|
|
|
152 |
{
|
|
|
153 |
ch = cmdbuf[i];
|
|
|
154 |
switch(stage)
|
|
|
155 |
{
|
|
|
156 |
case 0:
|
|
|
157 |
delnum = (unsigned int) (unsigned char) ch;
|
|
|
158 |
messid.len = 0; stage = 1; break;
|
|
|
159 |
case 1:
|
|
|
160 |
if (!stralloc_append(&messid,&ch)) flagabort = 1;
|
|
|
161 |
if (ch) break;
|
|
|
162 |
sender.len = 0; stage = 2; break;
|
|
|
163 |
case 2:
|
|
|
164 |
if (!stralloc_append(&sender,&ch)) flagabort = 1;
|
|
|
165 |
if (ch) break;
|
|
|
166 |
recip.len = 0; stage = 3; break;
|
|
|
167 |
case 3:
|
|
|
168 |
if (!stralloc_append(&recip,&ch)) flagabort = 1;
|
|
|
169 |
if (ch) break;
|
|
|
170 |
docmd();
|
|
|
171 |
flagabort = 0; stage = 0; break;
|
|
|
172 |
}
|
|
|
173 |
}
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
char inbuf[128];
|
|
|
177 |
|
|
|
178 |
void main(argc,argv)
|
|
|
179 |
int argc;
|
|
|
180 |
char **argv;
|
|
|
181 |
{
|
|
|
182 |
char ch;
|
|
|
183 |
int i;
|
|
|
184 |
int r;
|
|
|
185 |
fd_set rfds;
|
|
|
186 |
int nfds;
|
|
|
187 |
|
|
|
188 |
if (chdir(auto_qmail) == -1) _exit(111);
|
|
|
189 |
if (chdir("queue/mess") == -1) _exit(111);
|
|
|
190 |
if (!stralloc_copys(&messid,"")) _exit(111);
|
|
|
191 |
if (!stralloc_copys(&sender,"")) _exit(111);
|
|
|
192 |
if (!stralloc_copys(&recip,"")) _exit(111);
|
|
|
193 |
|
|
|
194 |
d = (struct delivery *) alloc((auto_spawn + 10) * sizeof(struct delivery));
|
|
|
195 |
if (!d) _exit(111);
|
|
|
196 |
|
|
|
197 |
substdio_fdbuf(&ssout,okwrite,1,outbuf,sizeof(outbuf));
|
|
|
198 |
|
|
|
199 |
sig_pipeignore();
|
|
|
200 |
sig_childcatch(sigchld);
|
|
|
201 |
|
|
|
202 |
initialize(argc,argv);
|
|
|
203 |
|
|
|
204 |
ch = auto_spawn; substdio_putflush(&ssout,&ch,1);
|
|
|
205 |
|
|
|
206 |
for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; }
|
|
|
207 |
|
|
|
208 |
for (;;)
|
|
|
209 |
{
|
|
|
210 |
if (!flagreading)
|
|
|
211 |
{
|
|
|
212 |
for (i = 0;i < auto_spawn;++i) if (d[i].used) break;
|
|
|
213 |
if (i >= auto_spawn) _exit(0);
|
|
|
214 |
}
|
|
|
215 |
sig_childunblock();
|
|
|
216 |
|
|
|
217 |
FD_ZERO(&rfds);
|
|
|
218 |
if (flagreading) FD_SET(0,&rfds);
|
|
|
219 |
nfds = 1;
|
|
|
220 |
for (i = 0;i < auto_spawn;++i) if (d[i].used)
|
|
|
221 |
{ FD_SET(d[i].fdin,&rfds); if (d[i].fdin >= nfds) nfds = d[i].fdin + 1; }
|
|
|
222 |
|
|
|
223 |
r = select(nfds,&rfds,(fd_set *) 0,(fd_set *) 0,(struct timeval *) 0);
|
|
|
224 |
sig_childblock();
|
|
|
225 |
|
|
|
226 |
if (r != -1)
|
|
|
227 |
{
|
|
|
228 |
if (flagreading)
|
|
|
229 |
if (FD_ISSET(0,&rfds))
|
|
|
230 |
getcmd();
|
|
|
231 |
for (i = 0;i < auto_spawn;++i) if (d[i].used)
|
|
|
232 |
if (FD_ISSET(d[i].fdin,&rfds))
|
|
|
233 |
{
|
|
|
234 |
r = read(d[i].fdin,inbuf,128);
|
|
|
235 |
if (r == -1)
|
|
|
236 |
continue; /* read error on a readable pipe? be serious */
|
|
|
237 |
if (r == 0)
|
|
|
238 |
{
|
|
|
239 |
ch = i; substdio_put(&ssout,&ch,1);
|
|
|
240 |
report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len);
|
|
|
241 |
substdio_put(&ssout,"",1);
|
|
|
242 |
substdio_flush(&ssout);
|
|
|
243 |
close(d[i].fdin); d[i].used = 0;
|
|
|
244 |
continue;
|
|
|
245 |
}
|
|
|
246 |
while (!stralloc_readyplus(&d[i].output,r)) sleep(10); /*XXX*/
|
|
|
247 |
byte_copy(d[i].output.s + d[i].output.len,r,inbuf);
|
|
|
248 |
d[i].output.len += r;
|
|
|
249 |
if (truncreport > 100)
|
|
|
250 |
if (d[i].output.len > truncreport)
|
|
|
251 |
{
|
|
|
252 |
char *truncmess = "\nError report too long, sorry.\n";
|
|
|
253 |
d[i].output.len = truncreport - str_len(truncmess) - 3;
|
|
|
254 |
stralloc_cats(&d[i].output,truncmess);
|
|
|
255 |
}
|
|
|
256 |
}
|
|
|
257 |
}
|
|
|
258 |
}
|
|
|
259 |
}
|