1 /* $OpenBSD: smtp_session.c,v 1.443 2024/08/12 09:32:44 op Exp $ */
2
3 /*
4 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6 * Copyright (c) 2008-2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <inttypes.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <tls.h>
29 #include <unistd.h>
30 #include <vis.h>
31
32 #include "smtpd.h"
33 #include "log.h"
34 #include "rfc5322.h"
35
36 #define SMTP_LINE_MAX 65535
37 #define DATA_HIWAT 65535
38 #define APPEND_DOMAIN_BUFFER_SIZE SMTP_LINE_MAX
39
40 enum smtp_state {
41 STATE_NEW = 0,
42 STATE_CONNECTED,
43 STATE_TLS,
44 STATE_HELO,
45 STATE_AUTH_INIT,
46 STATE_AUTH_USERNAME,
47 STATE_AUTH_PASSWORD,
48 STATE_AUTH_FINALIZE,
49 STATE_BODY,
50 STATE_QUIT,
51 };
52
53 enum session_flags {
54 SF_EHLO = 0x0001,
55 SF_8BITMIME = 0x0002,
56 SF_SECURE = 0x0004,
57 SF_AUTHENTICATED = 0x0008,
58 SF_BOUNCE = 0x0010,
59 SF_VERIFIED = 0x0020,
60 SF_BADINPUT = 0x0080,
61 };
62
63 enum {
64 TX_OK = 0,
65 TX_ERROR_ENVELOPE,
66 TX_ERROR_SIZE,
67 TX_ERROR_IO,
68 TX_ERROR_LOOP,
69 TX_ERROR_MALFORMED,
70 TX_ERROR_RESOURCES,
71 TX_ERROR_INTERNAL,
72 };
73
74 enum smtp_command {
75 CMD_HELO = 0,
76 CMD_EHLO,
77 CMD_STARTTLS,
78 CMD_AUTH,
79 CMD_MAIL_FROM,
80 CMD_RCPT_TO,
81 CMD_DATA,
82 CMD_RSET,
83 CMD_QUIT,
84 CMD_HELP,
85 CMD_WIZ,
86 CMD_NOOP,
87 CMD_COMMIT,
88 };
89
90 struct smtp_rcpt {
91 TAILQ_ENTRY(smtp_rcpt) entry;
92 uint64_t evpid;
93 struct mailaddr maddr;
94 size_t destcount;
95 };
96
97 struct smtp_tx {
98 struct smtp_session *session;
99 uint32_t msgid;
100
101 struct envelope evp;
102 size_t rcptcount;
103 size_t destcount;
104 TAILQ_HEAD(, smtp_rcpt) rcpts;
105
106 time_t time;
107 int error;
108 size_t datain;
109 size_t odatalen;
110 FILE *ofile;
111 struct io *filter;
112 struct rfc5322_parser *parser;
113 int rcvcount;
114 int has_date;
115 int has_message_id;
116
117 uint8_t junk;
118 };
119
120 struct smtp_session {
121 uint64_t id;
122 struct io *io;
123 struct listener *listener;
124 void *ssl_ctx;
125 struct sockaddr_storage ss;
126 char rdns[HOST_NAME_MAX+1];
127 char smtpname[HOST_NAME_MAX+1];
128 int fcrdns;
129
130 int flags;
131 enum smtp_state state;
132
133 uint8_t banner_sent;
134 char helo[LINE_MAX];
135 char cmd[LINE_MAX];
136 char username[SMTPD_MAXMAILADDRSIZE];
137
138 size_t mailcount;
139 struct event pause;
140
141 struct smtp_tx *tx;
142
143 enum smtp_command last_cmd;
144 enum filter_phase filter_phase;
145 const char *filter_param;
146
147 uint8_t junk;
148 };
149
150 #define ADVERTISE_TLS(s) \
151 ((s)->listener->flags & F_STARTTLS && !((s)->flags & SF_SECURE))
152
153 #define ADVERTISE_AUTH(s) \
154 ((s)->listener->flags & F_AUTH && (s)->flags & SF_SECURE && \
155 !((s)->flags & SF_AUTHENTICATED))
156
157 #define ADVERTISE_EXT_DSN(s) \
158 ((s)->listener->flags & F_EXT_DSN)
159
160 #define SESSION_FILTERED(s) \
161 ((s)->listener->flags & F_FILTERED)
162
163 #define SESSION_DATA_FILTERED(s) \
164 ((s)->listener->flags & F_FILTERED)
165
166
167 static int smtp_mailaddr(struct mailaddr *, char *, int, char **, const char *);
168 static void smtp_session_init(void);
169 static void smtp_lookup_servername(struct smtp_session *);
170 static void smtp_getnameinfo_cb(void *, int, const char *, const char *);
171 static void smtp_getaddrinfo_cb(void *, int, struct addrinfo *);
172 static void smtp_connected(struct smtp_session *);
173 static void smtp_send_banner(struct smtp_session *);
174 static void smtp_tls_init(struct smtp_session *);
175 static void smtp_tls_started(struct smtp_session *);
176 static void smtp_io(struct io *, int, void *);
177 static void smtp_enter_state(struct smtp_session *, int);
178 static void smtp_reply(struct smtp_session *, char *, ...);
179 static void smtp_command(struct smtp_session *, char *);
180 static void smtp_rfc4954_auth_plain(struct smtp_session *, char *);
181 static void smtp_rfc4954_auth_login(struct smtp_session *, char *);
182 static void smtp_free(struct smtp_session *, const char *);
183 static const char *smtp_strstate(int);
184 static void smtp_auth_failure_pause(struct smtp_session *);
185 static void smtp_auth_failure_resume(int, short, void *);
186
187 static int smtp_tx(struct smtp_session *);
188 static void smtp_tx_free(struct smtp_tx *);
189 static void smtp_tx_create_message(struct smtp_tx *);
190 static void smtp_tx_mail_from(struct smtp_tx *, const char *);
191 static void smtp_tx_rcpt_to(struct smtp_tx *, const char *);
192 static void smtp_tx_open_message(struct smtp_tx *);
193 static void smtp_tx_commit(struct smtp_tx *);
194 static void smtp_tx_rollback(struct smtp_tx *);
195 static int smtp_tx_dataline(struct smtp_tx *, const char *);
196 static int smtp_tx_filtered_dataline(struct smtp_tx *, const char *);
197 static void smtp_tx_eom(struct smtp_tx *);
198 static void smtp_filter_fd(struct smtp_tx *, int);
199 static int smtp_message_fd(struct smtp_tx *, int);
200 static void smtp_message_begin(struct smtp_tx *);
201 static void smtp_message_end(struct smtp_tx *);
202 static int smtp_filter_printf(struct smtp_tx *, const char *, ...)
203 __attribute__((__format__ (printf, 2, 3)));
204 static int smtp_message_printf(struct smtp_tx *, const char *, ...)
205 __attribute__((__format__ (printf, 2, 3)));
206
207 static int smtp_check_rset(struct smtp_session *, const char *);
208 static int smtp_check_helo(struct smtp_session *, const char *);
209 static int smtp_check_ehlo(struct smtp_session *, const char *);
210 static int smtp_check_auth(struct smtp_session *s, const char *);
211 static int smtp_check_starttls(struct smtp_session *, const char *);
212 static int smtp_check_mail_from(struct smtp_session *, const char *);
213 static int smtp_check_rcpt_to(struct smtp_session *, const char *);
214 static int smtp_check_data(struct smtp_session *, const char *);
215 static int smtp_check_noop(struct smtp_session *, const char *);
216 static int smtp_check_noparam(struct smtp_session *, const char *);
217
218 static void smtp_filter_phase(enum filter_phase, struct smtp_session *, const char *);
219
220 static void smtp_proceed_connected(struct smtp_session *);
221 static void smtp_proceed_rset(struct smtp_session *, const char *);
222 static void smtp_proceed_helo(struct smtp_session *, const char *);
223 static void smtp_proceed_ehlo(struct smtp_session *, const char *);
224 static void smtp_proceed_auth(struct smtp_session *, const char *);
225 static void smtp_proceed_starttls(struct smtp_session *, const char *);
226 static void smtp_proceed_mail_from(struct smtp_session *, const char *);
227 static void smtp_proceed_rcpt_to(struct smtp_session *, const char *);
228 static void smtp_proceed_data(struct smtp_session *, const char *);
229 static void smtp_proceed_noop(struct smtp_session *, const char *);
230 static void smtp_proceed_help(struct smtp_session *, const char *);
231 static void smtp_proceed_wiz(struct smtp_session *, const char *);
232 static void smtp_proceed_quit(struct smtp_session *, const char *);
233 static void smtp_proceed_commit(struct smtp_session *, const char *);
234 static void smtp_proceed_rollback(struct smtp_session *, const char *);
235
236 static void smtp_filter_begin(struct smtp_session *);
237 static void smtp_filter_end(struct smtp_session *);
238 static void smtp_filter_data_begin(struct smtp_session *);
239 static void smtp_filter_data_end(struct smtp_session *);
240
241 static void smtp_report_link_connect(struct smtp_session *, const char *, int,
242 const struct sockaddr_storage *,
243 const struct sockaddr_storage *);
244 static void smtp_report_link_greeting(struct smtp_session *, const char *);
245 static void smtp_report_link_identify(struct smtp_session *, const char *, const char *);
246 static void smtp_report_link_tls(struct smtp_session *, const char *);
247 static void smtp_report_link_disconnect(struct smtp_session *);
248 static void smtp_report_link_auth(struct smtp_session *, const char *, const char *);
249 static void smtp_report_tx_reset(struct smtp_session *, uint32_t);
250 static void smtp_report_tx_begin(struct smtp_session *, uint32_t);
251 static void smtp_report_tx_mail(struct smtp_session *, uint32_t, const char *, int);
252 static void smtp_report_tx_rcpt(struct smtp_session *, uint32_t, const char *, int);
253 static void smtp_report_tx_envelope(struct smtp_session *, uint32_t, uint64_t);
254 static void smtp_report_tx_data(struct smtp_session *, uint32_t, int);
255 static void smtp_report_tx_commit(struct smtp_session *, uint32_t, size_t);
256 static void smtp_report_tx_rollback(struct smtp_session *, uint32_t);
257 static void smtp_report_protocol_client(struct smtp_session *, const char *);
258 static void smtp_report_protocol_server(struct smtp_session *, const char *);
259 static void smtp_report_filter_response(struct smtp_session *, int, int, const char *);
260 static void smtp_report_timeout(struct smtp_session *);
261
262
263 static struct {
264 int code;
265 enum filter_phase filter_phase;
266 const char *cmd;
267
268 int (*check)(struct smtp_session *, const char *);
269 void (*proceed)(struct smtp_session *, const char *);
270 } commands[] = {
271 { CMD_HELO, FILTER_HELO, "HELO", smtp_check_helo, smtp_proceed_helo },
272 { CMD_EHLO, FILTER_EHLO, "EHLO", smtp_check_ehlo, smtp_proceed_ehlo },
273 { CMD_STARTTLS, FILTER_STARTTLS, "STARTTLS", smtp_check_starttls, smtp_proceed_starttls },
274 { CMD_AUTH, FILTER_AUTH, "AUTH", smtp_check_auth, smtp_proceed_auth },
275 { CMD_MAIL_FROM, FILTER_MAIL_FROM, "MAIL FROM", smtp_check_mail_from, smtp_proceed_mail_from },
276 { CMD_RCPT_TO, FILTER_RCPT_TO, "RCPT TO", smtp_check_rcpt_to, smtp_proceed_rcpt_to },
277 { CMD_DATA, FILTER_DATA, "DATA", smtp_check_data, smtp_proceed_data },
278 { CMD_RSET, FILTER_RSET, "RSET", smtp_check_rset, smtp_proceed_rset },
279 { CMD_QUIT, FILTER_QUIT, "QUIT", smtp_check_noparam, smtp_proceed_quit },
280 { CMD_NOOP, FILTER_NOOP, "NOOP", smtp_check_noop, smtp_proceed_noop },
281 { CMD_HELP, FILTER_HELP, "HELP", smtp_check_noparam, smtp_proceed_help },
282 { CMD_WIZ, FILTER_WIZ, "WIZ", smtp_check_noparam, smtp_proceed_wiz },
283 { CMD_COMMIT, FILTER_COMMIT, ".", smtp_check_noparam, smtp_proceed_commit },
284 { -1, 0, NULL, NULL },
285 };
286
287 static struct tree wait_lka_helo;
288 static struct tree wait_lka_mail;
289 static struct tree wait_lka_rcpt;
290 static struct tree wait_parent_auth;
291 static struct tree wait_queue_msg;
292 static struct tree wait_queue_fd;
293 static struct tree wait_queue_commit;
294 static struct tree wait_ssl_init;
295 static struct tree wait_ssl_verify;
296 static struct tree wait_filters;
297 static struct tree wait_filter_fd;
298
299 static void
header_append_domain_buffer(char * buffer,char * domain,size_t len)300 header_append_domain_buffer(char *buffer, char *domain, size_t len)
301 {
302 size_t i;
303 int escape, quote, comment, bracket;
304 int has_domain, has_bracket, has_group;
305 int pos_bracket, pos_component, pos_insert;
306 char copy[APPEND_DOMAIN_BUFFER_SIZE];
307
308 escape = quote = comment = bracket = 0;
309 has_domain = has_bracket = has_group = 0;
310 pos_bracket = pos_insert = pos_component = 0;
311 for (i = 0; buffer[i]; ++i) {
312 if (buffer[i] == '(' && !escape && !quote)
313 comment++;
314 if (buffer[i] == '"' && !escape && !comment)
315 quote = !quote;
316 if (buffer[i] == ')' && !escape && !quote && comment)
317 comment--;
318 if (buffer[i] == '\\' && !escape && !comment && !quote)
319 escape = 1;
320 else
321 escape = 0;
322 if (buffer[i] == '<' && !escape && !comment && !quote && !bracket) {
323 bracket++;
324 has_bracket = 1;
325 }
326 if (buffer[i] == '>' && !escape && !comment && !quote && bracket) {
327 bracket--;
328 pos_bracket = i;
329 }
330 if (buffer[i] == '@' && !escape && !comment && !quote)
331 has_domain = 1;
332 if (buffer[i] == ':' && !escape && !comment && !quote)
333 has_group = 1;
334
335 /* update insert point if not in comment and not on a whitespace */
336 if (!comment && buffer[i] != ')' && !isspace((unsigned char)buffer[i]))
337 pos_component = i;
338 }
339
340 /* parse error, do not attempt to modify */
341 if (escape || quote || comment || bracket)
342 return;
343
344 /* domain already present, no need to modify */
345 if (has_domain)
346 return;
347
348 /* address is group, skip */
349 if (has_group)
350 return;
351
352 /* there's an address between brackets, just append domain */
353 if (has_bracket) {
354 pos_bracket--;
355 while (isspace((unsigned char)buffer[pos_bracket]))
356 pos_bracket--;
357 if (buffer[pos_bracket] == '<')
358 return;
359 pos_insert = pos_bracket + 1;
360 }
361 else {
362 /* otherwise append address to last component */
363 pos_insert = pos_component + 1;
364
365 /* empty address */
366 if (buffer[pos_component] == '\0' ||
367 isspace((unsigned char)buffer[pos_component]))
368 return;
369 }
370
371 if (snprintf(copy, sizeof copy, "%.*s@%s%s",
372 (int)pos_insert, buffer,
373 domain,
374 buffer+pos_insert) >= (int)sizeof copy)
375 return;
376
377 memcpy(buffer, copy, len);
378 }
379
380 static void
header_address_rewrite_buffer(char * buffer,const char * address,size_t len)381 header_address_rewrite_buffer(char *buffer, const char *address, size_t len)
382 {
383 size_t i;
384 int address_len;
385 int escape, quote, comment, bracket;
386 int has_bracket, has_group;
387 int pos_bracket_beg, pos_bracket_end, pos_component_beg, pos_component_end;
388 int insert_beg, insert_end;
389 char copy[APPEND_DOMAIN_BUFFER_SIZE];
390
391 escape = quote = comment = bracket = 0;
392 has_bracket = has_group = 0;
393 pos_bracket_beg = pos_bracket_end = pos_component_beg = pos_component_end = 0;
394 for (i = 0; buffer[i]; ++i) {
395 if (buffer[i] == '(' && !escape && !quote)
396 comment++;
397 if (buffer[i] == '"' && !escape && !comment)
398 quote = !quote;
399 if (buffer[i] == ')' && !escape && !quote && comment)
400 comment--;
401 if (buffer[i] == '\\' && !escape && !comment && !quote)
402 escape = 1;
403 else
404 escape = 0;
405 if (buffer[i] == '<' && !escape && !comment && !quote && !bracket) {
406 bracket++;
407 has_bracket = 1;
408 pos_bracket_beg = i+1;
409 }
410 if (buffer[i] == '>' && !escape && !comment && !quote && bracket) {
411 bracket--;
412 pos_bracket_end = i;
413 }
414 if (buffer[i] == ':' && !escape && !comment && !quote)
415 has_group = 1;
416
417 /* update insert point if not in comment and not on a whitespace */
418 if (!comment && buffer[i] != ')' && !isspace((unsigned char)buffer[i]))
419 pos_component_end = i;
420 }
421
422 /* parse error, do not attempt to modify */
423 if (escape || quote || comment || bracket)
424 return;
425
426 /* address is group, skip */
427 if (has_group)
428 return;
429
430 /* there's an address between brackets, just replace everything brackets */
431 if (has_bracket) {
432 insert_beg = pos_bracket_beg;
433 insert_end = pos_bracket_end;
434 }
435 else {
436 if (pos_component_end == 0)
437 pos_component_beg = 0;
438 else {
439 for (pos_component_beg = pos_component_end; pos_component_beg >= 0; --pos_component_beg)
440 if (buffer[pos_component_beg] == ')' || isspace((unsigned char)buffer[pos_component_beg]))
441 break;
442 pos_component_beg += 1;
443 pos_component_end += 1;
444 }
445 insert_beg = pos_component_beg;
446 insert_end = pos_component_end;
447 }
448
449 /* check that masquerade won' t overflow */
450 address_len = strlen(address);
451 if (strlen(buffer) - (insert_end - insert_beg) + address_len >= len)
452 return;
453
454 (void)strlcpy(copy, buffer, sizeof copy);
455 (void)strlcpy(copy+insert_beg, address, sizeof (copy) - insert_beg);
456 (void)strlcat(copy, buffer+insert_end, sizeof (copy));
457 memcpy(buffer, copy, len);
458 }
459
460 static void
header_domain_append_callback(struct smtp_tx * tx,const char * hdr,const char * val)461 header_domain_append_callback(struct smtp_tx *tx, const char *hdr,
462 const char *val)
463 {
464 size_t i, j, linelen;
465 int escape, quote, comment, skip;
466 char buffer[APPEND_DOMAIN_BUFFER_SIZE];
467 const char *line, *end;
468
469 if (smtp_message_printf(tx, "%s:", hdr) == -1)
470 return;
471
472 j = 0;
473 escape = quote = comment = skip = 0;
474 memset(buffer, 0, sizeof buffer);
475
476 for (line = val; line; line = end) {
477 end = strchr(line, '\n');
478 if (end) {
479 linelen = end - line;
480 end++;
481 }
482 else
483 linelen = strlen(line);
484
485 for (i = 0; i < linelen; ++i) {
486 if (line[i] == '(' && !escape && !quote)
487 comment++;
488 if (line[i] == '"' && !escape && !comment)
489 quote = !quote;
490 if (line[i] == ')' && !escape && !quote && comment)
491 comment--;
492 if (line[i] == '\\' && !escape && !comment)
493 escape = 1;
494 else
495 escape = 0;
496
497 /* found a separator, buffer contains a full address */
498 if (line[i] == ',' && !escape && !quote && !comment) {
499 if (!skip && j + strlen(tx->session->listener->hostname) + 1 < sizeof buffer) {
500 header_append_domain_buffer(buffer, tx->session->listener->hostname, sizeof buffer);
501 if (tx->session->flags & SF_AUTHENTICATED &&
502 tx->session->listener->sendertable[0] &&
503 tx->session->listener->flags & F_MASQUERADE &&
504 !(strcasecmp(hdr, "From")))
505 header_address_rewrite_buffer(buffer, mailaddr_to_text(&tx->evp.sender),
506 sizeof buffer);
507 }
508 if (smtp_message_printf(tx, "%s,", buffer) == -1)
509 return;
510 j = 0;
511 skip = 0;
512 memset(buffer, 0, sizeof buffer);
513 }
514 else {
515 if (skip) {
516 if (smtp_message_printf(tx, "%c", line[i]) == -1)
517 return;
518 }
519 else {
520 buffer[j++] = line[i];
521 if (j == sizeof (buffer) - 1) {
522 if (smtp_message_printf(tx, "%s", buffer) == -1)
523 return;
524 skip = 1;
525 j = 0;
526 memset(buffer, 0, sizeof buffer);
527 }
528 }
529 }
530 }
531 if (skip) {
532 if (smtp_message_printf(tx, "\n") == -1)
533 return;
534 }
535 else {
536 buffer[j++] = '\n';
537 if (j == sizeof (buffer) - 1) {
538 if (smtp_message_printf(tx, "%s", buffer) == -1)
539 return;
540 skip = 1;
541 j = 0;
542 memset(buffer, 0, sizeof buffer);
543 }
544 }
545 }
546
547 /* end of header, if buffer is not empty we'll process it */
548 if (buffer[0]) {
549 if (j + strlen(tx->session->listener->hostname) + 1 < sizeof buffer) {
550 header_append_domain_buffer(buffer, tx->session->listener->hostname, sizeof buffer);
551 if (tx->session->flags & SF_AUTHENTICATED &&
552 tx->session->listener->sendertable[0] &&
553 tx->session->listener->flags & F_MASQUERADE &&
554 !(strcasecmp(hdr, "From")))
555 header_address_rewrite_buffer(buffer, mailaddr_to_text(&tx->evp.sender),
556 sizeof buffer);
557 }
558 smtp_message_printf(tx, "%s", buffer);
559 }
560 }
561
562 static void
smtp_session_init(void)563 smtp_session_init(void)
564 {
565 static int init = 0;
566
567 if (!init) {
568 tree_init(&wait_lka_helo);
569 tree_init(&wait_lka_mail);
570 tree_init(&wait_lka_rcpt);
571 tree_init(&wait_parent_auth);
572 tree_init(&wait_queue_msg);
573 tree_init(&wait_queue_fd);
574 tree_init(&wait_queue_commit);
575 tree_init(&wait_ssl_init);
576 tree_init(&wait_ssl_verify);
577 tree_init(&wait_filters);
578 tree_init(&wait_filter_fd);
579 init = 1;
580 }
581 }
582
583 int
smtp_session(struct listener * listener,int sock,const struct sockaddr_storage * ss,const char * hostname,struct io * io)584 smtp_session(struct listener *listener, int sock,
585 const struct sockaddr_storage *ss, const char *hostname, struct io *io)
586 {
587 struct smtp_session *s;
588
589 smtp_session_init();
590
591 if ((s = calloc(1, sizeof(*s))) == NULL)
592 return (-1);
593
594 s->id = generate_uid();
595 s->listener = listener;
596 memmove(&s->ss, ss, sizeof(*ss));
597
598 if (io != NULL)
599 s->io = io;
600 else
601 s->io = io_new();
602
603 io_set_callback(s->io, smtp_io, s);
604 io_set_fd(s->io, sock);
605 io_set_timeout(s->io, SMTPD_SESSION_TIMEOUT * 1000);
606 io_set_write(s->io);
607 s->state = STATE_NEW;
608
609 (void)strlcpy(s->smtpname, listener->hostname, sizeof(s->smtpname));
610
611 log_trace(TRACE_SMTP, "smtp: %p: connected to listener %p "
612 "[hostname=%s, port=%d, tag=%s]", s, listener,
613 listener->hostname, ntohs(listener->port), listener->tag);
614
615 /* For local enqueueing, the hostname is already set */
616 if (hostname) {
617 s->flags |= SF_AUTHENTICATED;
618 /* A bit of a hack */
619 if (!strcmp(hostname, "localhost"))
620 s->flags |= SF_BOUNCE;
621 (void)strlcpy(s->rdns, hostname, sizeof(s->rdns));
622 s->fcrdns = 1;
623 smtp_lookup_servername(s);
624 } else {
625 resolver_getnameinfo((struct sockaddr *)&s->ss,
626 NI_NAMEREQD | NI_NUMERICSERV, smtp_getnameinfo_cb, s);
627 }
628
629 /* session may have been freed by now */
630
631 return (0);
632 }
633
634 static void
smtp_getnameinfo_cb(void * arg,int gaierrno,const char * host,const char * serv)635 smtp_getnameinfo_cb(void *arg, int gaierrno, const char *host, const char *serv)
636 {
637 struct smtp_session *s = arg;
638 struct addrinfo hints;
639
640 if (gaierrno) {
641 (void)strlcpy(s->rdns, "<unknown>", sizeof(s->rdns));
642
643 if (gaierrno == EAI_NODATA || gaierrno == EAI_NONAME)
644 s->fcrdns = 0;
645 else {
646 log_warnx("getnameinfo: %s: %s", ss_to_text(&s->ss),
647 gai_strerror(gaierrno));
648 s->fcrdns = -1;
649 }
650
651 smtp_lookup_servername(s);
652 return;
653 }
654
655 (void)strlcpy(s->rdns, host, sizeof(s->rdns));
656
657 memset(&hints, 0, sizeof(hints));
658 hints.ai_family = s->ss.ss_family;
659 hints.ai_socktype = SOCK_STREAM;
660 resolver_getaddrinfo(s->rdns, NULL, &hints, smtp_getaddrinfo_cb, s);
661 }
662
663 static void
smtp_getaddrinfo_cb(void * arg,int gaierrno,struct addrinfo * ai0)664 smtp_getaddrinfo_cb(void *arg, int gaierrno, struct addrinfo *ai0)
665 {
666 struct smtp_session *s = arg;
667 struct addrinfo *ai;
668 char fwd[64], rev[64];
669
670 if (gaierrno) {
671 if (gaierrno == EAI_NODATA || gaierrno == EAI_NONAME)
672 s->fcrdns = 0;
673 else {
674 log_warnx("getaddrinfo: %s: %s", s->rdns,
675 gai_strerror(gaierrno));
676 s->fcrdns = -1;
677 }
678 }
679 else {
680 strlcpy(rev, ss_to_text(&s->ss), sizeof(rev));
681 for (ai = ai0; ai; ai = ai->ai_next) {
682 strlcpy(fwd, sa_to_text(ai->ai_addr), sizeof(fwd));
683 if (!strcmp(fwd, rev)) {
684 s->fcrdns = 1;
685 break;
686 }
687 }
688 freeaddrinfo(ai0);
689 }
690
691 smtp_lookup_servername(s);
692 }
693
694 void
smtp_session_imsg(struct mproc * p,struct imsg * imsg)695 smtp_session_imsg(struct mproc *p, struct imsg *imsg)
696 {
697 struct smtp_session *s;
698 struct smtp_rcpt *rcpt;
699 char user[SMTPD_MAXMAILADDRSIZE];
700 char tmp[SMTP_LINE_MAX];
701 struct msg m;
702 const char *line, *helo;
703 uint64_t reqid, evpid;
704 uint32_t msgid;
705 int status, success, fd;
706 int filter_response;
707 const char *filter_param;
708 uint8_t i;
709
710 switch (imsg->hdr.type) {
711
712 case IMSG_SMTP_CHECK_SENDER:
713 m_msg(&m, imsg);
714 m_get_id(&m, &reqid);
715 m_get_int(&m, &status);
716 m_end(&m);
717 s = tree_xpop(&wait_lka_mail, reqid);
718 switch (status) {
719 case LKA_OK:
720 smtp_tx_create_message(s->tx);
721 break;
722
723 case LKA_PERMFAIL:
724 smtp_tx_free(s->tx);
725 smtp_reply(s, "%d %s", 530, "Sender rejected");
726 break;
727 case LKA_TEMPFAIL:
728 smtp_tx_free(s->tx);
729 smtp_reply(s, "421 %s Temporary Error",
730 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
731 break;
732 }
733 return;
734
735 case IMSG_SMTP_EXPAND_RCPT:
736 m_msg(&m, imsg);
737 m_get_id(&m, &reqid);
738 m_get_int(&m, &status);
739 m_get_string(&m, &line);
740 m_end(&m);
741 s = tree_xpop(&wait_lka_rcpt, reqid);
742
743 tmp[0] = '\0';
744 if (s->tx->evp.rcpt.user[0]) {
745 (void)strlcpy(tmp, s->tx->evp.rcpt.user, sizeof tmp);
746 if (s->tx->evp.rcpt.domain[0]) {
747 (void)strlcat(tmp, "@", sizeof tmp);
748 (void)strlcat(tmp, s->tx->evp.rcpt.domain,
749 sizeof tmp);
750 }
751 }
752
753 switch (status) {
754 case LKA_OK:
755 fatalx("unexpected ok");
756 case LKA_PERMFAIL:
757 smtp_reply(s, "%s: <%s>", line, tmp);
758 break;
759 case LKA_TEMPFAIL:
760 smtp_reply(s, "%s: <%s>", line, tmp);
761 break;
762 }
763 return;
764
765 case IMSG_SMTP_LOOKUP_HELO:
766 m_msg(&m, imsg);
767 m_get_id(&m, &reqid);
768 s = tree_xpop(&wait_lka_helo, reqid);
769 m_get_int(&m, &status);
770 if (status == LKA_OK) {
771 m_get_string(&m, &helo);
772 (void)strlcpy(s->smtpname, helo, sizeof(s->smtpname));
773 }
774 m_end(&m);
775 smtp_connected(s);
776 return;
777
778 case IMSG_SMTP_MESSAGE_CREATE:
779 m_msg(&m, imsg);
780 m_get_id(&m, &reqid);
781 m_get_int(&m, &success);
782 s = tree_xpop(&wait_queue_msg, reqid);
783 if (success) {
784 m_get_msgid(&m, &msgid);
785 s->tx->msgid = msgid;
786 s->tx->evp.id = msgid_to_evpid(msgid);
787 s->tx->rcptcount = 0;
788 smtp_reply(s, "250 %s Ok",
789 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
790 } else {
791 smtp_reply(s, "421 %s Temporary Error",
792 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
793 smtp_tx_free(s->tx);
794 smtp_enter_state(s, STATE_QUIT);
795 }
796 m_end(&m);
797 return;
798
799 case IMSG_SMTP_MESSAGE_OPEN:
800 m_msg(&m, imsg);
801 m_get_id(&m, &reqid);
802 m_get_int(&m, &success);
803 m_end(&m);
804
805 fd = imsg_get_fd(imsg);
806 s = tree_xpop(&wait_queue_fd, reqid);
807 if (!success || fd == -1) {
808 if (fd != -1)
809 close(fd);
810 smtp_reply(s, "421 %s Temporary Error",
811 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
812 smtp_enter_state(s, STATE_QUIT);
813 return;
814 }
815
816 log_debug("smtp: %p: fd %d from queue", s, fd);
817
818 if (smtp_message_fd(s->tx, fd)) {
819 if (!SESSION_DATA_FILTERED(s))
820 smtp_message_begin(s->tx);
821 else
822 smtp_filter_data_begin(s);
823 }
824 return;
825
826 case IMSG_FILTER_SMTP_DATA_BEGIN:
827 m_msg(&m, imsg);
828 m_get_id(&m, &reqid);
829 m_get_int(&m, &success);
830 m_end(&m);
831
832 fd = imsg_get_fd(imsg);
833 s = tree_xpop(&wait_filter_fd, reqid);
834 if (!success || fd == -1) {
835 if (fd != -1)
836 close(fd);
837 smtp_reply(s, "421 %s Temporary Error",
838 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
839 smtp_enter_state(s, STATE_QUIT);
840 return;
841 }
842
843 log_debug("smtp: %p: fd %d from lka", s, fd);
844
845 smtp_filter_fd(s->tx, fd);
846 smtp_message_begin(s->tx);
847 return;
848
849 case IMSG_QUEUE_ENVELOPE_SUBMIT:
850 m_msg(&m, imsg);
851 m_get_id(&m, &reqid);
852 m_get_int(&m, &success);
853 s = tree_xget(&wait_lka_rcpt, reqid);
854 if (success) {
855 m_get_evpid(&m, &evpid);
856 s->tx->evp.id = evpid;
857 s->tx->destcount++;
858 smtp_report_tx_envelope(s, s->tx->msgid, evpid);
859 }
860 else
861 s->tx->error = TX_ERROR_ENVELOPE;
862 m_end(&m);
863 return;
864
865 case IMSG_QUEUE_ENVELOPE_COMMIT:
866 m_msg(&m, imsg);
867 m_get_id(&m, &reqid);
868 m_get_int(&m, &success);
869 m_end(&m);
870 if (!success)
871 fatalx("commit evp failed: not supposed to happen");
872 s = tree_xpop(&wait_lka_rcpt, reqid);
873 if (s->tx->error) {
874 /*
875 * If an envelope failed, we can't cancel the last
876 * RCPT only so we must cancel the whole transaction
877 * and close the connection.
878 */
879 smtp_reply(s, "421 %s Temporary failure",
880 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
881 smtp_enter_state(s, STATE_QUIT);
882 }
883 else {
884 rcpt = xcalloc(1, sizeof(*rcpt));
885 rcpt->evpid = s->tx->evp.id;
886 rcpt->destcount = s->tx->destcount;
887 rcpt->maddr = s->tx->evp.rcpt;
888 TAILQ_INSERT_TAIL(&s->tx->rcpts, rcpt, entry);
889
890 s->tx->destcount = 0;
891 s->tx->rcptcount++;
892 smtp_reply(s, "250 %s %s: Recipient ok",
893 esc_code(ESC_STATUS_OK, ESC_DESTINATION_ADDRESS_VALID),
894 esc_description(ESC_DESTINATION_ADDRESS_VALID));
895 }
896 return;
897
898 case IMSG_SMTP_MESSAGE_COMMIT:
899 m_msg(&m, imsg);
900 m_get_id(&m, &reqid);
901 m_get_int(&m, &success);
902 m_end(&m);
903 s = tree_xpop(&wait_queue_commit, reqid);
904 if (!success) {
905 smtp_reply(s, "421 %s Temporary failure",
906 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
907 smtp_tx_free(s->tx);
908 smtp_enter_state(s, STATE_QUIT);
909 return;
910 }
911
912 smtp_reply(s, "250 %s %08x Message accepted for delivery",
913 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS),
914 s->tx->msgid);
915 smtp_report_tx_commit(s, s->tx->msgid, s->tx->odatalen);
916 smtp_report_tx_reset(s, s->tx->msgid);
917
918 log_info("%016"PRIx64" smtp message "
919 "msgid=%08x size=%zu nrcpt=%zu proto=%s",
920 s->id,
921 s->tx->msgid,
922 s->tx->odatalen,
923 s->tx->rcptcount,
924 s->flags & SF_EHLO ? "ESMTP" : "SMTP");
925 TAILQ_FOREACH(rcpt, &s->tx->rcpts, entry) {
926 log_info("%016"PRIx64" smtp envelope "
927 "evpid=%016"PRIx64" from=<%s%s%s> to=<%s%s%s>",
928 s->id,
929 rcpt->evpid,
930 s->tx->evp.sender.user,
931 s->tx->evp.sender.user[0] == '\0' ? "" : "@",
932 s->tx->evp.sender.domain,
933 rcpt->maddr.user,
934 rcpt->maddr.user[0] == '\0' ? "" : "@",
935 rcpt->maddr.domain);
936 }
937 smtp_tx_free(s->tx);
938 s->mailcount++;
939 smtp_enter_state(s, STATE_HELO);
940 return;
941
942 case IMSG_SMTP_AUTHENTICATE:
943 m_msg(&m, imsg);
944 m_get_id(&m, &reqid);
945 m_get_int(&m, &success);
946 m_end(&m);
947
948 s = tree_xpop(&wait_parent_auth, reqid);
949 strnvis(user, s->username, sizeof user, VIS_WHITE | VIS_SAFE);
950 if (success == LKA_OK) {
951 log_info("%016"PRIx64" smtp "
952 "authentication user=%s "
953 "result=ok",
954 s->id, user);
955 s->flags |= SF_AUTHENTICATED;
956 smtp_report_link_auth(s, user, "pass");
957 smtp_reply(s, "235 %s Authentication succeeded",
958 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
959 }
960 else if (success == LKA_PERMFAIL) {
961 log_info("%016"PRIx64" smtp "
962 "authentication user=%s "
963 "result=permfail",
964 s->id, user);
965 smtp_report_link_auth(s, user, "fail");
966 smtp_auth_failure_pause(s);
967 return;
968 }
969 else if (success == LKA_TEMPFAIL) {
970 log_info("%016"PRIx64" smtp "
971 "authentication user=%s "
972 "result=tempfail",
973 s->id, user);
974 smtp_report_link_auth(s, user, "error");
975 smtp_reply(s, "421 %s Temporary failure",
976 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
977 }
978 else
979 fatalx("bad lka response");
980
981 smtp_enter_state(s, STATE_HELO);
982 return;
983
984 case IMSG_FILTER_SMTP_PROTOCOL:
985 m_msg(&m, imsg);
986 m_get_id(&m, &reqid);
987 m_get_int(&m, &filter_response);
988 if (filter_response != FILTER_PROCEED &&
989 filter_response != FILTER_JUNK)
990 m_get_string(&m, &filter_param);
991 else
992 filter_param = NULL;
993 m_end(&m);
994
995 s = tree_xpop(&wait_filters, reqid);
996
997 switch (filter_response) {
998 case FILTER_REJECT:
999 case FILTER_DISCONNECT:
1000 if (!valid_smtp_response(filter_param) ||
1001 (filter_param[0] != '4' && filter_param[0] != '5'))
1002 filter_param = "421 Internal server error";
1003 if (!strncmp(filter_param, "421", 3))
1004 filter_response = FILTER_DISCONNECT;
1005
1006 smtp_report_filter_response(s, s->filter_phase,
1007 filter_response, filter_param);
1008
1009 smtp_reply(s, "%s", filter_param);
1010
1011 if (filter_response == FILTER_DISCONNECT)
1012 smtp_enter_state(s, STATE_QUIT);
1013 else if (s->filter_phase == FILTER_COMMIT)
1014 smtp_proceed_rollback(s, NULL);
1015 break;
1016
1017
1018 case FILTER_JUNK:
1019 if (s->tx)
1020 s->tx->junk = 1;
1021 else
1022 s->junk = 1;
1023 /* fallthrough */
1024
1025 case FILTER_PROCEED:
1026 filter_param = s->filter_param;
1027 /* fallthrough */
1028
1029 case FILTER_REPORT:
1030 case FILTER_REWRITE:
1031 smtp_report_filter_response(s, s->filter_phase,
1032 filter_response,
1033 filter_param == s->filter_param ? NULL : filter_param);
1034 if (s->filter_phase == FILTER_CONNECT) {
1035 smtp_proceed_connected(s);
1036 return;
1037 }
1038 for (i = 0; i < nitems(commands); ++i)
1039 if (commands[i].filter_phase == s->filter_phase) {
1040 if (filter_response == FILTER_REWRITE)
1041 if (!commands[i].check(s, filter_param))
1042 break;
1043 commands[i].proceed(s, filter_param);
1044 break;
1045 }
1046 break;
1047 }
1048 return;
1049 }
1050
1051 log_warnx("smtp_session_imsg: unexpected %s imsg",
1052 imsg_to_str(imsg->hdr.type));
1053 fatalx(NULL);
1054 }
1055
1056 static void
smtp_tls_init(struct smtp_session * s)1057 smtp_tls_init(struct smtp_session *s)
1058 {
1059 io_set_read(s->io);
1060 if (io_accept_tls(s->io, s->listener->tls) == -1) {
1061 log_info("%016"PRIx64" smtp disconnected "
1062 "reason=tls-accept-failed",
1063 s->id);
1064 smtp_free(s, "accept failed");
1065 }
1066 }
1067
1068 static void
smtp_tls_started(struct smtp_session * s)1069 smtp_tls_started(struct smtp_session *s)
1070 {
1071 if (tls_peer_cert_provided(io_tls(s->io))) {
1072 log_info("%016"PRIx64" smtp "
1073 "cert-check result=\"%s\" fingerprint=\"%s\"",
1074 s->id,
1075 (s->flags & SF_VERIFIED) ? "verified" : "unchecked",
1076 tls_peer_cert_hash(io_tls(s->io)));
1077 }
1078
1079 if (s->listener->flags & F_SMTPS) {
1080 stat_increment("smtp.smtps", 1);
1081 io_set_write(s->io);
1082 smtp_send_banner(s);
1083 }
1084 else {
1085 stat_increment("smtp.tls", 1);
1086 smtp_enter_state(s, STATE_HELO);
1087 }
1088 }
1089
1090 static void
smtp_io(struct io * io,int evt,void * arg)1091 smtp_io(struct io *io, int evt, void *arg)
1092 {
1093 struct smtp_session *s = arg;
1094 char *line;
1095 size_t len;
1096 int eom;
1097
1098 log_trace(TRACE_IO, "smtp: %p: %s %s", s, io_strevent(evt),
1099 io_strio(io));
1100
1101 switch (evt) {
1102
1103 case IO_TLSREADY:
1104 log_info("%016"PRIx64" smtp tls ciphers=%s",
1105 s->id, tls_to_text(io_tls(s->io)));
1106
1107 smtp_report_link_tls(s, tls_to_text(io_tls(s->io)));
1108
1109 s->flags |= SF_SECURE;
1110 if (s->listener->flags & F_TLS_VERIFY)
1111 s->flags |= SF_VERIFIED;
1112 s->helo[0] = '\0';
1113
1114 smtp_tls_started(s);
1115 break;
1116
1117 case IO_DATAIN:
1118 nextline:
1119 line = io_getline(s->io, &len);
1120 if ((line == NULL && io_datalen(s->io) >= SMTP_LINE_MAX) ||
1121 (line && len >= SMTP_LINE_MAX)) {
1122 s->flags |= SF_BADINPUT;
1123 smtp_reply(s, "500 %s Line too long",
1124 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1125 smtp_enter_state(s, STATE_QUIT);
1126 io_set_write(io);
1127 return;
1128 }
1129
1130 /* No complete line received */
1131 if (line == NULL)
1132 return;
1133
1134 /* Strip trailing '\r' */
1135 if (len && line[len - 1] == '\r')
1136 line[--len] = '\0';
1137
1138 /* Message body */
1139 eom = 0;
1140 if (s->state == STATE_BODY) {
1141 if (strcmp(line, ".")) {
1142 s->tx->datain += strlen(line) + 1;
1143 if (s->tx->datain > env->sc_maxsize)
1144 s->tx->error = TX_ERROR_SIZE;
1145 }
1146 eom = (s->tx->filter == NULL) ?
1147 smtp_tx_dataline(s->tx, line) :
1148 smtp_tx_filtered_dataline(s->tx, line);
1149 if (eom == 0)
1150 goto nextline;
1151 }
1152
1153 /* Pipelining not supported */
1154 if (io_datalen(s->io)) {
1155 s->flags |= SF_BADINPUT;
1156 smtp_reply(s, "500 %s %s: Pipelining not supported",
1157 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1158 esc_description(ESC_INVALID_COMMAND));
1159 smtp_enter_state(s, STATE_QUIT);
1160 io_set_write(io);
1161 return;
1162 }
1163
1164 if (eom) {
1165 io_set_write(io);
1166 if (s->tx->filter == NULL)
1167 smtp_tx_eom(s->tx);
1168 return;
1169 }
1170
1171 /* Must be a command */
1172 if (strlcpy(s->cmd, line, sizeof(s->cmd)) >= sizeof(s->cmd)) {
1173 s->flags |= SF_BADINPUT;
1174 smtp_reply(s, "500 %s Command line too long",
1175 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1176 smtp_enter_state(s, STATE_QUIT);
1177 io_set_write(io);
1178 return;
1179 }
1180 io_set_write(io);
1181 smtp_command(s, line);
1182 break;
1183
1184 case IO_LOWAT:
1185 if (s->state == STATE_QUIT) {
1186 log_info("%016"PRIx64" smtp disconnected "
1187 "reason=quit",
1188 s->id);
1189 smtp_free(s, "done");
1190 break;
1191 }
1192
1193 /* Wait for the client to start tls */
1194 if (s->state == STATE_TLS) {
1195 smtp_tls_init(s);
1196 break;
1197 }
1198
1199 io_set_read(io);
1200 break;
1201
1202 case IO_TIMEOUT:
1203 log_info("%016"PRIx64" smtp disconnected "
1204 "reason=timeout",
1205 s->id);
1206 smtp_report_timeout(s);
1207 smtp_free(s, "timeout");
1208 break;
1209
1210 case IO_DISCONNECTED:
1211 log_info("%016"PRIx64" smtp disconnected "
1212 "reason=disconnect",
1213 s->id);
1214 smtp_free(s, "disconnected");
1215 break;
1216
1217 case IO_ERROR:
1218 log_info("%016"PRIx64" smtp disconnected "
1219 "reason=\"io-error: %s\"",
1220 s->id, io_error(io));
1221 smtp_free(s, "IO error");
1222 break;
1223
1224 default:
1225 fatalx("smtp_io()");
1226 }
1227 }
1228
1229 static void
smtp_command(struct smtp_session * s,char * line)1230 smtp_command(struct smtp_session *s, char *line)
1231 {
1232 char *args;
1233 int cmd, i;
1234
1235 log_trace(TRACE_SMTP, "smtp: %p: <<< %s", s, line);
1236
1237 /*
1238 * These states are special.
1239 */
1240 if (s->state == STATE_AUTH_INIT) {
1241 smtp_report_protocol_client(s, "********");
1242 smtp_rfc4954_auth_plain(s, line);
1243 return;
1244 }
1245 if (s->state == STATE_AUTH_USERNAME || s->state == STATE_AUTH_PASSWORD) {
1246 smtp_report_protocol_client(s, "********");
1247 smtp_rfc4954_auth_login(s, line);
1248 return;
1249 }
1250
1251 if (s->state == STATE_HELO && strncasecmp(line, "AUTH PLAIN ", 11) == 0)
1252 smtp_report_protocol_client(s, "AUTH PLAIN ********");
1253 else
1254 smtp_report_protocol_client(s, line);
1255
1256
1257 /*
1258 * Unlike other commands, "mail from" and "rcpt to" contain a
1259 * space in the command name.
1260 */
1261 if (strncasecmp("mail from:", line, 10) == 0 ||
1262 strncasecmp("rcpt to:", line, 8) == 0)
1263 args = strchr(line, ':');
1264 else
1265 args = strchr(line, ' ');
1266
1267 if (args) {
1268 *args++ = '\0';
1269 while (isspace((unsigned char)*args))
1270 args++;
1271 }
1272
1273 cmd = -1;
1274 for (i = 0; commands[i].code != -1; i++)
1275 if (!strcasecmp(line, commands[i].cmd)) {
1276 cmd = commands[i].code;
1277 break;
1278 }
1279
1280 s->last_cmd = cmd;
1281 switch (cmd) {
1282 /*
1283 * INIT
1284 */
1285 case CMD_HELO:
1286 if (!smtp_check_helo(s, args))
1287 break;
1288 smtp_filter_phase(FILTER_HELO, s, args);
1289 break;
1290
1291 case CMD_EHLO:
1292 if (!smtp_check_ehlo(s, args))
1293 break;
1294 smtp_filter_phase(FILTER_EHLO, s, args);
1295 break;
1296
1297 /*
1298 * SETUP
1299 */
1300 case CMD_STARTTLS:
1301 if (!smtp_check_starttls(s, args))
1302 break;
1303
1304 smtp_filter_phase(FILTER_STARTTLS, s, NULL);
1305 break;
1306
1307 case CMD_AUTH:
1308 if (!smtp_check_auth(s, args))
1309 break;
1310 smtp_filter_phase(FILTER_AUTH, s, args);
1311 break;
1312
1313 case CMD_MAIL_FROM:
1314 if (!smtp_check_mail_from(s, args))
1315 break;
1316 smtp_filter_phase(FILTER_MAIL_FROM, s, args);
1317 break;
1318
1319 /*
1320 * TRANSACTION
1321 */
1322 case CMD_RCPT_TO:
1323 if (!smtp_check_rcpt_to(s, args))
1324 break;
1325 smtp_filter_phase(FILTER_RCPT_TO, s, args);
1326 break;
1327
1328 case CMD_RSET:
1329 if (!smtp_check_rset(s, args))
1330 break;
1331 smtp_filter_phase(FILTER_RSET, s, NULL);
1332 break;
1333
1334 case CMD_DATA:
1335 if (!smtp_check_data(s, args))
1336 break;
1337 smtp_filter_phase(FILTER_DATA, s, NULL);
1338 break;
1339
1340 /*
1341 * ANY
1342 */
1343 case CMD_QUIT:
1344 if (!smtp_check_noparam(s, args))
1345 break;
1346 smtp_filter_phase(FILTER_QUIT, s, NULL);
1347 break;
1348
1349 case CMD_NOOP:
1350 if (!smtp_check_noop(s, args))
1351 break;
1352 smtp_filter_phase(FILTER_NOOP, s, NULL);
1353 break;
1354
1355 case CMD_HELP:
1356 if (!smtp_check_noparam(s, args))
1357 break;
1358 smtp_proceed_help(s, NULL);
1359 break;
1360
1361 case CMD_WIZ:
1362 if (!smtp_check_noparam(s, args))
1363 break;
1364 smtp_proceed_wiz(s, NULL);
1365 break;
1366
1367 default:
1368 smtp_reply(s, "500 %s %s: Command unrecognized",
1369 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1370 esc_description(ESC_INVALID_COMMAND));
1371 break;
1372 }
1373 }
1374
1375 static int
smtp_check_rset(struct smtp_session * s,const char * args)1376 smtp_check_rset(struct smtp_session *s, const char *args)
1377 {
1378 if (!smtp_check_noparam(s, args))
1379 return 0;
1380
1381 if (s->helo[0] == '\0') {
1382 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1383 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1384 esc_description(ESC_INVALID_COMMAND));
1385 return 0;
1386 }
1387 return 1;
1388 }
1389
1390 static int
smtp_check_helo(struct smtp_session * s,const char * args)1391 smtp_check_helo(struct smtp_session *s, const char *args)
1392 {
1393 if (!s->banner_sent) {
1394 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1395 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1396 esc_description(ESC_INVALID_COMMAND));
1397 return 0;
1398 }
1399
1400 if (s->helo[0]) {
1401 smtp_reply(s, "503 %s %s: Already identified",
1402 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1403 esc_description(ESC_INVALID_COMMAND));
1404 return 0;
1405 }
1406
1407 if (args == NULL) {
1408 smtp_reply(s, "501 %s %s: HELO requires domain name",
1409 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1410 esc_description(ESC_INVALID_COMMAND));
1411 return 0;
1412 }
1413
1414 if (!valid_domainpart(args)) {
1415 smtp_reply(s, "501 %s %s: Invalid domain name",
1416 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1417 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1418 return 0;
1419 }
1420
1421 return 1;
1422 }
1423
1424 static int
smtp_check_ehlo(struct smtp_session * s,const char * args)1425 smtp_check_ehlo(struct smtp_session *s, const char *args)
1426 {
1427 if (!s->banner_sent) {
1428 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1429 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1430 esc_description(ESC_INVALID_COMMAND));
1431 return 0;
1432 }
1433
1434 if (s->helo[0]) {
1435 smtp_reply(s, "503 %s %s: Already identified",
1436 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1437 esc_description(ESC_INVALID_COMMAND));
1438 return 0;
1439 }
1440
1441 if (args == NULL) {
1442 smtp_reply(s, "501 %s %s: EHLO requires domain name",
1443 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1444 esc_description(ESC_INVALID_COMMAND));
1445 return 0;
1446 }
1447
1448 if (!valid_domainpart(args)) {
1449 smtp_reply(s, "501 %s %s: Invalid domain name",
1450 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1451 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1452 return 0;
1453 }
1454
1455 return 1;
1456 }
1457
1458 static int
smtp_check_auth(struct smtp_session * s,const char * args)1459 smtp_check_auth(struct smtp_session *s, const char *args)
1460 {
1461 if (s->helo[0] == '\0' || s->tx) {
1462 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1463 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1464 esc_description(ESC_INVALID_COMMAND));
1465 return 0;
1466 }
1467
1468 if (s->flags & SF_AUTHENTICATED) {
1469 smtp_reply(s, "503 %s %s: Already authenticated",
1470 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1471 esc_description(ESC_INVALID_COMMAND));
1472 return 0;
1473 }
1474
1475 if (!ADVERTISE_AUTH(s)) {
1476 smtp_reply(s, "503 %s %s: Command not supported",
1477 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1478 esc_description(ESC_INVALID_COMMAND));
1479 return 0;
1480 }
1481
1482 if (args == NULL) {
1483 smtp_reply(s, "501 %s %s: No parameters given",
1484 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1485 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1486 return 0;
1487 }
1488
1489 return 1;
1490 }
1491
1492 static int
smtp_check_starttls(struct smtp_session * s,const char * args)1493 smtp_check_starttls(struct smtp_session *s, const char *args)
1494 {
1495 if (s->helo[0] == '\0' || s->tx) {
1496 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1497 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1498 esc_description(ESC_INVALID_COMMAND));
1499 return 0;
1500 }
1501
1502 if (!(s->listener->flags & F_STARTTLS)) {
1503 smtp_reply(s, "503 %s %s: Command not supported",
1504 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1505 esc_description(ESC_INVALID_COMMAND));
1506 return 0;
1507 }
1508
1509 if (s->flags & SF_SECURE) {
1510 smtp_reply(s, "503 %s %s: Channel already secured",
1511 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1512 esc_description(ESC_INVALID_COMMAND));
1513 return 0;
1514 }
1515
1516 if (args != NULL) {
1517 smtp_reply(s, "501 %s %s: No parameters allowed",
1518 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1519 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1520 return 0;
1521 }
1522
1523 return 1;
1524 }
1525
1526 static int
smtp_check_mail_from(struct smtp_session * s,const char * args)1527 smtp_check_mail_from(struct smtp_session *s, const char *args)
1528 {
1529 char *copy;
1530 char tmp[SMTP_LINE_MAX];
1531 struct mailaddr sender;
1532
1533 (void)strlcpy(tmp, args, sizeof tmp);
1534 copy = tmp;
1535
1536 if (s->helo[0] == '\0' || s->tx) {
1537 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1538 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1539 esc_description(ESC_INVALID_COMMAND));
1540 return 0;
1541 }
1542
1543 if (s->listener->flags & F_STARTTLS_REQUIRE &&
1544 !(s->flags & SF_SECURE)) {
1545 smtp_reply(s,
1546 "530 %s %s: Must issue a STARTTLS command first",
1547 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1548 esc_description(ESC_INVALID_COMMAND));
1549 return 0;
1550 }
1551
1552 if (s->listener->flags & F_AUTH_REQUIRE &&
1553 !(s->flags & SF_AUTHENTICATED)) {
1554 smtp_reply(s,
1555 "530 %s %s: Must issue an AUTH command first",
1556 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1557 esc_description(ESC_INVALID_COMMAND));
1558 return 0;
1559 }
1560
1561 if (s->mailcount >= env->sc_session_max_mails) {
1562 /* we can pretend we had too many recipients */
1563 smtp_reply(s, "452 %s %s: Too many messages sent",
1564 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1565 esc_description(ESC_TOO_MANY_RECIPIENTS));
1566 return 0;
1567 }
1568
1569 if (smtp_mailaddr(&sender, copy, 1, ©,
1570 s->smtpname) == 0) {
1571 smtp_reply(s, "553 %s Sender address syntax error",
1572 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1573 return 0;
1574 }
1575
1576 return 1;
1577 }
1578
1579 static int
smtp_check_rcpt_to(struct smtp_session * s,const char * args)1580 smtp_check_rcpt_to(struct smtp_session *s, const char *args)
1581 {
1582 char *copy;
1583 char tmp[SMTP_LINE_MAX];
1584
1585 (void)strlcpy(tmp, args, sizeof tmp);
1586 copy = tmp;
1587
1588 if (s->tx == NULL) {
1589 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1590 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1591 esc_description(ESC_INVALID_COMMAND));
1592 return 0;
1593 }
1594
1595 if (s->tx->rcptcount >= env->sc_session_max_rcpt) {
1596 smtp_reply(s->tx->session, "451 %s %s: Too many recipients",
1597 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1598 esc_description(ESC_TOO_MANY_RECIPIENTS));
1599 return 0;
1600 }
1601
1602 if (smtp_mailaddr(&s->tx->evp.rcpt, copy, 0, ©,
1603 s->tx->session->smtpname) == 0) {
1604 smtp_reply(s->tx->session,
1605 "501 %s Recipient address syntax error",
1606 esc_code(ESC_STATUS_PERMFAIL,
1607 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
1608 return 0;
1609 }
1610
1611 return 1;
1612 }
1613
1614 static int
smtp_check_data(struct smtp_session * s,const char * args)1615 smtp_check_data(struct smtp_session *s, const char *args)
1616 {
1617 if (!smtp_check_noparam(s, args))
1618 return 0;
1619
1620 if (s->tx == NULL) {
1621 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1622 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1623 esc_description(ESC_INVALID_COMMAND));
1624 return 0;
1625 }
1626
1627 if (s->tx->rcptcount == 0) {
1628 smtp_reply(s, "503 %s %s: No recipient specified",
1629 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1630 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1631 return 0;
1632 }
1633
1634 return 1;
1635 }
1636
1637 static int
smtp_check_noop(struct smtp_session * s,const char * args)1638 smtp_check_noop(struct smtp_session *s, const char *args)
1639 {
1640 return 1;
1641 }
1642
1643 static int
smtp_check_noparam(struct smtp_session * s,const char * args)1644 smtp_check_noparam(struct smtp_session *s, const char *args)
1645 {
1646 if (args != NULL) {
1647 smtp_reply(s, "500 %s %s: command does not accept arguments.",
1648 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1649 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1650 return 0;
1651 }
1652 return 1;
1653 }
1654
1655 static void
smtp_query_filters(enum filter_phase phase,struct smtp_session * s,const char * args)1656 smtp_query_filters(enum filter_phase phase, struct smtp_session *s, const char *args)
1657 {
1658 m_create(p_lka, IMSG_FILTER_SMTP_PROTOCOL, 0, 0, -1);
1659 m_add_id(p_lka, s->id);
1660 m_add_int(p_lka, phase);
1661 m_add_string(p_lka, args);
1662 m_close(p_lka);
1663 tree_xset(&wait_filters, s->id, s);
1664 }
1665
1666 static void
smtp_filter_begin(struct smtp_session * s)1667 smtp_filter_begin(struct smtp_session *s)
1668 {
1669 if (!SESSION_FILTERED(s))
1670 return;
1671
1672 m_create(p_lka, IMSG_FILTER_SMTP_BEGIN, 0, 0, -1);
1673 m_add_id(p_lka, s->id);
1674 m_add_string(p_lka, s->listener->filter_name);
1675 m_close(p_lka);
1676 }
1677
1678 static void
smtp_filter_end(struct smtp_session * s)1679 smtp_filter_end(struct smtp_session *s)
1680 {
1681 if (!SESSION_FILTERED(s))
1682 return;
1683
1684 m_create(p_lka, IMSG_FILTER_SMTP_END, 0, 0, -1);
1685 m_add_id(p_lka, s->id);
1686 m_close(p_lka);
1687 }
1688
1689 static void
smtp_filter_data_begin(struct smtp_session * s)1690 smtp_filter_data_begin(struct smtp_session *s)
1691 {
1692 if (!SESSION_FILTERED(s))
1693 return;
1694
1695 m_create(p_lka, IMSG_FILTER_SMTP_DATA_BEGIN, 0, 0, -1);
1696 m_add_id(p_lka, s->id);
1697 m_close(p_lka);
1698 tree_xset(&wait_filter_fd, s->id, s);
1699 }
1700
1701 static void
smtp_filter_data_end(struct smtp_session * s)1702 smtp_filter_data_end(struct smtp_session *s)
1703 {
1704 if (!SESSION_FILTERED(s))
1705 return;
1706
1707 if (s->tx->filter == NULL)
1708 return;
1709
1710 io_free(s->tx->filter);
1711 s->tx->filter = NULL;
1712
1713 m_create(p_lka, IMSG_FILTER_SMTP_DATA_END, 0, 0, -1);
1714 m_add_id(p_lka, s->id);
1715 m_close(p_lka);
1716 }
1717
1718 static void
smtp_filter_phase(enum filter_phase phase,struct smtp_session * s,const char * param)1719 smtp_filter_phase(enum filter_phase phase, struct smtp_session *s, const char *param)
1720 {
1721 uint8_t i;
1722
1723 s->filter_phase = phase;
1724 s->filter_param = param;
1725
1726 if (SESSION_FILTERED(s)) {
1727 smtp_query_filters(phase, s, param ? param : "");
1728 return;
1729 }
1730
1731 if (s->filter_phase == FILTER_CONNECT) {
1732 smtp_proceed_connected(s);
1733 return;
1734 }
1735
1736 for (i = 0; i < nitems(commands); ++i)
1737 if (commands[i].filter_phase == s->filter_phase) {
1738 commands[i].proceed(s, param);
1739 break;
1740 }
1741 }
1742
1743 static void
smtp_proceed_rset(struct smtp_session * s,const char * args)1744 smtp_proceed_rset(struct smtp_session *s, const char *args)
1745 {
1746 smtp_reply(s, "250 %s Reset state",
1747 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1748
1749 if (s->tx) {
1750 if (s->tx->msgid)
1751 smtp_tx_rollback(s->tx);
1752 smtp_tx_free(s->tx);
1753 }
1754 }
1755
1756 static void
smtp_proceed_helo(struct smtp_session * s,const char * args)1757 smtp_proceed_helo(struct smtp_session *s, const char *args)
1758 {
1759 (void)strlcpy(s->helo, args, sizeof(s->helo));
1760 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1761
1762 smtp_report_link_identify(s, "HELO", s->helo);
1763
1764 smtp_enter_state(s, STATE_HELO);
1765
1766 smtp_reply(s, "250 %s Hello %s %s%s%s, pleased to meet you",
1767 s->smtpname,
1768 s->helo,
1769 s->ss.ss_family == AF_INET6 ? "" : "[",
1770 ss_to_text(&s->ss),
1771 s->ss.ss_family == AF_INET6 ? "" : "]");
1772 }
1773
1774 static void
smtp_proceed_ehlo(struct smtp_session * s,const char * args)1775 smtp_proceed_ehlo(struct smtp_session *s, const char *args)
1776 {
1777 (void)strlcpy(s->helo, args, sizeof(s->helo));
1778 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1779 s->flags |= SF_EHLO;
1780 s->flags |= SF_8BITMIME;
1781
1782 smtp_report_link_identify(s, "EHLO", s->helo);
1783
1784 smtp_enter_state(s, STATE_HELO);
1785 smtp_reply(s, "250-%s Hello %s %s%s%s, pleased to meet you",
1786 s->smtpname,
1787 s->helo,
1788 s->ss.ss_family == AF_INET6 ? "" : "[",
1789 ss_to_text(&s->ss),
1790 s->ss.ss_family == AF_INET6 ? "" : "]");
1791
1792 smtp_reply(s, "250-8BITMIME");
1793 smtp_reply(s, "250-ENHANCEDSTATUSCODES");
1794 smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
1795 if (ADVERTISE_EXT_DSN(s))
1796 smtp_reply(s, "250-DSN");
1797 if (ADVERTISE_TLS(s))
1798 smtp_reply(s, "250-STARTTLS");
1799 if (ADVERTISE_AUTH(s))
1800 smtp_reply(s, "250-AUTH PLAIN LOGIN");
1801 smtp_reply(s, "250 HELP");
1802 }
1803
1804 static void
smtp_proceed_auth(struct smtp_session * s,const char * args)1805 smtp_proceed_auth(struct smtp_session *s, const char *args)
1806 {
1807 char tmp[SMTP_LINE_MAX];
1808 char *eom, *method;
1809
1810 (void)strlcpy(tmp, args, sizeof tmp);
1811
1812 method = tmp;
1813 eom = strchr(tmp, ' ');
1814 if (eom == NULL)
1815 eom = strchr(tmp, '\t');
1816 if (eom != NULL)
1817 *eom++ = '\0';
1818 if (strcasecmp(method, "PLAIN") == 0)
1819 smtp_rfc4954_auth_plain(s, eom);
1820 else if (strcasecmp(method, "LOGIN") == 0)
1821 smtp_rfc4954_auth_login(s, eom);
1822 else
1823 smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
1824 esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1825 esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1826 method);
1827 }
1828
1829 static void
smtp_proceed_starttls(struct smtp_session * s,const char * args)1830 smtp_proceed_starttls(struct smtp_session *s, const char *args)
1831 {
1832 smtp_reply(s, "220 %s Ready to start TLS",
1833 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1834 smtp_enter_state(s, STATE_TLS);
1835 }
1836
1837 static void
smtp_proceed_mail_from(struct smtp_session * s,const char * args)1838 smtp_proceed_mail_from(struct smtp_session *s, const char *args)
1839 {
1840 char *copy;
1841 char tmp[SMTP_LINE_MAX];
1842
1843 (void)strlcpy(tmp, args, sizeof tmp);
1844 copy = tmp;
1845
1846 if (!smtp_tx(s)) {
1847 smtp_reply(s, "421 %s Temporary Error",
1848 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
1849 smtp_enter_state(s, STATE_QUIT);
1850 return;
1851 }
1852
1853 if (smtp_mailaddr(&s->tx->evp.sender, copy, 1, ©,
1854 s->smtpname) == 0) {
1855 smtp_reply(s, "553 %s Sender address syntax error",
1856 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1857 smtp_tx_free(s->tx);
1858 return;
1859 }
1860
1861 smtp_tx_mail_from(s->tx, args);
1862 }
1863
1864 static void
smtp_proceed_rcpt_to(struct smtp_session * s,const char * args)1865 smtp_proceed_rcpt_to(struct smtp_session *s, const char *args)
1866 {
1867 smtp_tx_rcpt_to(s->tx, args);
1868 }
1869
1870 static void
smtp_proceed_data(struct smtp_session * s,const char * args)1871 smtp_proceed_data(struct smtp_session *s, const char *args)
1872 {
1873 smtp_tx_open_message(s->tx);
1874 }
1875
1876 static void
smtp_proceed_quit(struct smtp_session * s,const char * args)1877 smtp_proceed_quit(struct smtp_session *s, const char *args)
1878 {
1879 smtp_reply(s, "221 %s Bye",
1880 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1881 smtp_enter_state(s, STATE_QUIT);
1882 }
1883
1884 static void
smtp_proceed_noop(struct smtp_session * s,const char * args)1885 smtp_proceed_noop(struct smtp_session *s, const char *args)
1886 {
1887 smtp_reply(s, "250 %s Ok",
1888 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1889 }
1890
1891 static void
smtp_proceed_help(struct smtp_session * s,const char * args)1892 smtp_proceed_help(struct smtp_session *s, const char *args)
1893 {
1894 const char *code = esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS);
1895
1896 smtp_reply(s, "214-%s This is " SMTPD_NAME, code);
1897 smtp_reply(s, "214-%s To report bugs in the implementation, "
1898 "please contact bugs@openbsd.org", code);
1899 smtp_reply(s, "214-%s with full details", code);
1900 smtp_reply(s, "214 %s End of HELP info", code);
1901 }
1902
1903 static void
smtp_proceed_wiz(struct smtp_session * s,const char * args)1904 smtp_proceed_wiz(struct smtp_session *s, const char *args)
1905 {
1906 smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
1907 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1908 esc_description(ESC_INVALID_COMMAND));
1909 }
1910
1911 static void
smtp_proceed_commit(struct smtp_session * s,const char * args)1912 smtp_proceed_commit(struct smtp_session *s, const char *args)
1913 {
1914 smtp_message_end(s->tx);
1915 }
1916
1917 static void
smtp_proceed_rollback(struct smtp_session * s,const char * args)1918 smtp_proceed_rollback(struct smtp_session *s, const char *args)
1919 {
1920 struct smtp_tx *tx;
1921
1922 tx = s->tx;
1923
1924 fclose(tx->ofile);
1925 tx->ofile = NULL;
1926
1927 smtp_tx_rollback(tx);
1928 smtp_tx_free(tx);
1929 smtp_enter_state(s, STATE_HELO);
1930 }
1931
1932 static void
smtp_rfc4954_auth_plain(struct smtp_session * s,char * arg)1933 smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg)
1934 {
1935 char buf[1024], *user, *pass;
1936 int len;
1937
1938 switch (s->state) {
1939 case STATE_HELO:
1940 if (arg == NULL) {
1941 smtp_enter_state(s, STATE_AUTH_INIT);
1942 smtp_reply(s, "334 ");
1943 return;
1944 }
1945 smtp_enter_state(s, STATE_AUTH_INIT);
1946 /* FALLTHROUGH */
1947
1948 case STATE_AUTH_INIT:
1949 /* String is not NUL terminated, leave room. */
1950 if ((len = base64_decode(arg, (unsigned char *)buf,
1951 sizeof(buf) - 1)) == -1)
1952 goto abort;
1953 /* buf is a byte string, NUL terminate. */
1954 buf[len] = '\0';
1955
1956 /*
1957 * Skip "foo" in "foo\0user\0pass", if present.
1958 */
1959 user = memchr(buf, '\0', len);
1960 if (user == NULL || user >= buf + len - 2)
1961 goto abort;
1962 user++; /* skip NUL */
1963 if (strlcpy(s->username, user, sizeof(s->username))
1964 >= sizeof(s->username))
1965 goto abort;
1966
1967 pass = memchr(user, '\0', len - (user - buf));
1968 if (pass == NULL || pass >= buf + len - 2)
1969 goto abort;
1970 pass++; /* skip NUL */
1971
1972 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
1973 m_add_id(p_lka, s->id);
1974 m_add_string(p_lka, s->listener->authtable);
1975 m_add_string(p_lka, user);
1976 m_add_string(p_lka, pass);
1977 m_close(p_lka);
1978 tree_xset(&wait_parent_auth, s->id, s);
1979 return;
1980
1981 default:
1982 fatal("smtp_rfc4954_auth_plain: unknown state");
1983 }
1984
1985 abort:
1986 smtp_reply(s, "501 %s %s: Syntax error",
1987 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
1988 esc_description(ESC_SYNTAX_ERROR));
1989 smtp_enter_state(s, STATE_HELO);
1990 }
1991
1992 static void
smtp_rfc4954_auth_login(struct smtp_session * s,char * arg)1993 smtp_rfc4954_auth_login(struct smtp_session *s, char *arg)
1994 {
1995 char buf[LINE_MAX];
1996
1997 switch (s->state) {
1998 case STATE_HELO:
1999 smtp_enter_state(s, STATE_AUTH_USERNAME);
2000 if (arg != NULL && *arg != '\0') {
2001 smtp_rfc4954_auth_login(s, arg);
2002 return;
2003 }
2004 smtp_reply(s, "334 VXNlcm5hbWU6");
2005 return;
2006
2007 case STATE_AUTH_USERNAME:
2008 memset(s->username, 0, sizeof(s->username));
2009 if (base64_decode(arg, (unsigned char *)s->username,
2010 sizeof(s->username) - 1) == -1)
2011 goto abort;
2012
2013 smtp_enter_state(s, STATE_AUTH_PASSWORD);
2014 smtp_reply(s, "334 UGFzc3dvcmQ6");
2015 return;
2016
2017 case STATE_AUTH_PASSWORD:
2018 memset(buf, 0, sizeof(buf));
2019 if (base64_decode(arg, (unsigned char *)buf,
2020 sizeof(buf)-1) == -1)
2021 goto abort;
2022
2023 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
2024 m_add_id(p_lka, s->id);
2025 m_add_string(p_lka, s->listener->authtable);
2026 m_add_string(p_lka, s->username);
2027 m_add_string(p_lka, buf);
2028 m_close(p_lka);
2029 tree_xset(&wait_parent_auth, s->id, s);
2030 return;
2031
2032 default:
2033 fatal("smtp_rfc4954_auth_login: unknown state");
2034 }
2035
2036 abort:
2037 smtp_reply(s, "501 %s %s: Syntax error",
2038 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
2039 esc_description(ESC_SYNTAX_ERROR));
2040 smtp_enter_state(s, STATE_HELO);
2041 }
2042
2043 static void
smtp_lookup_servername(struct smtp_session * s)2044 smtp_lookup_servername(struct smtp_session *s)
2045 {
2046 if (s->listener->hostnametable[0]) {
2047 m_create(p_lka, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
2048 m_add_id(p_lka, s->id);
2049 m_add_string(p_lka, s->listener->hostnametable);
2050 m_add_sockaddr(p_lka, (struct sockaddr*)&s->listener->ss);
2051 m_close(p_lka);
2052 tree_xset(&wait_lka_helo, s->id, s);
2053 return;
2054 }
2055
2056 smtp_connected(s);
2057 }
2058
2059 static void
smtp_connected(struct smtp_session * s)2060 smtp_connected(struct smtp_session *s)
2061 {
2062 smtp_enter_state(s, STATE_CONNECTED);
2063
2064 log_info("%016"PRIx64" smtp connected address=%s host=%s",
2065 s->id, ss_to_text(&s->ss), s->rdns);
2066
2067 smtp_filter_begin(s);
2068
2069 smtp_report_link_connect(s, s->rdns, s->fcrdns, &s->ss,
2070 &s->listener->ss);
2071
2072 smtp_filter_phase(FILTER_CONNECT, s, ss_to_text(&s->ss));
2073 }
2074
2075 static void
smtp_proceed_connected(struct smtp_session * s)2076 smtp_proceed_connected(struct smtp_session *s)
2077 {
2078 if (s->listener->flags & F_SMTPS)
2079 smtp_tls_init(s);
2080 else
2081 smtp_send_banner(s);
2082 }
2083
2084 static void
smtp_send_banner(struct smtp_session * s)2085 smtp_send_banner(struct smtp_session *s)
2086 {
2087 smtp_reply(s, "220 %s ESMTP %s", s->smtpname, SMTPD_NAME);
2088 s->banner_sent = 1;
2089 smtp_report_link_greeting(s, s->smtpname);
2090 }
2091
2092 void
smtp_enter_state(struct smtp_session * s,int newstate)2093 smtp_enter_state(struct smtp_session *s, int newstate)
2094 {
2095 log_trace(TRACE_SMTP, "smtp: %p: %s -> %s", s,
2096 smtp_strstate(s->state),
2097 smtp_strstate(newstate));
2098
2099 s->state = newstate;
2100 }
2101
2102 static void
smtp_reply(struct smtp_session * s,char * fmt,...)2103 smtp_reply(struct smtp_session *s, char *fmt, ...)
2104 {
2105 va_list ap;
2106 int n;
2107 char buf[LINE_MAX*2], tmp[LINE_MAX*2];
2108
2109 va_start(ap, fmt);
2110 n = vsnprintf(buf, sizeof buf, fmt, ap);
2111 va_end(ap);
2112 if (n < 0)
2113 fatalx("smtp_reply: response format error");
2114 if (n < 4)
2115 fatalx("smtp_reply: response too short");
2116 if (n >= (int)sizeof buf) {
2117 /* only first three bytes are used by SMTP logic,
2118 * so if _our_ reply does not fit entirely in the
2119 * buffer, it's ok to truncate.
2120 */
2121 }
2122
2123 log_trace(TRACE_SMTP, "smtp: %p: >>> %s", s, buf);
2124 smtp_report_protocol_server(s, buf);
2125
2126 switch (buf[0]) {
2127 case '2':
2128 if (s->tx) {
2129 if (s->last_cmd == CMD_MAIL_FROM) {
2130 smtp_report_tx_begin(s, s->tx->msgid);
2131 smtp_report_tx_mail(s, s->tx->msgid, s->cmd + 10, 1);
2132 }
2133 else if (s->last_cmd == CMD_RCPT_TO)
2134 smtp_report_tx_rcpt(s, s->tx->msgid, s->cmd + 8, 1);
2135 }
2136 break;
2137 case '3':
2138 if (s->tx) {
2139 if (s->last_cmd == CMD_DATA)
2140 smtp_report_tx_data(s, s->tx->msgid, 1);
2141 }
2142 break;
2143 case '5':
2144 case '4':
2145 /* do not report smtp_tx_mail/smtp_tx_rcpt errors
2146 * if they happened outside of a transaction.
2147 */
2148 if (s->tx) {
2149 if (s->last_cmd == CMD_MAIL_FROM)
2150 smtp_report_tx_mail(s, s->tx->msgid,
2151 s->cmd + 10, buf[0] == '4' ? -1 : 0);
2152 else if (s->last_cmd == CMD_RCPT_TO)
2153 smtp_report_tx_rcpt(s,
2154 s->tx->msgid, s->cmd + 8, buf[0] == '4' ? -1 : 0);
2155 else if (s->last_cmd == CMD_DATA && s->tx->rcptcount)
2156 smtp_report_tx_data(s, s->tx->msgid,
2157 buf[0] == '4' ? -1 : 0);
2158 }
2159
2160 if (s->flags & SF_BADINPUT) {
2161 log_info("%016"PRIx64" smtp "
2162 "bad-input result=\"%.*s\"",
2163 s->id, n, buf);
2164 }
2165 else if (s->state == STATE_AUTH_INIT) {
2166 log_info("%016"PRIx64" smtp "
2167 "failed-command "
2168 "command=\"AUTH PLAIN (...)\" result=\"%.*s\"",
2169 s->id, n, buf);
2170 }
2171 else if (s->state == STATE_AUTH_USERNAME) {
2172 log_info("%016"PRIx64" smtp "
2173 "failed-command "
2174 "command=\"AUTH LOGIN (username)\" result=\"%.*s\"",
2175 s->id, n, buf);
2176 }
2177 else if (s->state == STATE_AUTH_PASSWORD) {
2178 log_info("%016"PRIx64" smtp "
2179 "failed-command "
2180 "command=\"AUTH LOGIN (password)\" result=\"%.*s\"",
2181 s->id, n, buf);
2182 }
2183 else {
2184 strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE | VIS_CSTYLE);
2185 log_info("%016"PRIx64" smtp "
2186 "failed-command command=\"%s\" "
2187 "result=\"%.*s\"",
2188 s->id, tmp, n, buf);
2189 }
2190 break;
2191 }
2192
2193 io_xprintf(s->io, "%s\r\n", buf);
2194 }
2195
2196 static void
smtp_free(struct smtp_session * s,const char * reason)2197 smtp_free(struct smtp_session *s, const char * reason)
2198 {
2199 if (s->tx) {
2200 if (s->tx->msgid)
2201 smtp_tx_rollback(s->tx);
2202 smtp_tx_free(s->tx);
2203 }
2204
2205 smtp_report_link_disconnect(s);
2206 smtp_filter_end(s);
2207
2208 if (s->flags & SF_SECURE && s->listener->flags & F_SMTPS)
2209 stat_decrement("smtp.smtps", 1);
2210 if (s->flags & SF_SECURE && s->listener->flags & F_STARTTLS)
2211 stat_decrement("smtp.tls", 1);
2212
2213 io_free(s->io);
2214 free(s);
2215
2216 smtp_collect();
2217 }
2218
2219 static int
smtp_mailaddr(struct mailaddr * maddr,char * line,int mailfrom,char ** args,const char * domain)2220 smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args,
2221 const char *domain)
2222 {
2223 char *p, *e;
2224
2225 if (line == NULL)
2226 return (0);
2227
2228 if (*line != '<')
2229 return (0);
2230
2231 e = strchr(line, '>');
2232 if (e == NULL)
2233 return (0);
2234 *e++ = '\0';
2235 while (*e == ' ')
2236 e++;
2237 *args = e;
2238
2239 if (!text_to_mailaddr(maddr, line + 1))
2240 return (0);
2241
2242 p = strchr(maddr->user, ':');
2243 if (p != NULL) {
2244 p++;
2245 memmove(maddr->user, p, strlen(p) + 1);
2246 }
2247
2248 /* accept empty return-path in MAIL FROM, required for bounces */
2249 if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0')
2250 return (1);
2251
2252 /* no or invalid user-part, reject */
2253 if (maddr->user[0] == '\0' || !valid_localpart(maddr->user))
2254 return (0);
2255
2256 /* no domain part, local user */
2257 if (maddr->domain[0] == '\0') {
2258 (void)strlcpy(maddr->domain, domain,
2259 sizeof(maddr->domain));
2260 }
2261
2262 if (!valid_domainpart(maddr->domain))
2263 return (0);
2264
2265 return (1);
2266 }
2267
2268 static void
smtp_auth_failure_resume(int fd,short event,void * p)2269 smtp_auth_failure_resume(int fd, short event, void *p)
2270 {
2271 struct smtp_session *s = p;
2272
2273 smtp_reply(s, "535 Authentication failed");
2274 smtp_enter_state(s, STATE_HELO);
2275 }
2276
2277 static void
smtp_auth_failure_pause(struct smtp_session * s)2278 smtp_auth_failure_pause(struct smtp_session *s)
2279 {
2280 struct timeval tv;
2281
2282 tv.tv_sec = 0;
2283 tv.tv_usec = arc4random_uniform(1000000);
2284 log_trace(TRACE_SMTP, "smtp: timing-attack protection triggered, "
2285 "will defer answer for %lu microseconds", (long)tv.tv_usec);
2286 evtimer_set(&s->pause, smtp_auth_failure_resume, s);
2287 evtimer_add(&s->pause, &tv);
2288 }
2289
2290 static int
smtp_tx(struct smtp_session * s)2291 smtp_tx(struct smtp_session *s)
2292 {
2293 struct smtp_tx *tx;
2294
2295 tx = calloc(1, sizeof(*tx));
2296 if (tx == NULL)
2297 return 0;
2298
2299 TAILQ_INIT(&tx->rcpts);
2300
2301 s->tx = tx;
2302 tx->session = s;
2303
2304 /* setup the envelope */
2305 tx->evp.ss = s->ss;
2306 (void)strlcpy(tx->evp.tag, s->listener->tag, sizeof(tx->evp.tag));
2307 (void)strlcpy(tx->evp.smtpname, s->smtpname, sizeof(tx->evp.smtpname));
2308 (void)strlcpy(tx->evp.hostname, s->rdns, sizeof tx->evp.hostname);
2309 (void)strlcpy(tx->evp.helo, s->helo, sizeof(tx->evp.helo));
2310 (void)strlcpy(tx->evp.username, s->username, sizeof(tx->evp.username));
2311
2312 if (s->flags & SF_BOUNCE)
2313 tx->evp.flags |= EF_BOUNCE;
2314 if (s->flags & SF_AUTHENTICATED)
2315 tx->evp.flags |= EF_AUTHENTICATED;
2316
2317 if ((tx->parser = rfc5322_parser_new()) == NULL) {
2318 free(tx);
2319 return 0;
2320 }
2321
2322 return 1;
2323 }
2324
2325 static void
smtp_tx_free(struct smtp_tx * tx)2326 smtp_tx_free(struct smtp_tx *tx)
2327 {
2328 struct smtp_rcpt *rcpt;
2329
2330 rfc5322_free(tx->parser);
2331
2332 while ((rcpt = TAILQ_FIRST(&tx->rcpts))) {
2333 TAILQ_REMOVE(&tx->rcpts, rcpt, entry);
2334 free(rcpt);
2335 }
2336
2337 if (tx->ofile)
2338 fclose(tx->ofile);
2339
2340 tx->session->tx = NULL;
2341
2342 free(tx);
2343 }
2344
2345 static void
smtp_tx_mail_from(struct smtp_tx * tx,const char * line)2346 smtp_tx_mail_from(struct smtp_tx *tx, const char *line)
2347 {
2348 char *opt;
2349 char *copy;
2350 char tmp[SMTP_LINE_MAX];
2351
2352 (void)strlcpy(tmp, line, sizeof tmp);
2353 copy = tmp;
2354
2355 if (smtp_mailaddr(&tx->evp.sender, copy, 1, ©,
2356 tx->session->smtpname) == 0) {
2357 smtp_reply(tx->session, "553 %s Sender address syntax error",
2358 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
2359 smtp_tx_free(tx);
2360 return;
2361 }
2362
2363 while ((opt = strsep(©, " "))) {
2364 if (*opt == '\0')
2365 continue;
2366
2367 if (strncasecmp(opt, "AUTH=", 5) == 0)
2368 log_debug("debug: smtp: AUTH in MAIL FROM command");
2369 else if (strncasecmp(opt, "SIZE=", 5) == 0)
2370 log_debug("debug: smtp: SIZE in MAIL FROM command");
2371 else if (strcasecmp(opt, "BODY=7BIT") == 0)
2372 /* XXX only for this transaction */
2373 tx->session->flags &= ~SF_8BITMIME;
2374 else if (strcasecmp(opt, "BODY=8BITMIME") == 0)
2375 ;
2376 else if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "RET=", 4) == 0) {
2377 opt += 4;
2378 if (strcasecmp(opt, "HDRS") == 0)
2379 tx->evp.dsn_ret = DSN_RETHDRS;
2380 else if (strcasecmp(opt, "FULL") == 0)
2381 tx->evp.dsn_ret = DSN_RETFULL;
2382 } else if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "ENVID=", 6) == 0) {
2383 opt += 6;
2384 if (strlcpy(tx->evp.dsn_envid, opt, sizeof(tx->evp.dsn_envid))
2385 >= sizeof(tx->evp.dsn_envid)) {
2386 smtp_reply(tx->session,
2387 "503 %s %s: option too large, truncated: %s",
2388 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2389 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2390 smtp_tx_free(tx);
2391 return;
2392 }
2393 } else {
2394 smtp_reply(tx->session, "503 %s %s: Unsupported option %s",
2395 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2396 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2397 smtp_tx_free(tx);
2398 return;
2399 }
2400 }
2401
2402 /* only check sendertable if defined and user has authenticated */
2403 if (tx->session->flags & SF_AUTHENTICATED &&
2404 tx->session->listener->sendertable[0]) {
2405 m_create(p_lka, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
2406 m_add_id(p_lka, tx->session->id);
2407 m_add_string(p_lka, tx->session->listener->sendertable);
2408 m_add_string(p_lka, tx->session->username);
2409 m_add_mailaddr(p_lka, &tx->evp.sender);
2410 m_close(p_lka);
2411 tree_xset(&wait_lka_mail, tx->session->id, tx->session);
2412 }
2413 else
2414 smtp_tx_create_message(tx);
2415 }
2416
2417 static void
smtp_tx_create_message(struct smtp_tx * tx)2418 smtp_tx_create_message(struct smtp_tx *tx)
2419 {
2420 m_create(p_queue, IMSG_SMTP_MESSAGE_CREATE, 0, 0, -1);
2421 m_add_id(p_queue, tx->session->id);
2422 m_close(p_queue);
2423 tree_xset(&wait_queue_msg, tx->session->id, tx->session);
2424 }
2425
2426 static void
smtp_tx_rcpt_to(struct smtp_tx * tx,const char * line)2427 smtp_tx_rcpt_to(struct smtp_tx *tx, const char *line)
2428 {
2429 char *opt, *p;
2430 char *copy;
2431 char tmp[SMTP_LINE_MAX];
2432
2433 (void)strlcpy(tmp, line, sizeof tmp);
2434 copy = tmp;
2435
2436 if (tx->rcptcount >= env->sc_session_max_rcpt) {
2437 smtp_reply(tx->session, "451 %s %s: Too many recipients",
2438 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
2439 esc_description(ESC_TOO_MANY_RECIPIENTS));
2440 return;
2441 }
2442
2443 if (smtp_mailaddr(&tx->evp.rcpt, copy, 0, ©,
2444 tx->session->smtpname) == 0) {
2445 smtp_reply(tx->session,
2446 "501 %s Recipient address syntax error",
2447 esc_code(ESC_STATUS_PERMFAIL,
2448 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
2449 return;
2450 }
2451
2452 while ((opt = strsep(©, " "))) {
2453 if (*opt == '\0')
2454 continue;
2455
2456 if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "NOTIFY=", 7) == 0) {
2457 opt += 7;
2458 while ((p = strsep(&opt, ","))) {
2459 if (strcasecmp(p, "SUCCESS") == 0)
2460 tx->evp.dsn_notify |= DSN_SUCCESS;
2461 else if (strcasecmp(p, "FAILURE") == 0)
2462 tx->evp.dsn_notify |= DSN_FAILURE;
2463 else if (strcasecmp(p, "DELAY") == 0)
2464 tx->evp.dsn_notify |= DSN_DELAY;
2465 else if (strcasecmp(p, "NEVER") == 0)
2466 tx->evp.dsn_notify |= DSN_NEVER;
2467 }
2468
2469 if (tx->evp.dsn_notify & DSN_NEVER &&
2470 tx->evp.dsn_notify & (DSN_SUCCESS | DSN_FAILURE |
2471 DSN_DELAY)) {
2472 smtp_reply(tx->session,
2473 "553 NOTIFY option NEVER cannot be"
2474 " combined with other options");
2475 return;
2476 }
2477 } else if (ADVERTISE_EXT_DSN(tx->session) &&
2478 strncasecmp(opt, "ORCPT=", 6) == 0) {
2479 size_t len = sizeof(tx->evp.dsn_orcpt);
2480
2481 opt += 6;
2482
2483 if ((p = strchr(opt, ';')) == NULL ||
2484 !valid_xtext(p + 1) ||
2485 strlcpy(tx->evp.dsn_orcpt, opt, len) >= len) {
2486 smtp_reply(tx->session,
2487 "553 ORCPT address syntax error");
2488 return;
2489 }
2490 } else {
2491 smtp_reply(tx->session, "503 Unsupported option %s", opt);
2492 return;
2493 }
2494 }
2495
2496 m_create(p_lka, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1);
2497 m_add_id(p_lka, tx->session->id);
2498 m_add_envelope(p_lka, &tx->evp);
2499 m_close(p_lka);
2500 tree_xset(&wait_lka_rcpt, tx->session->id, tx->session);
2501 }
2502
2503 static void
smtp_tx_open_message(struct smtp_tx * tx)2504 smtp_tx_open_message(struct smtp_tx *tx)
2505 {
2506 m_create(p_queue, IMSG_SMTP_MESSAGE_OPEN, 0, 0, -1);
2507 m_add_id(p_queue, tx->session->id);
2508 m_add_msgid(p_queue, tx->msgid);
2509 m_close(p_queue);
2510 tree_xset(&wait_queue_fd, tx->session->id, tx->session);
2511 }
2512
2513 static void
smtp_tx_commit(struct smtp_tx * tx)2514 smtp_tx_commit(struct smtp_tx *tx)
2515 {
2516 m_create(p_queue, IMSG_SMTP_MESSAGE_COMMIT, 0, 0, -1);
2517 m_add_id(p_queue, tx->session->id);
2518 m_add_msgid(p_queue, tx->msgid);
2519 m_close(p_queue);
2520 tree_xset(&wait_queue_commit, tx->session->id, tx->session);
2521 smtp_filter_data_end(tx->session);
2522 }
2523
2524 static void
smtp_tx_rollback(struct smtp_tx * tx)2525 smtp_tx_rollback(struct smtp_tx *tx)
2526 {
2527 m_create(p_queue, IMSG_SMTP_MESSAGE_ROLLBACK, 0, 0, -1);
2528 m_add_msgid(p_queue, tx->msgid);
2529 m_close(p_queue);
2530 smtp_report_tx_rollback(tx->session, tx->msgid);
2531 smtp_report_tx_reset(tx->session, tx->msgid);
2532 smtp_filter_data_end(tx->session);
2533 }
2534
2535 static int
smtp_tx_dataline(struct smtp_tx * tx,const char * line)2536 smtp_tx_dataline(struct smtp_tx *tx, const char *line)
2537 {
2538 struct rfc5322_result res;
2539 int r;
2540
2541 log_trace(TRACE_SMTP, "<<< [MSG] %s", line);
2542
2543 if (!strcmp(line, ".")) {
2544 smtp_report_protocol_client(tx->session, ".");
2545 log_trace(TRACE_SMTP, "<<< [EOM]");
2546 if (tx->error)
2547 return 1;
2548 line = NULL;
2549 }
2550 else {
2551 /* ignore data line if an error is set */
2552 if (tx->error)
2553 return 0;
2554
2555 /* escape lines starting with a '.' */
2556 if (line[0] == '.')
2557 line += 1;
2558 }
2559
2560 if (rfc5322_push(tx->parser, line) == -1) {
2561 log_warnx("failed to push dataline");
2562 tx->error = TX_ERROR_INTERNAL;
2563 return 0;
2564 }
2565
2566 for(;;) {
2567 r = rfc5322_next(tx->parser, &res);
2568 switch (r) {
2569 case -1:
2570 if (errno == ENOMEM)
2571 tx->error = TX_ERROR_INTERNAL;
2572 else
2573 tx->error = TX_ERROR_MALFORMED;
2574 return 0;
2575
2576 case RFC5322_NONE:
2577 /* Need more data */
2578 return 0;
2579
2580 case RFC5322_HEADER_START:
2581 /* ignore bcc */
2582 if (!strcasecmp("Bcc", res.hdr))
2583 continue;
2584
2585 if (!strcasecmp("To", res.hdr) ||
2586 !strcasecmp("Cc", res.hdr) ||
2587 !strcasecmp("From", res.hdr)) {
2588 rfc5322_unfold_header(tx->parser);
2589 continue;
2590 }
2591
2592 if (!strcasecmp("Received", res.hdr)) {
2593 if (++tx->rcvcount >= MAX_HOPS_COUNT) {
2594 log_warnx("warn: loop detected");
2595 tx->error = TX_ERROR_LOOP;
2596 return 0;
2597 }
2598 }
2599 else if (!tx->has_date && !strcasecmp("Date", res.hdr))
2600 tx->has_date = 1;
2601 else if (!tx->has_message_id &&
2602 !strcasecmp("Message-Id", res.hdr))
2603 tx->has_message_id = 1;
2604
2605 smtp_message_printf(tx, "%s:%s\n", res.hdr, res.value);
2606 break;
2607
2608 case RFC5322_HEADER_CONT:
2609
2610 if (!strcasecmp("Bcc", res.hdr) ||
2611 !strcasecmp("To", res.hdr) ||
2612 !strcasecmp("Cc", res.hdr) ||
2613 !strcasecmp("From", res.hdr))
2614 continue;
2615
2616 smtp_message_printf(tx, "%s\n", res.value);
2617 break;
2618
2619 case RFC5322_HEADER_END:
2620 if (!strcasecmp("To", res.hdr) ||
2621 !strcasecmp("Cc", res.hdr) ||
2622 !strcasecmp("From", res.hdr))
2623 header_domain_append_callback(tx, res.hdr,
2624 res.value);
2625 break;
2626
2627 case RFC5322_END_OF_HEADERS:
2628 if (tx->session->listener->local ||
2629 tx->session->listener->port == htons(587)) {
2630
2631 if (!tx->has_date) {
2632 log_debug("debug: %p: adding Date", tx);
2633 smtp_message_printf(tx, "Date: %s\n",
2634 time_to_text(tx->time));
2635 }
2636
2637 if (!tx->has_message_id) {
2638 log_debug("debug: %p: adding Message-ID", tx);
2639 smtp_message_printf(tx,
2640 "Message-ID: <%016"PRIx64"@%s>\n",
2641 generate_uid(),
2642 tx->session->listener->hostname);
2643 }
2644 }
2645 break;
2646
2647 case RFC5322_BODY_START:
2648 case RFC5322_BODY:
2649 smtp_message_printf(tx, "%s\n", res.value);
2650 break;
2651
2652 case RFC5322_END_OF_MESSAGE:
2653 return 1;
2654
2655 default:
2656 fatalx("%s", __func__);
2657 }
2658 }
2659 }
2660
2661 static int
smtp_tx_filtered_dataline(struct smtp_tx * tx,const char * line)2662 smtp_tx_filtered_dataline(struct smtp_tx *tx, const char *line)
2663 {
2664 if (!strcmp(line, "."))
2665 line = NULL;
2666 else {
2667 /* ignore data line if an error is set */
2668 if (tx->error)
2669 return 0;
2670 }
2671 io_printf(tx->filter, "%s\n", line ? line : ".");
2672 return line ? 0 : 1;
2673 }
2674
2675 static void
smtp_tx_eom(struct smtp_tx * tx)2676 smtp_tx_eom(struct smtp_tx *tx)
2677 {
2678 smtp_filter_phase(FILTER_COMMIT, tx->session, NULL);
2679 }
2680
2681 static int
smtp_message_fd(struct smtp_tx * tx,int fd)2682 smtp_message_fd(struct smtp_tx *tx, int fd)
2683 {
2684 struct smtp_session *s;
2685
2686 s = tx->session;
2687
2688 log_debug("smtp: %p: message fd %d", s, fd);
2689
2690 if ((tx->ofile = fdopen(fd, "w")) == NULL) {
2691 close(fd);
2692 smtp_reply(s, "421 %s Temporary Error",
2693 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2694 smtp_enter_state(s, STATE_QUIT);
2695 return 0;
2696 }
2697 return 1;
2698 }
2699
2700 static void
filter_session_io(struct io * io,int evt,void * arg)2701 filter_session_io(struct io *io, int evt, void *arg)
2702 {
2703 struct smtp_tx*tx = arg;
2704 char*line = NULL;
2705 ssize_t len;
2706
2707 log_trace(TRACE_IO, "filter session io (smtp): %p: %s %s", tx, io_strevent(evt),
2708 io_strio(io));
2709
2710 switch (evt) {
2711 case IO_DATAIN:
2712 nextline:
2713 line = io_getline(tx->filter, &len);
2714 /* No complete line received */
2715 if (line == NULL)
2716 return;
2717
2718 if (smtp_tx_dataline(tx, line)) {
2719 smtp_tx_eom(tx);
2720 return;
2721 }
2722
2723 goto nextline;
2724 }
2725 }
2726
2727 static void
smtp_filter_fd(struct smtp_tx * tx,int fd)2728 smtp_filter_fd(struct smtp_tx *tx, int fd)
2729 {
2730 struct smtp_session *s;
2731
2732 s = tx->session;
2733
2734 log_debug("smtp: %p: filter fd %d", s, fd);
2735
2736 tx->filter = io_new();
2737 io_set_fd(tx->filter, fd);
2738 io_set_callback(tx->filter, filter_session_io, tx);
2739 }
2740
2741 static void
smtp_message_begin(struct smtp_tx * tx)2742 smtp_message_begin(struct smtp_tx *tx)
2743 {
2744 struct smtp_session *s;
2745 struct smtp_rcpt *rcpt;
2746 int (*m_printf)(struct smtp_tx *, const char *, ...);
2747
2748 m_printf = smtp_message_printf;
2749 if (tx->filter)
2750 m_printf = smtp_filter_printf;
2751
2752 s = tx->session;
2753
2754 log_debug("smtp: %p: message begin", s);
2755
2756 smtp_reply(s, "354 Enter mail, end with \".\""
2757 " on a line by itself");
2758
2759 if (s->junk || (s->tx && s->tx->junk))
2760 m_printf(tx, "X-Spam: Yes\n");
2761
2762 m_printf(tx, "Received: ");
2763 if (!(s->listener->flags & F_MASK_SOURCE)) {
2764 m_printf(tx, "from %s (%s %s%s%s)",
2765 s->helo,
2766 s->rdns,
2767 s->ss.ss_family == AF_INET6 ? "" : "[",
2768 ss_to_text(&s->ss),
2769 s->ss.ss_family == AF_INET6 ? "" : "]");
2770 }
2771 m_printf(tx, "\n\tby %s (%s) with %sSMTP%s%s id %08x",
2772 s->smtpname,
2773 SMTPD_NAME,
2774 s->flags & SF_EHLO ? "E" : "",
2775 s->flags & SF_SECURE ? "S" : "",
2776 s->flags & SF_AUTHENTICATED ? "A" : "",
2777 tx->msgid);
2778
2779 if (s->flags & SF_SECURE) {
2780 m_printf(tx, " (%s:%s:%d:%s)",
2781 tls_conn_version(io_tls(s->io)),
2782 tls_conn_cipher(io_tls(s->io)),
2783 tls_conn_cipher_strength(io_tls(s->io)),
2784 (s->flags & SF_VERIFIED) ? "YES" : "NO");
2785
2786 if (s->listener->flags & F_RECEIVEDAUTH) {
2787 m_printf(tx, " auth=%s",
2788 s->username[0] ? "yes" : "no");
2789 if (s->username[0])
2790 m_printf(tx, " user=%s", s->username);
2791 }
2792 }
2793
2794 if (tx->rcptcount == 1) {
2795 rcpt = TAILQ_FIRST(&tx->rcpts);
2796 m_printf(tx, "\n\tfor <%s@%s>",
2797 rcpt->maddr.user,
2798 rcpt->maddr.domain);
2799 }
2800
2801 m_printf(tx, ";\n\t%s\n", time_to_text(time(&tx->time)));
2802
2803 smtp_enter_state(s, STATE_BODY);
2804 }
2805
2806 static void
smtp_message_end(struct smtp_tx * tx)2807 smtp_message_end(struct smtp_tx *tx)
2808 {
2809 struct smtp_session *s;
2810
2811 s = tx->session;
2812
2813 log_debug("debug: %p: end of message, error=%d", s, tx->error);
2814
2815 fclose(tx->ofile);
2816 tx->ofile = NULL;
2817
2818 switch(tx->error) {
2819 case TX_OK:
2820 smtp_tx_commit(tx);
2821 return;
2822
2823 case TX_ERROR_SIZE:
2824 smtp_reply(s, "554 %s %s: Transaction failed, message too big",
2825 esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM),
2826 esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM));
2827 break;
2828
2829 case TX_ERROR_LOOP:
2830 smtp_reply(s, "500 %s %s: Loop detected",
2831 esc_code(ESC_STATUS_PERMFAIL, ESC_ROUTING_LOOP_DETECTED),
2832 esc_description(ESC_ROUTING_LOOP_DETECTED));
2833 break;
2834
2835 case TX_ERROR_MALFORMED:
2836 smtp_reply(s, "550 %s %s: Message is not RFC 2822 compliant",
2837 esc_code(ESC_STATUS_PERMFAIL, ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED),
2838 esc_description(ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED));
2839 break;
2840
2841 case TX_ERROR_IO:
2842 case TX_ERROR_RESOURCES:
2843 smtp_reply(s, "421 %s Temporary Error",
2844 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2845 break;
2846
2847 default:
2848 /* fatal? */
2849 smtp_reply(s, "421 Internal server error");
2850 }
2851
2852 smtp_tx_rollback(tx);
2853 smtp_tx_free(tx);
2854 smtp_enter_state(s, STATE_HELO);
2855 }
2856
2857 static int
smtp_filter_printf(struct smtp_tx * tx,const char * fmt,...)2858 smtp_filter_printf(struct smtp_tx *tx, const char *fmt, ...)
2859 {
2860 va_list ap;
2861 int len;
2862
2863 if (tx->error)
2864 return -1;
2865
2866 va_start(ap, fmt);
2867 len = io_vprintf(tx->filter, fmt, ap);
2868 va_end(ap);
2869
2870 if (len < 0) {
2871 log_warn("smtp-in: session %016"PRIx64": vfprintf", tx->session->id);
2872 tx->error = TX_ERROR_IO;
2873 }
2874 else
2875 tx->odatalen += len;
2876
2877 return len;
2878 }
2879
2880 static int
smtp_message_printf(struct smtp_tx * tx,const char * fmt,...)2881 smtp_message_printf(struct smtp_tx *tx, const char *fmt, ...)
2882 {
2883 va_list ap;
2884 int len;
2885
2886 if (tx->error)
2887 return -1;
2888
2889 va_start(ap, fmt);
2890 len = vfprintf(tx->ofile, fmt, ap);
2891 va_end(ap);
2892
2893 if (len == -1) {
2894 log_warn("smtp-in: session %016"PRIx64": vfprintf", tx->session->id);
2895 tx->error = TX_ERROR_IO;
2896 }
2897 else
2898 tx->odatalen += len;
2899
2900 return len;
2901 }
2902
2903 #define CASE(x) case x : return #x
2904
2905 const char *
smtp_strstate(int state)2906 smtp_strstate(int state)
2907 {
2908 static char buf[32];
2909
2910 switch (state) {
2911 CASE(STATE_NEW);
2912 CASE(STATE_CONNECTED);
2913 CASE(STATE_TLS);
2914 CASE(STATE_HELO);
2915 CASE(STATE_AUTH_INIT);
2916 CASE(STATE_AUTH_USERNAME);
2917 CASE(STATE_AUTH_PASSWORD);
2918 CASE(STATE_AUTH_FINALIZE);
2919 CASE(STATE_BODY);
2920 CASE(STATE_QUIT);
2921 default:
2922 (void)snprintf(buf, sizeof(buf), "STATE_??? (%d)", state);
2923 return (buf);
2924 }
2925 }
2926
2927
2928 static void
smtp_report_link_connect(struct smtp_session * s,const char * rdns,int fcrdns,const struct sockaddr_storage * ss_src,const struct sockaddr_storage * ss_dest)2929 smtp_report_link_connect(struct smtp_session *s, const char *rdns, int fcrdns,
2930 const struct sockaddr_storage *ss_src,
2931 const struct sockaddr_storage *ss_dest)
2932 {
2933 if (! SESSION_FILTERED(s))
2934 return;
2935
2936 report_smtp_link_connect("smtp-in", s->id, rdns, fcrdns, ss_src, ss_dest);
2937 }
2938
2939 static void
smtp_report_link_greeting(struct smtp_session * s,const char * domain)2940 smtp_report_link_greeting(struct smtp_session *s,
2941 const char *domain)
2942 {
2943 if (! SESSION_FILTERED(s))
2944 return;
2945
2946 report_smtp_link_greeting("smtp-in", s->id, domain);
2947 }
2948
2949 static void
smtp_report_link_identify(struct smtp_session * s,const char * method,const char * identity)2950 smtp_report_link_identify(struct smtp_session *s, const char *method, const char *identity)
2951 {
2952 if (! SESSION_FILTERED(s))
2953 return;
2954
2955 report_smtp_link_identify("smtp-in", s->id, method, identity);
2956 }
2957
2958 static void
smtp_report_link_tls(struct smtp_session * s,const char * ssl)2959 smtp_report_link_tls(struct smtp_session *s, const char *ssl)
2960 {
2961 if (! SESSION_FILTERED(s))
2962 return;
2963
2964 report_smtp_link_tls("smtp-in", s->id, ssl);
2965 }
2966
2967 static void
smtp_report_link_disconnect(struct smtp_session * s)2968 smtp_report_link_disconnect(struct smtp_session *s)
2969 {
2970 if (! SESSION_FILTERED(s))
2971 return;
2972
2973 report_smtp_link_disconnect("smtp-in", s->id);
2974 }
2975
2976 static void
smtp_report_link_auth(struct smtp_session * s,const char * user,const char * result)2977 smtp_report_link_auth(struct smtp_session *s, const char *user, const char *result)
2978 {
2979 if (! SESSION_FILTERED(s))
2980 return;
2981
2982 report_smtp_link_auth("smtp-in", s->id, user, result);
2983 }
2984
2985 static void
smtp_report_tx_reset(struct smtp_session * s,uint32_t msgid)2986 smtp_report_tx_reset(struct smtp_session *s, uint32_t msgid)
2987 {
2988 if (! SESSION_FILTERED(s))
2989 return;
2990
2991 report_smtp_tx_reset("smtp-in", s->id, msgid);
2992 }
2993
2994 static void
smtp_report_tx_begin(struct smtp_session * s,uint32_t msgid)2995 smtp_report_tx_begin(struct smtp_session *s, uint32_t msgid)
2996 {
2997 if (! SESSION_FILTERED(s))
2998 return;
2999
3000 report_smtp_tx_begin("smtp-in", s->id, msgid);
3001 }
3002
3003 static void
smtp_report_tx_mail(struct smtp_session * s,uint32_t msgid,const char * address,int ok)3004 smtp_report_tx_mail(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3005 {
3006 char mailaddr[SMTPD_MAXMAILADDRSIZE];
3007 char *p;
3008
3009 if (! SESSION_FILTERED(s))
3010 return;
3011
3012 if ((p = strchr(address, '<')) == NULL)
3013 return;
3014 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3015 if ((p = strchr(mailaddr, '>')) == NULL)
3016 return;
3017 *p = '\0';
3018
3019 report_smtp_tx_mail("smtp-in", s->id, msgid, mailaddr, ok);
3020 }
3021
3022 static void
smtp_report_tx_rcpt(struct smtp_session * s,uint32_t msgid,const char * address,int ok)3023 smtp_report_tx_rcpt(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3024 {
3025 char mailaddr[SMTPD_MAXMAILADDRSIZE];
3026 char *p;
3027
3028 if (! SESSION_FILTERED(s))
3029 return;
3030
3031 if ((p = strchr(address, '<')) == NULL)
3032 return;
3033 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3034 if ((p = strchr(mailaddr, '>')) == NULL)
3035 return;
3036 *p = '\0';
3037
3038 report_smtp_tx_rcpt("smtp-in", s->id, msgid, mailaddr, ok);
3039 }
3040
3041 static void
smtp_report_tx_envelope(struct smtp_session * s,uint32_t msgid,uint64_t evpid)3042 smtp_report_tx_envelope(struct smtp_session *s, uint32_t msgid, uint64_t evpid)
3043 {
3044 if (! SESSION_FILTERED(s))
3045 return;
3046
3047 report_smtp_tx_envelope("smtp-in", s->id, msgid, evpid);
3048 }
3049
3050 static void
smtp_report_tx_data(struct smtp_session * s,uint32_t msgid,int ok)3051 smtp_report_tx_data(struct smtp_session *s, uint32_t msgid, int ok)
3052 {
3053 if (! SESSION_FILTERED(s))
3054 return;
3055
3056 report_smtp_tx_data("smtp-in", s->id, msgid, ok);
3057 }
3058
3059 static void
smtp_report_tx_commit(struct smtp_session * s,uint32_t msgid,size_t msgsz)3060 smtp_report_tx_commit(struct smtp_session *s, uint32_t msgid, size_t msgsz)
3061 {
3062 if (! SESSION_FILTERED(s))
3063 return;
3064
3065 report_smtp_tx_commit("smtp-in", s->id, msgid, msgsz);
3066 }
3067
3068 static void
smtp_report_tx_rollback(struct smtp_session * s,uint32_t msgid)3069 smtp_report_tx_rollback(struct smtp_session *s, uint32_t msgid)
3070 {
3071 if (! SESSION_FILTERED(s))
3072 return;
3073
3074 report_smtp_tx_rollback("smtp-in", s->id, msgid);
3075 }
3076
3077 static void
smtp_report_protocol_client(struct smtp_session * s,const char * command)3078 smtp_report_protocol_client(struct smtp_session *s, const char *command)
3079 {
3080 if (! SESSION_FILTERED(s))
3081 return;
3082
3083 report_smtp_protocol_client("smtp-in", s->id, command);
3084 }
3085
3086 static void
smtp_report_protocol_server(struct smtp_session * s,const char * response)3087 smtp_report_protocol_server(struct smtp_session *s, const char *response)
3088 {
3089 if (! SESSION_FILTERED(s))
3090 return;
3091
3092 report_smtp_protocol_server("smtp-in", s->id, response);
3093 }
3094
3095 static void
smtp_report_filter_response(struct smtp_session * s,int phase,int response,const char * param)3096 smtp_report_filter_response(struct smtp_session *s, int phase, int response, const char *param)
3097 {
3098 if (! SESSION_FILTERED(s))
3099 return;
3100
3101 report_smtp_filter_response("smtp-in", s->id, phase, response, param);
3102 }
3103
3104 static void
smtp_report_timeout(struct smtp_session * s)3105 smtp_report_timeout(struct smtp_session *s)
3106 {
3107 if (! SESSION_FILTERED(s))
3108 return;
3109
3110 report_smtp_timeout("smtp-in", s->id);
3111 }
3112