qmail-qmqpd.c (3815B)
1 #include "noreturn.h" 2 #include "auto_qmail.h" 3 #include "qmail.h" 4 #include "received.h" 5 #include "sig.h" 6 #include "substdio.h" 7 #include "readwrite.h" 8 #include "exit.h" 9 #include "now.h" 10 #include "fmt.h" 11 #include "byte.h" 12 #include "env.h" 13 #include "str.h" 14 #include "netstrings.h" 15 16 void _noreturn_ resources() { _exit(111); } 17 void _noreturn_ badproto() { _exit(100); } 18 void _noreturn_ die_wtf() { _exit(100); } 19 20 ssize_t safewrite(int fd, const void *buf, size_t len) 21 { 22 ssize_t r; 23 r = write(fd,buf,len); 24 if (r == 0 || r == -1) _exit(0); 25 return r; 26 } 27 ssize_t saferead(int fd, void *buf, size_t len) 28 { 29 ssize_t r; 30 r = read(fd,buf,len); 31 if (r == 0 || r == -1) _exit(0); 32 return r; 33 } 34 35 char ssinbuf[512]; 36 substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof(ssinbuf)); 37 char ssoutbuf[256]; 38 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof(ssoutbuf)); 39 40 unsigned long long bytesleft = 100; 41 42 void getbyte(ch) 43 char *ch; 44 { 45 if (!bytesleft--) _exit(100); 46 substdio_get(&ssin,ch,1); 47 } 48 49 unsigned long long getlen() 50 { 51 unsigned long long len = 0; 52 switch (ns_getlength(&ssin,&len)) { 53 case NS_SUCCESS: return len; break; 54 case NS_TOOMUCH: resources(); break; 55 case NS_PROTOCOL: badproto(); break; 56 case NS_INVAL: die_wtf(); break; 57 case NS_BIOERR: die_wtf(); break; 58 } 59 // we won't reach here. 60 return len; 61 #if 0 62 char ch; 63 64 for (;;) { 65 getbyte(&ch); 66 if (ch == ':') return len; 67 if (len > 200000000) resources(); 68 len = 10 * len + (ch - '0'); 69 } 70 #endif 71 } 72 73 void getcomma() 74 { 75 switch (ns_getcomma(&ssin)) { 76 case NS_SUCCESS: break; 77 case NS_PROTOCOL: badproto(); break; 78 } 79 80 #if 0 81 char ch; 82 getbyte(&ch); 83 if (ch != ',') _exit(100); 84 #endif 85 } 86 87 struct qmail qq; 88 89 void identify() 90 { 91 char *remotehost; 92 char *remoteinfo; 93 char *remoteip; 94 char *local; 95 96 remotehost = env_get("TCPREMOTEHOST"); 97 if (!remotehost) remotehost = "unknown"; 98 remoteinfo = env_get("TCPREMOTEINFO"); 99 remoteip = env_get("TCPREMOTEIP"); 100 if (!remoteip) remoteip = "unknown"; 101 local = env_get("TCPLOCALHOST"); 102 if (!local) local = env_get("TCPLOCALIP"); 103 if (!local) local = "unknown"; 104 105 received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,NULL); 106 } 107 108 char buf[1000]; 109 char strnum[FMT_ULONG]; 110 111 int getbuf() 112 { 113 unsigned long long len; 114 int i; 115 116 len = getlen(); 117 if (len >= 1000) { 118 for (i = 0;i < len;++i) getbyte(buf); 119 getcomma(); 120 buf[0] = 0; 121 return 0; 122 } 123 124 for (i = 0;i < len;++i) getbyte(buf + i); 125 getcomma(); 126 buf[len] = 0; 127 return byte_chr(buf,len,'\0') == len; 128 } 129 130 int flagok = 1; 131 132 int 133 main() 134 { 135 char *result; 136 unsigned long long qp; 137 unsigned long long len; 138 char ch; 139 140 sig_pipeignore(); 141 sig_alarmcatch(resources); 142 alarm(3600); 143 144 bytesleft = getlen(); 145 146 len = getlen(); 147 148 if (chdir(auto_qmail) == -1) resources(); 149 if (qmail_open(&qq) == -1) resources(); 150 qp = qmail_qp(&qq); 151 identify(); 152 153 while (len > 0) { /* XXX: could speed this up */ 154 getbyte(&ch); 155 --len; 156 qmail_put(&qq,&ch,1); 157 } 158 getcomma(); 159 160 if (getbuf()) 161 qmail_from(&qq,buf); 162 else { 163 qmail_from(&qq,""); 164 qmail_fail(&qq); 165 flagok = 0; 166 } 167 168 while (bytesleft) 169 if (getbuf()) 170 qmail_to(&qq,buf); 171 else { 172 qmail_fail(&qq); 173 flagok = 0; 174 } 175 176 bytesleft = 1; 177 getcomma(); 178 179 result = qmail_close(&qq); 180 181 if (!*result) { 182 len = fmt_str(buf,"Kok "); 183 len += fmt_ulong(buf + len,(unsigned long) now()); 184 len += fmt_str(buf + len," qp "); 185 len += fmt_ulong(buf + len,qp); 186 buf[len] = 0; 187 result = buf; 188 } 189 190 if (!flagok) 191 result = "Dsorry, I can't accept addresses like that (#5.1.3)"; 192 193 substdio_put(&ssout,strnum,fmt_ulong(strnum,(unsigned long) str_len(result))); 194 substdio_puts(&ssout,":"); 195 substdio_puts(&ssout,result); 196 substdio_puts(&ssout,","); 197 substdio_flush(&ssout); 198 _exit(0); 199 }