|
1 #include "stralloc.h" |
|
2 #include "substdio.h" |
|
3 #include "qmail.h" |
|
4 #include "now.h" |
|
5 #include "str.h" |
|
6 #include "fmt.h" |
|
7 #include "env.h" |
|
8 #include "sig.h" |
|
9 #include "rcpthosts.h" |
|
10 #include "auto_qmail.h" |
|
11 #include "readwrite.h" |
|
12 #include "control.h" |
|
13 #include "received.h" |
|
14 |
|
15 void badproto() { _exit(100); } |
|
16 void resources() { _exit(111); } |
|
17 |
|
18 int safewrite(fd,buf,len) int fd; char *buf; int len; |
|
19 { |
|
20 int r; |
|
21 r = write(fd,buf,len); |
|
22 if (r <= 0) _exit(0); |
|
23 return r; |
|
24 } |
|
25 |
|
26 char ssoutbuf[256]; |
|
27 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf); |
|
28 |
|
29 int saferead(fd,buf,len) int fd; char *buf; int len; |
|
30 { |
|
31 int r; |
|
32 substdio_flush(&ssout); |
|
33 r = read(fd,buf,len); |
|
34 if (r <= 0) _exit(0); |
|
35 return r; |
|
36 } |
|
37 |
|
38 char ssinbuf[512]; |
|
39 substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf); |
|
40 |
|
41 unsigned long getlen() |
|
42 { |
|
43 unsigned long len = 0; |
|
44 char ch; |
|
45 for (;;) { |
|
46 substdio_get(&ssin,&ch,1); |
|
47 if (ch == ':') return len; |
|
48 if (len > 200000000) resources(); |
|
49 len = 10 * len + (ch - '0'); |
|
50 } |
|
51 } |
|
52 |
|
53 void getcomma() |
|
54 { |
|
55 char ch; |
|
56 substdio_get(&ssin,&ch,1); |
|
57 if (ch != ',') badproto(); |
|
58 } |
|
59 |
|
60 unsigned int databytes = 0; |
|
61 unsigned int bytestooverflow = 0; |
|
62 struct qmail qq; |
|
63 |
|
64 char buf[1000]; |
|
65 char buf2[100]; |
|
66 |
|
67 char *remotehost; |
|
68 char *remoteinfo; |
|
69 char *remoteip; |
|
70 char *local; |
|
71 |
|
72 stralloc failure = {0}; |
|
73 |
|
74 char *relayclient; |
|
75 int relayclientlen; |
|
76 |
|
77 main() |
|
78 { |
|
79 char ch; |
|
80 int i; |
|
81 unsigned long biglen; |
|
82 unsigned long len; |
|
83 int flagdos; |
|
84 int flagsenderok; |
|
85 int flagbother; |
|
86 unsigned long qp; |
|
87 char *result; |
|
88 char *x; |
|
89 unsigned long u; |
|
90 |
|
91 sig_pipeignore(); |
|
92 sig_alarmcatch(resources); |
|
93 alarm(3600); |
|
94 |
|
95 if (chdir(auto_qmail) == -1) resources(); |
|
96 |
|
97 if (control_init() == -1) resources(); |
|
98 if (rcpthosts_init() == -1) resources(); |
|
99 relayclient = env_get("RELAYCLIENT"); |
|
100 relayclientlen = relayclient ? str_len(relayclient) : 0; |
|
101 |
|
102 if (control_readint(&databytes,"control/databytes") == -1) resources(); |
|
103 x = env_get("DATABYTES"); |
|
104 if (x) { scan_ulong(x,&u); databytes = u; } |
|
105 if (!(databytes + 1)) --databytes; |
|
106 |
|
107 remotehost = env_get("TCPREMOTEHOST"); |
|
108 if (!remotehost) remotehost = "unknown"; |
|
109 remoteinfo = env_get("TCPREMOTEINFO"); |
|
110 remoteip = env_get("TCPREMOTEIP"); |
|
111 if (!remoteip) remoteip = "unknown"; |
|
112 local = env_get("TCPLOCALHOST"); |
|
113 if (!local) local = env_get("TCPLOCALIP"); |
|
114 if (!local) local = "unknown"; |
|
115 |
|
116 for (;;) { |
|
117 if (!stralloc_copys(&failure,"")) resources(); |
|
118 flagsenderok = 1; |
|
119 |
|
120 len = getlen(); |
|
121 if (len == 0) badproto(); |
|
122 |
|
123 if (databytes) bytestooverflow = databytes + 1; |
|
124 if (qmail_open(&qq) == -1) resources(); |
|
125 qp = qmail_qp(&qq); |
|
126 |
|
127 substdio_get(&ssin,&ch,1); |
|
128 --len; |
|
129 if (ch == 10) flagdos = 0; |
|
130 else if (ch == 13) flagdos = 1; |
|
131 else badproto(); |
|
132 |
|
133 received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0); |
|
134 |
|
135 /* XXX: check for loops? only if len is big? */ |
|
136 |
|
137 if (flagdos) |
|
138 while (len > 0) { |
|
139 substdio_get(&ssin,&ch,1); |
|
140 --len; |
|
141 while ((ch == 13) && len) { |
|
142 substdio_get(&ssin,&ch,1); |
|
143 --len; |
|
144 if (ch == 10) break; |
|
145 if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); |
|
146 qmail_put(&qq,"\015",1); |
|
147 } |
|
148 if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq); |
|
149 qmail_put(&qq,&ch,1); |
|
150 } |
|
151 else { |
|
152 if (databytes) |
|
153 if (len > databytes) { |
|
154 bytestooverflow = 0; |
|
155 qmail_fail(&qq); |
|
156 } |
|
157 while (len > 0) { /* XXX: could speed this up, obviously */ |
|
158 substdio_get(&ssin,&ch,1); |
|
159 --len; |
|
160 qmail_put(&qq,&ch,1); |
|
161 } |
|
162 } |
|
163 getcomma(); |
|
164 |
|
165 len = getlen(); |
|
166 |
|
167 if (len >= 1000) { |
|
168 buf[0] = 0; |
|
169 flagsenderok = 0; |
|
170 for (i = 0;i < len;++i) |
|
171 substdio_get(&ssin,&ch,1); |
|
172 } |
|
173 else { |
|
174 for (i = 0;i < len;++i) { |
|
175 substdio_get(&ssin,buf + i,1); |
|
176 if (!buf[i]) flagsenderok = 0; |
|
177 } |
|
178 buf[len] = 0; |
|
179 } |
|
180 getcomma(); |
|
181 |
|
182 flagbother = 0; |
|
183 qmail_from(&qq,buf); |
|
184 if (!flagsenderok) qmail_fail(&qq); |
|
185 |
|
186 biglen = getlen(); |
|
187 while (biglen > 0) { |
|
188 if (!stralloc_append(&failure,"")) resources(); |
|
189 |
|
190 len = 0; |
|
191 for (;;) { |
|
192 if (!biglen) badproto(); |
|
193 substdio_get(&ssin,&ch,1); |
|
194 --biglen; |
|
195 if (ch == ':') break; |
|
196 if (len > 200000000) resources(); |
|
197 len = 10 * len + (ch - '0'); |
|
198 } |
|
199 if (len >= biglen) badproto(); |
|
200 if (len + relayclientlen >= 1000) { |
|
201 failure.s[failure.len - 1] = 'L'; |
|
202 for (i = 0;i < len;++i) |
|
203 substdio_get(&ssin,&ch,1); |
|
204 } |
|
205 else { |
|
206 for (i = 0;i < len;++i) { |
|
207 substdio_get(&ssin,buf + i,1); |
|
208 if (!buf[i]) failure.s[failure.len - 1] = 'N'; |
|
209 } |
|
210 buf[len] = 0; |
|
211 |
|
212 if (relayclient) |
|
213 str_copy(buf + len,relayclient); |
|
214 else |
|
215 switch(rcpthosts(buf,len)) { |
|
216 case -1: resources(); |
|
217 case 0: failure.s[failure.len - 1] = 'D'; |
|
218 } |
|
219 |
|
220 if (!failure.s[failure.len - 1]) { |
|
221 qmail_to(&qq,buf); |
|
222 flagbother = 1; |
|
223 } |
|
224 } |
|
225 getcomma(); |
|
226 biglen -= (len + 1); |
|
227 } |
|
228 getcomma(); |
|
229 |
|
230 if (!flagbother) qmail_fail(&qq); |
|
231 result = qmail_close(&qq); |
|
232 if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)"; |
|
233 if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)"; |
|
234 |
|
235 if (*result) |
|
236 len = str_len(result); |
|
237 else { |
|
238 /* success! */ |
|
239 len = 0; |
|
240 len += fmt_str(buf2 + len,"Kok "); |
|
241 len += fmt_ulong(buf2 + len,(unsigned long) now()); |
|
242 len += fmt_str(buf2 + len," qp "); |
|
243 len += fmt_ulong(buf2 + len,qp); |
|
244 buf2[len] = 0; |
|
245 result = buf2; |
|
246 } |
|
247 |
|
248 len = fmt_ulong(buf,len); |
|
249 buf[len++] = ':'; |
|
250 len += fmt_str(buf + len,result); |
|
251 buf[len++] = ','; |
|
252 |
|
253 for (i = 0;i < failure.len;++i) |
|
254 switch(failure.s[i]) { |
|
255 case 0: |
|
256 substdio_put(&ssout,buf,len); |
|
257 break; |
|
258 case 'D': |
|
259 substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),"); |
|
260 break; |
|
261 default: |
|
262 substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),"); |
|
263 break; |
|
264 } |
|
265 |
|
266 /* ssout will be flushed when we read from the network again */ |
|
267 } |
|
268 } |