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 }