s/qmail 4.4.13
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-queue.c
Go to the documentation of this file.
1#include <unistd.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include "sig.h"
6#include "exit.h"
7#include "open.h"
8#include "seek.h"
9#include "fmt.h"
10#include "alloc.h"
11#include "buffer.h"
12#include "byte.h"
13#include "constmap.h"
14#include "control.h"
15#include "stralloc.h"
16#include "datetime.h"
17#include "now.h"
18#include "str.h"
19#include "triggerpull.h"
20#include "extra.h"
21#include "auto_qmail.h"
22#include "auto_queue.h"
23#include "auto_uids.h"
24#include "date822fmt.h"
25#include "fmtqfn.h"
26#include "env.h"
27#include "wait.h"
28#include "scan.h"
29#include "qmail.h"
30#include "wildmat.h"
31
32#define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
33#define ADDRL 1003
34
36struct buffer bi;
38struct buffer bo;
39
40#ifdef TAP
41int tapcontrol(stralloc *,stralloc *,stralloc *);
42
43stralloc taps = {0};
44stralloc tapcontrols = {0};
45struct constmap maptaps;
46
47stralloc fromaddr = {0}; // only one: <
48stralloc toaddrs = {0}; // could be several: >
49stralloc tapaddr = {0}; // could be more
50#endif
51
53struct datetime dt;
54unsigned long mypid;
55unsigned long uid;
56char *pidfn;
57struct stat pidst;
58unsigned long messnum;
59char *messfn;
60char *todofn;
61char *intdfn;
66
67void cleanup()
68{
69 if (flagmadeintd) {
70 seek_trunc(intdfd,0);
71 if (unlink(intdfn) == -1) return;
72 }
73 if (flagmademess) {
74 seek_trunc(messfd,0);
75 if (unlink(messfn) == -1) return;
76 }
77}
78
79void die(int e) { _exit(e); }
80#ifdef TAP
81void die_mem() { cleanup(); die(51); };
82void die_ctl() { cleanup(); die(55); };
83#endif
84void die_qhpsi() { cleanup(); die(71); }
85void die_write() { cleanup(); die(53); }
86void die_read() { cleanup(); die(54); }
87void sigalrm() { /* thou shalt not clean up here */ die(52); }
88void sigbug() { die(81); }
89
90unsigned int receivedlen;
92/* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */
93
94static unsigned int receivedfmt(char *s)
95{
96 unsigned int i;
97 unsigned int len;
98 len = 0;
99
100 i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i;
101 i = fmt_ulong(s,mypid); len += i; if (s) s += i;
102 i = fmt_str(s," invoked "); len += i; if (s) s += i;
103 if (uid == auto_uida) {
104 i = fmt_str(s,"by alias"); len += i; if (s) s += i;
105 } else if (uid == auto_uidd) {
106 i = fmt_str(s,"from network"); len += i; if (s) s += i;
107 } else if (uid == auto_uids) {
108 i = fmt_str(s,"for bounce"); len += i; if (s) s += i;
109 } else {
110 i = fmt_str(s,"by uid "); len += i; if (s) s += i;
111 i = fmt_ulong(s,uid); len += i; if (s) s += i;
112 }
113 i = fmt_str(s,"); "); len += i; if (s) s += i;
114 i = date822fmt(s,&dt); len += i; if (s) s += i;
115 return len;
116}
117
119{
120 receivedlen = receivedfmt((char *) 0);
121 received = alloc(receivedlen + 1);
122 if (!received) die(51);
123 receivedfmt(received);
124}
125
126unsigned int pidfmt(char *s,unsigned long seq)
127{
128 unsigned int i;
129 unsigned int len;
130
131 len = 0;
132 i = fmt_str(s,"pid/"); len += i; if (s) s += i;
133 i = fmt_ulong(s,mypid); len += i; if (s) s += i;
134 i = fmt_str(s,"."); len += i; if (s) s += i;
135 i = fmt_ulong(s,starttime); len += i; if (s) s += i;
136 i = fmt_str(s,"."); len += i; if (s) s += i;
137 i = fmt_ulong(s,seq); len += i; if (s) s += i;
138 ++len; if (s) *s++ = 0;
139
140 return len;
141}
142
143char *fnnum(char *dirslash,int flagsplit)
144{
145 char *s;
146
147 s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit));
148 if (!s) die(51);
149 fmtqfn(s,dirslash,messnum,flagsplit);
150 return s;
151}
152
153void pidopen(void)
154{
155 unsigned int len;
156 unsigned long seq;
157
158 seq = 1;
159 len = pidfmt((char *) 0,seq);
160 pidfn = alloc(len);
161 if (!pidfn) die(51);
162
163 for (seq = 1; seq < 10; ++seq) {
164 if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */
165 pidfmt(pidfn,seq);
166 messfd = open_excl(pidfn);
167 if (messfd != -1) return;
168 }
169
170 die(63);
171}
172
173char *qhpsi;
174
175void qhpsiprog(char *arg)
176{
177 int wstat;
178 int child;
179 char *qhpsiargs[6] = { 0, 0, 0, 0, 0, 0 };
180 char *x;
181 unsigned long u;
182 int childrc;
183 int qhpsirc = 1;
184 unsigned int size;
185 unsigned int qhpsiminsize = 0;
186 unsigned int qhpsimaxsize = 0;
187
188 struct stat st;
189
190 if (stat(messfn,&st) == -1) die(63);
191 size = (unsigned int) st.st_size;
192
193 x = env_get("QHPSIMINSIZE");
194 if (x) { scan_ulong(x,&u); qhpsiminsize = (int) u; }
195 if (qhpsiminsize) if (size < qhpsiminsize) return;
196 x = env_get("QHPSIMAXSIZE");
197 if (x) { scan_ulong(x,&u); qhpsimaxsize = (int) u; }
198 if (qhpsimaxsize) if (size > qhpsimaxsize) return;
199
200 if (*arg) {
201 switch (child = fork()) {
202 case -1:
203 die_qhpsi();
204 case 0:
205 qhpsiargs[0] = arg;
206 qhpsiargs[1] = messfn;
207 qhpsiargs[2] = env_get("QHPSIARG1");
208 if (!qhpsiargs[2]) qhpsiargs[2] = 0;
209 qhpsiargs[3] = env_get("QHPSIARG2");
210 if (!qhpsiargs[3]) qhpsiargs[3] = 0;
211 qhpsiargs[4] = env_get("QHPSIARG3");
212 if (!qhpsiargs[4]) qhpsiargs[4] = 0;
213 x = env_get("QHPSIRC");
214 if (x) { scan_ulong(x,&u); qhpsirc = (int) u; }
215 execvp(*qhpsiargs,qhpsiargs);
216 die_qhpsi();
217 }
218 if (wait_pid(&wstat,child) == -1) die_qhpsi();
219 if (wait_crashed(wstat)) die_qhpsi();
220 childrc = wait_exitcode(wstat);
221 if (childrc == qhpsirc) { cleanup(); die(32); }
222 else if (childrc != 0) die_qhpsi();
223 }
224}
225
226char tmp[FMT_ULONG];
227
228int main()
229{
230 unsigned int len;
231 char ch;
232 int fd;
233
234 sig_blocknone();
235 umask(033);
236 if (chdir(auto_queue) == -1) die(62);
237 if (chdir("queue") == -1) die(62);
238
239 mypid = getpid();
240 uid = getuid();
241 starttime = now();
243 qhpsi = env_get("QHPSI");
244
246
247 sig_pipeignore();
248 sig_miscignore();
249 sig_alarmcatch((void *)sigalrm);
250 sig_bugcatch((void *)sigbug);
251
252 alarm(DEATH);
253
254#ifdef TAP
255 if (control_init() == -1) die_ctl();
256
257 if (!stralloc_copys(&tapcontrols,auto_qmail)) die_mem();
258 if (!stralloc_cats(&tapcontrols,"/control/tapaddresses")) die_mem();
259 if (!stralloc_0(&tapcontrols)) die_mem();
260
261 if (control_readfile(&taps,tapcontrols.s,0) != -1) {
262 if (!constmap_init(&maptaps,taps.s,taps.len,1)) die_mem();
263 } else die_ctl();
264#endif
265
266 pidopen();
267 if (fstat(messfd,&pidst) == -1) die(63);
268
269 messnum = pidst.st_ino;
270 messfn = fnnum("mess/",1);
271 todofn = fnnum("todo/",1);
272 intdfn = fnnum("intd/",1);
273
274 if (link(pidfn,messfn) == -1) die(64);
275 if (unlink(pidfn) == -1) die(63);
276 flagmademess = 1;
277
278 buffer_init(&bo,buffer_unixwrite,messfd,outbuf,sizeof(outbuf));
279 buffer_init(&bi,buffer_unixread,0,inbuf,sizeof(inbuf));
280
281 if (buffer_put(&bo,received,receivedlen) == -1) die_write();
282
283 switch (buffer_copy(&bo,&bi)) {
284 case -2: die_read();
285 case -3: die_write(); // usual suspects
286 }
287 if (buffer_flush(&bo) == -1) die_write();
288 if (fsync(messfd) == -1) die_write();
289
290 intdfd = open_excl(intdfn);
291 if (intdfd == -1) die(65);
292 flagmadeintd = 1;
293
294 buffer_init(&bo,buffer_unixwrite,intdfd,outbuf,sizeof(outbuf));
295 buffer_init(&bi,buffer_unixread,1,inbuf,sizeof(inbuf));
296
297 if (buffer_put(&bo,"u",1) == -1) die_write(); // uid
298 if (buffer_put(&bo,tmp,fmt_ulong(tmp,uid)) == -1) die_write();
299 if (buffer_put(&bo,"",1) == -1) die_write();
300
301 if (buffer_put(&bo,"p",1) == -1) die_write(); // pid
302 if (buffer_put(&bo,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();
303 if (buffer_put(&bo,"",1) == -1) die_write();
304
305 if (buffer_get(&bi,&ch,1) < 1) die_read();
306 if (ch != 'F') die(91);
307 if (buffer_put(&bo,&ch,1) == -1) die_write();
308#ifdef TAP
309 if (!stralloc_copyb(&fromaddr,"<",1)) die_mem();
310#endif
311 for (len = 0; len < ADDRL; ++len) {
312 if (buffer_get(&bi,&ch,1) < 1) die_read();
313 if (buffer_put(&bo,&ch,1) == -1) die_write();
314 if (!ch) break;
315#ifdef TAP // From: address
316 if (!stralloc_catb(&fromaddr,&ch,1)) die_mem();
317#endif
318 }
319 if (len >= ADDRL) die(11);
320
321 if (buffer_put(&bo,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
322
323#ifdef TAP
324 if (!stralloc_copys(&toaddrs,"")) die_mem();
325#endif
326 for (;;) {
327 if (buffer_get(&bi,&ch,1) < 1) die_read();
328 if (!ch) break;
329 if (ch == 'Q') { qhpsi = 0; break; }
330 if (ch != 'T') die(91);
331 if (buffer_put(&bo,&ch,1) == -1) die_write();
332#ifdef TAP
333 if (!stralloc_catb(&toaddrs,">",1)) die_mem();
334#endif
335 for (len = 0; len < ADDRL; ++len) {
336 if (buffer_get(&bi,&ch,1) < 1) die_read();
337 if (buffer_put(&bo,&ch,1) == -1) die_write();
338 if (!ch) break;
339#ifdef TAP // To: address
340 if (!stralloc_catb(&toaddrs,&ch,1)) die_mem();
341#endif
342 }
343 if (len >= ADDRL) die(11);
344 }
345
346#ifdef TAP // Check for tapped addresses
347 if (tapcontrol(&tapaddr,&fromaddr,&toaddrs) > 0) {
348 if (buffer_put(&bo,tapaddr.s,tapaddr.len) == -1) die_write();
349 if (buffer_puts(&bo,"") == -1) die_write();
350 }
351#endif
352 if (qhpsi) qhpsiprog(qhpsi);
353
354 if (buffer_flush(&bo) == -1) die_write();
355 if (fsync(intdfd) == -1) die_write();
356
357 if (link(intdfn,todofn) == -1) die(66);
358 if ((fd = open(todofn,O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd)) die(66);
359
360 triggerpull();
361 die(0);
362}
363
364#ifdef TAP
365int tapcontrol(stralloc *tapaddress,stralloc *mailfrom,stralloc *rcpttos)
366{
367 int i, j, k;
368 int at, r = 0;
369 char ch;
370 char *tapaddr = 0;
371
372 stralloc chkaddr = {0};
373 stralloc rcptaddr = {0};
374
375 if (!stralloc_copys(tapaddress,"")) die_mem();
376
377 /* addr prefix: !: not, <: from, >: to -- addr are not \0 terminated */
378
379 if (!stralloc_copyb(&chkaddr,"!",1)) die_mem();
380 if (!stralloc_catb(&chkaddr,mailfrom->s + 1,mailfrom->len - 1)) die_mem();
381 if (constmap(&maptaps,chkaddr.s,chkaddr.len)) return -1;
382
383 /* 1. straight Mailfrom: <mailfrom@domain */
384
385 tapaddr = constmap(&maptaps,mailfrom->s,mailfrom->len);
386 if (tapaddr) {
387 j = 0; k = str_len(tapaddr);
388 if (k) if (!stralloc_catb(tapaddress,"T",1)) die_mem();
389 while (j < k) {
390 ch = tapaddr[j++];
391 if (ch == ',') {
392 if (!stralloc_0(tapaddress)) die_mem();
393 if (!stralloc_catb(tapaddress,"T",1)) die_mem();
394 } else
395 if (!stralloc_catb(tapaddress,&ch,1)) die_mem();
396 }
397 if (!stralloc_0(tapaddress)) die_mem();
398 r = 1;
399 }
400
401 /* 2. domain Mailfrom: <@domain */
402
403 at = byte_rchr(mailfrom->s,mailfrom->len,'@');
404 if (at < mailfrom->len) {
405 if (!stralloc_copyb(&chkaddr,"<",1)) die_mem();
406 if (!stralloc_catb(&chkaddr,mailfrom->s + at,mailfrom->len - at)) die_mem();
407
408 tapaddr = constmap(&maptaps,chkaddr.s,chkaddr.len);
409 if (tapaddr) {
410 j = 0; k = str_len(tapaddr);
411 if (k) if (!stralloc_catb(tapaddress,"T",1)) die_mem();
412 while (j < k) {
413 ch = tapaddr[j++];
414 if (ch == ',') {
415 if (!stralloc_0(tapaddress)) die_mem();
416 if (!stralloc_catb(tapaddress,"T",1)) die_mem();
417 } else
418 if (!stralloc_catb(tapaddress,&ch,1)) die_mem();
419 }
420 if (!stralloc_0(tapaddress)) die_mem();
421 r = 2;
422 }
423 }
424
425 /* 3. Straight Rcpttos: >rcptto1>rcptto2>... for each >rcptto */
426
427 r = rcpttos->len;
428 for (int n = 0; n < rcpttos->len; n++) {
429 if (n > 1) r = byte_chr(rcpttos->s + n,rcpttos->len,'>');
430 if (!stralloc_copyb(&rcptaddr,rcpttos->s + n,r)) die_mem();
431 n += r;
432
433 tapaddr = constmap(&maptaps,rcptaddr.s,rcptaddr.len);
434 if (tapaddr) {
435 j = 0; k = str_len(tapaddr);
436 if (k) if (!stralloc_catb(tapaddress,"T",1)) die_mem();
437 while (j < k) {
438 ch = tapaddr[j++];
439 if (ch == ',') {
440 if (!stralloc_0(tapaddress)) die_mem();
441 if (!stralloc_catb(tapaddress,"T",1)) die_mem();
442 } else
443 if (!stralloc_catb(tapaddress,&ch,1)) die_mem();
444 }
445 if (!stralloc_0(tapaddress)) die_mem();
446 r = 3;
447 }
448
449 /* 4. domain Rcptto: >@rcptto */
450
451 at = byte_rchr(rcptaddr.s,rcptaddr.len,'@');
452 if (at < rcptaddr.len) {
453 if (!stralloc_copyb(&chkaddr,">",1)) die_mem();
454 if (!stralloc_catb(&chkaddr,rcptaddr.s + at,rcptaddr.len - at)) die_mem();
455
456 tapaddr = constmap(&maptaps,chkaddr.s,chkaddr.len);
457 if (tapaddr) {
458 j = 0; k = str_len(tapaddr);
459 if (k) if (!stralloc_catb(tapaddress,"T",1)) die_mem();
460 while (j < k) {
461 ch = tapaddr[j++];
462 if (ch == ',') {
463 if (!stralloc_0(tapaddress)) die_mem();
464 if (!stralloc_catb(tapaddress,"T",1)) die_mem();
465 } else
466 if (!stralloc_catb(tapaddress,&ch,1)) die_mem();
467 }
468 if (!stralloc_0(tapaddress)) die_mem();
469 r = 4;
470 }
471 }
472 }
473
474 return r;
475}
476#endif
char auto_qmail[]
char auto_queue[]
int auto_uidd
int auto_uida
int auto_uids
int constmap_init(struct constmap *cm, char *s, int len, int flagcolon)
Definition: constmap.c:35
int control_readfile(stralloc *sa, char *fn, int flagme)
Definition: control.c:87
int control_init(void)
Definition: control.c:33
unsigned int date822fmt(char *s, struct datetime *dt)
Definition: date822fmt.c:9
void datetime_tai(struct datetime *dt, datetime_sec t)
Definition: datetime.c:4
long datetime_sec
Definition: datetime.h:15
int stralloc_copys(stralloc *, char const *)
void _exit(int)
#define QUEUE_EXTRA
Definition: extra.h:4
#define QUEUE_EXTRALEN
Definition: extra.h:5
unsigned int fmtqfn(char *s, char *dirslash, unsigned long id, int flagsplit)
Definition: fmtqfn.c:5
unsigned int
Definition: ipalloc.h:19
datetime_sec now()
Definition: now.c:5
int fd
unsigned long size
Definition: qmail-qread.c:59
void die_qhpsi()
Definition: qmail-queue.c:84
struct stat pidst
Definition: qmail-queue.c:57
unsigned long messnum
Definition: qmail-queue.c:58
char * qhpsi
Definition: qmail-queue.c:173
char tmp[FMT_ULONG]
Definition: qmail-queue.c:226
unsigned int pidfmt(char *s, unsigned long seq)
Definition: qmail-queue.c:126
int intdfd
Definition: qmail-queue.c:63
void sigalrm()
Definition: qmail-queue.c:87
char * todofn
Definition: qmail-queue.c:60
void cleanup()
Definition: qmail-queue.c:67
datetime_sec starttime
Definition: qmail-queue.c:52
void sigbug()
Definition: qmail-queue.c:88
unsigned long uid
Definition: qmail-queue.c:55
int flagmademess
Definition: qmail-queue.c:64
#define ADDRL
Definition: qmail-queue.c:33
struct buffer bi
Definition: qmail-queue.c:36
void die_write()
Definition: qmail-queue.c:85
#define DEATH
Definition: qmail-queue.c:32
char * fnnum(char *dirslash, int flagsplit)
Definition: qmail-queue.c:143
char * pidfn
Definition: qmail-queue.c:56
int flagmadeintd
Definition: qmail-queue.c:65
void qhpsiprog(char *arg)
Definition: qmail-queue.c:175
void pidopen(void)
Definition: qmail-queue.c:153
void die_read()
Definition: qmail-queue.c:86
char outbuf[BUFSIZE_LINE]
Definition: qmail-queue.c:37
char inbuf[BUFSIZE_MESS]
Definition: qmail-queue.c:35
unsigned long mypid
Definition: qmail-queue.c:54
char * messfn
Definition: qmail-queue.c:59
int messfd
Definition: qmail-queue.c:62
struct buffer bo
Definition: qmail-queue.c:38
struct datetime dt
Definition: qmail-queue.c:53
char * intdfn
Definition: qmail-queue.c:61
char * received
Definition: qmail-queue.c:91
int main()
Definition: qmail-queue.c:228
void received_setup()
Definition: qmail-queue.c:118
unsigned int receivedlen
Definition: qmail-queue.c:90
int j
Definition: qmail-send.c:926
stralloc mailfrom
Definition: qmail-smtpd.c:532
void die()
Definition: qmail-start.c:14
#define BUFSIZE_MESS
Definition: qmail.h:7
#define BUFSIZE_LINE
Definition: qmail.h:8
uint32_t k[64]
Definition: sha256.c:27
void triggerpull(void)
Definition: trigger.c:31