nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

nmail-smtpd.c (18597B)


      1 #include "sig.h"
      2 #include "ndelay.h"
      3 #include "readwrite.h"
      4 #include "stralloc.h"
      5 #include "substdio.h"
      6 #include "alloc.h"
      7 #include "auto_qmail.h"
      8 #include "control.h"
      9 #include "datetime.h"
     10 #include "received.h"
     11 #include "constmap.h"
     12 #include "error.h"
     13 #include "ipme.h"
     14 #include "ip.h"
     15 #include "qmail.h"
     16 #include "str.h"
     17 #include "fmt.h"
     18 #include "scan.h"
     19 #include "byte.h"
     20 #include "case.h"
     21 #include "env.h"
     22 #include "now.h"
     23 #include "exit.h"
     24 #include "rcpthosts.h"
     25 #include "realrcptto.h"
     26 #include "timeoutread.h"
     27 #include "timeoutwrite.h"
     28 #include "commands.h"
     29 #include "dns.h"
     30 #include "fd.h"
     31 
     32 #define MAXHOPS 100
     33 unsigned int databytes = 0;
     34 int timeout = 1200;
     35 
     36 GEN_SAFE_TIMEOUTWRITE(safewrite, timeout, fd, _exit(10))
     37 
     38 char ssoutbuf[512];
     39 substdio ssout = SUBSTDIO_FDBUF(safewrite, 1, ssoutbuf, sizeof(ssoutbuf));
     40 
     41 void flush() {
     42 	substdio_flush(&ssout);
     43 }
     44 void out(s)
     45 char *s; {
     46 	substdio_puts(&ssout, s);
     47 }
     48 
     49 void die_read() {
     50 	_exit(1);
     51 }
     52 void die_alarm() {
     53 	out("451 4.4.2 Timeout\r\n");
     54 	flush();
     55 	_exit(2);
     56 }
     57 void die_nomem() {
     58 	out("421 4.3.0 Out of memory\r\n");
     59 	flush();
     60 	_exit(3);
     61 }
     62 void die_control() {
     63 	out("421 4.3.0 Unable to read controls\r\n");
     64 	flush();
     65 	_exit(4);
     66 }
     67 void die_ipme() {
     68 	out("421 4.3.0 Unable to figure out my IP addresses\r\n");
     69 	flush();
     70 	_exit(5);
     71 }
     72 void die_ip6me() {
     73 	out("421 4.3.0 Unable to figure out my IPv6 addresses\r\n");
     74 	flush();
     75 	_exit(6);
     76 }
     77 void straynewline() {
     78 	out("451-You sent a stray newline. See https://cr.yp.to/docs/smtplf.html.\r\n451 This error should be going away soon.");
     79 	flush();
     80 	_exit(1);
     81 }
     82 
     83 char ssebuf[1024];
     84 substdio sse = SUBSTDIO_FDBUF(write, 2, ssebuf, sizeof(ssebuf));
     85 void err(char *s){
     86 	substdio_putsflush(&sse, s);
     87 }
     88 
     89 void err_bmf() {
     90 	out("553 5.7.1 Sorry, your envelope sender is in my badmailfrom list.\r\n");
     91 	flush();
     92 }
     93 void err_nogateway() {
     94 	out("553 5.7.1 Sorry, that domain isn't in my list of allowed rcpthosts\r\n");
     95 	flush();
     96 }
     97 void err_unimpl(char *arg){
     98 	out("502 5.5.1 Unimplemented\r\n");
     99 	flush();
    100 }
    101 void err_syntax() {
    102 	out("555 5.5.4 Syntax error\r\n");
    103 	flush();
    104 }
    105 void die_wtf(int d, char *arg){
    106 	out("421 4.3.2 inconsistent state: ");
    107 	out(arg);
    108 	out(" - shutting down!\r\n");
    109 	flush();
    110 	err("421 4.3.2 inconsistent state: ");
    111 	err(arg);
    112 	err(" - shutting down!\r\n");
    113 	_exit(d);
    114 }
    115 void err_wantmail() {
    116 	out("503 5.5.1 You must execute MAIL first\r\n");
    117 	flush();
    118 }
    119 void err_wantrcpt() {
    120 	out("503 5.5.1 You must execute RCPT first\r\n");
    121 	flush();
    122 }
    123 void err_notlshere() {
    124 	out("454 4.7.6 STARTTLS is not available at this site.\r\n");
    125 	flush();
    126 }
    127 void err_alreadytlshere() {
    128 	out("454 5.7.6 STARTTLS is already active on this connection.\r\n");
    129 	flush();
    130 }
    131 void die_cdb() {
    132 	out("421 4.3.0 Unable to read cdb user database\r\n");
    133 	flush();
    134 	_exit(7);
    135 }
    136 void die_sys() {
    137 	out("421 4.3.0 Unable to read system user database\r\n");
    138 	flush();
    139 	_exit(8);
    140 }
    141 void die_addresses() {
    142 	out("501 5.3.0 That's too many addresses!\r\n");
    143 	flush();
    144 	_exit(11);
    145 }
    146 void err_addresses() {
    147 	out("501 5.3.0 That's too many addresses!\r\n");
    148 	flush();
    149 }
    150 void err_noop(char *arg){
    151 	out("250 As requested, no operation performed.\r\n");
    152 	flush();
    153 }
    154 void err_vrfy(char *arg){
    155 	out("252 Send something and we'll give it a shot.\r\n");
    156 	flush();
    157 }
    158 void err_qqt() {
    159 	out("451 4.3.0 Temporarily unavailable: cannot inject message into queue.\r\n");
    160 	flush();
    161 }
    162 void
    163 die_dnsbl(char *arg)
    164 {
    165 	out("421 Your IP is currently blacklisted. If available at this site, auth first. (");
    166 	out(arg);
    167 	out(")\r\n");
    168 	flush();
    169 	_exit(9);
    170 }
    171 
    172 stralloc greeting = {0};
    173 int starttlsready = 0, sslctlfd = -1, sslrfd = -1, sslwfd = -1, isstarttls = 0, isesmtp = 0;
    174 
    175 void
    176 smtp_greet(code)
    177 	char *code;
    178 {
    179 	substdio_puts(&ssout, code);
    180 	substdio_put(&ssout, greeting.s, greeting.len);
    181 }
    182 void
    183 smtp_help(char *arg)
    184 {
    185 	out("214-NightmareMail home page: <https://umbrellix.net./software/nightmaremail/index.html>\r\n");
    186 	out("214-NightmareMail is based on notqmail. notqmail home page: <https://notqmail.org>\r\n");
    187 	out("214-We accept the following commands: HELO, EHLO, (SEND/SOML/SAML/MAIL) FROM:<, RCPT TO:<, DATA, RSET");
    188 	if (starttlsready)
    189 		out(", STARTTLS");
    190 	out("\r\n");
    191 	out("214 Note that SMTP is not a user interface. It should only be used thus to verify correct operation of the mail system.\r\n");
    192 }
    193 void
    194 smtp_quit(char *arg)
    195 {
    196 	smtp_greet("221 ");
    197 	out("\r\n");
    198 	flush();
    199 	_exit(0);
    200 }
    201 
    202 char *remoteip;
    203 char *remotehost;
    204 char *remoteinfo;
    205 char *local;
    206 char *relayclient;
    207 char *dnsblskip;
    208 
    209 stralloc helohost = {0};
    210 char *fakehelo;			/* pointer into helohost, or 0 */
    211 
    212 void
    213 dohelo(char *arg)
    214 {
    215 	if (!stralloc_copys(&helohost, arg))
    216 		die_nomem();
    217 	if (!stralloc_0(&helohost))
    218 		die_nomem();
    219 	fakehelo = case_diffs(remotehost, helohost.s) ? helohost.s : 0;
    220 }
    221 
    222 int liphostok = 0;
    223 stralloc liphost = {0};
    224 int bmfok = 0;
    225 stralloc bmf = {0};
    226 struct constmap mapbmf;
    227 
    228 void
    229 setuptls()
    230 {
    231 	char *x;
    232 	unsigned long u;
    233 
    234 	x = env_get("SSLCTLFD");
    235 	if (x) {
    236 		scan_ulong(x, &u);
    237 		sslctlfd = u;
    238 	} else
    239 		return;
    240 	x = env_get("SSLREADFD");
    241 	if (x) {
    242 		scan_ulong(x, &u);
    243 		sslrfd = u;
    244 	} else
    245 		return;
    246 	x = env_get("SSLWRITEFD");
    247 	if (x) {
    248 		scan_ulong(x, &u);
    249 		sslwfd = u;
    250 	} else
    251 		return;
    252 	ndelay_on(sslctlfd);
    253 	/* ndelay_on(sslrfd); */
    254 	/* ndelay_on(sslwfd); */
    255 	starttlsready = 1;	/* when reached, then we can do starttls */
    256 	return;
    257 }
    258 
    259 int seenmail = 0;
    260 int flagbarf;			/* defined when seenmail */
    261 stralloc mailfrom = {0};
    262 stralloc rcptto = {0};
    263 int rcpttos = 0, maxrcpttos = 5;
    264 
    265 void
    266 setup()
    267 {
    268 	char *x;
    269 	unsigned long u;
    270 
    271 	if (control_init() == -1)
    272 		die_control();
    273 	if (control_rldef(&greeting, "control/smtpgreeting", 1, NULL) != 1)
    274 		die_control();
    275 	liphostok = control_rldef(&liphost, "control/localiphost", 1, NULL);
    276 	if (liphostok == -1)
    277 		die_control();
    278 	if (control_readint(&timeout, "control/timeoutsmtpd") == -1)
    279 		die_control();
    280 	if (timeout <= 0)
    281 		timeout = 1;
    282 
    283 	if (rcpthosts_init() == -1)
    284 		die_control();
    285 
    286 	bmfok = control_readfile(&bmf, "control/badmailfrom", 0);
    287 	if (bmfok == -1)
    288 		die_control();
    289 	if (bmfok)
    290 		if (!constmap_init(&mapbmf, bmf.s, bmf.len, 0))
    291 			die_nomem();
    292 
    293 	/* manually merged from prj's realrcptto patch */
    294 	realrcptto_init();
    295 
    296 	if (control_readint(&databytes, "control/databytes") == -1)
    297 		die_control();
    298 	if (control_readint(&maxrcpttos, "control/maxrcpts") == -1)
    299 		maxrcpttos = 128;	/* proceed with this limit */
    300 	x = env_get("DATABYTES");
    301 	if (x) {
    302 		scan_ulong(x, &u);
    303 		databytes = u;
    304 	}
    305 	if (!(databytes + 1))
    306 		--databytes;
    307 	setuptls();
    308 
    309 	remoteip = env_get("TCPREMOTEIP");
    310 	if (!remoteip)
    311 		remoteip = "unknown";
    312 	local = env_get("TCPLOCALHOST");
    313 	if (!local)
    314 		local = env_get("TCPLOCALIP");
    315 	if (!local)
    316 		local = "unknown";
    317 	remotehost = env_get("TCPREMOTEHOST");
    318 	if (!remotehost)
    319 		remotehost = "unknown";
    320 	remoteinfo = env_get("TCPREMOTEINFO");
    321 	relayclient = env_get("RELAYCLIENT");
    322 	dnsblskip = env_get("DNSBLSKIP");
    323 	dohelo(remotehost);
    324 }
    325 
    326 extern void realrcptto_init();
    327 extern void realrcptto_start();
    328 extern int realrcptto();
    329 extern int realrcptto_deny();
    330 
    331 stralloc addr = {0};		/* will be 0-terminated, if addrparse returns 1 */
    332 
    333 int
    334 addrparse(char *arg)
    335 {
    336 	int i;
    337 	char ch;
    338 	char terminator;
    339 	struct ip_address ip;
    340 	int flagesc;
    341 	int flagquoted;
    342 
    343 	terminator = '>';
    344 	i = str_chr(arg, '<');
    345 	if (arg[i])
    346 		arg += i + 1;
    347 	else {			/* partner should go read rfc 821 */
    348 		terminator = ' ';
    349 		arg += str_chr(arg, ':');
    350 		if (*arg == ':')
    351 			++arg;
    352 		while (*arg == ' ')
    353 			++arg;
    354 	}
    355 
    356 	/* strip source route
    357 	 * query: should source route really be stripped? L */
    358 	if (*arg == '@')
    359 		while (*arg)
    360 			if (*arg++ == ':')
    361 				break;
    362 
    363 	if (!stralloc_copys(&addr, ""))
    364 		die_nomem();
    365 	flagesc = 0;
    366 	flagquoted = 0;
    367 	for (i = 0; (ch = arg[i]); ++i) {	/* copy arg to addr, stripping quotes */
    368 		if (flagesc) {
    369 			if (!stralloc_append(&addr, &ch))
    370 				die_nomem();
    371 			flagesc = 0;
    372 		} else {
    373 			if (!flagquoted && (ch == terminator))
    374 				break;
    375 			switch (ch) {
    376 			case '\\':
    377 				flagesc = 1;
    378 				break;
    379 			case '"':
    380 				flagquoted = !flagquoted;
    381 				break;
    382 			default:
    383 				if (!stralloc_append(&addr, &ch))
    384 					die_nomem();
    385 			}
    386 		}
    387 	}
    388 	/* could check for termination failure here, but why bother? */
    389 	if (!stralloc_append(&addr, ""))
    390 		die_nomem();
    391 
    392 	if (liphostok) {
    393 		i = byte_rchr(addr.s, addr.len, '@');
    394 		if (i < addr.len)	/* if not, partner should go read rfc 821 */
    395 			if (addr.s[i + 1] == '[')
    396 				if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1, &ip)])
    397 					if (ipme_is(&ip)) {
    398 						addr.len = i + 1;
    399 						if (!stralloc_cat(&addr, &liphost))
    400 							die_nomem();
    401 						if (!stralloc_0(&addr))
    402 							die_nomem();
    403 					}
    404 	}
    405 
    406 	if (addr.len > 900)
    407 		return 0;
    408 	return 1;
    409 }
    410 
    411 int
    412 bmfcheck()
    413 {
    414 	int j;
    415 	if (!bmfok)
    416 		return 0;
    417 	if (constmap(&mapbmf, addr.s, addr.len - 1))
    418 		return 1;
    419 	j = byte_rchr(addr.s, addr.len, '@');
    420 	if (j < addr.len)
    421 		if (constmap(&mapbmf, addr.s + j, addr.len - j - 1))
    422 			return 1;
    423 	return 0;
    424 }
    425 
    426 int
    427 addrallowed()
    428 {
    429 	int r;
    430 	r = rcpthosts(addr.s, str_len(addr.s));
    431 	if (r == -1)
    432 		die_control();
    433 	return r;
    434 }
    435 
    436 int flagdnsbl = 0;
    437 stralloc dnsblhost = {0};
    438 
    439 int
    440 dnsblcheck()
    441 {
    442 	char *ch;
    443 	static stralloc dnsblbyte = {
    444 		0
    445 	};
    446 	static stralloc dnsblrev = {
    447 		0
    448 	};
    449 	static ipalloc dnsblip = {
    450 		0
    451 	};
    452 	static ip6alloc dnsblip6 = {
    453 		0
    454 	};
    455 	static stralloc dnsbllist = {
    456 		0
    457 	};
    458 
    459 	ch = remoteip;
    460 	if (control_readfile(&dnsbllist, "control/dnsbllist", 0) != 1)
    461 		return 0;
    462 
    463 	if (!stralloc_copys(&dnsblrev, ""))
    464 		return 0;
    465 	for (;;) {
    466 		if (!stralloc_copys(&dnsblbyte, ""))
    467 			return 0;
    468 		while (ch[0] && (ch[0] != '.')) {
    469 			if (!stralloc_append(&dnsblbyte, ch))
    470 				return 0;
    471 			ch++;
    472 		}
    473 		if (!stralloc_append(&dnsblbyte, "."))
    474 			return 0;
    475 		if (!stralloc_cat(&dnsblbyte, &dnsblrev))
    476 			return 0;
    477 		if (!stralloc_copy(&dnsblrev, &dnsblbyte))
    478 			return 0;
    479 
    480 		if (!ch[0])
    481 			break;
    482 		ch++;
    483 	}
    484 
    485 	flagdnsbl = 1;
    486 	ch = dnsbllist.s;
    487 	while (ch < (dnsbllist.s + dnsbllist.len)) {
    488 		if (!stralloc_copy(&dnsblhost, &dnsblrev))
    489 			return 0;
    490 		if (!stralloc_cats(&dnsblhost, ch))
    491 			return 0;
    492 		if (!stralloc_0(&dnsblhost))
    493 			return 0;
    494 
    495 		if (!dns_ip(&dnsblip, &dnsblhost))
    496 			return 1;
    497 		while (*ch++);
    498 	}
    499 
    500 	return 0;
    501 }
    502 
    503 ssize_t
    504 saferead(int fd, void *buf, size_t len)
    505 {
    506 	ssize_t r;
    507 	r = timeoutread(timeout, fd, buf, len);
    508 	if (r == -1)
    509 		if (errno == error_timeout)
    510 			die_alarm();
    511 	if (r == 0 || r == -1)
    512 		die_read();
    513 	return r;
    514 }
    515 
    516 char ssinbuf[1024];
    517 substdio ssin = SUBSTDIO_FDBUF(saferead, 0, ssinbuf, sizeof(ssinbuf));
    518 
    519 
    520 void
    521 smtp_starttls(char *arg)
    522 {
    523 	char fdou[1920];	/* compare skarnet s-s-proxy: OUTSIZE 1920. Me thinks I cribbed too much. */
    524 	ssize_t hsread = 0, hsr = 0;
    525 	if (str_len(arg) != 0) {
    526 		err_syntax();
    527 		return;
    528 	}
    529 	if (!starttlsready) {
    530 		err_notlshere();
    531 		return;
    532 	}
    533 	if (timeoutwrite(1, sslctlfd, "Y", 1) != 1) {
    534 		die_wtf(errno, "could not cut over to TLS in one second");
    535 	}
    536 	out("220 2.7.0 Ready to start TLS\r\n");
    537 	substdio_flush(&ssout);
    538 	for (;;) {
    539 		hsread += (hsr = timeoutread(1, sslctlfd, fdou, 1920));
    540 		if (hsr < 0) {
    541 			if (errno != EAGAIN)
    542 				die_wtf(errno, "could not cut over to TLS in 1 second");
    543 		}
    544 		if (!hsr)
    545 			break;
    546 		isstarttls = 1;	/* just use the global variable (TODO: make TL when npthread) */
    547 	}
    548 	if (!isstarttls) {
    549 		_exit(10);
    550 	}
    551 	/* At this point, we are starttls. We must now cut sslwfd to fd 1 and sslrfd to fd 0. */
    552 	ssout.fd = sslwfd;
    553 	ssin.fd = sslrfd;
    554 	substdio_flush(&ssout);
    555 	substdio_flush(&sse);
    556 }
    557 void
    558 smtp_helo(char *arg)
    559 {
    560 	smtp_greet("250 ");
    561 	out("\r\n");
    562 	seenmail = 0;
    563 	dohelo(arg);
    564 }
    565 void
    566 smtp_ehlo(char *arg)
    567 {
    568 	isesmtp = 1;
    569 	smtp_greet("250-");
    570 	out("\r\n");
    571 	out("250-PIPELINING\r\n");
    572 	out("250-ENHANCEDSTATUSCODES\r\n");
    573 	/* TODO: add startTLS cutover support */
    574 	if (starttlsready && !isstarttls) {
    575 		out("250-8BITMIME\r\n");
    576 		out("250 STARTTLS\r\n");
    577 	} else
    578 		out("250 8BITMIME\r\n");
    579 	seenmail = 0;
    580 	dohelo(arg);
    581 }
    582 void
    583 smtp_rset(char *arg)
    584 {
    585 	seenmail = 0;
    586 	out("250 Envelope flushed\r\n");
    587 }
    588 void
    589 smtp_mail(char *arg)
    590 {
    591 	if (!addrparse(arg)) {
    592 		err_syntax();
    593 		return;
    594 	}
    595 	flagbarf = bmfcheck();
    596 	seenmail = 1;
    597 	if (!stralloc_copys(&rcptto, ""))
    598 		die_nomem();
    599 	if (!stralloc_copys(&mailfrom, addr.s))
    600 		die_nomem();
    601 	if (!stralloc_0(&mailfrom))
    602 		die_nomem();
    603 	realrcptto_start();
    604 	out("250 Go on...\r\n");
    605 }
    606 void
    607 smtp_rcpt(char *arg)
    608 {
    609 	if (!seenmail) {
    610 		err_wantmail();
    611 		return;
    612 	}
    613 	if (!addrparse(arg)) {
    614 		err_syntax();
    615 		return;
    616 	}
    617 	if (flagbarf) {
    618 		err_bmf();
    619 		return;
    620 	}
    621 	if (relayclient) {
    622 		--addr.len;
    623 		if (!stralloc_cats(&addr, relayclient))
    624 			die_nomem();
    625 		if (!stralloc_0(&addr))
    626 			die_nomem();
    627 	} else if (!addrallowed()) {
    628 		err_nogateway();
    629 		return;
    630 	}
    631 	if (rcpttos > maxrcpttos) {
    632 		err_addresses();
    633 		return;
    634 	}
    635 	if (!realrcptto(addr.s)) {
    636 		out("550 5.1.1 That user has elected not to receive emails.\r\n");
    637 		return;
    638 	}
    639 	if (!(relayclient || dnsblskip || flagdnsbl))
    640 		if (dnsblcheck())
    641 			die_dnsbl(dnsblhost.s);
    642 	if (!stralloc_cats(&rcptto, "T"))
    643 		die_nomem();
    644 	if (!stralloc_cats(&rcptto, addr.s))
    645 		die_nomem();
    646 	if (!stralloc_0(&rcptto))
    647 		die_nomem();
    648 	++rcpttos;
    649 	out("250 Go on...\r\n");
    650 }
    651 
    652 struct qmail qqt;
    653 unsigned int bytestooverflow = 0;
    654 
    655 void
    656 put(char *ch)
    657 {
    658 	if (bytestooverflow)
    659 		if (!--bytestooverflow)
    660 			qmail_fail(&qqt);
    661 	qmail_put(&qqt, ch, 1);
    662 }
    663 
    664 void
    665 blast(int *hops)
    666 {
    667 	char ch;
    668 	int state;
    669 	int flaginheader;
    670 	int pos;		/* number of bytes since most recent \n, if fih */
    671 	int flagmaybex;		/* 1 if this line might match RECEIVED, if fih */
    672 	int flagmaybey;		/* 1 if this line might match \r\n, if fih */
    673 	int flagmaybez;		/* 1 if this line might match DELIVERED, if fih */
    674 
    675 	state = 1;
    676 	*hops = 0;
    677 	flaginheader = 1;
    678 	pos = 0;
    679 	flagmaybex = flagmaybey = flagmaybez = 1;
    680 	for (;;) {
    681 		/* This isn't very optimized -- Amelia B */
    682 		substdio_get(&ssin, &ch, 1);
    683 		if (flaginheader) {
    684 			if (pos >= 0 && pos < 9) {	/* something about method and madness? bro literally just use strcmp it won't hurt you */
    685 				if (ch != "delivered"[pos])
    686 					if (ch != "DELIVERED"[pos])
    687 						flagmaybez = 0;
    688 				if (flagmaybez)
    689 					if (pos == 8)
    690 						++* hops;
    691 				if (pos < 8)
    692 					if (ch != "received"[pos])
    693 						if (ch != "RECEIVED"[pos])
    694 							flagmaybex = 0;
    695 				if (flagmaybex)
    696 					if (pos == 7)
    697 						++* hops;
    698 				if (pos < 2)
    699 					if (ch != "\r\n"[pos])
    700 						flagmaybey = 0;
    701 				if (flagmaybey)
    702 					if (pos == 1)
    703 						flaginheader = 0;
    704 				++pos;
    705 			}
    706 			if (ch == '\n') {
    707 				pos = 0;
    708 				flagmaybex = flagmaybey = flagmaybez = 1;
    709 			}
    710 		}
    711 		switch (state) {
    712 		case 0:
    713 			if (ch == '\n')
    714 				straynewline();
    715 			if (ch == '\r') {
    716 				state = 4;
    717 				continue;
    718 			}
    719 			break;
    720 		case 1:		/* \r\n */
    721 			if (ch == '\n')
    722 				straynewline();
    723 			if (ch == '.') {
    724 				state = 2;
    725 				continue;
    726 			}
    727 			if (ch == '\r') {
    728 				state = 4;
    729 				continue;
    730 			}
    731 			state = 0;
    732 			break;
    733 		case 2:		/* \r\n + . */
    734 			if (ch == '\n')
    735 				straynewline();
    736 			if (ch == '\r') {
    737 				state = 3;
    738 				continue;
    739 			}
    740 			state = 0;
    741 			break;
    742 		case 3:		/* \r\n + .\r */
    743 			if (ch == '\n')
    744 				return;
    745 			put(".");
    746 			put("\r");
    747 			if (ch == '\r') {
    748 				state = 4;
    749 				continue;
    750 			}
    751 			state = 0;
    752 			break;
    753 		case 4:		/* + \r */
    754 			if (ch == '\n') {
    755 				state = 1;
    756 				break;
    757 			}
    758 			if (ch != '\r') {
    759 				put("\r");
    760 				state = 0;
    761 			}
    762 		}
    763 		put(&ch);
    764 	}
    765 }
    766 
    767 char accept_buf[FMT_ULONG];
    768 void
    769 acceptmessage(qp)
    770 	unsigned long qp;
    771 {
    772 	datetime_sec when;
    773 	when = now();
    774 	out("250 Accepted responsibility at time ");
    775 	accept_buf[fmt_ulong(accept_buf, (unsigned long)when)] = 0;
    776 	out(accept_buf);
    777 	out(" queue process ");
    778 	accept_buf[fmt_ulong(accept_buf, qp)] = 0;
    779 	out(accept_buf);
    780 	out(" - we'll do our best!\r\n");
    781 	flush();
    782 }
    783 
    784 /*
    785   unsigned long alen, plen, len;
    786 
    787   if (databytes && ((alen = str_len(arg)) != 0)) {
    788     / We now accept the optional argument to DATA which is a ulong which must < databytes + 1.
    789     plen = scan_ulong(arg, &len);
    790     if (alen != plen) { err_syntax(); return; } // crap at the end of the argument
    791     if (len > databytes) { out("552 5.3.4 This message is too big for me (rapid rejection).\r\n"); return; }
    792   }
    793  */
    794 void
    795 smtp_data(char *arg)
    796 {
    797 	int hops;
    798 	unsigned long qp;
    799 	char *qqx;
    800 	char *esmtps;
    801 
    802 	if (!seenmail) {
    803 		err_wantmail();
    804 		return;
    805 	}
    806 	if (!rcptto.len) {
    807 		err_wantrcpt();
    808 		return;
    809 	}
    810 	if (realrcptto_deny()) {
    811 		out("554 5.1.1 That user has elected not to receive emails.\r\n");
    812 		return;
    813 	}
    814 	seenmail = 0;
    815 	if (databytes)
    816 		bytestooverflow = databytes + 1;
    817 	if (qmail_open(&qqt) == -1) {
    818 		err_qqt();
    819 		return;
    820 	}
    821 	qp = qmail_qp(&qqt);
    822 	out("354 go ahead\r\n");
    823 	substdio_flush(&ssout);
    824 
    825 	switch ((isesmtp & 1) + ((isstarttls & 1) << 1) + ((relayclient != NULL) << 2)) {
    826 	case 7:
    827 		esmtps = "ESMTPSA";
    828 		break;
    829 	case 6:
    830 		esmtps = "SMTPSA";	/* Compliant clients should never do this, but it's not pathological. */
    831 		break;
    832 	case 5:
    833 		esmtps = "ESMTPA";
    834 		break;
    835 	case 4:
    836 		esmtps = "SMTPA";	/* Clients, at all, will never do this, as we don't process SMTP AUTH. */
    837 		break;
    838 	case 3:
    839 		esmtps = "ESMTPS";
    840 		break;
    841 	case 2:
    842 		esmtps = "SMTPS";	/* Compliant clients should never do this, but it's not pathological. */
    843 		break;
    844 	case 1:
    845 		esmtps = "ESMTP";
    846 		break;
    847 	default:
    848 		esmtps = "SMTP";
    849 	}
    850 	received(&qqt, esmtps, local, remoteip, remotehost, remoteinfo, fakehelo);
    851 	blast(&hops);
    852 	hops = (hops >= MAXHOPS);
    853 	if (hops)
    854 		qmail_fail(&qqt);
    855 	qmail_from(&qqt, mailfrom.s);
    856 	qmail_put(&qqt, rcptto.s, rcptto.len);
    857 
    858 	qqx = qmail_close(&qqt);
    859 	if (!*qqx) {
    860 		acceptmessage(qp);
    861 		return;
    862 	}
    863 	if (hops) {
    864 		out("554 5.4.6 This message has gone through too many SMTP, QMTP or other mail protocol servers; it may be looping. It ends with me.\r\n");
    865 		return;
    866 	}
    867 	if (databytes)
    868 		if (!bytestooverflow) {
    869 			out("552 5.3.4 This message is too big for me.\r\n");
    870 			return;
    871 		}
    872 	if (*qqx == 'D')
    873 		out("554 ");
    874 	else
    875 		out("451 ");
    876 	out(qqx + 1);
    877 	out("\r\n");
    878 }
    879 
    880 struct commands smtpcommands[] = {
    881 	{"rcpt", smtp_rcpt, flush}
    882 	,{"mail", smtp_mail, flush}
    883 	,{"send", smtp_mail, flush}	/* not recommended */
    884 	,{"soml", smtp_mail, flush}	/* not recommended */
    885 	,{"saml", smtp_mail, flush}	/* not recommended */
    886 	,{"data", smtp_data, flush}
    887 	,{"quit", smtp_quit, flush}
    888 	,{"helo", smtp_helo, flush}
    889 	,{"ehlo", smtp_ehlo, flush}
    890 	,{"rset", smtp_rset, flush}
    891 	,{"help", smtp_help, flush}
    892 	,{"starttls", smtp_starttls, flush}
    893 	,{"noop", err_noop, flush}
    894 	,{"vrfy", err_vrfy, flush}
    895 	,{0, err_unimpl, flush}
    896 };
    897 
    898 int
    899 main(void)
    900 {
    901 	/* ndelay_on(0); */
    902 	/* ndelay_on(1); */
    903 	maxrcpttos = 5; // will be overwritten
    904 	sig_pipeignore();
    905 	if (chdir(auto_qmail) == -1)
    906 		die_control();
    907 	setup();
    908 	if (ipme_init() != 1)
    909 		die_ipme();
    910 	if (ip6me_init() != 1)
    911 		die_ip6me();
    912 	smtp_greet("220 ");
    913 	out(" ESMTP\r\n");
    914 	substdio_flush(&ssout);
    915 	if (commands(&ssin, &smtpcommands) == 0)
    916 		die_read();
    917 	die_nomem();
    918 }