mess822x 1.23
mess822x
Loading...
Searching...
No Matches
ofmipd.c
Go to the documentation of this file.
1#include <unistd.h>
2#include "commands.h"
3#include "sig.h"
4#include "auto_qmail.h"
5#include "qmail.h"
6#include "readwrite.h"
7#include "timeout.h"
8#include "stralloc.h"
9#include "buffer.h"
10#include "config.h"
11#include "env.h"
12#include "exit.h"
13#include "error.h"
14#include "str.h"
15#include "mess822.h"
16#include "tai.h"
17#include "caltime.h"
18#include "cdbread.h"
19#include "open.h"
20#include "getln.h"
21#include "byte.h"
22#include "leapsecs.h"
23#include "rwhconfig.h"
24#include "rewritehost.h"
25#include "alloc.h"
26
27int timeout = 1200;
28
29ssize_t safewrite(int fd,char *buf,int len)
30{
31 int r;
32 r = timeoutwrite(timeout,fd,buf,len);
33 if (r <= 0) _exit(1);
34 return r;
35}
36
37char outbuf[512];
38buffer bo = BUFFER_INIT(safewrite,1,outbuf,sizeof(outbuf));
39
40static void flush() { buffer_flush(&bo); }
41static void out(char *s) { buffer_puts(&bo,s); }
42
43static void die_read() { _exit(1); }
44static void nomem() { out("451 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
45static void die_config() { out("451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1); }
46static void smtp_quit() { out("221 ofmipd.local\r\n"); flush(); _exit(0); }
47static void smtp_help() { out("214 s/qmail home page: https://fehcom.de/sqmail/sqmail.html\r\n"); }
48static void smtp_noop() { out("250 ok\r\n"); }
49static void smtp_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
50static void smtp_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
51static void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
52static void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
53static void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
54static void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
55static void err_cdb() { out("451 unable to read cdb (#4.3.0)\r\n"); }
56
58stralloc idappend = {0};
59
60stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
61stralloc rwaddr = {0};
62
63static int addrparse(char *arg)
64{
65 int i;
66 char ch;
67 char terminator;
68 int flagesc;
69 int flagquoted;
70
71 terminator = '>';
72 i = str_chr(arg,'<');
73 if (arg[i])
74 arg += i + 1;
75 else { /* partner should go read rfc 821 */
76 terminator = ' ';
77 arg += str_chr(arg,':');
78 if (*arg == ':') ++arg;
79 while (*arg == ' ') ++arg;
80 }
81
82 if (*arg == '@') while (*arg) if (*arg++ == ':') break;
83
84 if (!stralloc_copys(&addr,"")) nomem();
85 flagesc = 0;
86 flagquoted = 0;
87 for (i = 0; (ch = arg[i]); ++i) { /* copy arg to addr, stripping quotes */
88 if (flagesc) {
89 if (!stralloc_append(&addr,&ch)) nomem();
90 flagesc = 0;
91 }
92 else {
93 if (!flagquoted && (ch == terminator)) break;
94 switch(ch) {
95 case '\\': flagesc = 1; break;
96 case '"': flagquoted = !flagquoted; break;
97 default: if (!stralloc_append(&addr,&ch)) nomem();
98 }
99 }
100 }
101
102 if (!rewritehost_addr(&rwaddr,addr.s,addr.len,config_data(&rewrite))) nomem();
103
104 return rwaddr.len < 900;
105}
106
107static char *fncdb;
108static int fdcdb;
109stralloc cdbresult = {0};
110static struct cdb cdb;
111
112int seenmail = 0;
113char *name; /* defined if seenmail; points into cdbresult */
114
115stralloc mailfrom = {0};
116stralloc rcptto = {0};
117
118static void smtp_helo(char *arg)
119{
120 seenmail = 0;
121 out("250 ofmipd.local\r\n");
122}
123static void smtp_ehlo(char *arg)
124{
125 seenmail = 0;
126 out("250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
127}
128static void smtp_rset()
129{
130 seenmail = 0;
131 out("250 flushed\r\n");
132}
133static void smtp_mail(char *arg)
134{
135 char *data;
136 unsigned int datalen;
137
138 if (!addrparse(arg)) { err_syntax(); return; }
139
140 name = 0;
141 if (fncdb) {
142 uint32 dlen = 0;
143 int r;
144
145 cdb_init(&cdb,fdcdb);
146 r = cdb_find(&cdb,rwaddr.s,rwaddr.len);
147 if (r == -1) { err_cdb(); return; }
148 if (r) {
149 datalen = cdb_datalen(&cdb);
150 data = alloc(datalen);
151 if (!data || !datalen) { err_cdb(); return; }
152 if (!stralloc_ready(&cdbresult,(unsigned int) dlen)) nomem();
153 cdbresult.len = dlen;
154 name = cdbresult.s;
155 if (cdb_read(&cdb,name,cdbresult.len,cdb_datapos(&cdb)) == -1) { err_cdb(); return; }
156 r = byte_chr(name,cdbresult.len,'\0');
157 if (r == cdbresult.len) { err_cdb(); return; }
158 if (!stralloc_copyb(&rwaddr,cdbresult.s + r + 1,cdbresult.len - r - 1)) nomem();
159 }
160 }
161
162 if (!stralloc_copy(&mailfrom,&rwaddr)) nomem();
163 if (!stralloc_0(&mailfrom)) nomem();
164 if (!stralloc_copys(&rcptto,"")) nomem();
165 seenmail = 1;
166 out("250 ok\r\n");
167}
168static void smtp_rcpt(char *arg)
169{
170 if (!seenmail) { err_wantmail(); return; }
171 if (!addrparse(arg)) { err_syntax(); return; }
172 if (!stralloc_0(&rwaddr)) nomem();
173 if (!stralloc_cats(&rcptto,"T")) nomem();
174 if (!stralloc_cats(&rcptto,rwaddr.s)) nomem();
175 if (!stralloc_0(&rcptto)) nomem();
176 out("250 ok\r\n");
177}
178
179struct qmail qqt;
180static void put(buf,len) char *buf; int len; { qmail_put(&qqt,buf,len); }
181static void spit(buf) char *buf; { qmail_puts(&qqt,buf); }
182
183stralloc tmp = {0};
184stralloc tmp2 = {0};
185
186static void rewritelist(stralloc *list)
187{
188 if (!rewritehost_list(&tmp,list->s,list->len,config_data(&rewrite))) nomem();
189 if (!stralloc_copy(list,&tmp)) nomem();
190}
191
192static void putlist(char *name,stralloc *list)
193{
194 if (!list->len) return;
195 if (!mess822_quotelist(&tmp,list)) nomem();
196 if (!mess822_fold(&tmp2,&tmp,name,78)) nomem();
197 put(tmp2.s,tmp2.len);
198}
199
201stralloc datastamp = {0};
202
204stralloc to = {0};
205stralloc cc = {0};
206stralloc nrudt = {0};
207stralloc from = {0};
208stralloc headersender = {0};
209stralloc replyto = {0};
210stralloc mailreplyto = {0};
211stralloc followupto = {0};
212
213stralloc msgid = {0};
214stralloc top = {0};
215stralloc bottom = {0};
216
219 { "date", 0, 0, 0, 0, &date, 0 }
220, { "to", 0, 0, 0, &to, 0, 0 }
221, { "cc", 0, 0, 0, &cc, 0, 0 }
222, { "notice-requested-upon-delivery-to", 0, 0, 0, &nrudt, 0, 0 }
223, { "from", 0, 0, 0, &from, 0, 0 }
224, { "sender", 0, 0, 0, &headersender, 0, 0 }
225, { "reply-to", 0, 0, 0, &replyto, 0, 0 }
226, { "mail-reply-to", 0, 0, 0, &mailreplyto, 0, 0 }
227, { "mail-followup-to", 0, 0, 0, &followupto, 0, 0 }
228, { "message-id", 0, &msgid, 0, 0, 0, 0 }
229, { "received", 0, &top, 0, 0, 0, 0 }
230, { "delivered-to", 0, &top, 0, 0, 0, 0 }
231, { "errors-to", 0, &top, 0, 0, 0, 0 }
232, { "return-receipt-to", 0, &top, 0, 0, 0, 0 }
233, { "resent-sender", 0, &top, 0, 0, 0, 0 }
234, { "resent-from", 0, &top, 0, 0, 0, 0 }
235, { "resent-reply-to", 0, &top, 0, 0, 0, 0 }
236, { "resent-to", 0, &top, 0, 0, 0, 0 }
237, { "resent-cc", 0, &top, 0, 0, 0, 0 }
238, { "resent-bcc", 0, &top, 0, 0, 0, 0 }
239, { "resent-date", 0, &top, 0, 0, 0, 0 }
240, { "resent-message-id", 0, &top, 0, 0, 0, 0 }
241, { "bcc", 0, 0, 0, 0, 0, 0 }
242, { "return-path", 0, 0, 0, 0, 0, 0 }
243, { "apparently-to", 0, 0, 0, 0, 0, 0 }
244, { "content-length", 0, 0, 0, 0, 0, 0 }
245, { 0, 0, &bottom, 0, 0, 0, 0 }
246} ;
247
248static void finishheader()
249{
250 if (!mess822_end(&h)) nomem();
251
252 if (name) from.len = 0;
253
254 rewritelist(&to);
255 rewritelist(&cc);
256 rewritelist(&nrudt);
257 rewritelist(&from);
258 rewritelist(&headersender);
259 rewritelist(&replyto);
260 rewritelist(&mailreplyto);
261 rewritelist(&followupto);
262
263 put(top.s,top.len);
264
265 if (!date.known) date = datastart;
266 if (!mess822_date(&tmp,&date)) nomem();
267 spit("Date: ");
268 put(tmp.s,tmp.len);
269 spit("\n");
270
271 if (!msgid.len) {
272 static int idcounter = 0;
273
274 if (!stralloc_copys(&msgid,"Message-ID: <")) nomem();
275 if (!stralloc_catlong(&msgid,date.ct.date.year)) nomem();
276 if (!stralloc_catint0(&msgid,date.ct.date.month,2)) nomem();
277 if (!stralloc_catint0(&msgid,date.ct.date.day,2)) nomem();
278 if (!stralloc_catint0(&msgid,date.ct.hour,2)) nomem();
279 if (!stralloc_catint0(&msgid,date.ct.minute,2)) nomem();
280 if (!stralloc_catint0(&msgid,date.ct.second,2)) nomem();
281 if (!stralloc_cats(&msgid,".")) nomem();
282 if (!stralloc_catint(&msgid,++idcounter)) nomem();
283 if (!stralloc_cat(&msgid,&idappend)) nomem();
284 if (!stralloc_cats(&msgid,">\n")) nomem();
285 }
286 put(msgid.s,msgid.len);
287
288 putlist("From: ",&from);
289 if (!from.len) {
290 spit("From: ");
291 if (!mess822_quote(&tmp,mailfrom.s,name)) nomem();
292 put(tmp.s,tmp.len);
293 spit("\n");
294 }
295
296 putlist("Sender: ",&headersender);
297 putlist("Reply-To: ",&replyto);
298 putlist("Mail-Reply-To: ",&mailreplyto);
299 putlist("Mail-Followup-To: ",&followupto);
300 if (!to.len && !cc.len)
301 spit("Cc: recipient list not shown: ;\n");
302 putlist("To: ",&to);
303 putlist("Cc: ",&cc);
304 putlist("Notice-Requested-Upon-Delivery-To: ",&nrudt);
305
306 put(bottom.s,bottom.len);
307}
308
309static ssize_t saferead(int fd,char *buf,int len)
310{
311 int r;
312 flush();
313 r = timeoutread(timeout,fd,buf,len);
314 if (r <= 0) die_read();
315 return r;
316}
317
318char inbuf[1024];
319buffer bin = BUFFER_INIT(saferead,0,inbuf,sizeof(inbuf));
320
321stralloc line = {0};
323
324static void blast()
325{
326 int flagheader = 1;
327 int i;
328
329 if (!mess822_begin(&h,a)) nomem();
330
331 for (;;) {
332 if (getln(&bin,&line,&match,'\n') == -1) die_read();
333 if (!match) die_read();
334
335 --line.len;
336 if (line.len && (line.s[line.len - 1] == '\r')) --line.len;
337 if (line.len && (line.s[0] == '.')) {
338 --line.len;
339 if (!line.len) break;
340 for (i = 0; i < line.len; ++i) line.s[i] = line.s[i + 1];
341 }
342 line.s[line.len++] = '\n';
343
344 if (flagheader)
345 if (!mess822_ok(&line)) {
346 finishheader();
347 flagheader = 0;
348 if (line.len > 1) put("\n",1);
349 }
350 if (!flagheader)
351 put(line.s,line.len);
352 else
353 if (!mess822_line(&h,&line)) nomem();
354 }
355
356 if (flagheader)
357 finishheader();
358}
359
360stralloc received = {0};
361
362static void smtp_data() {
363 struct tai now;
364 char *qqx;
365
366 tai_now(&now);
367 caltime_utc(&datastart.ct,&now,(int *) 0,(int *) 0);
368 datastart.known = 1;
369 if (!mess822_date(&datastamp,&datastart)) nomem();
370
371 if (!seenmail) { err_wantmail(); return; }
372 if (!rcptto.len) { err_wantrcpt(); return; }
373 seenmail = 0;
374 if (qmail_open(&qqt) == -1) { err_qqt(); return; }
375 out("354 go ahead\r\n");
376
379 qmail_puts(&qqt,"\n");
380 blast();
382 qmail_put(&qqt,rcptto.s,rcptto.len);
383
384 qqx = qmail_close(&qqt);
385 if (!*qqx) { out("250 ok\r\n"); return; }
386 if (*qqx == 'D') out("554 "); else out("451 ");
387 out(qqx + 1);
388 out("\r\n");
389}
390
391static void safecats(stralloc *out,char *in)
392{
393 char ch;
394
395 while ((ch = *in++)) {
396 if (ch < 33) ch = '?';
397 if (ch > 126) ch = '?';
398 if (ch == '(') ch = '?';
399 if (ch == ')') ch = '?';
400 if (ch == '@') ch = '?';
401 if (ch == '\\') ch = '?';
402 if (!stralloc_append(out,&ch)) nomem();
403 }
404}
405
406static void received_init()
407{
408 char *x;
409
410 if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem();
411 x = env_get("TCPREMOTEINFO");
412 if (x) {
413 safecats(&received,x);
414 if (!stralloc_append(&received,"@")) nomem();
415 }
416 x = env_get("TCPREMOTEIP");
417 if (!x) x = "unknown";
418 safecats(&received,x);
419 if (!stralloc_cats(&received,"); ")) nomem();
420}
421
423 { "rcpt", smtp_rcpt, 0 }
424, { "mail", smtp_mail, 0 }
425, { "data", smtp_data, flush }
426, { "quit", smtp_quit, flush }
427, { "helo", smtp_helo, flush }
428, { "ehlo", smtp_ehlo, flush }
429, { "rset", smtp_rset, 0 }
430, { "help", smtp_help, flush }
431, { "noop", smtp_noop, flush }
432, { "vrfy", smtp_vrfy, flush }
433, { 0, smtp_unimpl, flush }
434} ;
435
436int main(int argc,char **argv)
437{
438 sig_pipeignore();
439
440 fncdb = argv[1];
441 if (fncdb) {
442 fdcdb = open_read(fncdb);
443 if (fdcdb == -1) die_config();
444 }
445
446 received_init();
447 if (leapsecs_init() == -1) die_config();
448 if (chdir(auto_qmail) == -1) die_config();
449 if (rwhconfig(&rewrite,&idappend) == -1) die_config();
450
451 out("220 ofmipd.local ESMTP\r\n");
453 nomem();
454}
stralloc data
Definition: ofmipname.c:35
int main()
Definition: 822print.c:351
stralloc out
Definition: b64decode.c:12
stralloc tmp2
Definition: ofmipd.c:184
stralloc rcptto
Definition: ofmipd.c:116
mess822_action a[]
Definition: ofmipd.c:218
char inbuf[1024]
Definition: ofmipd.c:318
stralloc headersender
Definition: ofmipd.c:208
int timeout
Definition: ofmipd.c:27
buffer bin
Definition: ofmipd.c:319
stralloc bottom
Definition: ofmipd.c:215
stralloc nrudt
Definition: ofmipd.c:206
char * name
Definition: ofmipd.c:113
stralloc msgid
Definition: ofmipd.c:213
stralloc replyto
Definition: ofmipd.c:209
stralloc idappend
Definition: ofmipd.c:58
struct qmail qqt
Definition: ofmipd.c:179
stralloc rwaddr
Definition: ofmipd.c:61
stralloc mailfrom
Definition: ofmipd.c:115
mess822_header h
Definition: ofmipd.c:217
stralloc followupto
Definition: ofmipd.c:211
mess822_time date
Definition: ofmipd.c:203
char outbuf[512]
Definition: ofmipd.c:37
stralloc from
Definition: ofmipd.c:207
stralloc tmp
Definition: ofmipd.c:183
stralloc datastamp
Definition: ofmipd.c:201
config_str rewrite
Definition: ofmipd.c:57
stralloc line
Definition: ofmipd.c:321
struct commands smtpcommands[]
Definition: ofmipd.c:422
int seenmail
Definition: ofmipd.c:112
stralloc cdbresult
Definition: ofmipd.c:109
ssize_t safewrite(int fd, char *buf, int len)
Definition: ofmipd.c:29
stralloc received
Definition: ofmipd.c:360
int match
Definition: ofmipd.c:322
stralloc cc
Definition: ofmipd.c:205
buffer bo
Definition: ofmipd.c:38
stralloc addr
Definition: ofmipd.c:60
stralloc top
Definition: ofmipd.c:214
mess822_time datastart
Definition: ofmipd.c:200
stralloc to
Definition: ofmipd.c:204
stralloc mailreplyto
Definition: ofmipd.c:210
#define CONFIG_STR
Definition: config.h:11
#define config_data(c)
Definition: config.h:14
int rewritehost_list(stralloc *, char *, unsigned int, stralloc *)
Definition: rewritehost.c:76
int rewritehost_addr(stralloc *, char *, unsigned int, stralloc *)
Definition: rewritehost.c:70
int leapsecs_init(void)
Definition: leapsecs_init.c:5
char auto_qmail[]
int mess822_quote(stralloc *, char *, char *)
int mess822_line(mess822_header *, stralloc *)
Definition: mess822_line.c:107
int mess822_end(mess822_header *)
Definition: mess822_line.c:26
int mess822_ok(stralloc *)
Definition: mess822_ok.c:4
#define MESS822_HEADER
Definition: mess822.h:48
int mess822_fold(stralloc *, stralloc *, char *, int)
Definition: mess822_fold.c:3
int mess822_date(stralloc *, mess822_time *)
Definition: mess822_date.c:8
int mess822_begin(mess822_header *, mess822_action *)
Definition: mess822_line.c:5
int mess822_quotelist(stralloc *, stralloc *)
int rwhconfig(config_str *, stralloc *)
Definition: rwhconfig.c:25
void qmail_from(struct qmail *, char *)
Definition: qmail.c:73
void qmail_put(struct qmail *, char *, int)
Definition: qmail.c:63
char * qmail_close(struct qmail *)
Definition: qmail.c:90
void qmail_puts(struct qmail *, char *)
Definition: qmail.c:68
int qmail_open(struct qmail *)
Definition: qmail.c:21
void caltime_utc(struct caltime *ct, struct tai *t, int *pwday, int *pyday)
Definition: caltime_utc.c:8
int day
Definition: caldate.h:7
long year
Definition: caldate.h:5
int month
Definition: caldate.h:6
int hour
Definition: caltime.h:9
struct caldate date
Definition: caltime.h:8
int minute
Definition: caltime.h:10
int second
Definition: caltime.h:11
void(* flush)()
Definition: commands.h:7
int known
Definition: mess822.h:9
struct caltime ct
Definition: mess822.h:8
Definition: qmail.h:6
char buf[1024]
Definition: qmail.h:12