xref: /openbsd-src/usr.sbin/smtpd/smtp_session.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: smtp_session.c,v 1.79 2009/04/28 21:56:45 jacekm Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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 <ctype.h>
30 #include <errno.h>
31 #include <event.h>
32 #include <pwd.h>
33 #include <regex.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include <keynote.h>
40 
41 #include "smtpd.h"
42 
43 int		session_rfc5321_helo_handler(struct session *, char *);
44 int		session_rfc5321_ehlo_handler(struct session *, char *);
45 int		session_rfc5321_rset_handler(struct session *, char *);
46 int		session_rfc5321_noop_handler(struct session *, char *);
47 int		session_rfc5321_data_handler(struct session *, char *);
48 int		session_rfc5321_mail_handler(struct session *, char *);
49 int		session_rfc5321_rcpt_handler(struct session *, char *);
50 int		session_rfc5321_vrfy_handler(struct session *, char *);
51 int		session_rfc5321_expn_handler(struct session *, char *);
52 int		session_rfc5321_turn_handler(struct session *, char *);
53 int		session_rfc5321_help_handler(struct session *, char *);
54 int		session_rfc5321_quit_handler(struct session *, char *);
55 int		session_rfc5321_none_handler(struct session *, char *);
56 
57 int		session_rfc1652_mail_handler(struct session *, char *);
58 
59 int		session_rfc3207_stls_handler(struct session *, char *);
60 
61 int		session_rfc4954_auth_handler(struct session *, char *);
62 int		session_rfc4954_auth_plain(struct session *, char *, size_t);
63 int		session_rfc4954_auth_login(struct session *, char *, size_t);
64 void		session_auth_pickup(struct session *, char *, size_t);
65 
66 void		session_read(struct bufferevent *, void *);
67 int		session_read_data(struct session *, char *, size_t);
68 void		session_write(struct bufferevent *, void *);
69 void		session_error(struct bufferevent *, short, void *);
70 void		session_command(struct session *, char *, char *);
71 int		session_set_path(struct path *, char *);
72 void		session_imsg(struct session *, enum smtp_proc_type,
73 		    enum imsg_type, u_int32_t, pid_t, int, void *, u_int16_t);
74 
75 extern struct s_session	s_smtp;
76 
77 struct session_cmd {
78 	char	 *name;
79 	int		(*func)(struct session *, char *);
80 };
81 
82 struct session_cmd rfc5321_cmdtab[] = {
83 	{ "helo",	session_rfc5321_helo_handler },
84 	{ "ehlo",	session_rfc5321_ehlo_handler },
85 	{ "rset",	session_rfc5321_rset_handler },
86 	{ "noop",	session_rfc5321_noop_handler },
87 	{ "data",	session_rfc5321_data_handler },
88 	{ "mail from",	session_rfc5321_mail_handler },
89 	{ "rcpt to",	session_rfc5321_rcpt_handler },
90 	{ "vrfy",	session_rfc5321_vrfy_handler },
91 	{ "expn",	session_rfc5321_expn_handler },
92 	{ "turn",	session_rfc5321_turn_handler },
93 	{ "help",	session_rfc5321_help_handler },
94 	{ "quit",	session_rfc5321_quit_handler }
95 };
96 
97 struct session_cmd rfc1652_cmdtab[] = {
98 	{ "mail from",	session_rfc1652_mail_handler },
99 };
100 
101 struct session_cmd rfc3207_cmdtab[] = {
102 	{ "starttls",	session_rfc3207_stls_handler }
103 };
104 
105 struct session_cmd rfc4954_cmdtab[] = {
106 	{ "auth",	session_rfc4954_auth_handler }
107 };
108 
109 int
110 session_rfc3207_stls_handler(struct session *s, char *args)
111 {
112 	if (s->s_state == S_GREETED) {
113 		session_respond(s, "503 Polite people say HELO first");
114 		return 1;
115 	}
116 
117 	if (args != NULL) {
118 		session_respond(s, "501 No parameters allowed");
119 		return 1;
120 	}
121 
122 	session_respond(s, "220 Ready to start TLS");
123 
124 	s->s_state = S_TLS;
125 
126 	return 1;
127 }
128 
129 int
130 session_rfc4954_auth_handler(struct session *s, char *args)
131 {
132 	char	*method;
133 	char	*eom;
134 
135 	if (s->s_state == S_GREETED) {
136 		session_respond(s, "503 Polite people say HELO first");
137 		return 1;
138 	}
139 
140 	if (args == NULL) {
141 		session_respond(s, "501 No parameters given");
142 		return 1;
143 	}
144 
145 	method = args;
146 	eom = strchr(args, ' ');
147 	if (eom == NULL)
148 		eom = strchr(args, '\t');
149 	if (eom != NULL)
150 		*eom++ = '\0';
151 
152 	if (strcasecmp(method, "PLAIN") == 0)
153 		return session_rfc4954_auth_plain(s, eom, eom ? strlen(eom) : 0);
154 	else if (strcasecmp(method, "LOGIN") == 0)
155 		return session_rfc4954_auth_login(s, eom, eom ? strlen(eom) : 0);
156 
157 	session_respond(s, "501 Syntax error");
158 	return 1;
159 
160 }
161 
162 int
163 session_rfc4954_auth_plain(struct session *s, char *arg, size_t nr)
164 {
165 	if (arg == NULL) {
166 		session_respond(s, "334");
167 		s->s_state = S_AUTH_INIT;
168 		return 1;
169 	}
170 
171 	s->s_auth.session_id = s->s_id;
172 	if (strlcpy(s->s_auth.buffer, arg, sizeof(s->s_auth.buffer)) >=
173 	    sizeof(s->s_auth.buffer)) {
174 		session_respond(s, "501 Syntax error");
175 		return 1;
176 	}
177 
178 	s->s_state = S_AUTH_FINALIZE;
179 
180 	session_imsg(s, PROC_PARENT, IMSG_PARENT_AUTHENTICATE, 0, 0, -1,
181 	    &s->s_auth, sizeof(s->s_auth));
182 
183 	return 1;
184 }
185 
186 int
187 session_rfc4954_auth_login(struct session *s, char *arg, size_t nr)
188 {
189 	struct session_auth_req req;
190 	int blen = 0;
191 	size_t len = 0;
192 
193 	switch (s->s_state) {
194 	case S_HELO:
195 		/* "Username:" base64 encoded is "VXNlcm5hbWU6" */
196 		session_respond(s, "334 VXNlcm5hbWU6");
197 		s->s_auth.session_id = s->s_id;
198 		s->s_state = S_AUTH_USERNAME;
199 		return 1;
200 
201 	case S_AUTH_USERNAME:
202 		bzero(s->s_auth.buffer, sizeof(s->s_auth.buffer));
203 		if ((blen = kn_decode_base64(arg, req.buffer, sizeof(req.buffer) - 1)) == -1)
204 			goto err;
205 		/* req.buffer is a byte string, NUL terminate */
206 		req.buffer[blen] = '\0';
207 		if (! bsnprintf(s->s_auth.buffer + 1, sizeof(s->s_auth.buffer) - 1, "%s", req.buffer))
208 			goto err;
209 
210 		/* "Password:" base64 encoded is "UGFzc3dvcmQ6" */
211 		session_respond(s, "334 UGFzc3dvcmQ6");
212 		s->s_state = S_AUTH_PASSWORD;
213 
214 		return 1;
215 
216 	case S_AUTH_PASSWORD: {
217 		if ((blen = kn_decode_base64(arg, req.buffer, sizeof(req.buffer) - 1)) == -1)
218 			goto err;
219 		/* req.buffer is a byte string, NUL terminate */
220 		req.buffer[blen] = '\0';
221 
222 		len = strlen(s->s_auth.buffer + 1);
223 		if (! bsnprintf(s->s_auth.buffer + len + 2, sizeof(s->s_auth.buffer) - len - 2, "%s", req.buffer))
224 			goto err;
225 
226 		break;
227 	}
228 	default:
229 		fatal("session_rfc4954_auth_login: unknown state");
230 	}
231 
232 	s->s_state = S_AUTH_FINALIZE;
233 
234 	req = s->s_auth;
235 	len = strlen(s->s_auth.buffer + 1) + strlen(arg) + 2;
236 	if (kn_encode_base64(req.buffer, len, s->s_auth.buffer, sizeof(s->s_auth.buffer)) == -1)
237 		goto err;
238 
239 	session_imsg(s, PROC_PARENT, IMSG_PARENT_AUTHENTICATE, 0, 0, -1,
240 	    &s->s_auth, sizeof(s->s_auth));
241 
242 	return 1;
243 err:
244 	s->s_state = S_HELO;
245 	session_respond(s, "535 Authentication failed");
246 	return 1;
247 }
248 
249 int
250 session_rfc1652_mail_handler(struct session *s, char *args)
251 {
252 	char *body;
253 
254 	if (s->s_state == S_GREETED) {
255 		session_respond(s, "503 Polite people say HELO first");
256 		return 1;
257 	}
258 
259 	body = strrchr(args, ' ');
260 	if (body != NULL) {
261 		*body++ = '\0';
262 
263 		if (strcasecmp("body=7bit", body) == 0) {
264 			s->s_flags &= ~F_8BITMIME;
265 		}
266 
267 		else if (strcasecmp("body=8bitmime", body) != 0) {
268 			session_respond(s, "503 Invalid BODY");
269 			return 1;
270 		}
271 
272 		return session_rfc5321_mail_handler(s, args);
273 	}
274 
275 	return 0;
276 }
277 
278 int
279 session_rfc5321_helo_handler(struct session *s, char *args)
280 {
281 	if (args == NULL) {
282 		session_respond(s, "501 HELO requires domain address");
283 		return 1;
284 	}
285 
286 	if (strlcpy(s->s_msg.session_helo, args, sizeof(s->s_msg.session_helo))
287 	    >= sizeof(s->s_msg.session_helo)) {
288 		session_respond(s, "501 Invalid domain name");
289 		return 1;
290 	}
291 
292 	s->s_state = S_HELO;
293 	s->s_flags &= F_SECURE;
294 
295 	session_respond(s, "250 %s Hello %s [%s], pleased to meet you",
296 	    s->s_env->sc_hostname, args, ss_to_text(&s->s_ss));
297 
298 	return 1;
299 }
300 
301 int
302 session_rfc5321_ehlo_handler(struct session *s, char *args)
303 {
304 	if (args == NULL) {
305 		session_respond(s, "501 EHLO requires domain address");
306 		return 1;
307 	}
308 
309 	if (strlcpy(s->s_msg.session_helo, args, sizeof(s->s_msg.session_helo))
310 	    >= sizeof(s->s_msg.session_helo)) {
311 		session_respond(s, "501 Invalid domain name");
312 		return 1;
313 	}
314 
315 	s->s_state = S_HELO;
316 	s->s_flags &= F_SECURE;
317 	s->s_flags |= F_EHLO;
318 	s->s_flags |= F_8BITMIME;
319 
320 	session_respond(s, "250-%s Hello %s [%s], pleased to meet you",
321 	    s->s_env->sc_hostname, args, ss_to_text(&s->s_ss));
322 	session_respond(s, "250-8BITMIME");
323 
324 	/* only advertise starttls if listener can support it */
325 	if (s->s_l->flags & F_STARTTLS)
326 		session_respond(s, "250-STARTTLS");
327 
328 	/* only advertise auth if session is secure */
329 	if ((s->s_l->flags & F_AUTH) && (s->s_flags & F_SECURE))
330 		session_respond(s, "250-AUTH PLAIN LOGIN");
331 
332 	session_respond(s, "250 HELP");
333 
334 	return 1;
335 }
336 
337 int
338 session_rfc5321_rset_handler(struct session *s, char *args)
339 {
340 	s->s_state = S_HELO;
341 	session_respond(s, "250 Reset state");
342 
343 	return 1;
344 }
345 
346 int
347 session_rfc5321_noop_handler(struct session *s, char *args)
348 {
349 	session_respond(s, "250 OK");
350 
351 	return 1;
352 }
353 
354 int
355 session_rfc5321_mail_handler(struct session *s, char *args)
356 {
357 	if (s->s_state == S_GREETED) {
358 		session_respond(s, "503 Polite people say HELO first");
359 		return 1;
360 	}
361 
362 	if (s->s_state != S_HELO) {
363 		session_respond(s, "503 Sender already specified");
364 		return 1;
365 	}
366 
367 	if (! session_set_path(&s->s_msg.sender, args)) {
368 		/* No need to even transmit to MFA, path is invalid */
369 		session_respond(s, "553 Sender address syntax error");
370 		return 1;
371 	}
372 
373 	s->rcptcount = 0;
374 	s->s_state = S_MAILREQUEST;
375 	s->s_msg.id = s->s_id;
376 	s->s_msg.session_id = s->s_id;
377 	s->s_msg.session_ss = s->s_ss;
378 
379 	log_debug("session_mail_handler: sending notification to mfa");
380 
381 	session_imsg(s, PROC_MFA, IMSG_MFA_MAIL, 0, 0, -1, &s->s_msg,
382 	    sizeof(s->s_msg));
383 	return 1;
384 }
385 
386 int
387 session_rfc5321_rcpt_handler(struct session *s, char *args)
388 {
389 	if (s->s_state == S_GREETED) {
390 		session_respond(s, "503 Polite people say HELO first");
391 		return 1;
392 	}
393 
394 	if (s->s_state == S_HELO) {
395 		session_respond(s, "503 Need MAIL before RCPT");
396 		return 1;
397 	}
398 
399 	if (! session_set_path(&s->s_msg.session_rcpt, args)) {
400 		/* No need to even transmit to MFA, path is invalid */
401 		session_respond(s, "553 Recipient address syntax error");
402 		return 1;
403 	}
404 
405 	s->s_state = S_RCPTREQUEST;
406 
407 	if (s->s_flags & F_AUTHENTICATED) {
408 		s->s_msg.flags |= F_MESSAGE_AUTHENTICATED;
409 	}
410 
411 	session_imsg(s, PROC_MFA, IMSG_MFA_RCPT, 0, 0, -1, &s->s_msg,
412 	    sizeof(s->s_msg));
413 	return 1;
414 }
415 
416 int
417 session_rfc5321_quit_handler(struct session *s, char *args)
418 {
419 	session_respond(s, "221 %s Closing connection", s->s_env->sc_hostname);
420 
421 	s->s_flags |= F_QUIT;
422 	bufferevent_disable(s->s_bev, EV_READ);
423 
424 	return 1;
425 }
426 
427 int
428 session_rfc5321_data_handler(struct session *s, char *args)
429 {
430 	if (s->s_state == S_GREETED) {
431 		session_respond(s, "503 Polite people say HELO first");
432 		return 1;
433 	}
434 
435 	if (s->s_state == S_HELO) {
436 		session_respond(s, "503 Need MAIL before DATA");
437 		return 1;
438 	}
439 
440 	if (s->s_state == S_MAIL) {
441 		session_respond(s, "503 Need RCPT before DATA");
442 		return 1;
443 	}
444 
445 	s->s_state = S_DATAREQUEST;
446 
447 	session_imsg(s, PROC_QUEUE, IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1,
448 	    &s->s_msg, sizeof(s->s_msg));
449 
450 	return 1;
451 }
452 
453 int
454 session_rfc5321_vrfy_handler(struct session *s, char *args)
455 {
456 	session_respond(s, "252 Cannot VRFY; try RCPT to attempt delivery");
457 
458 	return 1;
459 }
460 
461 int
462 session_rfc5321_expn_handler(struct session *s, char *args)
463 {
464 	session_respond(s, "502 Sorry, we do not allow this operation");
465 
466 	return 1;
467 }
468 
469 int
470 session_rfc5321_turn_handler(struct session *s, char *args)
471 {
472 	session_respond(s, "502 Sorry, we do not allow this operation");
473 
474 	return 1;
475 }
476 
477 int
478 session_rfc5321_help_handler(struct session *s, char *args)
479 {
480 	session_respond(s, "214- This is OpenSMTPD");
481 	session_respond(s, "214- To report bugs in the implementation, please "
482 	    "contact bugs@openbsd.org");
483 	session_respond(s, "214- with full details");
484 	session_respond(s, "214 End of HELP info");
485 
486 	return 1;
487 }
488 
489 void
490 session_command(struct session *s, char *cmd, char *args)
491 {
492 	int	i;
493 
494 	if (!(s->s_flags & F_EHLO))
495 		goto rfc5321;
496 
497 	/* RFC 1652 - 8BITMIME */
498 	for (i = 0; i < (int)(sizeof(rfc1652_cmdtab) / sizeof(struct session_cmd)); ++i)
499 		if (strcasecmp(rfc1652_cmdtab[i].name, cmd) == 0)
500 			break;
501 	if (i < (int)(sizeof(rfc1652_cmdtab) / sizeof(struct session_cmd))) {
502 		if (rfc1652_cmdtab[i].func(s, args))
503 			return;
504 	}
505 
506 	/* RFC 3207 - STARTTLS */
507 	for (i = 0; i < (int)(sizeof(rfc3207_cmdtab) / sizeof(struct session_cmd)); ++i)
508 		if (strcasecmp(rfc3207_cmdtab[i].name, cmd) == 0)
509 			break;
510 	if (i < (int)(sizeof(rfc3207_cmdtab) / sizeof(struct session_cmd))) {
511 		if (rfc3207_cmdtab[i].func(s, args))
512 			return;
513 	}
514 
515 	/* RFC 4954 - AUTH */
516 	if ((s->s_l->flags & F_AUTH) && (s->s_flags & F_SECURE)) {
517 		for (i = 0; i < (int)(sizeof(rfc4954_cmdtab) / sizeof(struct session_cmd)); ++i)
518 			if (strcasecmp(rfc4954_cmdtab[i].name, cmd) == 0)
519 				break;
520 		if (i < (int)(sizeof(rfc4954_cmdtab) / sizeof(struct session_cmd))) {
521 			if (rfc4954_cmdtab[i].func(s, args))
522 				return;
523 		}
524 	}
525 
526 rfc5321:
527 	/* RFC 5321 - SMTP */
528 	for (i = 0; i < (int)(sizeof(rfc5321_cmdtab) / sizeof(struct session_cmd)); ++i)
529 		if (strcasecmp(rfc5321_cmdtab[i].name, cmd) == 0)
530 			break;
531 	if (i < (int)(sizeof(rfc5321_cmdtab) / sizeof(struct session_cmd))) {
532 		if (rfc5321_cmdtab[i].func(s, args))
533 			return;
534 	}
535 
536 	session_respond(s, "500 Command unrecognized");
537 }
538 
539 void
540 session_auth_pickup(struct session *s, char *arg, size_t nr)
541 {
542 	if (s == NULL)
543 		fatal("session_pickup: desynchronized");
544 
545 	bufferevent_enable(s->s_bev, EV_READ);
546 
547 	switch (s->s_state) {
548 	case S_AUTH_INIT:
549 		session_rfc4954_auth_plain(s, arg, nr);
550 		break;
551 	case S_AUTH_USERNAME:
552 		session_rfc4954_auth_login(s, arg, nr);
553 		break;
554 	case S_AUTH_PASSWORD:
555 		session_rfc4954_auth_login(s, arg, nr);
556 		break;
557 	case S_AUTH_FINALIZE:
558 		if (s->s_flags & F_AUTHENTICATED)
559 			session_respond(s, "235 Authentication succeeded");
560 		else
561 			session_respond(s, "535 Authentication failed");
562 		s->s_state = S_HELO;
563 		break;
564 	default:
565 		fatal("session_auth_pickup: unknown state");
566 	}
567 	return;
568 }
569 
570 void
571 session_pickup(struct session *s, struct submit_status *ss)
572 {
573 	if (s == NULL)
574 		fatal("session_pickup: desynchronized");
575 
576 	bufferevent_enable(s->s_bev, EV_READ);
577 
578 	if ((ss != NULL && ss->code == 421) ||
579 	    (s->s_msg.status & S_MESSAGE_TEMPFAILURE)) {
580 		session_respond(s, "421 Service temporarily unavailable");
581 		s->s_flags |= F_QUIT;
582 		bufferevent_disable(s->s_bev, EV_READ);
583 		return;
584 	}
585 
586 	switch (s->s_state) {
587 	case S_INIT:
588 		s->s_state = S_GREETED;
589 		log_debug("session_pickup: greeting client");
590 		session_respond(s, SMTPD_BANNER, s->s_env->sc_hostname);
591 		break;
592 
593 	case S_GREETED:
594 	case S_HELO:
595 		break;
596 
597 	case S_TLS:
598 		s->s_flags |= F_EVLOCKED;
599 		bufferevent_disable(s->s_bev, EV_READ|EV_WRITE);
600 		s->s_state = S_GREETED;
601 		ssl_session_init(s);
602 		break;
603 
604 	case S_MAILREQUEST:
605 		if (ss == NULL)
606 			fatalx("bad ss at S_MAILREQUEST");
607 		/* sender was not accepted, downgrade state */
608 		if (ss->code != 250) {
609 			s->s_state = S_HELO;
610 			session_respond(s, "%d Sender rejected", ss->code);
611 			return;
612 		}
613 
614 		s->s_state = S_MAIL;
615 		s->s_msg.sender = ss->u.path;
616 
617 		session_imsg(s, PROC_QUEUE, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1,
618 		    &s->s_msg, sizeof(s->s_msg));
619 		break;
620 
621 	case S_MAIL:
622 		if (ss == NULL)
623 			fatalx("bad ss at S_MAIL");
624 		session_respond(s, "%d Sender ok", ss->code);
625 		break;
626 
627 	case S_RCPTREQUEST:
628 		if (ss == NULL)
629 			fatalx("bad ss at S_RCPTREQUEST");
630 		/* recipient was not accepted */
631 		if (ss->code != 250) {
632 			/* We do not have a valid recipient, downgrade state */
633 			if (s->rcptcount == 0)
634 				s->s_state = S_MAIL;
635 			else
636 				s->s_state = S_RCPT;
637 			session_respond(s, "%d Recipient rejected", ss->code);
638 			return;
639 		}
640 
641 		s->s_state = S_RCPT;
642 		s->rcptcount++;
643 		s->s_msg.recipient = ss->u.path;
644 
645 		session_respond(s, "%d Recipient ok", ss->code);
646 		break;
647 
648 	case S_DATAREQUEST:
649 		s->s_state = S_DATACONTENT;
650 		session_respond(s, "354 Enter mail, end with \".\" on a line by"
651 		    " itself");
652 		break;
653 
654 	case S_DONE:
655 		s->s_state = S_HELO;
656 		session_respond(s, "250 %s Message accepted for delivery",
657 		    s->s_msg.message_id);
658 		log_info("%s: from=<%s@%s>, nrcpts=%zd, proto=%s, relay=%s [%s]",
659 		    s->s_msg.message_id,
660 		    s->s_msg.sender.user,
661 		    s->s_msg.sender.domain,
662 		    s->rcptcount,
663 		    s->s_flags & F_EHLO ? "ESMTP" : "SMTP",
664 		    s->s_hostname,
665 		    ss_to_text(&s->s_ss));
666 
667 		s->s_msg.message_id[0] = '\0';
668 		s->s_msg.message_uid[0] = '\0';
669 		break;
670 
671 	default:
672 		fatal("session_pickup: unknown state");
673 	}
674 }
675 
676 void
677 session_init(struct listener *l, struct session *s)
678 {
679 	s->s_state = S_INIT;
680 
681 	if ((s->s_bev = bufferevent_new(s->s_fd, session_read, session_write,
682 	    session_error, s)) == NULL)
683 		fatalx("session_init: bufferevent_new failed");
684 
685 	bufferevent_settimeout(s->s_bev, SMTPD_SESSION_TIMEOUT, 0);
686 
687 	if (l->flags & F_SMTPS) {
688 		log_debug("session_init: initializing ssl");
689 		s->s_flags |= F_EVLOCKED;
690 		bufferevent_disable(s->s_bev, EV_READ|EV_WRITE);
691 		ssl_session_init(s);
692 		return;
693 	}
694 
695 	session_pickup(s, NULL);
696 }
697 
698 void
699 session_read(struct bufferevent *bev, void *p)
700 {
701 	struct session	*s = p;
702 	char		*line;
703 	char		*ep;
704 	char		*args;
705 	size_t		 nr;
706 
707 read:
708 	nr = EVBUFFER_LENGTH(bev->input);
709 	line = evbuffer_readline(bev->input);
710 	if (line == NULL) {
711 		if (EVBUFFER_LENGTH(bev->input) > SMTP_ANYLINE_MAX) {
712 			session_respond(s, "500 Line too long");
713 			s->s_flags |= F_QUIT;
714 			bufferevent_disable(s->s_bev, EV_READ);
715 		}
716 		return;
717 	}
718 	nr -= EVBUFFER_LENGTH(bev->input);
719 
720 	if (s->s_state == S_DATACONTENT) {
721 		if (session_read_data(s, line, nr)) {
722 			free(line);
723 			return;
724 		}
725 		free(line);
726 		goto read;
727 	}
728 
729 	if (IS_AUTH(s->s_state)) {
730 		session_auth_pickup(s, line, nr);
731 		free(line);
732 		return;
733 	}
734 
735 	if (nr > SMTP_CMDLINE_MAX) {
736 		session_respond(s, "500 Line too long");
737 		return;
738 	}
739 
740 	if ((ep = strchr(line, ':')) == NULL)
741 		ep = strchr(line, ' ');
742 	if (ep != NULL) {
743 		*ep = '\0';
744 		args = ++ep;
745 		while (isspace((int)*args))
746 			args++;
747 	} else
748 		args = NULL;
749 	log_debug("command: %s\targs: %s", line, args);
750 	session_command(s, line, args);
751 	free(line);
752 	return;
753 }
754 
755 int
756 session_read_data(struct session *s, char *line, size_t nread)
757 {
758 	size_t len;
759 	size_t i;
760 
761 	if (strcmp(line, ".") == 0) {
762 		if (! safe_fclose(s->datafp))
763 			s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
764 		s->datafp = NULL;
765 
766 		if (s->s_msg.status & S_MESSAGE_PERMFAILURE) {
767 			session_respond(s, "554 Transaction failed");
768 			s->s_state = S_HELO;
769 		} else if (s->s_msg.status & S_MESSAGE_TEMPFAILURE) {
770 			session_respond(s, "421 Temporary failure");
771 			s->s_state = S_HELO;
772 		} else {
773 			session_imsg(s, PROC_QUEUE, IMSG_QUEUE_COMMIT_MESSAGE,
774 			    0, 0, -1, &s->s_msg, sizeof(s->s_msg));
775 			s->s_state = S_DONE;
776 		}
777 
778 		return 1;
779 	}
780 
781 	/* Don't waste resources on message if it's going to bin anyway. */
782 	if (s->s_msg.status & (S_MESSAGE_PERMFAILURE|S_MESSAGE_TEMPFAILURE))
783 		return 0;
784 
785 	if (nread > SMTP_TEXTLINE_MAX) {
786 		s->s_msg.status |= S_MESSAGE_PERMFAILURE;
787 		return 0;
788 	}
789 
790 	/* "If the first character is a period and there are other characters
791 	 *  on the line, the first character is deleted." [4.5.2]
792 	 */
793 	if (*line == '.')
794 		line++;
795 
796 	len = strlen(line);
797 
798 	if (fwrite(line, len, 1, s->datafp) != 1 ||
799 	    fwrite("\n", 1, 1, s->datafp) != 1) {
800 		s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
801 		return 0;
802 	}
803 
804 	if (! (s->s_flags & F_8BITMIME)) {
805 		for (i = 0; i < len; ++i)
806 			if (line[i] & 0x80)
807 				break;
808 		if (i != len) {
809 			s->s_msg.status |= S_MESSAGE_PERMFAILURE;
810 			return 0;
811 		}
812 	}
813 
814 	return 0;
815 }
816 
817 void
818 session_write(struct bufferevent *bev, void *p)
819 {
820 	struct session	*s = p;
821 
822 	if (!(s->s_flags & F_QUIT)) {
823 
824 		if (s->s_state == S_TLS)
825 			session_pickup(s, NULL);
826 
827 		return;
828 	}
829 
830 	session_destroy(s);
831 }
832 
833 void
834 session_destroy(struct session *s)
835 {
836 	log_debug("session_destroy: killing client: %p", s);
837 
838 	if (s->datafp != NULL)
839 		fclose(s->datafp);
840 
841 	if (s->s_msg.message_id[0] != '\0' && s->s_state != S_DONE) {
842 		/*
843 		 * IMSG_QUEUE_REMOVE_MESSAGE must not be sent using session_imsg
844 		 * since no reply for it is expected.
845 		 */
846 		imsg_compose(s->s_env->sc_ibufs[PROC_QUEUE],
847 		    IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1, &s->s_msg,
848 		    sizeof(s->s_msg));
849 		s->s_msg.message_id[0] = '\0';
850 		s->s_msg.message_uid[0] = '\0';
851 	}
852 
853 	close(s->s_fd);
854 
855 	s_smtp.sessions_active--;
856 	if (s_smtp.sessions_active < s->s_env->sc_maxconn &&
857 	    !(s->s_msg.flags & F_MESSAGE_ENQUEUED))
858 		event_add(&s->s_l->ev, NULL);
859 
860 	if (s->s_bev != NULL) {
861 		bufferevent_free(s->s_bev);
862 	}
863 	ssl_session_destroy(s);
864 
865 	SPLAY_REMOVE(sessiontree, &s->s_env->sc_sessions, s);
866 	bzero(s, sizeof(*s));
867 	free(s);
868 }
869 
870 void
871 session_error(struct bufferevent *bev, short event, void *p)
872 {
873 	struct session	*s = p;
874 
875 	if (event & EVBUFFER_TIMEOUT)
876 		s_smtp.timeout++;
877 	else
878 		s_smtp.aborted++;
879 
880 	/* If events are locked, do not destroy session
881 	 * but set F_QUIT flag so that we destroy it as
882 	 * soon as the event lock is removed.
883 	 */
884 	if (s->s_flags & F_EVLOCKED) {
885 		s->s_flags |= F_QUIT;
886 		bufferevent_disable(s->s_bev, EV_READ);
887 	} else
888 		session_destroy(s);
889 }
890 
891 int
892 session_cmp(struct session *s1, struct session *s2)
893 {
894 	/*
895 	 * do not return u_int64_t's
896 	 */
897 	if (s1->s_id < s2->s_id)
898 		return (-1);
899 
900 	if (s1->s_id > s2->s_id)
901 		return (1);
902 
903 	return (0);
904 }
905 
906 int
907 session_set_path(struct path *path, char *line)
908 {
909 	size_t len;
910 
911 	len = strlen(line);
912 	if (*line != '<' || line[len - 1] != '>')
913 		return 0;
914 	line[len - 1] = '\0';
915 
916 	return recipient_to_path(path, line + 1);
917 }
918 
919 void
920 session_respond(struct session *s, char *fmt, ...)
921 {
922 	va_list ap;
923 
924 	va_start(ap, fmt);
925 	if (evbuffer_add_vprintf(EVBUFFER_OUTPUT(s->s_bev), fmt, ap) == -1 ||
926 	    evbuffer_add_printf(EVBUFFER_OUTPUT(s->s_bev), "\r\n") == -1)
927 		fatal("session_respond: evbuffer_add_vprintf failed");
928 	va_end(ap);
929 
930 	bufferevent_enable(s->s_bev, EV_WRITE);
931 }
932 
933 /*
934  * Send IMSG, waiting for reply safely.
935  */
936 void
937 session_imsg(struct session *s, enum smtp_proc_type proc, enum imsg_type type,
938     u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
939 {
940 	imsg_compose(s->s_env->sc_ibufs[proc], type, peerid, pid, fd, data,
941 	    datalen);
942 
943 	/*
944 	 * Most IMSGs require replies before session can be safely resumed.
945 	 * Ignore client events so that malicious client cannot trigger
946 	 * session_pickup at a bad time.
947 	 */
948 	bufferevent_disable(s->s_bev, EV_READ);
949 
950 	/*
951 	 * If session is unexpectedly teared down, event(3) calls session_error
952 	 * without honoring EV_READ block.
953 	 * To avoid session data being destroyed while an IMSG requiring it
954 	 * is with other process, provide a flag that session_error can use to
955 	 * determine if it is safe to destroy session data.
956 	 */
957 	if (s->s_flags & F_EVLOCKED)
958 		fatalx("session_imsg: imsg sent when another is pending");
959 	s->s_flags |= F_EVLOCKED;
960 }
961 
962 SPLAY_GENERATE(sessiontree, session, s_nodes, session_cmp);
963