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