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 }