nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

qmail-queue.c (6334B)


      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 #include "readwrite.h"
      4 #include "sig.h"
      5 #include "exit.h"
      6 #include "open.h"
      7 #include "seek.h"
      8 #include "fmt.h"
      9 #include "alloc.h"
     10 #include "substdio.h"
     11 #include "datetime.h"
     12 #include "now.h"
     13 #include "triggerpull.h"
     14 #include "extra.h"
     15 #include "noreturn.h"
     16 #include "uidgid.h"
     17 #include "auto_qmail.h"
     18 #include "auto_uids.h"
     19 #include "auto_users.h"
     20 #include "date822fmt.h"
     21 #include "fmtqfn.h"
     22 #include "error.h"
     23 
     24 #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
     25 #define ADDR 1003
     26 
     27 char inbuf[2048];
     28 struct substdio ssin;
     29 char outbuf[256];
     30 struct substdio ssout;
     31 char errbuf[256];
     32 struct substdio sserr;
     33 
     34 datetime_sec starttime;
     35 struct datetime dt;
     36 unsigned long mypid;
     37 uid_t uid;
     38 char *pidfn;
     39 struct stat pidst;
     40 unsigned long messnum;
     41 char *messfn;
     42 char *todofn;
     43 char *intdfn;
     44 int messfd;
     45 int intdfd;
     46 int flagmademess = 0;
     47 int flagmadeintd = 0;
     48 
     49 uid_t auto_uida;
     50 uid_t auto_uidd;
     51 uid_t auto_uids;
     52 
     53 void cleanup()
     54 {
     55  if (flagmadeintd)
     56   {
     57    seek_trunc(intdfd,0);
     58    if (unlink(intdfn) == -1) return;
     59   }
     60  if (flagmademess)
     61   {
     62    seek_trunc(messfd,0);
     63    if (unlink(messfn) == -1) return;
     64   }
     65 }
     66 
     67 void _noreturn_ die(int e) { _exit(e); }
     68 void _noreturn_ die_write() { cleanup(); die(53); }
     69 void _noreturn_ die_read() { cleanup(); die(54); }
     70 void _noreturn_ sigalrm() { /* thou shalt not clean up here */ die(52); }
     71 void _noreturn_ sigbug() { die(81); }
     72 
     73 unsigned int receivedlen;
     74 char *received;
     75 /* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */
     76 
     77 static unsigned int receivedfmt(s)
     78 char *s;
     79 {
     80  unsigned int i;
     81  unsigned int len;
     82  len = 0;
     83  i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i;
     84  i = fmt_ulong(s,mypid); len += i; if (s) s += i;
     85  i = fmt_str(s," invoked "); len += i; if (s) s += i;
     86  if (uid == auto_uida)
     87   { i = fmt_str(s,"by alias"); len += i; if (s) s += i; }
     88  else if (uid == auto_uidd)
     89   { i = fmt_str(s,"from network"); len += i; if (s) s += i; }
     90  else if (uid == auto_uids)
     91   { i = fmt_str(s,"for bounce"); len += i; if (s) s += i; }
     92  else
     93   {
     94    i = fmt_str(s,"by uid "); len += i; if (s) s += i;
     95    i = fmt_ulong(s,uid); len += i; if (s) s += i;
     96   }
     97  i = fmt_str(s,"); "); len += i; if (s) s += i;
     98  i = date822fmt(s,&dt); len += i; if (s) s += i;
     99  return len;
    100 }
    101 
    102 void received_setup()
    103 {
    104  receivedlen = receivedfmt(NULL);
    105  received = alloc(receivedlen + 1);
    106  if (!received) die(51);
    107  receivedfmt(received);
    108 }
    109 
    110 unsigned int pidfmt(s,seq)
    111 char *s;
    112 unsigned long seq;
    113 {
    114  unsigned int i;
    115  unsigned int len;
    116 
    117  len = 0;
    118  i = fmt_str(s,"pid/"); len += i; if (s) s += i;
    119  i = fmt_ulong(s,mypid); len += i; if (s) s += i;
    120  i = fmt_str(s,"."); len += i; if (s) s += i;
    121  i = fmt_ulong(s,starttime); len += i; if (s) s += i;
    122  i = fmt_str(s,"."); len += i; if (s) s += i;
    123  i = fmt_ulong(s,seq); len += i; if (s) s += i;
    124  ++len; if (s) *s++ = 0;
    125 
    126  return len;
    127 }
    128 
    129 char *fnnum(dirslash,flagsplit)
    130 char *dirslash;
    131 int flagsplit;
    132 {
    133  char *s;
    134 
    135  s = alloc(fmtqfn(NULL,dirslash,messnum,flagsplit));
    136  if (!s) die(51);
    137  fmtqfn(s,dirslash,messnum,flagsplit);
    138  return s;
    139 }
    140 
    141 void pidopen()
    142 {
    143  unsigned int len;
    144  unsigned long seq;
    145 
    146  seq = 1;
    147  len = pidfmt(NULL,seq);
    148  pidfn = alloc(len);
    149  if (!pidfn) die(51);
    150 
    151  for (seq = 1;seq < 10;++seq)
    152   {
    153    if (pidfmt(NULL,seq) > len) die(81); /* paranoia */
    154    pidfmt(pidfn,seq);
    155    messfd = open_excl(pidfn);
    156    if (messfd != -1) return;
    157   }
    158 
    159  die(63);
    160 }
    161 
    162 char tmp[FMT_ULONG];
    163 
    164 int main(void)
    165 {
    166  unsigned int len;
    167  char ch;
    168 
    169  sig_blocknone();
    170  umask(033);
    171  if (chdir(auto_qmail) == -1) die(61);
    172  if (chdir("queue") == -1) die(62);
    173 
    174  mypid = getpid();
    175  uid = getuid();
    176  starttime = now();
    177  datetime_tai(&dt,starttime);
    178 
    179  auto_uida = inituid(auto_usera);
    180  auto_uidd = inituid(auto_userd);
    181  auto_uids = inituid(auto_users);
    182 
    183  received_setup();
    184 
    185  sig_pipeignore();
    186  sig_miscignore();
    187  sig_alarmcatch(sigalrm);
    188  sig_bugcatch(sigbug);
    189 
    190  alarm(DEATH);
    191 
    192  pidopen();
    193  if (fstat(messfd,&pidst) == -1) die(63);
    194 
    195  messnum = pidst.st_ino;
    196  messfn = fnnum("mess/",1);
    197  todofn = fnnum("todo/",0);
    198  intdfn = fnnum("intd/",0);
    199 
    200  substdio_fdbuf(&sserr,write,2,errbuf,sizeof(errbuf));
    201  if (link(pidfn,messfn) == -1) {
    202   substdio_putsflush(&sserr, error_str(errno));
    203   die(64);
    204  }
    205  if (unlink(pidfn) == -1) die(63);
    206  flagmademess = 1; // created pid file, linked it to mesg file, unlinked pid file.
    207 
    208  substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
    209  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
    210 
    211  if (substdio_bput(&ssout,received,receivedlen) == -1) die_write();
    212 
    213  switch(substdio_copy(&ssout,&ssin))
    214   {
    215    case -2: die_read();
    216    case -3: die_write();
    217   }
    218 
    219  if (substdio_flush(&ssout) == -1) die_write();
    220  if (fsync(messfd) == -1) die_write();
    221 
    222  intdfd = open_excl(intdfn);
    223  if (intdfd == -1) die(65);
    224  flagmadeintd = 1;
    225 
    226  substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf));
    227  substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf));
    228 
    229  if (substdio_bput(&ssout,"u",1) == -1) die_write();
    230  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,uid)) == -1) die_write();
    231  if (substdio_bput(&ssout,"",1) == -1) die_write();
    232 
    233  if (substdio_bput(&ssout,"p",1) == -1) die_write();
    234  if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();
    235  if (substdio_bput(&ssout,"",1) == -1) die_write();
    236  // it's not immediately clear that fmt_ulong actually runs first out of
    237  // each invokation of bput containing it
    238 
    239  if (substdio_get(&ssin,&ch,1) < 1) die_read();
    240  if (ch != 'F') die(91);
    241  if (substdio_bput(&ssout,&ch,1) == -1) die_write();
    242  for (len = 0;len < ADDR;++len)
    243   {
    244    if (substdio_get(&ssin,&ch,1) < 1) die_read();
    245    if (substdio_put(&ssout,&ch,1) == -1) die_write();
    246    if (!ch) break;
    247   }
    248  if (len >= ADDR) die(11);
    249 
    250  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
    251 
    252  for (;;)
    253   {
    254    if (substdio_get(&ssin,&ch,1) < 1) die_read();
    255    if (!ch) break;
    256    if (ch != 'T') die(91);
    257    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
    258    for (len = 0;len < ADDR;++len)
    259     {
    260      if (substdio_get(&ssin,&ch,1) < 1) die_read();
    261      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
    262      if (!ch) break;
    263     }
    264    if (len >= ADDR) die(11);
    265   }
    266 
    267  if (substdio_flush(&ssout) == -1) die_write();
    268  if (fsync(intdfd) == -1) die_write();
    269 
    270  if (link(intdfn,todofn) == -1) die(66);
    271 
    272  triggerpull(); // xxx should be a triggerpull on the appropriate queue.
    273  return 0;
    274 }