nightmaremail

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

qmail-start-np.c (5499B)


      1 #include <sys/stat.h>
      2 #include <unistd.h>
      3 #include "fd.h"
      4 #include "prot.h"
      5 #include "exit.h"
      6 #include "fork.h"
      7 #include "noreturn.h"
      8 #include "uidgid.h"
      9 #include "auto_uids.h"
     10 #include "auto_users.h"
     11 #include "auto_qmail.h" // auto_qmail.o
     12 #include "select.h" // ...?
     13 #include "fifo.h" // fifo.something
     14 #include "open.h" // open.a
     15 #include "hasnpbg1.h"
     16 
     17 /* MXF NOTES:
     18  * This qmail-start is special. It creates named pipes for channel
     19  * drivers (to wit, lspawn and rspawn) and the logger, and fires off
     20  * an extra process that creates a triggerpull which qmsend should
     21  * yank when it has picked up the stdin pipes of clean, logger and
     22  * channel drivers.
     23  */
     24 
     25 #define RDEND 0
     26 #define WREND 1
     27 
     28 char *(qsargs[]) = { "qmail-send", 0 };
     29 char *(qcargs[]) = { "qmail-clean", 0 };
     30 char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
     31 char *(qrargs[]) = { "qmail-rspawn", 0 };
     32 
     33 void _noreturn_ die() { _exit(111); }
     34 
     35 int pi0[2];
     36 int pi1[2];
     37 int pi2[2];
     38 int pi3[2];
     39 int pi4[2];
     40 int pi5[2];
     41 int pi6[2];
     42 
     43 uid_t auto_uidl;
     44 uid_t auto_uidq;
     45 uid_t auto_uidr;
     46 uid_t auto_uids;
     47 
     48 gid_t auto_gidn;
     49 gid_t auto_gidq;
     50 
     51 void close23456() { close(2); close(3); close(4); close(5); close(6); }
     52 
     53 // sort of same semantics as pipe()
     54 int makeorusenp(char *n, int *f) {
     55   if (fifo_make(n, 0600) == -1) {
     56     if (errno != EEXIST) {
     57       return -1;
     58     }
     59   }
     60   f[0] = open_read(n);
     61   if (f[0] == -1) return -1;
     62   fchown(f[0], auto_uids);
     63   fchown(f[0], auto_gidq);
     64   fchmod(f[0], 0600);
     65   f[1] = open_write(n);
     66   if (f[1] == -1) return -1;
     67   return 0;
     68 }
     69 
     70 void closepipes() {
     71   close(pi1[RDEND]); close(pi1[WREND]); close(pi2[RDEND]); close(pi2[WREND]);
     72   close(pi3[RDEND]); close(pi3[WREND]); close(pi4[RDEND]); close(pi4[WREND]);
     73   close(pi5[RDEND]); close(pi5[WREND]); close(pi6[RDEND]); close(pi6[WREND]);
     74 }
     75 
     76 int main(int argc, char **argv)
     77 {
     78   if (chdir("/") == -1) die();
     79   umask(077);
     80 
     81   auto_uidl = inituid(auto_userl);
     82   auto_uidq = inituid(auto_userq);
     83   auto_uidr = inituid(auto_userr);
     84   auto_uids = inituid(auto_users);
     85 
     86   auto_gidn = initgid(auto_groupn);
     87   auto_gidq = initgid(auto_groupq);
     88 
     89   if (prot_gid(auto_gidq) == -1) die();
     90 
     91   if (fd_copy(2,0) == -1) die();
     92   if (fd_copy(3,0) == -1) die();
     93   if (fd_copy(4,0) == -1) die();
     94   if (fd_copy(5,0) == -1) die();
     95   if (fd_copy(6,0) == -1) die();
     96 
     97   if (argv[1]) {
     98     qlargs[1] = argv[1];
     99     ++argv;
    100   }
    101 
    102   if (chdir(auto_qmail) == -1) die();
    103 
    104   // logger
    105   if (argv[1]) {
    106     if (makeorusenp("queue/lock/loggersin", &pi0) == -1) die();
    107     switch(fork()) {
    108       case -1:
    109 	die();
    110       case 0:
    111         if (prot_gid(auto_gidn) == -1) die();
    112         if (prot_uid(auto_uidl) == -1) die();
    113         close(pi0[WREND]);
    114         if (fd_move(0,pi0[RDEND]) == -1) die();
    115         close23456();
    116         execvp(argv[1],argv + 1);
    117 	die();
    118     }
    119     close(pi0[RDEND]);
    120     if (fd_move(1,pi0[WREND]) == -1) die();
    121   }
    122 
    123   if (makeorusenp("queue/lock/chan0sin", &pi1) == -1) die();  // si [
    124   if (makeorusenp("queue/lock/chan0sout", &pi2) == -1) die(); // so ] lspawn
    125   if (makeorusenp("queue/lock/chan1sin", &pi3) == -1) die();  // si [
    126   if (makeorusenp("queue/lock/chan1sout", &pi4) == -1) die(); // so ] rspawn
    127   if (makeorusenp("queue/lock/cleansin", &pi5) == -1) die();  // si [
    128   if (makeorusenp("queue/lock/cleansout", &pi6) == -1) die(); // so ] cleanup
    129 
    130   // channelspawn: local
    131   switch(fork()) {
    132     case -1: die();
    133     case 0:
    134       if (fd_copy(0,pi1[RDEND]) == -1) die();
    135       if (fd_copy(1,pi2[WREND]) == -1) die();
    136       close23456();
    137       closepipes();
    138       execvp(*qlargs,qlargs);
    139       die();
    140   }
    141 
    142   // channelspawn: remote
    143   switch(fork()) {
    144     case -1: die();
    145     case 0:
    146       if (prot_uid(auto_uidr) == -1) die();
    147       if (fd_copy(0,pi3[RDEND]) == -1) die();
    148       if (fd_copy(1,pi4[WREND]) == -1) die();
    149       close23456();
    150       closepipes();
    151       execvp(*qrargs,qrargs);
    152       die();
    153   }
    154 
    155   // cleanup
    156   switch(fork()) {
    157     case -1: die();
    158     case 0:
    159       if (prot_uid(auto_uidq) == -1) die();
    160       if (fd_copy(0,pi5[RDEND]) == -1) die();
    161       if (fd_copy(1,pi6[WREND]) == -1) die();
    162       close23456();
    163       closepipes();
    164       execvp(*qcargs,qcargs);
    165       die();
    166   }
    167 
    168   // readiness
    169   switch (fork()) {
    170     case -1: die();
    171     case 0:
    172       close23456();
    173 #ifdef HASNAMEDPIPEBUG1
    174       if (fd_copy(2,pi1[WREND]) == -1) die();
    175       if (fd_copy(3,pi3[WREND]) == -1) die();
    176       if (fd_copy(4,pi5[WREND]) == -1) die();
    177       // on some systems, named pipes that are only open at one end
    178       // constantly check readability. This turns their selects into
    179       // a spinlock. Prevent this by keeping the WRENDs of pipes whose
    180       // RDENDs are passed into the above processes open.
    181 #endif
    182       closepipes();
    183       if (makeorusenp("queue/lock/sendready", &pi0) == -1) die()
    184       fd_set rfds;
    185       FD_ZERO(&rfds);
    186       FD_SET(pi0[0], &rfds);
    187       if (select(pi0[0] + 1, &rfds, NULL, NULL, NULL) > 0) {
    188         // this can only mean one thing: someone wrote to our readiness FD.
    189         // that means they now have the WRENDs of the loggersin and chanNsin
    190         // pipes.
    191         _exit(0); // we can now report.
    192       }
    193   }
    194 
    195   // exec into qmsend
    196   if (prot_uid(auto_uids) == -1) die();
    197   if (fd_copy(0,1) == -1) die();
    198   if (fd_copy(1,pi1[WREND]) == -1) die();
    199   if (fd_copy(2,pi2[RDEND]) == -1) die();
    200   if (fd_copy(3,pi3[WREND]) == -1) die();
    201   if (fd_copy(4,pi4[RDEND]) == -1) die();
    202   if (fd_copy(5,pi5[WREND]) == -1) die();
    203   if (fd_copy(6,pi6[RDEND]) == -1) die();
    204   closepipes();
    205   execvp(*qsargs,qsargs);
    206   die();
    207 }