From 89b7b67a13ebb7965cc7f13ad0595e2194a2d34c Mon Sep 17 00:00:00 2001 From: Jannis Hoffmann Date: Wed, 3 Jul 2024 15:48:04 +0200 Subject: add sqmail-4.2.29a --- src/qmail-queue.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/qmail-queue.c (limited to 'src/qmail-queue.c') diff --git a/src/qmail-queue.c b/src/qmail-queue.c new file mode 100644 index 0000000..b1289dc --- /dev/null +++ b/src/qmail-queue.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include "sig.h" +#include "exit.h" +#include "open.h" +#include "seek.h" +#include "fmt.h" +#include "alloc.h" +#include "buffer.h" +#include "datetime.h" +#include "now.h" +#include "triggerpull.h" +#include "extra.h" +#include "auto_qmail.h" +#include "auto_uids.h" +#include "date822fmt.h" +#include "fmtqfn.h" +#include "env.h" +#include "wait.h" +#include "scan.h" + +#define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */ +#define ADDR 1003 + +char inbuf[2048]; +struct buffer bi; +char outbuf[256]; +struct buffer bo; + +datetime_sec starttime; +struct datetime dt; +unsigned long mypid; +unsigned long uid; +char *pidfn; +struct stat pidst; +unsigned long messnum; +char *messfn; +char *todofn; +char *intdfn; +int messfd; +int intdfd; +int flagmademess = 0; +int flagmadeintd = 0; + +void cleanup() +{ + if (flagmadeintd) { + seek_trunc(intdfd,0); + if (unlink(intdfn) == -1) return; + } + if (flagmademess) { + seek_trunc(messfd,0); + if (unlink(messfn) == -1) return; + } +} + +void die(int e) { _exit(e); } +void die_qhpsi() { cleanup(); die(71); } +void die_write() { cleanup(); die(53); } +void die_read() { cleanup(); die(54); } +void sigalrm() { /* thou shalt not clean up here */ die(52); } +void sigbug() { die(81); } + +unsigned int receivedlen; +char *received; +/* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */ + +static unsigned int receivedfmt(char *s) +{ + unsigned int i; + unsigned int len; + len = 0; + + i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i; + i = fmt_ulong(s,mypid); len += i; if (s) s += i; + i = fmt_str(s," invoked "); len += i; if (s) s += i; + if (uid == auto_uida) { + i = fmt_str(s,"by alias"); len += i; if (s) s += i; + } else if (uid == auto_uidd) { + i = fmt_str(s,"from network"); len += i; if (s) s += i; + } else if (uid == auto_uids) { + i = fmt_str(s,"for bounce"); len += i; if (s) s += i; + } else { + i = fmt_str(s,"by uid "); len += i; if (s) s += i; + i = fmt_ulong(s,uid); len += i; if (s) s += i; + } + i = fmt_str(s,"); "); len += i; if (s) s += i; + i = date822fmt(s,&dt); len += i; if (s) s += i; + return len; +} + +void received_setup() +{ + receivedlen = receivedfmt((char *) 0); + received = alloc(receivedlen + 1); + if (!received) die(51); + receivedfmt(received); +} + +unsigned int pidfmt(char *s,unsigned long seq) +{ + unsigned int i; + unsigned int len; + + len = 0; + i = fmt_str(s,"pid/"); len += i; if (s) s += i; + i = fmt_ulong(s,mypid); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,starttime); len += i; if (s) s += i; + i = fmt_str(s,"."); len += i; if (s) s += i; + i = fmt_ulong(s,seq); len += i; if (s) s += i; + ++len; if (s) *s++ = 0; + + return len; +} + +char *fnnum(char *dirslash,int flagsplit) +{ + char *s; + + s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit)); + if (!s) die(51); + fmtqfn(s,dirslash,messnum,flagsplit); + return s; +} + +void pidopen(void) +{ + unsigned int len; + unsigned long seq; + + seq = 1; + len = pidfmt((char *) 0,seq); + pidfn = alloc(len); + if (!pidfn) die(51); + + for (seq = 1; seq < 10; ++seq) { + if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */ + pidfmt(pidfn,seq); + messfd = open_excl(pidfn); + if (messfd != -1) return; + } + + die(63); +} + +char *qhpsi; + +void qhpsiprog(char *arg) +{ + int wstat; + int child; + char *qhpsiargs[6] = { 0, 0, 0, 0, 0, 0 }; + char *x; + unsigned long u; + int childrc; + int qhpsirc = 1; + unsigned int size; + unsigned int qhpsiminsize = 0; + unsigned int qhpsimaxsize = 0; + + struct stat st; + + if (stat(messfn,&st) == -1) die(63); + size = (unsigned int) st.st_size; + + x = env_get("QHPSIMINSIZE"); + if (x) { scan_ulong(x,&u); qhpsiminsize = (int) u; } + if (qhpsiminsize) if (size < qhpsiminsize) return; + x = env_get("QHPSIMAXSIZE"); + if (x) { scan_ulong(x,&u); qhpsimaxsize = (int) u; } + if (qhpsimaxsize) if (size > qhpsimaxsize) return; + + if (*arg) { + switch (child = fork()) { + case -1: + die_qhpsi(); + case 0: + qhpsiargs[0] = arg; + qhpsiargs[1] = messfn; + qhpsiargs[2] = env_get("QHPSIARG1"); + if (!qhpsiargs[2]) qhpsiargs[2] = 0; + qhpsiargs[3] = env_get("QHPSIARG2"); + if (!qhpsiargs[3]) qhpsiargs[3] = 0; + qhpsiargs[4] = env_get("QHPSIARG3"); + if (!qhpsiargs[4]) qhpsiargs[4] = 0; + x = env_get("QHPSIRC"); + if (x) { scan_ulong(x,&u); qhpsirc = (int) u; } + execvp(*qhpsiargs,qhpsiargs); + die_qhpsi(); + } + if (wait_pid(&wstat,child) == -1) die_qhpsi(); + if (wait_crashed(wstat)) die_qhpsi(); + childrc = wait_exitcode(wstat); + if (childrc == qhpsirc) { cleanup(); die(32); } + else if (childrc != 0) die_qhpsi(); + } +} + +char tmp[FMT_ULONG]; + +int main() +{ + unsigned int len; + char ch; + int fd; + + sig_blocknone(); + umask(033); + if (chdir(auto_qmail) == -1) die(61); + if (chdir("queue") == -1) die(62); + + mypid = getpid(); + uid = getuid(); + starttime = now(); + datetime_tai(&dt,starttime); + qhpsi = env_get("QHPSI"); + + received_setup(); + + sig_pipeignore(); + sig_miscignore(); + sig_alarmcatch(sigalrm); + sig_bugcatch(sigbug); + + alarm(DEATH); + + pidopen(); + if (fstat(messfd,&pidst) == -1) die(63); + + messnum = pidst.st_ino; + messfn = fnnum("mess/",1); + todofn = fnnum("todo/",1); + intdfn = fnnum("intd/",1); + + if (link(pidfn,messfn) == -1) die(64); + if (unlink(pidfn) == -1) die(63); + flagmademess = 1; + + buffer_init(&bo,write,messfd,outbuf,sizeof(outbuf)); + buffer_init(&bi,read,0,inbuf,sizeof(inbuf)); + + if (buffer_put(&bo,received,receivedlen) == -1) die_write(); + + switch (buffer_copy(&bo,&bi)) { + case -2: die_read(); + case -3: die_write(); + } + if (buffer_flush(&bo) == -1) die_write(); + if (fsync(messfd) == -1) die_write(); + + intdfd = open_excl(intdfn); + if (intdfd == -1) die(65); + flagmadeintd = 1; + + buffer_init(&bo,write,intdfd,outbuf,sizeof(outbuf)); + buffer_init(&bi,read,1,inbuf,sizeof(inbuf)); + + if (buffer_put(&bo,"u",1) == -1) die_write(); + if (buffer_put(&bo,tmp,fmt_ulong(tmp,uid)) == -1) die_write(); + if (buffer_put(&bo,"",1) == -1) die_write(); + + if (buffer_put(&bo,"p",1) == -1) die_write(); + if (buffer_put(&bo,tmp,fmt_ulong(tmp,mypid)) == -1) die_write(); + if (buffer_put(&bo,"",1) == -1) die_write(); + + if (buffer_get(&bi,&ch,1) < 1) die_read(); + if (ch != 'F') die(91); + if (buffer_put(&bo,&ch,1) == -1) die_write(); + for (len = 0; len < ADDR; ++len) { + if (buffer_get(&bi,&ch,1) < 1) die_read(); + if (buffer_put(&bo,&ch,1) == -1) die_write(); + if (!ch) break; + } + if (len >= ADDR) die(11); + + if (buffer_put(&bo,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write(); + + for (;;) { + if (buffer_get(&bi,&ch,1) < 1) die_read(); + if (!ch) break; + if (ch == 'Q') { qhpsi = 0; break; } + if (ch != 'T') die(91); + if (buffer_put(&bo,&ch,1) == -1) die_write(); + for (len = 0; len < ADDR; ++len) { + if (buffer_get(&bi,&ch,1) < 1) die_read(); + if (buffer_put(&bo,&ch,1) == -1) die_write(); + if (!ch) break; + } + if (len >= ADDR) die(11); + } + + if (qhpsi) qhpsiprog(qhpsi); + + if (buffer_flush(&bo) == -1) die_write(); + if (fsync(intdfd) == -1) die_write(); + + if (link(intdfn,todofn) == -1) die(66); + if ((fd = open(todofn,O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd)) die(66); + + triggerpull(); + die(0); +} -- cgit v1.2.3