debian/rules: Use `git' potty wrapper.
[qmail] / qmail-qmtpd.c
CommitLineData
2117e02e
MW
1#include "stralloc.h"
2#include "substdio.h"
2117e02e
MW
3#include "qmail.h"
4#include "now.h"
5#include "str.h"
6#include "fmt.h"
7#include "env.h"
8#include "sig.h"
212b6f5d 9#include "rcpthosts.h"
2117e02e 10#include "auto_qmail.h"
2117e02e
MW
11#include "readwrite.h"
12#include "control.h"
2117e02e
MW
13#include "received.h"
14
2117e02e
MW
15void badproto() { _exit(100); }
16void resources() { _exit(111); }
2117e02e 17
212b6f5d 18int safewrite(fd,buf,len) int fd; char *buf; int len;
2117e02e 19{
212b6f5d
MW
20 int r;
21 r = write(fd,buf,len);
22 if (r <= 0) _exit(0);
23 return r;
24}
25
26char ssoutbuf[256];
27substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
2117e02e 28
212b6f5d
MW
29int 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
38char ssinbuf[512];
39substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
40
41unsigned 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');
2117e02e
MW
50 }
51}
52
53void getcomma()
54{
212b6f5d
MW
55 char ch;
56 substdio_get(&ssin,&ch,1);
57 if (ch != ',') badproto();
2117e02e
MW
58}
59
212b6f5d
MW
60unsigned int databytes = 0;
61unsigned int bytestooverflow = 0;
62struct qmail qq;
63
2117e02e
MW
64char buf[1000];
65char buf2[100];
66
67char *remotehost;
68char *remoteinfo;
69char *remoteip;
70char *local;
71
72stralloc failure = {0};
73
2117e02e
MW
74char *relayclient;
75int relayclientlen;
76
2117e02e
MW
77main()
78{
212b6f5d
MW
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);
2117e02e 147 }
212b6f5d
MW
148 if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq);
149 qmail_put(&qq,&ch,1);
2117e02e 150 }
212b6f5d
MW
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);
2117e02e 161 }
2117e02e 162 }
212b6f5d
MW
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;
2117e02e 177 }
212b6f5d 178 buf[len] = 0;
2117e02e 179 }
212b6f5d
MW
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');
2117e02e 198 }
212b6f5d
MW
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);
2117e02e 204 }
212b6f5d
MW
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;
2117e02e 223 }
2117e02e 224 }
212b6f5d
MW
225 getcomma();
226 biglen -= (len + 1);
2117e02e 227 }
212b6f5d
MW
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;
2117e02e 246 }
212b6f5d
MW
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;
2117e02e 264 }
212b6f5d
MW
265
266 /* ssout will be flushed when we read from the network again */
2117e02e
MW
267 }
268}