xref: /openbsd-src/usr.sbin/smtpd/mta.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: mta.c,v 1.39 2009/03/29 14:18:20 jacekm Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/tree.h>
23 #include <sys/param.h>
24 #include <sys/socket.h>
25 
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #include <ssl/ssl.h>
30 
31 #include <errno.h>
32 #include <event.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 
40 #include "smtpd.h"
41 
42 __dead void	mta_shutdown(void);
43 void		mta_sig_handler(int, short, void *);
44 void		mta_dispatch_parent(int, short, void *);
45 void		mta_dispatch_queue(int, short, void *);
46 void		mta_dispatch_runner(int, short, void *);
47 void		mta_dispatch_lka(int, short, void *);
48 void		mta_setup_events(struct smtpd *);
49 void		mta_disable_events(struct smtpd *);
50 void		mta_timeout(int, short, void *);
51 void		mta_write(int, short, void *);
52 int		mta_connect(struct session *);
53 void		mta_read_handler(struct bufferevent *, void *);
54 void		mta_write_handler(struct bufferevent *, void *);
55 void		mta_error_handler(struct bufferevent *, short, void *);
56 int		mta_reply_handler(struct bufferevent *, void *);
57 void		mta_batch_update_queue(struct batch *);
58 void		mta_mxlookup(struct smtpd *, struct session *, char *, struct rule *);
59 void		ssl_client_init(struct session *);
60 
61 void
62 mta_sig_handler(int sig, short event, void *p)
63 {
64 	switch (sig) {
65 	case SIGINT:
66 	case SIGTERM:
67 		mta_shutdown();
68 		break;
69 	default:
70 		fatalx("mta_sig_handler: unexpected signal");
71 	}
72 }
73 
74 void
75 mta_dispatch_parent(int sig, short event, void *p)
76 {
77 	struct smtpd		*env = p;
78 	struct imsgbuf		*ibuf;
79 	struct imsg		 imsg;
80 	ssize_t			 n;
81 
82 	ibuf = env->sc_ibufs[PROC_PARENT];
83 	switch (event) {
84 	case EV_READ:
85 		if ((n = imsg_read(ibuf)) == -1)
86 			fatal("imsg_read_error");
87 		if (n == 0) {
88 			/* this pipe is dead, so remove the event handler */
89 			event_del(&ibuf->ev);
90 			event_loopexit(NULL);
91 			return;
92 		}
93 		break;
94 	case EV_WRITE:
95 		if (msgbuf_write(&ibuf->w) == -1)
96 			fatal("msgbuf_write");
97 		imsg_event_add(ibuf);
98 		return;
99 	default:
100 		fatalx("unknown event");
101 	}
102 
103 	for (;;) {
104 		if ((n = imsg_get(ibuf, &imsg)) == -1)
105 			fatal("parent_dispatch_mta: imsg_read error");
106 		if (n == 0)
107 			break;
108 
109 		switch (imsg.hdr.type) {
110 		default:
111 			log_warnx("mta_dispatch_parent: got imsg %d",
112 			    imsg.hdr.type);
113 			fatalx("mta_dispatch_parent: unexpected imsg");
114 		}
115 		imsg_free(&imsg);
116 	}
117 	imsg_event_add(ibuf);
118 }
119 
120 void
121 mta_dispatch_lka(int sig, short event, void *p)
122 {
123 	struct smtpd		*env = p;
124 	struct imsgbuf		*ibuf;
125 	struct imsg		 imsg;
126 	ssize_t			 n;
127 
128 	ibuf = env->sc_ibufs[PROC_LKA];
129 	switch (event) {
130 	case EV_READ:
131 		if ((n = imsg_read(ibuf)) == -1)
132 			fatal("imsg_read_error");
133 		if (n == 0) {
134 			/* this pipe is dead, so remove the event handler */
135 			event_del(&ibuf->ev);
136 			event_loopexit(NULL);
137 			return;
138 		}
139 		break;
140 	case EV_WRITE:
141 		if (msgbuf_write(&ibuf->w) == -1)
142 			fatal("msgbuf_write");
143 		imsg_event_add(ibuf);
144 		return;
145 	default:
146 		fatalx("unknown event");
147 	}
148 
149 	for (;;) {
150 		if ((n = imsg_get(ibuf, &imsg)) == -1)
151 			fatal("mta_dispatch_lka: imsg_read error");
152 		if (n == 0)
153 			break;
154 
155 		switch (imsg.hdr.type) {
156 		case IMSG_LKA_MX: {
157 			struct session key;
158 			struct mxrep *mxrep;
159 			struct session *s;
160 			struct mxhost *mxhost;
161 
162 			mxrep = imsg.data;
163 			key.s_id = mxrep->id;
164 
165 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
166 			if (s == NULL)
167 				fatal("mta_dispatch_lka: session is gone");
168 
169 			mxhost = calloc(1, sizeof(struct mxhost));
170 			if (mxhost == NULL)
171 				fatal("mta_dispatch_lka: calloc");
172 
173 			*mxhost = mxrep->mxhost;
174  			TAILQ_INSERT_TAIL(&s->mxhosts, mxhost, entry);
175 
176 			break;
177 		}
178 		case IMSG_LKA_MX_END: {
179 			struct session key;
180 			struct mxrep *mxrep;
181 			struct session *s;
182 			int ret;
183 
184 			mxrep = imsg.data;
185 			key.s_id = mxrep->id;
186 
187 			s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
188 			if (s == NULL)
189 				fatal("smtp_dispatch_parent: session is gone");
190 
191 			s->batch->flags |= F_BATCH_RESOLVED;
192 
193 			do {
194 				ret = mta_connect(s);
195 			} while (ret == 0);
196 
197 			if (ret < 0) {
198 				mta_batch_update_queue(s->batch);
199 				session_destroy(s);
200 			}
201 
202 			break;
203 		}
204 		default:
205 			log_warnx("mta_dispatch_parent: got imsg %d",
206 			    imsg.hdr.type);
207 			fatalx("mta_dispatch_lka: unexpected imsg");
208 		}
209 		imsg_free(&imsg);
210 	}
211 	imsg_event_add(ibuf);
212 }
213 
214 void
215 mta_dispatch_queue(int sig, short event, void *p)
216 {
217 	struct smtpd		*env = p;
218 	struct imsgbuf		*ibuf;
219 	struct imsg		 imsg;
220 	ssize_t			 n;
221 
222 	ibuf = env->sc_ibufs[PROC_QUEUE];
223 	switch (event) {
224 	case EV_READ:
225 		if ((n = imsg_read(ibuf)) == -1)
226 			fatal("imsg_read_error");
227 		if (n == 0) {
228 			/* this pipe is dead, so remove the event handler */
229 			event_del(&ibuf->ev);
230 			event_loopexit(NULL);
231 			return;
232 		}
233 		break;
234 	case EV_WRITE:
235 		if (msgbuf_write(&ibuf->w) == -1)
236 			fatal("msgbuf_write");
237 		imsg_event_add(ibuf);
238 		return;
239 	default:
240 		fatalx("unknown event");
241 	}
242 
243 	for (;;) {
244 		if ((n = imsg_get(ibuf, &imsg)) == -1)
245 			fatal("parent_dispatch_mta: imsg_read error");
246 		if (n == 0)
247 			break;
248 
249 		switch (imsg.hdr.type) {
250 		case IMSG_QUEUE_MESSAGE_FD: {
251 			struct batch	*batchp;
252 			struct session	*sessionp;
253 			int fd;
254 
255 			if ((fd = imsg_get_fd(ibuf, &imsg)) == -1) {
256 				/* NEEDS_FIX - unsure yet how it must be handled */
257 				fatalx("mta_dispatch_queue: imsg_get_fd");
258 			}
259 
260 			batchp = (struct batch *)imsg.data;
261 			batchp = batch_by_id(env, batchp->id);
262 			sessionp = batchp->sessionp;
263 
264 			if ((batchp->messagefp = fdopen(fd, "r")) == NULL)
265 				fatal("mta_dispatch_queue: fdopen");
266 
267 			session_respond(sessionp, "DATA");
268 			bufferevent_enable(sessionp->s_bev, EV_READ);
269 			break;
270 		}
271 		default:
272 			log_warnx("mta_dispatch_queue: got imsg %d",
273 			    imsg.hdr.type);
274 			fatalx("mta_dispatch_queue: unexpected imsg");
275 		}
276 		imsg_free(&imsg);
277 	}
278 	imsg_event_add(ibuf);
279 }
280 
281 void
282 mta_dispatch_runner(int sig, short event, void *p)
283 {
284 	struct smtpd		*env = p;
285 	struct imsgbuf		*ibuf;
286 	struct imsg		 imsg;
287 	ssize_t			 n;
288 
289 	ibuf = env->sc_ibufs[PROC_RUNNER];
290 	switch (event) {
291 	case EV_READ:
292 		if ((n = imsg_read(ibuf)) == -1)
293 			fatal("imsg_read_error");
294 		if (n == 0) {
295 			/* this pipe is dead, so remove the event handler */
296 			event_del(&ibuf->ev);
297 			event_loopexit(NULL);
298 			return;
299 		}
300 		break;
301 	case EV_WRITE:
302 		if (msgbuf_write(&ibuf->w) == -1)
303 			fatal("msgbuf_write");
304 		imsg_event_add(ibuf);
305 		return;
306 	default:
307 		fatalx("unknown event");
308 	}
309 
310 	for (;;) {
311 		if ((n = imsg_get(ibuf, &imsg)) == -1)
312 			fatal("mta_dispatch_runner: imsg_read error");
313 		if (n == 0)
314 			break;
315 
316 		switch (imsg.hdr.type) {
317 		case IMSG_BATCH_CREATE: {
318 			struct session *s;
319 			struct batch *batchp;
320 
321 			/* create a client session */
322 			if ((s = calloc(1, sizeof(*s))) == NULL)
323 				fatal(NULL);
324 			s->s_state = S_INIT;
325 			s->s_env = env;
326 			s->s_id = queue_generate_id();
327 			TAILQ_INIT(&s->mxhosts);
328 			SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
329 
330 			/* create the batch for this session */
331 			batchp = calloc(1, sizeof (struct batch));
332 			if (batchp == NULL)
333 				fatal("mta_dispatch_runner: calloc");
334 
335 			*batchp = *(struct batch *)imsg.data;
336 			batchp->session_id = s->s_id;
337 			batchp->env = env;
338 			batchp->flags = 0;
339 			batchp->sessionp = s;
340 
341 			s->batch = batchp;
342 
343 			TAILQ_INIT(&batchp->messages);
344 			SPLAY_INSERT(batchtree, &env->batch_queue, batchp);
345 
346 			break;
347 		}
348 		case IMSG_BATCH_APPEND: {
349 			struct batch	*batchp;
350 			struct message	*messagep;
351 
352 			messagep = calloc(1, sizeof (struct message));
353 			if (messagep == NULL)
354 				fatal("mta_dispatch_runner: calloc");
355 
356 			*messagep = *(struct message *)imsg.data;
357 
358 			batchp = batch_by_id(env, messagep->batch_id);
359 			if (batchp == NULL)
360 				fatalx("mta_dispatch_runner: internal inconsistency.");
361 
362 			batchp->session_ss = messagep->session_ss;
363 			strlcpy(batchp->session_hostname,
364 			    messagep->session_hostname,
365 			    sizeof(batchp->session_hostname));
366 			strlcpy(batchp->session_helo, messagep->session_helo,
367 			    sizeof(batchp->session_helo));
368 
369  			TAILQ_INSERT_TAIL(&batchp->messages, messagep, entry);
370 			break;
371 		}
372 		case IMSG_BATCH_CLOSE: {
373 			struct batch		*batchp;
374 			struct session		*s;
375 
376 			batchp = (struct batch *)imsg.data;
377 			batchp = batch_by_id(env, batchp->id);
378 			if (batchp == NULL)
379 				fatalx("mta_dispatch_runner: internal inconsistency.");
380 
381 			batchp->flags |= F_BATCH_COMPLETE;
382 
383 			log_debug("batch ready, we can initiate a session");
384 
385 			s = batchp->sessionp;
386 
387 			mta_mxlookup(env, s, batchp->hostname, &batchp->rule);
388 
389 			break;
390 		}
391 		default:
392 			log_warnx("mta_dispatch_runner: got imsg %d",
393 			    imsg.hdr.type);
394 			fatalx("mta_dispatch_runner: unexpected imsg");
395 		}
396 		imsg_free(&imsg);
397 	}
398 	imsg_event_add(ibuf);
399 }
400 
401 void
402 mta_shutdown(void)
403 {
404 	log_info("mail transfer agent exiting");
405 	_exit(0);
406 }
407 
408 void
409 mta_setup_events(struct smtpd *env)
410 {
411 	struct timeval	 tv;
412 
413 	evtimer_set(&env->sc_ev, mta_timeout, env);
414 	tv.tv_sec = 3;
415 	tv.tv_usec = 0;
416 	evtimer_add(&env->sc_ev, &tv);
417 }
418 
419 void
420 mta_disable_events(struct smtpd *env)
421 {
422 	evtimer_del(&env->sc_ev);
423 }
424 
425 void
426 mta_timeout(int fd, short event, void *p)
427 {
428 	struct smtpd		*env = p;
429 	struct timeval		 tv;
430 
431 	tv.tv_sec = 3;
432 	tv.tv_usec = 0;
433 	evtimer_add(&env->sc_ev, &tv);
434 }
435 
436 pid_t
437 mta(struct smtpd *env)
438 {
439 	pid_t		 pid;
440 
441 	struct passwd	*pw;
442 	struct event	 ev_sigint;
443 	struct event	 ev_sigterm;
444 
445 	struct peer peers[] = {
446 		{ PROC_QUEUE,	mta_dispatch_queue },
447 		{ PROC_RUNNER,	mta_dispatch_runner },
448 		{ PROC_LKA,	mta_dispatch_lka }
449 	};
450 
451 	switch (pid = fork()) {
452 	case -1:
453 		fatal("mta: cannot fork");
454 	case 0:
455 		break;
456 	default:
457 		return (pid);
458 	}
459 
460 	ssl_init();
461 	purge_config(env, PURGE_EVERYTHING);
462 
463 	pw = env->sc_pw;
464 #ifndef DEBUG
465 	if (chroot(pw->pw_dir) == -1)
466 		fatal("mta: chroot");
467 	if (chdir("/") == -1)
468 		fatal("mta: chdir(\"/\")");
469 #else
470 #warning disabling privilege revocation and chroot in DEBUG MODE
471 #endif
472 
473 	setproctitle("mail transfer agent");
474 	smtpd_process = PROC_MTA;
475 
476 #ifndef DEBUG
477 	if (setgroups(1, &pw->pw_gid) ||
478 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
479 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
480 		fatal("mta: cannot drop privileges");
481 #endif
482 
483 	event_init();
484 
485 	signal_set(&ev_sigint, SIGINT, mta_sig_handler, env);
486 	signal_set(&ev_sigterm, SIGTERM, mta_sig_handler, env);
487 	signal_add(&ev_sigint, NULL);
488 	signal_add(&ev_sigterm, NULL);
489 	signal(SIGPIPE, SIG_IGN);
490 	signal(SIGHUP, SIG_IGN);
491 
492 	config_pipes(env, peers, 3);
493 	config_peers(env, peers, 3);
494 
495 	SPLAY_INIT(&env->batch_queue);
496 
497 	mta_setup_events(env);
498 	event_dispatch();
499 	mta_shutdown();
500 
501 	return (0);
502 }
503 
504 void
505 mta_mxlookup(struct smtpd *env, struct session *sessionp, char *hostname, struct rule *rule)
506 {
507 	struct mxreq mxreq;
508 
509 	mxreq.id = sessionp->s_id;
510 	mxreq.rule = *rule;
511 	(void)strlcpy(mxreq.hostname, hostname, MAXHOSTNAMELEN);
512 	imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_MX, 0, 0, -1,
513 	    &mxreq, sizeof(struct mxreq));
514 }
515 
516 /* shamelessly ripped usr.sbin/relayd/check_tcp.c ;) */
517 int
518 mta_connect(struct session *sessionp)
519 {
520 	int s;
521 	int type;
522 	struct linger lng;
523 	struct sockaddr_in ssin;
524 	struct sockaddr_in6 ssin6;
525 	struct mxhost *mxhost;
526 
527 	mxhost = TAILQ_FIRST(&sessionp->mxhosts);
528 	if (mxhost == NULL)
529 		return -1;
530 
531 	if ((s = socket(mxhost->ss.ss_family, SOCK_STREAM, 0)) == -1) {
532 		goto bad;
533 	}
534 
535 	bzero(&lng, sizeof(lng));
536 	if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof (lng)) == -1) {
537 		goto bad;
538 	}
539 
540 	type = 1;
541 	if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &type, sizeof (type)) == -1) {
542 		goto bad;
543 	}
544 
545 	session_socket_blockmode(s, BM_NONBLOCK);
546 
547 	if (mxhost->ss.ss_family == PF_INET) {
548 		ssin = *(struct sockaddr_in *)&mxhost->ss;
549 		if (connect(s, (struct sockaddr *)&ssin, sizeof(struct sockaddr_in)) == -1) {
550 			if (errno != EINPROGRESS) {
551 				goto bad;
552 			}
553 		}
554 	}
555 
556 	if (mxhost->ss.ss_family == PF_INET6) {
557 		ssin6 = *(struct sockaddr_in6 *)&mxhost->ss;
558 		if (connect(s, (struct sockaddr *)&ssin6, sizeof(struct sockaddr_in6)) == -1) {
559 			if (errno != EINPROGRESS) {
560 				goto bad;
561 			}
562 		}
563 	}
564 	sessionp->s_tv.tv_sec = SMTPD_CONNECT_TIMEOUT;
565 	sessionp->s_tv.tv_usec = 0;
566 	sessionp->s_fd = s;
567 	event_set(&sessionp->s_ev, s, EV_TIMEOUT|EV_WRITE, mta_write, sessionp);
568 	event_add(&sessionp->s_ev, &sessionp->s_tv);
569 
570 	return 1;
571 
572 bad:
573 	if (mxhost) {
574 		TAILQ_REMOVE(&sessionp->mxhosts, mxhost, entry);
575 		free(mxhost);
576 	}
577 	close(s);
578 	return 0;
579 }
580 
581 void
582 mta_write(int s, short event, void *arg)
583 {
584 	struct session *sessionp = arg;
585 	struct batch *batchp = sessionp->batch;
586 	struct mxhost *mxhost;
587 	int ret;
588 
589 	mxhost = TAILQ_FIRST(&sessionp->mxhosts);
590 
591 	if (event == EV_TIMEOUT) {
592 
593 		if (mxhost) {
594 			TAILQ_REMOVE(&sessionp->mxhosts, mxhost, entry);
595 			free(mxhost);
596 		}
597 		close(s);
598 
599 		if (sessionp->s_bev) {
600 			bufferevent_free(sessionp->s_bev);
601 			sessionp->s_bev = NULL;
602 		}
603 		strlcpy(batchp->errorline, "connection timed-out.",
604 		    sizeof(batchp->errorline));
605 
606 		do {
607 			ret = mta_connect(sessionp);
608 		} while (ret == 0);
609 
610 		if (ret < 0) {
611 			mta_batch_update_queue(batchp);
612 			session_destroy(sessionp);
613 		}
614 
615 		return;
616 	}
617 
618 	sessionp->s_bev = bufferevent_new(s, mta_read_handler, mta_write_handler,
619 	    mta_error_handler, sessionp);
620 
621 	if (sessionp->s_bev == NULL) {
622 		mta_batch_update_queue(batchp);
623 		session_destroy(sessionp);
624 		return;
625 	}
626 
627 	if (mxhost && mxhost->flags & F_SSMTP) {
628 		ssl_client_init(sessionp);
629 		return;
630 	}
631 	bufferevent_enable(sessionp->s_bev, EV_READ);
632 }
633 
634 void
635 mta_read_handler(struct bufferevent *bev, void *arg)
636 {
637 	while (mta_reply_handler(bev, arg))
638 		;
639 }
640 
641 int
642 mta_reply_handler(struct bufferevent *bev, void *arg)
643 {
644 	struct session *sessionp = arg;
645 	struct batch *batchp = sessionp->batch;
646 	struct smtpd *env = batchp->env;
647 	struct message *messagep = NULL;
648 	char *line;
649 	int i;
650 	int code;
651 #define F_ISINFO	0x1
652 #define F_ISPROTOERROR	0x2
653 	char codebuf[4];
654 	const char *errstr;
655 	int flags = 0;
656 	struct mxhost *mxhost = TAILQ_FIRST(&sessionp->mxhosts);
657 
658 	line = evbuffer_readline(bev->input);
659 	if (line == NULL)
660 		return 0;
661 
662 	log_debug("remote server sent: [%s]", line);
663 
664 	strlcpy(codebuf, line, sizeof(codebuf));
665 	code = strtonum(codebuf, 0, UINT16_MAX, &errstr);
666 	if (errstr || code < 100) {
667 		/* Server sent invalid line, protocol error */
668 		batchp->status |= S_BATCH_PERMFAILURE;
669 		strlcpy(batchp->errorline, line, sizeof(batchp->errorline));
670 		mta_batch_update_queue(batchp);
671 		session_destroy(sessionp);
672 		return 0;
673 	}
674 
675 	if (line[3] == '-') {
676 		if (strcasecmp(&line[4], "STARTTLS") == 0)
677 			sessionp->s_flags |= F_PEERHASTLS;
678 		else if (strncasecmp(&line[4], "AUTH ", 5) == 0 ||
679 		    strncasecmp(&line[4], "AUTH-", 5) == 0)
680 			sessionp->s_flags |= F_PEERHASAUTH;
681 		return 1;
682 	}
683 
684 	switch (code) {
685 	case 250:
686 		if (sessionp->s_state == S_DONE) {
687 			mta_batch_update_queue(batchp);
688 			session_destroy(sessionp);
689 			return 0;
690 		}
691 
692 		if (sessionp->s_state == S_GREETED &&
693 		    (sessionp->s_flags & F_PEERHASTLS) &&
694 		    !(sessionp->s_flags & F_SECURE)) {
695 			session_respond(sessionp, "STARTTLS");
696 			sessionp->s_state = S_TLS;
697 			return 0;
698 		}
699 
700 		if (sessionp->s_state == S_GREETED &&
701 		    (sessionp->s_flags & F_PEERHASAUTH) &&
702 		    (sessionp->s_flags & F_SECURE) &&
703 		    (mxhost->flags & F_AUTH) &&
704 		    (mxhost->credentials[0] != '\0')) {
705 			log_debug("AUTH PLAIN %s", mxhost->credentials);
706 			session_respond(sessionp, "AUTH PLAIN %s",
707 			    mxhost->credentials);
708 			sessionp->s_state = S_AUTH_INIT;
709 			return 0;
710 		}
711 
712 		if (sessionp->s_state == S_GREETED &&
713 		    !(sessionp->s_flags & F_PEERHASTLS) &&
714 		    mxhost->flags & F_STARTTLS) {
715 			/* PERM - we want TLS but it is not advertised */
716 			batchp->status |= S_BATCH_PERMFAILURE;
717 			mta_batch_update_queue(batchp);
718 			session_destroy(sessionp);
719 			return 0;
720 		}
721 
722 		if (sessionp->s_state == S_GREETED &&
723 		    !(sessionp->s_flags & F_PEERHASAUTH) &&
724 		    mxhost->flags & F_AUTH) {
725 			/* PERM - we want AUTH but it is not advertised */
726 			batchp->status |= S_BATCH_PERMFAILURE;
727 			mta_batch_update_queue(batchp);
728 			session_destroy(sessionp);
729 			return 0;
730 		}
731 
732 		break;
733 
734 	case 220:
735 		if (sessionp->s_state == S_TLS) {
736 			ssl_client_init(sessionp);
737 			bufferevent_disable(bev, EV_READ|EV_WRITE);
738 			sessionp->s_state = S_GREETED;
739 			return 0;
740 		}
741 
742 		session_respond(sessionp, "EHLO %s", env->sc_hostname);
743 		sessionp->s_state = S_GREETED;
744 		return 1;
745 
746 	case 235:
747 		if (sessionp->s_state == S_AUTH_INIT) {
748 			sessionp->s_flags |= F_AUTHENTICATED;
749 			sessionp->s_state = S_GREETED;
750 			break;
751 		}
752 		return 0;
753 	case 421:
754 	case 450:
755 	case 451:
756 		batchp->status |= S_BATCH_TEMPFAILURE;
757 		strlcpy(batchp->errorline, line, sizeof(batchp->errorline));
758 		mta_batch_update_queue(batchp);
759 		session_destroy(sessionp);
760 		return 0;
761 
762 		/* The following codes are state dependant and will cause
763 		 * a batch rejection if returned at the wrong state.
764 		 */
765 	case 530:
766 	case 550:
767 		if (sessionp->s_state == S_RCPT) {
768 			batchp->messagep->status = (S_MESSAGE_REJECTED|S_MESSAGE_PERMFAILURE);
769 			strlcpy(batchp->messagep->session_errorline, line,
770 			    sizeof(batchp->messagep->session_errorline));
771 			break;
772 		}
773 	case 354:
774 		if (sessionp->s_state == S_RCPT && batchp->messagep == NULL) {
775 			sessionp->s_state = S_DATA;
776 			break;
777 		}
778 
779 	case 221:
780 		if (sessionp->s_state == S_DONE) {
781 			mta_batch_update_queue(batchp);
782 			session_destroy(sessionp);
783 			return 0;
784 		}
785 
786 	case 535:
787 		/* Authentication failed*/
788 	case 552:
789 	case 553:
790 		flags |= F_ISPROTOERROR;
791 	default:
792 		/* Server sent code we know nothing about, error */
793 		if (!(flags & F_ISPROTOERROR))
794 			log_debug("Ouch, SMTP session returned unhandled %d status.", code);
795 
796 		batchp->status |= S_BATCH_PERMFAILURE;
797 		strlcpy(batchp->errorline, line, sizeof(batchp->errorline));
798 		mta_batch_update_queue(batchp);
799 		session_destroy(sessionp);
800 		return 0;
801 	}
802 
803 
804 	switch (sessionp->s_state) {
805 	case S_GREETED: {
806 		char *user;
807 		char *domain;
808 
809 		if (batchp->type & T_DAEMON_BATCH) {
810 			user = "MAILER-DAEMON";
811 			domain = env->sc_hostname;
812 		}
813 		else {
814 			messagep = TAILQ_FIRST(&batchp->messages);
815 			user = messagep->sender.user;
816 			domain = messagep->sender.domain;
817 		}
818 
819 		if (user[0] == '\0' && domain[0] == '\0')
820 			session_respond(sessionp, "MAIL FROM:<>");
821 		else
822 			session_respond(sessionp,  "MAIL FROM:<%s@%s>", user, domain);
823 
824 		sessionp->s_state = S_MAIL;
825 
826 		break;
827 	}
828 
829 	case S_MAIL:
830 		sessionp->s_state = S_RCPT;
831 
832 	case S_RCPT: {
833 		char *user;
834 		char *domain;
835 
836 		/* Is this the first RCPT ? */
837 		if (batchp->messagep == NULL)
838 			messagep = TAILQ_FIRST(&batchp->messages);
839 		else {
840 			/* We already had a RCPT, mark is as accepted and
841 			 * fetch next one from queue if we aren't dealing
842 			 * with a daemon batch.
843 			 */
844 			if (batchp->type & T_DAEMON_BATCH)
845 				messagep = NULL;
846 			else {
847 				messagep = batchp->messagep;
848 				if ((messagep->status & S_MESSAGE_REJECTED) == 0)
849 					messagep->status = S_MESSAGE_ACCEPTED;
850 				messagep = TAILQ_NEXT(batchp->messagep, entry);
851 			}
852 		}
853 		batchp->messagep = messagep;
854 
855 		if (messagep) {
856 			if (batchp->type & T_DAEMON_BATCH) {
857 				user = messagep->sender.user;
858 				domain = messagep->sender.domain;
859 			}
860 			else {
861 				user = messagep->recipient.user;
862 				domain = messagep->recipient.domain;
863 			}
864 			session_respond(sessionp, "RCPT TO:<%s@%s>", user, domain);
865 		}
866 		else {
867 			/* Do we have at least one accepted recipient ? */
868 			if ((batchp->type & T_DAEMON_BATCH) == 0) {
869 				TAILQ_FOREACH(messagep, &batchp->messages, entry) {
870 					if (messagep->status & S_MESSAGE_ACCEPTED)
871 						break;
872 				}
873 				if (messagep == NULL) {
874 					batchp->status |= S_BATCH_PERMFAILURE;
875 					mta_batch_update_queue(batchp);
876 					session_destroy(sessionp);
877 					return 0;
878 				}
879 			}
880 
881 			imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_MESSAGE_FD,
882 			    0, 0, -1, batchp, sizeof(*batchp));
883 			bufferevent_disable(sessionp->s_bev, EV_READ);
884 		}
885 		break;
886 	}
887 
888 	case S_DATA: {
889 		session_respond(sessionp, "Received: from %s (%s [%s])",
890 		    batchp->session_helo, batchp->session_hostname,
891 		    ss_to_text(&batchp->session_ss));
892 
893 		session_respond(sessionp, "\tby %s with ESMTP id %s;",
894 		    batchp->env->sc_hostname, batchp->message_id);
895 
896 		session_respond(sessionp, "\t%s", time_to_text(batchp->creation));
897 
898 		if (sessionp->s_flags & F_SECURE) {
899 			log_info("%s: version=%s cipher=%s bits=%d",
900 			batchp->message_id,
901 			SSL_get_cipher_version(sessionp->s_ssl),
902 			SSL_get_cipher_name(sessionp->s_ssl),
903 			SSL_get_cipher_bits(sessionp->s_ssl, NULL));
904 		}
905 
906 		TAILQ_FOREACH(messagep, &batchp->messages, entry) {
907 			session_respond(sessionp, "X-OpenSMTPD-Loop: %s@%s",
908 			    messagep->session_rcpt.user,
909 			    messagep->session_rcpt.domain);
910 		}
911 
912 		if (batchp->type & T_DAEMON_BATCH) {
913 			session_respond(sessionp, "Hi !");
914 			session_respond(sessionp, "%s", "");
915 			session_respond(sessionp, "This is the MAILER-DAEMON, please DO NOT REPLY to this e-mail it is");
916 			session_respond(sessionp, "just a notification to let you know that an error has occured.");
917 			session_respond(sessionp, "%s", "");
918 
919 			if (batchp->status & S_BATCH_PERMFAILURE) {
920 				session_respond(sessionp, "You ran into a PERMANENT FAILURE, which means that the e-mail can't");
921 				session_respond(sessionp, "be delivered to the remote host no matter how much I'll try.");
922 				session_respond(sessionp, "%s", "");
923 				session_respond(sessionp, "Diagnostic:");
924 				session_respond(sessionp, "%s", batchp->errorline);
925 				session_respond(sessionp, "%s", "");
926 			}
927 
928 			if (batchp->status & S_BATCH_TEMPFAILURE) {
929 				session_respond(sessionp, "You ran into a TEMPORARY FAILURE, which means that the e-mail can't");
930 				session_respond(sessionp, "be delivered right now, but could be deliberable at a later time. I");
931 				session_respond(sessionp, "will attempt until it succeeds for the next four days, then let you");
932 				session_respond(sessionp, "know if it didn't work out.");
933 				session_respond(sessionp, "%s", "");
934 				session_respond(sessionp, "Diagnostic:");
935 				session_respond(sessionp, "%s", batchp->errorline);
936 				session_respond(sessionp, "%s", "");
937 			}
938 
939 			i = 0;
940 			TAILQ_FOREACH(messagep, &batchp->messages, entry) {
941 				if (messagep->status & S_MESSAGE_TEMPFAILURE) {
942 					if (i == 0) {
943 						session_respond(sessionp, "The following recipients caused a temporary failure:");
944 						++i;
945 					}
946 
947 					session_respond(sessionp,
948 					    "\t<%s@%s>:", messagep->recipient.user, messagep->recipient.domain);
949 					session_respond(sessionp,
950 					    "%s", messagep->session_errorline);
951 					session_respond(sessionp, "%s", "");
952 				}
953 			}
954 
955 			i = 0;
956 			TAILQ_FOREACH(messagep, &batchp->messages, entry) {
957 				if (messagep->status & S_MESSAGE_PERMFAILURE) {
958 					if (i == 0) {
959 						session_respond(sessionp,
960 						    "The following recipients caused a permanent failure:");
961 						++i;
962 					}
963 
964 					session_respond(sessionp,
965 					    "\t<%s@%s>:", messagep->recipient.user, messagep->recipient.domain);
966 					session_respond(sessionp,
967 					    "%s", messagep->session_errorline);
968 					session_respond(sessionp, "%s", "");
969 				}
970 			}
971 
972 			session_respond(sessionp, "Below is a copy of the original message:");
973 			session_respond(sessionp, "%s", "");
974 		}
975 
976 		break;
977 	}
978 	case S_DONE:
979 		session_respond(sessionp, "QUIT");
980 		sessionp->s_state = S_QUIT;
981 		break;
982 
983 	default:
984 		log_info("unknown command: %d", sessionp->s_state);
985 	}
986 
987 	return 1;
988 }
989 
990 void
991 mta_write_handler(struct bufferevent *bev, void *arg)
992 {
993 	struct session *sessionp = arg;
994 	struct batch *batchp = sessionp->batch;
995 	char *buf, *lbuf;
996 	size_t len;
997 
998 	if (sessionp->s_state == S_QUIT) {
999 		bufferevent_disable(bev, EV_READ|EV_WRITE);
1000 		log_debug("closing connection because of QUIT");
1001 		close(sessionp->s_fd);
1002 		return;
1003 	}
1004 
1005 	/* Progressively fill the output buffer with data */
1006 	if (sessionp->s_state == S_DATA) {
1007 
1008 		lbuf = NULL;
1009 		if ((buf = fgetln(batchp->messagefp, &len))) {
1010 			if (buf[len - 1] == '\n')
1011 				buf[len - 1] = '\0';
1012 			else {
1013 				if ((lbuf = malloc(len + 1)) == NULL)
1014 					fatal("mta_write_handler: malloc");
1015 				memcpy(lbuf, buf, len);
1016 				lbuf[len] = '\0';
1017 				buf = lbuf;
1018 			}
1019 
1020 			/* "If first character of the line is a period, one
1021 			 *  additional period is inserted at the beginning."
1022 			 * [4.5.2]
1023 			 */
1024 			if (*buf == '.')
1025 				evbuffer_add_printf(sessionp->s_bev->output, ".");
1026 
1027 			session_respond(sessionp, "%s", buf);
1028 			free(lbuf);
1029 			lbuf = NULL;
1030 		}
1031 		else {
1032 			session_respond(sessionp, ".");
1033 			sessionp->s_state = S_DONE;
1034 			fclose(batchp->messagefp);
1035 			batchp->messagefp = NULL;
1036 		}
1037 	}
1038 }
1039 
1040 void
1041 mta_error_handler(struct bufferevent *bev, short error, void *arg)
1042 {
1043 	struct session *sessionp = arg;
1044 
1045 	if (error & (EVBUFFER_TIMEOUT|EVBUFFER_EOF)) {
1046 		bufferevent_disable(bev, EV_READ|EV_WRITE);
1047 		log_debug("closing connection because of an error");
1048 		close(sessionp->s_fd);
1049 		return;
1050 	}
1051 }
1052 
1053 void
1054 mta_batch_update_queue(struct batch *batchp)
1055 {
1056 	struct smtpd *env = batchp->env;
1057 	struct message *messagep;
1058 
1059 	while ((messagep = TAILQ_FIRST(&batchp->messages)) != NULL) {
1060 
1061 		if (batchp->status & S_BATCH_PERMFAILURE) {
1062 			messagep->status |= S_MESSAGE_PERMFAILURE;
1063 		}
1064 
1065 		if (batchp->status & S_BATCH_TEMPFAILURE) {
1066 			if (messagep->status != S_MESSAGE_PERMFAILURE)
1067 				messagep->status |= S_MESSAGE_TEMPFAILURE;
1068 		}
1069 
1070 		if ((messagep->status & S_MESSAGE_TEMPFAILURE) == 0 &&
1071 		    (messagep->status & S_MESSAGE_PERMFAILURE) == 0) {
1072 			log_info("%s: to=<%s@%s>, delay=%d, stat=Sent",
1073 			    messagep->message_uid,
1074 			    messagep->recipient.user,
1075 			    messagep->recipient.domain,
1076 			    time(NULL) - messagep->creation);
1077 		}
1078 
1079 		imsg_compose(env->sc_ibufs[PROC_QUEUE],
1080 		    IMSG_QUEUE_MESSAGE_UPDATE, 0, 0, -1, messagep,
1081 		    sizeof(struct message));
1082 		TAILQ_REMOVE(&batchp->messages, messagep, entry);
1083 		free(messagep);
1084 	}
1085 
1086 	SPLAY_REMOVE(batchtree, &env->batch_queue, batchp);
1087 
1088 	if (batchp->messagefp)
1089 		fclose(batchp->messagefp);
1090 
1091 	free(batchp);
1092 
1093 }
1094