1 /* $OpenBSD: smtp_session.c,v 1.442 2024/03/20 17:52:43 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_REWRITE:
1030 smtp_report_filter_response(s, s->filter_phase,
1031 filter_response,
1032 filter_param == s->filter_param ? NULL : filter_param);
1033 if (s->filter_phase == FILTER_CONNECT) {
1034 smtp_proceed_connected(s);
1035 return;
1036 }
1037 for (i = 0; i < nitems(commands); ++i)
1038 if (commands[i].filter_phase == s->filter_phase) {
1039 if (filter_response == FILTER_REWRITE)
1040 if (!commands[i].check(s, filter_param))
1041 break;
1042 commands[i].proceed(s, filter_param);
1043 break;
1044 }
1045 break;
1046 }
1047 return;
1048 }
1049
1050 log_warnx("smtp_session_imsg: unexpected %s imsg",
1051 imsg_to_str(imsg->hdr.type));
1052 fatalx(NULL);
1053 }
1054
1055 static void
smtp_tls_init(struct smtp_session * s)1056 smtp_tls_init(struct smtp_session *s)
1057 {
1058 io_set_read(s->io);
1059 if (io_accept_tls(s->io, s->listener->tls) == -1) {
1060 log_info("%016"PRIx64" smtp disconnected "
1061 "reason=tls-accept-failed",
1062 s->id);
1063 smtp_free(s, "accept failed");
1064 }
1065 }
1066
1067 static void
smtp_tls_started(struct smtp_session * s)1068 smtp_tls_started(struct smtp_session *s)
1069 {
1070 if (tls_peer_cert_provided(io_tls(s->io))) {
1071 log_info("%016"PRIx64" smtp "
1072 "cert-check result=\"%s\" fingerprint=\"%s\"",
1073 s->id,
1074 (s->flags & SF_VERIFIED) ? "verified" : "unchecked",
1075 tls_peer_cert_hash(io_tls(s->io)));
1076 }
1077
1078 if (s->listener->flags & F_SMTPS) {
1079 stat_increment("smtp.smtps", 1);
1080 io_set_write(s->io);
1081 smtp_send_banner(s);
1082 }
1083 else {
1084 stat_increment("smtp.tls", 1);
1085 smtp_enter_state(s, STATE_HELO);
1086 }
1087 }
1088
1089 static void
smtp_io(struct io * io,int evt,void * arg)1090 smtp_io(struct io *io, int evt, void *arg)
1091 {
1092 struct smtp_session *s = arg;
1093 char *line;
1094 size_t len;
1095 int eom;
1096
1097 log_trace(TRACE_IO, "smtp: %p: %s %s", s, io_strevent(evt),
1098 io_strio(io));
1099
1100 switch (evt) {
1101
1102 case IO_TLSREADY:
1103 log_info("%016"PRIx64" smtp tls ciphers=%s",
1104 s->id, tls_to_text(io_tls(s->io)));
1105
1106 smtp_report_link_tls(s, tls_to_text(io_tls(s->io)));
1107
1108 s->flags |= SF_SECURE;
1109 if (s->listener->flags & F_TLS_VERIFY)
1110 s->flags |= SF_VERIFIED;
1111 s->helo[0] = '\0';
1112
1113 smtp_tls_started(s);
1114 break;
1115
1116 case IO_DATAIN:
1117 nextline:
1118 line = io_getline(s->io, &len);
1119 if ((line == NULL && io_datalen(s->io) >= SMTP_LINE_MAX) ||
1120 (line && len >= SMTP_LINE_MAX)) {
1121 s->flags |= SF_BADINPUT;
1122 smtp_reply(s, "500 %s Line too long",
1123 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1124 smtp_enter_state(s, STATE_QUIT);
1125 io_set_write(io);
1126 return;
1127 }
1128
1129 /* No complete line received */
1130 if (line == NULL)
1131 return;
1132
1133 /* Strip trailing '\r' */
1134 if (len && line[len - 1] == '\r')
1135 line[--len] = '\0';
1136
1137 /* Message body */
1138 eom = 0;
1139 if (s->state == STATE_BODY) {
1140 if (strcmp(line, ".")) {
1141 s->tx->datain += strlen(line) + 1;
1142 if (s->tx->datain > env->sc_maxsize)
1143 s->tx->error = TX_ERROR_SIZE;
1144 }
1145 eom = (s->tx->filter == NULL) ?
1146 smtp_tx_dataline(s->tx, line) :
1147 smtp_tx_filtered_dataline(s->tx, line);
1148 if (eom == 0)
1149 goto nextline;
1150 }
1151
1152 /* Pipelining not supported */
1153 if (io_datalen(s->io)) {
1154 s->flags |= SF_BADINPUT;
1155 smtp_reply(s, "500 %s %s: Pipelining not supported",
1156 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1157 esc_description(ESC_INVALID_COMMAND));
1158 smtp_enter_state(s, STATE_QUIT);
1159 io_set_write(io);
1160 return;
1161 }
1162
1163 if (eom) {
1164 io_set_write(io);
1165 if (s->tx->filter == NULL)
1166 smtp_tx_eom(s->tx);
1167 return;
1168 }
1169
1170 /* Must be a command */
1171 if (strlcpy(s->cmd, line, sizeof(s->cmd)) >= sizeof(s->cmd)) {
1172 s->flags |= SF_BADINPUT;
1173 smtp_reply(s, "500 %s Command line too long",
1174 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1175 smtp_enter_state(s, STATE_QUIT);
1176 io_set_write(io);
1177 return;
1178 }
1179 io_set_write(io);
1180 smtp_command(s, line);
1181 break;
1182
1183 case IO_LOWAT:
1184 if (s->state == STATE_QUIT) {
1185 log_info("%016"PRIx64" smtp disconnected "
1186 "reason=quit",
1187 s->id);
1188 smtp_free(s, "done");
1189 break;
1190 }
1191
1192 /* Wait for the client to start tls */
1193 if (s->state == STATE_TLS) {
1194 smtp_tls_init(s);
1195 break;
1196 }
1197
1198 io_set_read(io);
1199 break;
1200
1201 case IO_TIMEOUT:
1202 log_info("%016"PRIx64" smtp disconnected "
1203 "reason=timeout",
1204 s->id);
1205 smtp_report_timeout(s);
1206 smtp_free(s, "timeout");
1207 break;
1208
1209 case IO_DISCONNECTED:
1210 log_info("%016"PRIx64" smtp disconnected "
1211 "reason=disconnect",
1212 s->id);
1213 smtp_free(s, "disconnected");
1214 break;
1215
1216 case IO_ERROR:
1217 log_info("%016"PRIx64" smtp disconnected "
1218 "reason=\"io-error: %s\"",
1219 s->id, io_error(io));
1220 smtp_free(s, "IO error");
1221 break;
1222
1223 default:
1224 fatalx("smtp_io()");
1225 }
1226 }
1227
1228 static void
smtp_command(struct smtp_session * s,char * line)1229 smtp_command(struct smtp_session *s, char *line)
1230 {
1231 char *args;
1232 int cmd, i;
1233
1234 log_trace(TRACE_SMTP, "smtp: %p: <<< %s", s, line);
1235
1236 /*
1237 * These states are special.
1238 */
1239 if (s->state == STATE_AUTH_INIT) {
1240 smtp_report_protocol_client(s, "********");
1241 smtp_rfc4954_auth_plain(s, line);
1242 return;
1243 }
1244 if (s->state == STATE_AUTH_USERNAME || s->state == STATE_AUTH_PASSWORD) {
1245 smtp_report_protocol_client(s, "********");
1246 smtp_rfc4954_auth_login(s, line);
1247 return;
1248 }
1249
1250 if (s->state == STATE_HELO && strncasecmp(line, "AUTH PLAIN ", 11) == 0)
1251 smtp_report_protocol_client(s, "AUTH PLAIN ********");
1252 else
1253 smtp_report_protocol_client(s, line);
1254
1255
1256 /*
1257 * Unlike other commands, "mail from" and "rcpt to" contain a
1258 * space in the command name.
1259 */
1260 if (strncasecmp("mail from:", line, 10) == 0 ||
1261 strncasecmp("rcpt to:", line, 8) == 0)
1262 args = strchr(line, ':');
1263 else
1264 args = strchr(line, ' ');
1265
1266 if (args) {
1267 *args++ = '\0';
1268 while (isspace((unsigned char)*args))
1269 args++;
1270 }
1271
1272 cmd = -1;
1273 for (i = 0; commands[i].code != -1; i++)
1274 if (!strcasecmp(line, commands[i].cmd)) {
1275 cmd = commands[i].code;
1276 break;
1277 }
1278
1279 s->last_cmd = cmd;
1280 switch (cmd) {
1281 /*
1282 * INIT
1283 */
1284 case CMD_HELO:
1285 if (!smtp_check_helo(s, args))
1286 break;
1287 smtp_filter_phase(FILTER_HELO, s, args);
1288 break;
1289
1290 case CMD_EHLO:
1291 if (!smtp_check_ehlo(s, args))
1292 break;
1293 smtp_filter_phase(FILTER_EHLO, s, args);
1294 break;
1295
1296 /*
1297 * SETUP
1298 */
1299 case CMD_STARTTLS:
1300 if (!smtp_check_starttls(s, args))
1301 break;
1302
1303 smtp_filter_phase(FILTER_STARTTLS, s, NULL);
1304 break;
1305
1306 case CMD_AUTH:
1307 if (!smtp_check_auth(s, args))
1308 break;
1309 smtp_filter_phase(FILTER_AUTH, s, args);
1310 break;
1311
1312 case CMD_MAIL_FROM:
1313 if (!smtp_check_mail_from(s, args))
1314 break;
1315 smtp_filter_phase(FILTER_MAIL_FROM, s, args);
1316 break;
1317
1318 /*
1319 * TRANSACTION
1320 */
1321 case CMD_RCPT_TO:
1322 if (!smtp_check_rcpt_to(s, args))
1323 break;
1324 smtp_filter_phase(FILTER_RCPT_TO, s, args);
1325 break;
1326
1327 case CMD_RSET:
1328 if (!smtp_check_rset(s, args))
1329 break;
1330 smtp_filter_phase(FILTER_RSET, s, NULL);
1331 break;
1332
1333 case CMD_DATA:
1334 if (!smtp_check_data(s, args))
1335 break;
1336 smtp_filter_phase(FILTER_DATA, s, NULL);
1337 break;
1338
1339 /*
1340 * ANY
1341 */
1342 case CMD_QUIT:
1343 if (!smtp_check_noparam(s, args))
1344 break;
1345 smtp_filter_phase(FILTER_QUIT, s, NULL);
1346 break;
1347
1348 case CMD_NOOP:
1349 if (!smtp_check_noop(s, args))
1350 break;
1351 smtp_filter_phase(FILTER_NOOP, s, NULL);
1352 break;
1353
1354 case CMD_HELP:
1355 if (!smtp_check_noparam(s, args))
1356 break;
1357 smtp_proceed_help(s, NULL);
1358 break;
1359
1360 case CMD_WIZ:
1361 if (!smtp_check_noparam(s, args))
1362 break;
1363 smtp_proceed_wiz(s, NULL);
1364 break;
1365
1366 default:
1367 smtp_reply(s, "500 %s %s: Command unrecognized",
1368 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1369 esc_description(ESC_INVALID_COMMAND));
1370 break;
1371 }
1372 }
1373
1374 static int
smtp_check_rset(struct smtp_session * s,const char * args)1375 smtp_check_rset(struct smtp_session *s, const char *args)
1376 {
1377 if (!smtp_check_noparam(s, args))
1378 return 0;
1379
1380 if (s->helo[0] == '\0') {
1381 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1382 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1383 esc_description(ESC_INVALID_COMMAND));
1384 return 0;
1385 }
1386 return 1;
1387 }
1388
1389 static int
smtp_check_helo(struct smtp_session * s,const char * args)1390 smtp_check_helo(struct smtp_session *s, const char *args)
1391 {
1392 if (!s->banner_sent) {
1393 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1394 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1395 esc_description(ESC_INVALID_COMMAND));
1396 return 0;
1397 }
1398
1399 if (s->helo[0]) {
1400 smtp_reply(s, "503 %s %s: Already identified",
1401 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1402 esc_description(ESC_INVALID_COMMAND));
1403 return 0;
1404 }
1405
1406 if (args == NULL) {
1407 smtp_reply(s, "501 %s %s: HELO requires domain name",
1408 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1409 esc_description(ESC_INVALID_COMMAND));
1410 return 0;
1411 }
1412
1413 if (!valid_domainpart(args)) {
1414 smtp_reply(s, "501 %s %s: Invalid domain name",
1415 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1416 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1417 return 0;
1418 }
1419
1420 return 1;
1421 }
1422
1423 static int
smtp_check_ehlo(struct smtp_session * s,const char * args)1424 smtp_check_ehlo(struct smtp_session *s, const char *args)
1425 {
1426 if (!s->banner_sent) {
1427 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1428 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1429 esc_description(ESC_INVALID_COMMAND));
1430 return 0;
1431 }
1432
1433 if (s->helo[0]) {
1434 smtp_reply(s, "503 %s %s: Already identified",
1435 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1436 esc_description(ESC_INVALID_COMMAND));
1437 return 0;
1438 }
1439
1440 if (args == NULL) {
1441 smtp_reply(s, "501 %s %s: EHLO requires domain name",
1442 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1443 esc_description(ESC_INVALID_COMMAND));
1444 return 0;
1445 }
1446
1447 if (!valid_domainpart(args)) {
1448 smtp_reply(s, "501 %s %s: Invalid domain name",
1449 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1450 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1451 return 0;
1452 }
1453
1454 return 1;
1455 }
1456
1457 static int
smtp_check_auth(struct smtp_session * s,const char * args)1458 smtp_check_auth(struct smtp_session *s, const char *args)
1459 {
1460 if (s->helo[0] == '\0' || s->tx) {
1461 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1462 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1463 esc_description(ESC_INVALID_COMMAND));
1464 return 0;
1465 }
1466
1467 if (s->flags & SF_AUTHENTICATED) {
1468 smtp_reply(s, "503 %s %s: Already authenticated",
1469 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1470 esc_description(ESC_INVALID_COMMAND));
1471 return 0;
1472 }
1473
1474 if (!ADVERTISE_AUTH(s)) {
1475 smtp_reply(s, "503 %s %s: Command not supported",
1476 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1477 esc_description(ESC_INVALID_COMMAND));
1478 return 0;
1479 }
1480
1481 if (args == NULL) {
1482 smtp_reply(s, "501 %s %s: No parameters given",
1483 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1484 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1485 return 0;
1486 }
1487
1488 return 1;
1489 }
1490
1491 static int
smtp_check_starttls(struct smtp_session * s,const char * args)1492 smtp_check_starttls(struct smtp_session *s, const char *args)
1493 {
1494 if (s->helo[0] == '\0' || s->tx) {
1495 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1496 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1497 esc_description(ESC_INVALID_COMMAND));
1498 return 0;
1499 }
1500
1501 if (!(s->listener->flags & F_STARTTLS)) {
1502 smtp_reply(s, "503 %s %s: Command not supported",
1503 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1504 esc_description(ESC_INVALID_COMMAND));
1505 return 0;
1506 }
1507
1508 if (s->flags & SF_SECURE) {
1509 smtp_reply(s, "503 %s %s: Channel already secured",
1510 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1511 esc_description(ESC_INVALID_COMMAND));
1512 return 0;
1513 }
1514
1515 if (args != NULL) {
1516 smtp_reply(s, "501 %s %s: No parameters allowed",
1517 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1518 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1519 return 0;
1520 }
1521
1522 return 1;
1523 }
1524
1525 static int
smtp_check_mail_from(struct smtp_session * s,const char * args)1526 smtp_check_mail_from(struct smtp_session *s, const char *args)
1527 {
1528 char *copy;
1529 char tmp[SMTP_LINE_MAX];
1530 struct mailaddr sender;
1531
1532 (void)strlcpy(tmp, args, sizeof tmp);
1533 copy = tmp;
1534
1535 if (s->helo[0] == '\0' || s->tx) {
1536 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1537 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1538 esc_description(ESC_INVALID_COMMAND));
1539 return 0;
1540 }
1541
1542 if (s->listener->flags & F_STARTTLS_REQUIRE &&
1543 !(s->flags & SF_SECURE)) {
1544 smtp_reply(s,
1545 "530 %s %s: Must issue a STARTTLS command first",
1546 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1547 esc_description(ESC_INVALID_COMMAND));
1548 return 0;
1549 }
1550
1551 if (s->listener->flags & F_AUTH_REQUIRE &&
1552 !(s->flags & SF_AUTHENTICATED)) {
1553 smtp_reply(s,
1554 "530 %s %s: Must issue an AUTH command first",
1555 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1556 esc_description(ESC_INVALID_COMMAND));
1557 return 0;
1558 }
1559
1560 if (s->mailcount >= env->sc_session_max_mails) {
1561 /* we can pretend we had too many recipients */
1562 smtp_reply(s, "452 %s %s: Too many messages sent",
1563 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1564 esc_description(ESC_TOO_MANY_RECIPIENTS));
1565 return 0;
1566 }
1567
1568 if (smtp_mailaddr(&sender, copy, 1, ©,
1569 s->smtpname) == 0) {
1570 smtp_reply(s, "553 %s Sender address syntax error",
1571 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1572 return 0;
1573 }
1574
1575 return 1;
1576 }
1577
1578 static int
smtp_check_rcpt_to(struct smtp_session * s,const char * args)1579 smtp_check_rcpt_to(struct smtp_session *s, const char *args)
1580 {
1581 char *copy;
1582 char tmp[SMTP_LINE_MAX];
1583
1584 (void)strlcpy(tmp, args, sizeof tmp);
1585 copy = tmp;
1586
1587 if (s->tx == NULL) {
1588 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1589 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1590 esc_description(ESC_INVALID_COMMAND));
1591 return 0;
1592 }
1593
1594 if (s->tx->rcptcount >= env->sc_session_max_rcpt) {
1595 smtp_reply(s->tx->session, "451 %s %s: Too many recipients",
1596 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1597 esc_description(ESC_TOO_MANY_RECIPIENTS));
1598 return 0;
1599 }
1600
1601 if (smtp_mailaddr(&s->tx->evp.rcpt, copy, 0, ©,
1602 s->tx->session->smtpname) == 0) {
1603 smtp_reply(s->tx->session,
1604 "501 %s Recipient address syntax error",
1605 esc_code(ESC_STATUS_PERMFAIL,
1606 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
1607 return 0;
1608 }
1609
1610 return 1;
1611 }
1612
1613 static int
smtp_check_data(struct smtp_session * s,const char * args)1614 smtp_check_data(struct smtp_session *s, const char *args)
1615 {
1616 if (!smtp_check_noparam(s, args))
1617 return 0;
1618
1619 if (s->tx == NULL) {
1620 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1621 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1622 esc_description(ESC_INVALID_COMMAND));
1623 return 0;
1624 }
1625
1626 if (s->tx->rcptcount == 0) {
1627 smtp_reply(s, "503 %s %s: No recipient specified",
1628 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1629 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1630 return 0;
1631 }
1632
1633 return 1;
1634 }
1635
1636 static int
smtp_check_noop(struct smtp_session * s,const char * args)1637 smtp_check_noop(struct smtp_session *s, const char *args)
1638 {
1639 return 1;
1640 }
1641
1642 static int
smtp_check_noparam(struct smtp_session * s,const char * args)1643 smtp_check_noparam(struct smtp_session *s, const char *args)
1644 {
1645 if (args != NULL) {
1646 smtp_reply(s, "500 %s %s: command does not accept arguments.",
1647 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1648 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1649 return 0;
1650 }
1651 return 1;
1652 }
1653
1654 static void
smtp_query_filters(enum filter_phase phase,struct smtp_session * s,const char * args)1655 smtp_query_filters(enum filter_phase phase, struct smtp_session *s, const char *args)
1656 {
1657 m_create(p_lka, IMSG_FILTER_SMTP_PROTOCOL, 0, 0, -1);
1658 m_add_id(p_lka, s->id);
1659 m_add_int(p_lka, phase);
1660 m_add_string(p_lka, args);
1661 m_close(p_lka);
1662 tree_xset(&wait_filters, s->id, s);
1663 }
1664
1665 static void
smtp_filter_begin(struct smtp_session * s)1666 smtp_filter_begin(struct smtp_session *s)
1667 {
1668 if (!SESSION_FILTERED(s))
1669 return;
1670
1671 m_create(p_lka, IMSG_FILTER_SMTP_BEGIN, 0, 0, -1);
1672 m_add_id(p_lka, s->id);
1673 m_add_string(p_lka, s->listener->filter_name);
1674 m_close(p_lka);
1675 }
1676
1677 static void
smtp_filter_end(struct smtp_session * s)1678 smtp_filter_end(struct smtp_session *s)
1679 {
1680 if (!SESSION_FILTERED(s))
1681 return;
1682
1683 m_create(p_lka, IMSG_FILTER_SMTP_END, 0, 0, -1);
1684 m_add_id(p_lka, s->id);
1685 m_close(p_lka);
1686 }
1687
1688 static void
smtp_filter_data_begin(struct smtp_session * s)1689 smtp_filter_data_begin(struct smtp_session *s)
1690 {
1691 if (!SESSION_FILTERED(s))
1692 return;
1693
1694 m_create(p_lka, IMSG_FILTER_SMTP_DATA_BEGIN, 0, 0, -1);
1695 m_add_id(p_lka, s->id);
1696 m_close(p_lka);
1697 tree_xset(&wait_filter_fd, s->id, s);
1698 }
1699
1700 static void
smtp_filter_data_end(struct smtp_session * s)1701 smtp_filter_data_end(struct smtp_session *s)
1702 {
1703 if (!SESSION_FILTERED(s))
1704 return;
1705
1706 if (s->tx->filter == NULL)
1707 return;
1708
1709 io_free(s->tx->filter);
1710 s->tx->filter = NULL;
1711
1712 m_create(p_lka, IMSG_FILTER_SMTP_DATA_END, 0, 0, -1);
1713 m_add_id(p_lka, s->id);
1714 m_close(p_lka);
1715 }
1716
1717 static void
smtp_filter_phase(enum filter_phase phase,struct smtp_session * s,const char * param)1718 smtp_filter_phase(enum filter_phase phase, struct smtp_session *s, const char *param)
1719 {
1720 uint8_t i;
1721
1722 s->filter_phase = phase;
1723 s->filter_param = param;
1724
1725 if (SESSION_FILTERED(s)) {
1726 smtp_query_filters(phase, s, param ? param : "");
1727 return;
1728 }
1729
1730 if (s->filter_phase == FILTER_CONNECT) {
1731 smtp_proceed_connected(s);
1732 return;
1733 }
1734
1735 for (i = 0; i < nitems(commands); ++i)
1736 if (commands[i].filter_phase == s->filter_phase) {
1737 commands[i].proceed(s, param);
1738 break;
1739 }
1740 }
1741
1742 static void
smtp_proceed_rset(struct smtp_session * s,const char * args)1743 smtp_proceed_rset(struct smtp_session *s, const char *args)
1744 {
1745 smtp_reply(s, "250 %s Reset state",
1746 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1747
1748 if (s->tx) {
1749 if (s->tx->msgid)
1750 smtp_tx_rollback(s->tx);
1751 smtp_tx_free(s->tx);
1752 }
1753 }
1754
1755 static void
smtp_proceed_helo(struct smtp_session * s,const char * args)1756 smtp_proceed_helo(struct smtp_session *s, const char *args)
1757 {
1758 (void)strlcpy(s->helo, args, sizeof(s->helo));
1759 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1760
1761 smtp_report_link_identify(s, "HELO", s->helo);
1762
1763 smtp_enter_state(s, STATE_HELO);
1764
1765 smtp_reply(s, "250 %s Hello %s %s%s%s, pleased to meet you",
1766 s->smtpname,
1767 s->helo,
1768 s->ss.ss_family == AF_INET6 ? "" : "[",
1769 ss_to_text(&s->ss),
1770 s->ss.ss_family == AF_INET6 ? "" : "]");
1771 }
1772
1773 static void
smtp_proceed_ehlo(struct smtp_session * s,const char * args)1774 smtp_proceed_ehlo(struct smtp_session *s, const char *args)
1775 {
1776 (void)strlcpy(s->helo, args, sizeof(s->helo));
1777 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1778 s->flags |= SF_EHLO;
1779 s->flags |= SF_8BITMIME;
1780
1781 smtp_report_link_identify(s, "EHLO", s->helo);
1782
1783 smtp_enter_state(s, STATE_HELO);
1784 smtp_reply(s, "250-%s Hello %s %s%s%s, pleased to meet you",
1785 s->smtpname,
1786 s->helo,
1787 s->ss.ss_family == AF_INET6 ? "" : "[",
1788 ss_to_text(&s->ss),
1789 s->ss.ss_family == AF_INET6 ? "" : "]");
1790
1791 smtp_reply(s, "250-8BITMIME");
1792 smtp_reply(s, "250-ENHANCEDSTATUSCODES");
1793 smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
1794 if (ADVERTISE_EXT_DSN(s))
1795 smtp_reply(s, "250-DSN");
1796 if (ADVERTISE_TLS(s))
1797 smtp_reply(s, "250-STARTTLS");
1798 if (ADVERTISE_AUTH(s))
1799 smtp_reply(s, "250-AUTH PLAIN LOGIN");
1800 smtp_reply(s, "250 HELP");
1801 }
1802
1803 static void
smtp_proceed_auth(struct smtp_session * s,const char * args)1804 smtp_proceed_auth(struct smtp_session *s, const char *args)
1805 {
1806 char tmp[SMTP_LINE_MAX];
1807 char *eom, *method;
1808
1809 (void)strlcpy(tmp, args, sizeof tmp);
1810
1811 method = tmp;
1812 eom = strchr(tmp, ' ');
1813 if (eom == NULL)
1814 eom = strchr(tmp, '\t');
1815 if (eom != NULL)
1816 *eom++ = '\0';
1817 if (strcasecmp(method, "PLAIN") == 0)
1818 smtp_rfc4954_auth_plain(s, eom);
1819 else if (strcasecmp(method, "LOGIN") == 0)
1820 smtp_rfc4954_auth_login(s, eom);
1821 else
1822 smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
1823 esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1824 esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1825 method);
1826 }
1827
1828 static void
smtp_proceed_starttls(struct smtp_session * s,const char * args)1829 smtp_proceed_starttls(struct smtp_session *s, const char *args)
1830 {
1831 smtp_reply(s, "220 %s Ready to start TLS",
1832 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1833 smtp_enter_state(s, STATE_TLS);
1834 }
1835
1836 static void
smtp_proceed_mail_from(struct smtp_session * s,const char * args)1837 smtp_proceed_mail_from(struct smtp_session *s, const char *args)
1838 {
1839 char *copy;
1840 char tmp[SMTP_LINE_MAX];
1841
1842 (void)strlcpy(tmp, args, sizeof tmp);
1843 copy = tmp;
1844
1845 if (!smtp_tx(s)) {
1846 smtp_reply(s, "421 %s Temporary Error",
1847 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
1848 smtp_enter_state(s, STATE_QUIT);
1849 return;
1850 }
1851
1852 if (smtp_mailaddr(&s->tx->evp.sender, copy, 1, ©,
1853 s->smtpname) == 0) {
1854 smtp_reply(s, "553 %s Sender address syntax error",
1855 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1856 smtp_tx_free(s->tx);
1857 return;
1858 }
1859
1860 smtp_tx_mail_from(s->tx, args);
1861 }
1862
1863 static void
smtp_proceed_rcpt_to(struct smtp_session * s,const char * args)1864 smtp_proceed_rcpt_to(struct smtp_session *s, const char *args)
1865 {
1866 smtp_tx_rcpt_to(s->tx, args);
1867 }
1868
1869 static void
smtp_proceed_data(struct smtp_session * s,const char * args)1870 smtp_proceed_data(struct smtp_session *s, const char *args)
1871 {
1872 smtp_tx_open_message(s->tx);
1873 }
1874
1875 static void
smtp_proceed_quit(struct smtp_session * s,const char * args)1876 smtp_proceed_quit(struct smtp_session *s, const char *args)
1877 {
1878 smtp_reply(s, "221 %s Bye",
1879 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1880 smtp_enter_state(s, STATE_QUIT);
1881 }
1882
1883 static void
smtp_proceed_noop(struct smtp_session * s,const char * args)1884 smtp_proceed_noop(struct smtp_session *s, const char *args)
1885 {
1886 smtp_reply(s, "250 %s Ok",
1887 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1888 }
1889
1890 static void
smtp_proceed_help(struct smtp_session * s,const char * args)1891 smtp_proceed_help(struct smtp_session *s, const char *args)
1892 {
1893 const char *code = esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS);
1894
1895 smtp_reply(s, "214-%s This is " SMTPD_NAME, code);
1896 smtp_reply(s, "214-%s To report bugs in the implementation, "
1897 "please contact bugs@openbsd.org", code);
1898 smtp_reply(s, "214-%s with full details", code);
1899 smtp_reply(s, "214 %s End of HELP info", code);
1900 }
1901
1902 static void
smtp_proceed_wiz(struct smtp_session * s,const char * args)1903 smtp_proceed_wiz(struct smtp_session *s, const char *args)
1904 {
1905 smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
1906 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1907 esc_description(ESC_INVALID_COMMAND));
1908 }
1909
1910 static void
smtp_proceed_commit(struct smtp_session * s,const char * args)1911 smtp_proceed_commit(struct smtp_session *s, const char *args)
1912 {
1913 smtp_message_end(s->tx);
1914 }
1915
1916 static void
smtp_proceed_rollback(struct smtp_session * s,const char * args)1917 smtp_proceed_rollback(struct smtp_session *s, const char *args)
1918 {
1919 struct smtp_tx *tx;
1920
1921 tx = s->tx;
1922
1923 fclose(tx->ofile);
1924 tx->ofile = NULL;
1925
1926 smtp_tx_rollback(tx);
1927 smtp_tx_free(tx);
1928 smtp_enter_state(s, STATE_HELO);
1929 }
1930
1931 static void
smtp_rfc4954_auth_plain(struct smtp_session * s,char * arg)1932 smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg)
1933 {
1934 char buf[1024], *user, *pass;
1935 int len;
1936
1937 switch (s->state) {
1938 case STATE_HELO:
1939 if (arg == NULL) {
1940 smtp_enter_state(s, STATE_AUTH_INIT);
1941 smtp_reply(s, "334 ");
1942 return;
1943 }
1944 smtp_enter_state(s, STATE_AUTH_INIT);
1945 /* FALLTHROUGH */
1946
1947 case STATE_AUTH_INIT:
1948 /* String is not NUL terminated, leave room. */
1949 if ((len = base64_decode(arg, (unsigned char *)buf,
1950 sizeof(buf) - 1)) == -1)
1951 goto abort;
1952 /* buf is a byte string, NUL terminate. */
1953 buf[len] = '\0';
1954
1955 /*
1956 * Skip "foo" in "foo\0user\0pass", if present.
1957 */
1958 user = memchr(buf, '\0', len);
1959 if (user == NULL || user >= buf + len - 2)
1960 goto abort;
1961 user++; /* skip NUL */
1962 if (strlcpy(s->username, user, sizeof(s->username))
1963 >= sizeof(s->username))
1964 goto abort;
1965
1966 pass = memchr(user, '\0', len - (user - buf));
1967 if (pass == NULL || pass >= buf + len - 2)
1968 goto abort;
1969 pass++; /* skip NUL */
1970
1971 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
1972 m_add_id(p_lka, s->id);
1973 m_add_string(p_lka, s->listener->authtable);
1974 m_add_string(p_lka, user);
1975 m_add_string(p_lka, pass);
1976 m_close(p_lka);
1977 tree_xset(&wait_parent_auth, s->id, s);
1978 return;
1979
1980 default:
1981 fatal("smtp_rfc4954_auth_plain: unknown state");
1982 }
1983
1984 abort:
1985 smtp_reply(s, "501 %s %s: Syntax error",
1986 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
1987 esc_description(ESC_SYNTAX_ERROR));
1988 smtp_enter_state(s, STATE_HELO);
1989 }
1990
1991 static void
smtp_rfc4954_auth_login(struct smtp_session * s,char * arg)1992 smtp_rfc4954_auth_login(struct smtp_session *s, char *arg)
1993 {
1994 char buf[LINE_MAX];
1995
1996 switch (s->state) {
1997 case STATE_HELO:
1998 smtp_enter_state(s, STATE_AUTH_USERNAME);
1999 if (arg != NULL && *arg != '\0') {
2000 smtp_rfc4954_auth_login(s, arg);
2001 return;
2002 }
2003 smtp_reply(s, "334 VXNlcm5hbWU6");
2004 return;
2005
2006 case STATE_AUTH_USERNAME:
2007 memset(s->username, 0, sizeof(s->username));
2008 if (base64_decode(arg, (unsigned char *)s->username,
2009 sizeof(s->username) - 1) == -1)
2010 goto abort;
2011
2012 smtp_enter_state(s, STATE_AUTH_PASSWORD);
2013 smtp_reply(s, "334 UGFzc3dvcmQ6");
2014 return;
2015
2016 case STATE_AUTH_PASSWORD:
2017 memset(buf, 0, sizeof(buf));
2018 if (base64_decode(arg, (unsigned char *)buf,
2019 sizeof(buf)-1) == -1)
2020 goto abort;
2021
2022 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
2023 m_add_id(p_lka, s->id);
2024 m_add_string(p_lka, s->listener->authtable);
2025 m_add_string(p_lka, s->username);
2026 m_add_string(p_lka, buf);
2027 m_close(p_lka);
2028 tree_xset(&wait_parent_auth, s->id, s);
2029 return;
2030
2031 default:
2032 fatal("smtp_rfc4954_auth_login: unknown state");
2033 }
2034
2035 abort:
2036 smtp_reply(s, "501 %s %s: Syntax error",
2037 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
2038 esc_description(ESC_SYNTAX_ERROR));
2039 smtp_enter_state(s, STATE_HELO);
2040 }
2041
2042 static void
smtp_lookup_servername(struct smtp_session * s)2043 smtp_lookup_servername(struct smtp_session *s)
2044 {
2045 if (s->listener->hostnametable[0]) {
2046 m_create(p_lka, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
2047 m_add_id(p_lka, s->id);
2048 m_add_string(p_lka, s->listener->hostnametable);
2049 m_add_sockaddr(p_lka, (struct sockaddr*)&s->listener->ss);
2050 m_close(p_lka);
2051 tree_xset(&wait_lka_helo, s->id, s);
2052 return;
2053 }
2054
2055 smtp_connected(s);
2056 }
2057
2058 static void
smtp_connected(struct smtp_session * s)2059 smtp_connected(struct smtp_session *s)
2060 {
2061 smtp_enter_state(s, STATE_CONNECTED);
2062
2063 log_info("%016"PRIx64" smtp connected address=%s host=%s",
2064 s->id, ss_to_text(&s->ss), s->rdns);
2065
2066 smtp_filter_begin(s);
2067
2068 smtp_report_link_connect(s, s->rdns, s->fcrdns, &s->ss,
2069 &s->listener->ss);
2070
2071 smtp_filter_phase(FILTER_CONNECT, s, ss_to_text(&s->ss));
2072 }
2073
2074 static void
smtp_proceed_connected(struct smtp_session * s)2075 smtp_proceed_connected(struct smtp_session *s)
2076 {
2077 if (s->listener->flags & F_SMTPS)
2078 smtp_tls_init(s);
2079 else
2080 smtp_send_banner(s);
2081 }
2082
2083 static void
smtp_send_banner(struct smtp_session * s)2084 smtp_send_banner(struct smtp_session *s)
2085 {
2086 smtp_reply(s, "220 %s ESMTP %s", s->smtpname, SMTPD_NAME);
2087 s->banner_sent = 1;
2088 smtp_report_link_greeting(s, s->smtpname);
2089 }
2090
2091 void
smtp_enter_state(struct smtp_session * s,int newstate)2092 smtp_enter_state(struct smtp_session *s, int newstate)
2093 {
2094 log_trace(TRACE_SMTP, "smtp: %p: %s -> %s", s,
2095 smtp_strstate(s->state),
2096 smtp_strstate(newstate));
2097
2098 s->state = newstate;
2099 }
2100
2101 static void
smtp_reply(struct smtp_session * s,char * fmt,...)2102 smtp_reply(struct smtp_session *s, char *fmt, ...)
2103 {
2104 va_list ap;
2105 int n;
2106 char buf[LINE_MAX*2], tmp[LINE_MAX*2];
2107
2108 va_start(ap, fmt);
2109 n = vsnprintf(buf, sizeof buf, fmt, ap);
2110 va_end(ap);
2111 if (n < 0)
2112 fatalx("smtp_reply: response format error");
2113 if (n < 4)
2114 fatalx("smtp_reply: response too short");
2115 if (n >= (int)sizeof buf) {
2116 /* only first three bytes are used by SMTP logic,
2117 * so if _our_ reply does not fit entirely in the
2118 * buffer, it's ok to truncate.
2119 */
2120 }
2121
2122 log_trace(TRACE_SMTP, "smtp: %p: >>> %s", s, buf);
2123 smtp_report_protocol_server(s, buf);
2124
2125 switch (buf[0]) {
2126 case '2':
2127 if (s->tx) {
2128 if (s->last_cmd == CMD_MAIL_FROM) {
2129 smtp_report_tx_begin(s, s->tx->msgid);
2130 smtp_report_tx_mail(s, s->tx->msgid, s->cmd + 10, 1);
2131 }
2132 else if (s->last_cmd == CMD_RCPT_TO)
2133 smtp_report_tx_rcpt(s, s->tx->msgid, s->cmd + 8, 1);
2134 }
2135 break;
2136 case '3':
2137 if (s->tx) {
2138 if (s->last_cmd == CMD_DATA)
2139 smtp_report_tx_data(s, s->tx->msgid, 1);
2140 }
2141 break;
2142 case '5':
2143 case '4':
2144 /* do not report smtp_tx_mail/smtp_tx_rcpt errors
2145 * if they happened outside of a transaction.
2146 */
2147 if (s->tx) {
2148 if (s->last_cmd == CMD_MAIL_FROM)
2149 smtp_report_tx_mail(s, s->tx->msgid,
2150 s->cmd + 10, buf[0] == '4' ? -1 : 0);
2151 else if (s->last_cmd == CMD_RCPT_TO)
2152 smtp_report_tx_rcpt(s,
2153 s->tx->msgid, s->cmd + 8, buf[0] == '4' ? -1 : 0);
2154 else if (s->last_cmd == CMD_DATA && s->tx->rcptcount)
2155 smtp_report_tx_data(s, s->tx->msgid,
2156 buf[0] == '4' ? -1 : 0);
2157 }
2158
2159 if (s->flags & SF_BADINPUT) {
2160 log_info("%016"PRIx64" smtp "
2161 "bad-input result=\"%.*s\"",
2162 s->id, n, buf);
2163 }
2164 else if (s->state == STATE_AUTH_INIT) {
2165 log_info("%016"PRIx64" smtp "
2166 "failed-command "
2167 "command=\"AUTH PLAIN (...)\" result=\"%.*s\"",
2168 s->id, n, buf);
2169 }
2170 else if (s->state == STATE_AUTH_USERNAME) {
2171 log_info("%016"PRIx64" smtp "
2172 "failed-command "
2173 "command=\"AUTH LOGIN (username)\" result=\"%.*s\"",
2174 s->id, n, buf);
2175 }
2176 else if (s->state == STATE_AUTH_PASSWORD) {
2177 log_info("%016"PRIx64" smtp "
2178 "failed-command "
2179 "command=\"AUTH LOGIN (password)\" result=\"%.*s\"",
2180 s->id, n, buf);
2181 }
2182 else {
2183 strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE | VIS_CSTYLE);
2184 log_info("%016"PRIx64" smtp "
2185 "failed-command command=\"%s\" "
2186 "result=\"%.*s\"",
2187 s->id, tmp, n, buf);
2188 }
2189 break;
2190 }
2191
2192 io_xprintf(s->io, "%s\r\n", buf);
2193 }
2194
2195 static void
smtp_free(struct smtp_session * s,const char * reason)2196 smtp_free(struct smtp_session *s, const char * reason)
2197 {
2198 if (s->tx) {
2199 if (s->tx->msgid)
2200 smtp_tx_rollback(s->tx);
2201 smtp_tx_free(s->tx);
2202 }
2203
2204 smtp_report_link_disconnect(s);
2205 smtp_filter_end(s);
2206
2207 if (s->flags & SF_SECURE && s->listener->flags & F_SMTPS)
2208 stat_decrement("smtp.smtps", 1);
2209 if (s->flags & SF_SECURE && s->listener->flags & F_STARTTLS)
2210 stat_decrement("smtp.tls", 1);
2211
2212 io_free(s->io);
2213 free(s);
2214
2215 smtp_collect();
2216 }
2217
2218 static int
smtp_mailaddr(struct mailaddr * maddr,char * line,int mailfrom,char ** args,const char * domain)2219 smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args,
2220 const char *domain)
2221 {
2222 char *p, *e;
2223
2224 if (line == NULL)
2225 return (0);
2226
2227 if (*line != '<')
2228 return (0);
2229
2230 e = strchr(line, '>');
2231 if (e == NULL)
2232 return (0);
2233 *e++ = '\0';
2234 while (*e == ' ')
2235 e++;
2236 *args = e;
2237
2238 if (!text_to_mailaddr(maddr, line + 1))
2239 return (0);
2240
2241 p = strchr(maddr->user, ':');
2242 if (p != NULL) {
2243 p++;
2244 memmove(maddr->user, p, strlen(p) + 1);
2245 }
2246
2247 /* accept empty return-path in MAIL FROM, required for bounces */
2248 if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0')
2249 return (1);
2250
2251 /* no or invalid user-part, reject */
2252 if (maddr->user[0] == '\0' || !valid_localpart(maddr->user))
2253 return (0);
2254
2255 /* no domain part, local user */
2256 if (maddr->domain[0] == '\0') {
2257 (void)strlcpy(maddr->domain, domain,
2258 sizeof(maddr->domain));
2259 }
2260
2261 if (!valid_domainpart(maddr->domain))
2262 return (0);
2263
2264 return (1);
2265 }
2266
2267 static void
smtp_auth_failure_resume(int fd,short event,void * p)2268 smtp_auth_failure_resume(int fd, short event, void *p)
2269 {
2270 struct smtp_session *s = p;
2271
2272 smtp_reply(s, "535 Authentication failed");
2273 smtp_enter_state(s, STATE_HELO);
2274 }
2275
2276 static void
smtp_auth_failure_pause(struct smtp_session * s)2277 smtp_auth_failure_pause(struct smtp_session *s)
2278 {
2279 struct timeval tv;
2280
2281 tv.tv_sec = 0;
2282 tv.tv_usec = arc4random_uniform(1000000);
2283 log_trace(TRACE_SMTP, "smtp: timing-attack protection triggered, "
2284 "will defer answer for %lu microseconds", (long)tv.tv_usec);
2285 evtimer_set(&s->pause, smtp_auth_failure_resume, s);
2286 evtimer_add(&s->pause, &tv);
2287 }
2288
2289 static int
smtp_tx(struct smtp_session * s)2290 smtp_tx(struct smtp_session *s)
2291 {
2292 struct smtp_tx *tx;
2293
2294 tx = calloc(1, sizeof(*tx));
2295 if (tx == NULL)
2296 return 0;
2297
2298 TAILQ_INIT(&tx->rcpts);
2299
2300 s->tx = tx;
2301 tx->session = s;
2302
2303 /* setup the envelope */
2304 tx->evp.ss = s->ss;
2305 (void)strlcpy(tx->evp.tag, s->listener->tag, sizeof(tx->evp.tag));
2306 (void)strlcpy(tx->evp.smtpname, s->smtpname, sizeof(tx->evp.smtpname));
2307 (void)strlcpy(tx->evp.hostname, s->rdns, sizeof tx->evp.hostname);
2308 (void)strlcpy(tx->evp.helo, s->helo, sizeof(tx->evp.helo));
2309 (void)strlcpy(tx->evp.username, s->username, sizeof(tx->evp.username));
2310
2311 if (s->flags & SF_BOUNCE)
2312 tx->evp.flags |= EF_BOUNCE;
2313 if (s->flags & SF_AUTHENTICATED)
2314 tx->evp.flags |= EF_AUTHENTICATED;
2315
2316 if ((tx->parser = rfc5322_parser_new()) == NULL) {
2317 free(tx);
2318 return 0;
2319 }
2320
2321 return 1;
2322 }
2323
2324 static void
smtp_tx_free(struct smtp_tx * tx)2325 smtp_tx_free(struct smtp_tx *tx)
2326 {
2327 struct smtp_rcpt *rcpt;
2328
2329 rfc5322_free(tx->parser);
2330
2331 while ((rcpt = TAILQ_FIRST(&tx->rcpts))) {
2332 TAILQ_REMOVE(&tx->rcpts, rcpt, entry);
2333 free(rcpt);
2334 }
2335
2336 if (tx->ofile)
2337 fclose(tx->ofile);
2338
2339 tx->session->tx = NULL;
2340
2341 free(tx);
2342 }
2343
2344 static void
smtp_tx_mail_from(struct smtp_tx * tx,const char * line)2345 smtp_tx_mail_from(struct smtp_tx *tx, const char *line)
2346 {
2347 char *opt;
2348 char *copy;
2349 char tmp[SMTP_LINE_MAX];
2350
2351 (void)strlcpy(tmp, line, sizeof tmp);
2352 copy = tmp;
2353
2354 if (smtp_mailaddr(&tx->evp.sender, copy, 1, ©,
2355 tx->session->smtpname) == 0) {
2356 smtp_reply(tx->session, "553 %s Sender address syntax error",
2357 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
2358 smtp_tx_free(tx);
2359 return;
2360 }
2361
2362 while ((opt = strsep(©, " "))) {
2363 if (*opt == '\0')
2364 continue;
2365
2366 if (strncasecmp(opt, "AUTH=", 5) == 0)
2367 log_debug("debug: smtp: AUTH in MAIL FROM command");
2368 else if (strncasecmp(opt, "SIZE=", 5) == 0)
2369 log_debug("debug: smtp: SIZE in MAIL FROM command");
2370 else if (strcasecmp(opt, "BODY=7BIT") == 0)
2371 /* XXX only for this transaction */
2372 tx->session->flags &= ~SF_8BITMIME;
2373 else if (strcasecmp(opt, "BODY=8BITMIME") == 0)
2374 ;
2375 else if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "RET=", 4) == 0) {
2376 opt += 4;
2377 if (strcasecmp(opt, "HDRS") == 0)
2378 tx->evp.dsn_ret = DSN_RETHDRS;
2379 else if (strcasecmp(opt, "FULL") == 0)
2380 tx->evp.dsn_ret = DSN_RETFULL;
2381 } else if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "ENVID=", 6) == 0) {
2382 opt += 6;
2383 if (strlcpy(tx->evp.dsn_envid, opt, sizeof(tx->evp.dsn_envid))
2384 >= sizeof(tx->evp.dsn_envid)) {
2385 smtp_reply(tx->session,
2386 "503 %s %s: option too large, truncated: %s",
2387 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2388 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2389 smtp_tx_free(tx);
2390 return;
2391 }
2392 } else {
2393 smtp_reply(tx->session, "503 %s %s: Unsupported option %s",
2394 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2395 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2396 smtp_tx_free(tx);
2397 return;
2398 }
2399 }
2400
2401 /* only check sendertable if defined and user has authenticated */
2402 if (tx->session->flags & SF_AUTHENTICATED &&
2403 tx->session->listener->sendertable[0]) {
2404 m_create(p_lka, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
2405 m_add_id(p_lka, tx->session->id);
2406 m_add_string(p_lka, tx->session->listener->sendertable);
2407 m_add_string(p_lka, tx->session->username);
2408 m_add_mailaddr(p_lka, &tx->evp.sender);
2409 m_close(p_lka);
2410 tree_xset(&wait_lka_mail, tx->session->id, tx->session);
2411 }
2412 else
2413 smtp_tx_create_message(tx);
2414 }
2415
2416 static void
smtp_tx_create_message(struct smtp_tx * tx)2417 smtp_tx_create_message(struct smtp_tx *tx)
2418 {
2419 m_create(p_queue, IMSG_SMTP_MESSAGE_CREATE, 0, 0, -1);
2420 m_add_id(p_queue, tx->session->id);
2421 m_close(p_queue);
2422 tree_xset(&wait_queue_msg, tx->session->id, tx->session);
2423 }
2424
2425 static void
smtp_tx_rcpt_to(struct smtp_tx * tx,const char * line)2426 smtp_tx_rcpt_to(struct smtp_tx *tx, const char *line)
2427 {
2428 char *opt, *p;
2429 char *copy;
2430 char tmp[SMTP_LINE_MAX];
2431
2432 (void)strlcpy(tmp, line, sizeof tmp);
2433 copy = tmp;
2434
2435 if (tx->rcptcount >= env->sc_session_max_rcpt) {
2436 smtp_reply(tx->session, "451 %s %s: Too many recipients",
2437 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
2438 esc_description(ESC_TOO_MANY_RECIPIENTS));
2439 return;
2440 }
2441
2442 if (smtp_mailaddr(&tx->evp.rcpt, copy, 0, ©,
2443 tx->session->smtpname) == 0) {
2444 smtp_reply(tx->session,
2445 "501 %s Recipient address syntax error",
2446 esc_code(ESC_STATUS_PERMFAIL,
2447 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
2448 return;
2449 }
2450
2451 while ((opt = strsep(©, " "))) {
2452 if (*opt == '\0')
2453 continue;
2454
2455 if (ADVERTISE_EXT_DSN(tx->session) && strncasecmp(opt, "NOTIFY=", 7) == 0) {
2456 opt += 7;
2457 while ((p = strsep(&opt, ","))) {
2458 if (strcasecmp(p, "SUCCESS") == 0)
2459 tx->evp.dsn_notify |= DSN_SUCCESS;
2460 else if (strcasecmp(p, "FAILURE") == 0)
2461 tx->evp.dsn_notify |= DSN_FAILURE;
2462 else if (strcasecmp(p, "DELAY") == 0)
2463 tx->evp.dsn_notify |= DSN_DELAY;
2464 else if (strcasecmp(p, "NEVER") == 0)
2465 tx->evp.dsn_notify |= DSN_NEVER;
2466 }
2467
2468 if (tx->evp.dsn_notify & DSN_NEVER &&
2469 tx->evp.dsn_notify & (DSN_SUCCESS | DSN_FAILURE |
2470 DSN_DELAY)) {
2471 smtp_reply(tx->session,
2472 "553 NOTIFY option NEVER cannot be"
2473 " combined with other options");
2474 return;
2475 }
2476 } else if (ADVERTISE_EXT_DSN(tx->session) &&
2477 strncasecmp(opt, "ORCPT=", 6) == 0) {
2478 size_t len = sizeof(tx->evp.dsn_orcpt);
2479
2480 opt += 6;
2481
2482 if ((p = strchr(opt, ';')) == NULL ||
2483 !valid_xtext(p + 1) ||
2484 strlcpy(tx->evp.dsn_orcpt, opt, len) >= len) {
2485 smtp_reply(tx->session,
2486 "553 ORCPT address syntax error");
2487 return;
2488 }
2489 } else {
2490 smtp_reply(tx->session, "503 Unsupported option %s", opt);
2491 return;
2492 }
2493 }
2494
2495 m_create(p_lka, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1);
2496 m_add_id(p_lka, tx->session->id);
2497 m_add_envelope(p_lka, &tx->evp);
2498 m_close(p_lka);
2499 tree_xset(&wait_lka_rcpt, tx->session->id, tx->session);
2500 }
2501
2502 static void
smtp_tx_open_message(struct smtp_tx * tx)2503 smtp_tx_open_message(struct smtp_tx *tx)
2504 {
2505 m_create(p_queue, IMSG_SMTP_MESSAGE_OPEN, 0, 0, -1);
2506 m_add_id(p_queue, tx->session->id);
2507 m_add_msgid(p_queue, tx->msgid);
2508 m_close(p_queue);
2509 tree_xset(&wait_queue_fd, tx->session->id, tx->session);
2510 }
2511
2512 static void
smtp_tx_commit(struct smtp_tx * tx)2513 smtp_tx_commit(struct smtp_tx *tx)
2514 {
2515 m_create(p_queue, IMSG_SMTP_MESSAGE_COMMIT, 0, 0, -1);
2516 m_add_id(p_queue, tx->session->id);
2517 m_add_msgid(p_queue, tx->msgid);
2518 m_close(p_queue);
2519 tree_xset(&wait_queue_commit, tx->session->id, tx->session);
2520 smtp_filter_data_end(tx->session);
2521 }
2522
2523 static void
smtp_tx_rollback(struct smtp_tx * tx)2524 smtp_tx_rollback(struct smtp_tx *tx)
2525 {
2526 m_create(p_queue, IMSG_SMTP_MESSAGE_ROLLBACK, 0, 0, -1);
2527 m_add_msgid(p_queue, tx->msgid);
2528 m_close(p_queue);
2529 smtp_report_tx_rollback(tx->session, tx->msgid);
2530 smtp_report_tx_reset(tx->session, tx->msgid);
2531 smtp_filter_data_end(tx->session);
2532 }
2533
2534 static int
smtp_tx_dataline(struct smtp_tx * tx,const char * line)2535 smtp_tx_dataline(struct smtp_tx *tx, const char *line)
2536 {
2537 struct rfc5322_result res;
2538 int r;
2539
2540 log_trace(TRACE_SMTP, "<<< [MSG] %s", line);
2541
2542 if (!strcmp(line, ".")) {
2543 smtp_report_protocol_client(tx->session, ".");
2544 log_trace(TRACE_SMTP, "<<< [EOM]");
2545 if (tx->error)
2546 return 1;
2547 line = NULL;
2548 }
2549 else {
2550 /* ignore data line if an error is set */
2551 if (tx->error)
2552 return 0;
2553
2554 /* escape lines starting with a '.' */
2555 if (line[0] == '.')
2556 line += 1;
2557 }
2558
2559 if (rfc5322_push(tx->parser, line) == -1) {
2560 log_warnx("failed to push dataline");
2561 tx->error = TX_ERROR_INTERNAL;
2562 return 0;
2563 }
2564
2565 for(;;) {
2566 r = rfc5322_next(tx->parser, &res);
2567 switch (r) {
2568 case -1:
2569 if (errno == ENOMEM)
2570 tx->error = TX_ERROR_INTERNAL;
2571 else
2572 tx->error = TX_ERROR_MALFORMED;
2573 return 0;
2574
2575 case RFC5322_NONE:
2576 /* Need more data */
2577 return 0;
2578
2579 case RFC5322_HEADER_START:
2580 /* ignore bcc */
2581 if (!strcasecmp("Bcc", res.hdr))
2582 continue;
2583
2584 if (!strcasecmp("To", res.hdr) ||
2585 !strcasecmp("Cc", res.hdr) ||
2586 !strcasecmp("From", res.hdr)) {
2587 rfc5322_unfold_header(tx->parser);
2588 continue;
2589 }
2590
2591 if (!strcasecmp("Received", res.hdr)) {
2592 if (++tx->rcvcount >= MAX_HOPS_COUNT) {
2593 log_warnx("warn: loop detected");
2594 tx->error = TX_ERROR_LOOP;
2595 return 0;
2596 }
2597 }
2598 else if (!tx->has_date && !strcasecmp("Date", res.hdr))
2599 tx->has_date = 1;
2600 else if (!tx->has_message_id &&
2601 !strcasecmp("Message-Id", res.hdr))
2602 tx->has_message_id = 1;
2603
2604 smtp_message_printf(tx, "%s:%s\n", res.hdr, res.value);
2605 break;
2606
2607 case RFC5322_HEADER_CONT:
2608
2609 if (!strcasecmp("Bcc", res.hdr) ||
2610 !strcasecmp("To", res.hdr) ||
2611 !strcasecmp("Cc", res.hdr) ||
2612 !strcasecmp("From", res.hdr))
2613 continue;
2614
2615 smtp_message_printf(tx, "%s\n", res.value);
2616 break;
2617
2618 case RFC5322_HEADER_END:
2619 if (!strcasecmp("To", res.hdr) ||
2620 !strcasecmp("Cc", res.hdr) ||
2621 !strcasecmp("From", res.hdr))
2622 header_domain_append_callback(tx, res.hdr,
2623 res.value);
2624 break;
2625
2626 case RFC5322_END_OF_HEADERS:
2627 if (tx->session->listener->local ||
2628 tx->session->listener->port == htons(587)) {
2629
2630 if (!tx->has_date) {
2631 log_debug("debug: %p: adding Date", tx);
2632 smtp_message_printf(tx, "Date: %s\n",
2633 time_to_text(tx->time));
2634 }
2635
2636 if (!tx->has_message_id) {
2637 log_debug("debug: %p: adding Message-ID", tx);
2638 smtp_message_printf(tx,
2639 "Message-ID: <%016"PRIx64"@%s>\n",
2640 generate_uid(),
2641 tx->session->listener->hostname);
2642 }
2643 }
2644 break;
2645
2646 case RFC5322_BODY_START:
2647 case RFC5322_BODY:
2648 smtp_message_printf(tx, "%s\n", res.value);
2649 break;
2650
2651 case RFC5322_END_OF_MESSAGE:
2652 return 1;
2653
2654 default:
2655 fatalx("%s", __func__);
2656 }
2657 }
2658 }
2659
2660 static int
smtp_tx_filtered_dataline(struct smtp_tx * tx,const char * line)2661 smtp_tx_filtered_dataline(struct smtp_tx *tx, const char *line)
2662 {
2663 if (!strcmp(line, "."))
2664 line = NULL;
2665 else {
2666 /* ignore data line if an error is set */
2667 if (tx->error)
2668 return 0;
2669 }
2670 io_printf(tx->filter, "%s\n", line ? line : ".");
2671 return line ? 0 : 1;
2672 }
2673
2674 static void
smtp_tx_eom(struct smtp_tx * tx)2675 smtp_tx_eom(struct smtp_tx *tx)
2676 {
2677 smtp_filter_phase(FILTER_COMMIT, tx->session, NULL);
2678 }
2679
2680 static int
smtp_message_fd(struct smtp_tx * tx,int fd)2681 smtp_message_fd(struct smtp_tx *tx, int fd)
2682 {
2683 struct smtp_session *s;
2684
2685 s = tx->session;
2686
2687 log_debug("smtp: %p: message fd %d", s, fd);
2688
2689 if ((tx->ofile = fdopen(fd, "w")) == NULL) {
2690 close(fd);
2691 smtp_reply(s, "421 %s Temporary Error",
2692 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2693 smtp_enter_state(s, STATE_QUIT);
2694 return 0;
2695 }
2696 return 1;
2697 }
2698
2699 static void
filter_session_io(struct io * io,int evt,void * arg)2700 filter_session_io(struct io *io, int evt, void *arg)
2701 {
2702 struct smtp_tx*tx = arg;
2703 char*line = NULL;
2704 ssize_t len;
2705
2706 log_trace(TRACE_IO, "filter session io (smtp): %p: %s %s", tx, io_strevent(evt),
2707 io_strio(io));
2708
2709 switch (evt) {
2710 case IO_DATAIN:
2711 nextline:
2712 line = io_getline(tx->filter, &len);
2713 /* No complete line received */
2714 if (line == NULL)
2715 return;
2716
2717 if (smtp_tx_dataline(tx, line)) {
2718 smtp_tx_eom(tx);
2719 return;
2720 }
2721
2722 goto nextline;
2723 }
2724 }
2725
2726 static void
smtp_filter_fd(struct smtp_tx * tx,int fd)2727 smtp_filter_fd(struct smtp_tx *tx, int fd)
2728 {
2729 struct smtp_session *s;
2730
2731 s = tx->session;
2732
2733 log_debug("smtp: %p: filter fd %d", s, fd);
2734
2735 tx->filter = io_new();
2736 io_set_fd(tx->filter, fd);
2737 io_set_callback(tx->filter, filter_session_io, tx);
2738 }
2739
2740 static void
smtp_message_begin(struct smtp_tx * tx)2741 smtp_message_begin(struct smtp_tx *tx)
2742 {
2743 struct smtp_session *s;
2744 struct smtp_rcpt *rcpt;
2745 int (*m_printf)(struct smtp_tx *, const char *, ...);
2746
2747 m_printf = smtp_message_printf;
2748 if (tx->filter)
2749 m_printf = smtp_filter_printf;
2750
2751 s = tx->session;
2752
2753 log_debug("smtp: %p: message begin", s);
2754
2755 smtp_reply(s, "354 Enter mail, end with \".\""
2756 " on a line by itself");
2757
2758 if (s->junk || (s->tx && s->tx->junk))
2759 m_printf(tx, "X-Spam: Yes\n");
2760
2761 m_printf(tx, "Received: ");
2762 if (!(s->listener->flags & F_MASK_SOURCE)) {
2763 m_printf(tx, "from %s (%s %s%s%s)",
2764 s->helo,
2765 s->rdns,
2766 s->ss.ss_family == AF_INET6 ? "" : "[",
2767 ss_to_text(&s->ss),
2768 s->ss.ss_family == AF_INET6 ? "" : "]");
2769 }
2770 m_printf(tx, "\n\tby %s (%s) with %sSMTP%s%s id %08x",
2771 s->smtpname,
2772 SMTPD_NAME,
2773 s->flags & SF_EHLO ? "E" : "",
2774 s->flags & SF_SECURE ? "S" : "",
2775 s->flags & SF_AUTHENTICATED ? "A" : "",
2776 tx->msgid);
2777
2778 if (s->flags & SF_SECURE) {
2779 m_printf(tx, " (%s:%s:%d:%s)",
2780 tls_conn_version(io_tls(s->io)),
2781 tls_conn_cipher(io_tls(s->io)),
2782 tls_conn_cipher_strength(io_tls(s->io)),
2783 (s->flags & SF_VERIFIED) ? "YES" : "NO");
2784
2785 if (s->listener->flags & F_RECEIVEDAUTH) {
2786 m_printf(tx, " auth=%s",
2787 s->username[0] ? "yes" : "no");
2788 if (s->username[0])
2789 m_printf(tx, " user=%s", s->username);
2790 }
2791 }
2792
2793 if (tx->rcptcount == 1) {
2794 rcpt = TAILQ_FIRST(&tx->rcpts);
2795 m_printf(tx, "\n\tfor <%s@%s>",
2796 rcpt->maddr.user,
2797 rcpt->maddr.domain);
2798 }
2799
2800 m_printf(tx, ";\n\t%s\n", time_to_text(time(&tx->time)));
2801
2802 smtp_enter_state(s, STATE_BODY);
2803 }
2804
2805 static void
smtp_message_end(struct smtp_tx * tx)2806 smtp_message_end(struct smtp_tx *tx)
2807 {
2808 struct smtp_session *s;
2809
2810 s = tx->session;
2811
2812 log_debug("debug: %p: end of message, error=%d", s, tx->error);
2813
2814 fclose(tx->ofile);
2815 tx->ofile = NULL;
2816
2817 switch(tx->error) {
2818 case TX_OK:
2819 smtp_tx_commit(tx);
2820 return;
2821
2822 case TX_ERROR_SIZE:
2823 smtp_reply(s, "554 %s %s: Transaction failed, message too big",
2824 esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM),
2825 esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM));
2826 break;
2827
2828 case TX_ERROR_LOOP:
2829 smtp_reply(s, "500 %s %s: Loop detected",
2830 esc_code(ESC_STATUS_PERMFAIL, ESC_ROUTING_LOOP_DETECTED),
2831 esc_description(ESC_ROUTING_LOOP_DETECTED));
2832 break;
2833
2834 case TX_ERROR_MALFORMED:
2835 smtp_reply(s, "550 %s %s: Message is not RFC 2822 compliant",
2836 esc_code(ESC_STATUS_PERMFAIL, ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED),
2837 esc_description(ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED));
2838 break;
2839
2840 case TX_ERROR_IO:
2841 case TX_ERROR_RESOURCES:
2842 smtp_reply(s, "421 %s Temporary Error",
2843 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2844 break;
2845
2846 default:
2847 /* fatal? */
2848 smtp_reply(s, "421 Internal server error");
2849 }
2850
2851 smtp_tx_rollback(tx);
2852 smtp_tx_free(tx);
2853 smtp_enter_state(s, STATE_HELO);
2854 }
2855
2856 static int
smtp_filter_printf(struct smtp_tx * tx,const char * fmt,...)2857 smtp_filter_printf(struct smtp_tx *tx, const char *fmt, ...)
2858 {
2859 va_list ap;
2860 int len;
2861
2862 if (tx->error)
2863 return -1;
2864
2865 va_start(ap, fmt);
2866 len = io_vprintf(tx->filter, fmt, ap);
2867 va_end(ap);
2868
2869 if (len < 0) {
2870 log_warn("smtp-in: session %016"PRIx64": vfprintf", tx->session->id);
2871 tx->error = TX_ERROR_IO;
2872 }
2873 else
2874 tx->odatalen += len;
2875
2876 return len;
2877 }
2878
2879 static int
smtp_message_printf(struct smtp_tx * tx,const char * fmt,...)2880 smtp_message_printf(struct smtp_tx *tx, const char *fmt, ...)
2881 {
2882 va_list ap;
2883 int len;
2884
2885 if (tx->error)
2886 return -1;
2887
2888 va_start(ap, fmt);
2889 len = vfprintf(tx->ofile, fmt, ap);
2890 va_end(ap);
2891
2892 if (len == -1) {
2893 log_warn("smtp-in: session %016"PRIx64": vfprintf", tx->session->id);
2894 tx->error = TX_ERROR_IO;
2895 }
2896 else
2897 tx->odatalen += len;
2898
2899 return len;
2900 }
2901
2902 #define CASE(x) case x : return #x
2903
2904 const char *
smtp_strstate(int state)2905 smtp_strstate(int state)
2906 {
2907 static char buf[32];
2908
2909 switch (state) {
2910 CASE(STATE_NEW);
2911 CASE(STATE_CONNECTED);
2912 CASE(STATE_TLS);
2913 CASE(STATE_HELO);
2914 CASE(STATE_AUTH_INIT);
2915 CASE(STATE_AUTH_USERNAME);
2916 CASE(STATE_AUTH_PASSWORD);
2917 CASE(STATE_AUTH_FINALIZE);
2918 CASE(STATE_BODY);
2919 CASE(STATE_QUIT);
2920 default:
2921 (void)snprintf(buf, sizeof(buf), "STATE_??? (%d)", state);
2922 return (buf);
2923 }
2924 }
2925
2926
2927 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)2928 smtp_report_link_connect(struct smtp_session *s, const char *rdns, int fcrdns,
2929 const struct sockaddr_storage *ss_src,
2930 const struct sockaddr_storage *ss_dest)
2931 {
2932 if (! SESSION_FILTERED(s))
2933 return;
2934
2935 report_smtp_link_connect("smtp-in", s->id, rdns, fcrdns, ss_src, ss_dest);
2936 }
2937
2938 static void
smtp_report_link_greeting(struct smtp_session * s,const char * domain)2939 smtp_report_link_greeting(struct smtp_session *s,
2940 const char *domain)
2941 {
2942 if (! SESSION_FILTERED(s))
2943 return;
2944
2945 report_smtp_link_greeting("smtp-in", s->id, domain);
2946 }
2947
2948 static void
smtp_report_link_identify(struct smtp_session * s,const char * method,const char * identity)2949 smtp_report_link_identify(struct smtp_session *s, const char *method, const char *identity)
2950 {
2951 if (! SESSION_FILTERED(s))
2952 return;
2953
2954 report_smtp_link_identify("smtp-in", s->id, method, identity);
2955 }
2956
2957 static void
smtp_report_link_tls(struct smtp_session * s,const char * ssl)2958 smtp_report_link_tls(struct smtp_session *s, const char *ssl)
2959 {
2960 if (! SESSION_FILTERED(s))
2961 return;
2962
2963 report_smtp_link_tls("smtp-in", s->id, ssl);
2964 }
2965
2966 static void
smtp_report_link_disconnect(struct smtp_session * s)2967 smtp_report_link_disconnect(struct smtp_session *s)
2968 {
2969 if (! SESSION_FILTERED(s))
2970 return;
2971
2972 report_smtp_link_disconnect("smtp-in", s->id);
2973 }
2974
2975 static void
smtp_report_link_auth(struct smtp_session * s,const char * user,const char * result)2976 smtp_report_link_auth(struct smtp_session *s, const char *user, const char *result)
2977 {
2978 if (! SESSION_FILTERED(s))
2979 return;
2980
2981 report_smtp_link_auth("smtp-in", s->id, user, result);
2982 }
2983
2984 static void
smtp_report_tx_reset(struct smtp_session * s,uint32_t msgid)2985 smtp_report_tx_reset(struct smtp_session *s, uint32_t msgid)
2986 {
2987 if (! SESSION_FILTERED(s))
2988 return;
2989
2990 report_smtp_tx_reset("smtp-in", s->id, msgid);
2991 }
2992
2993 static void
smtp_report_tx_begin(struct smtp_session * s,uint32_t msgid)2994 smtp_report_tx_begin(struct smtp_session *s, uint32_t msgid)
2995 {
2996 if (! SESSION_FILTERED(s))
2997 return;
2998
2999 report_smtp_tx_begin("smtp-in", s->id, msgid);
3000 }
3001
3002 static void
smtp_report_tx_mail(struct smtp_session * s,uint32_t msgid,const char * address,int ok)3003 smtp_report_tx_mail(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3004 {
3005 char mailaddr[SMTPD_MAXMAILADDRSIZE];
3006 char *p;
3007
3008 if (! SESSION_FILTERED(s))
3009 return;
3010
3011 if ((p = strchr(address, '<')) == NULL)
3012 return;
3013 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3014 if ((p = strchr(mailaddr, '>')) == NULL)
3015 return;
3016 *p = '\0';
3017
3018 report_smtp_tx_mail("smtp-in", s->id, msgid, mailaddr, ok);
3019 }
3020
3021 static void
smtp_report_tx_rcpt(struct smtp_session * s,uint32_t msgid,const char * address,int ok)3022 smtp_report_tx_rcpt(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3023 {
3024 char mailaddr[SMTPD_MAXMAILADDRSIZE];
3025 char *p;
3026
3027 if (! SESSION_FILTERED(s))
3028 return;
3029
3030 if ((p = strchr(address, '<')) == NULL)
3031 return;
3032 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3033 if ((p = strchr(mailaddr, '>')) == NULL)
3034 return;
3035 *p = '\0';
3036
3037 report_smtp_tx_rcpt("smtp-in", s->id, msgid, mailaddr, ok);
3038 }
3039
3040 static void
smtp_report_tx_envelope(struct smtp_session * s,uint32_t msgid,uint64_t evpid)3041 smtp_report_tx_envelope(struct smtp_session *s, uint32_t msgid, uint64_t evpid)
3042 {
3043 if (! SESSION_FILTERED(s))
3044 return;
3045
3046 report_smtp_tx_envelope("smtp-in", s->id, msgid, evpid);
3047 }
3048
3049 static void
smtp_report_tx_data(struct smtp_session * s,uint32_t msgid,int ok)3050 smtp_report_tx_data(struct smtp_session *s, uint32_t msgid, int ok)
3051 {
3052 if (! SESSION_FILTERED(s))
3053 return;
3054
3055 report_smtp_tx_data("smtp-in", s->id, msgid, ok);
3056 }
3057
3058 static void
smtp_report_tx_commit(struct smtp_session * s,uint32_t msgid,size_t msgsz)3059 smtp_report_tx_commit(struct smtp_session *s, uint32_t msgid, size_t msgsz)
3060 {
3061 if (! SESSION_FILTERED(s))
3062 return;
3063
3064 report_smtp_tx_commit("smtp-in", s->id, msgid, msgsz);
3065 }
3066
3067 static void
smtp_report_tx_rollback(struct smtp_session * s,uint32_t msgid)3068 smtp_report_tx_rollback(struct smtp_session *s, uint32_t msgid)
3069 {
3070 if (! SESSION_FILTERED(s))
3071 return;
3072
3073 report_smtp_tx_rollback("smtp-in", s->id, msgid);
3074 }
3075
3076 static void
smtp_report_protocol_client(struct smtp_session * s,const char * command)3077 smtp_report_protocol_client(struct smtp_session *s, const char *command)
3078 {
3079 if (! SESSION_FILTERED(s))
3080 return;
3081
3082 report_smtp_protocol_client("smtp-in", s->id, command);
3083 }
3084
3085 static void
smtp_report_protocol_server(struct smtp_session * s,const char * response)3086 smtp_report_protocol_server(struct smtp_session *s, const char *response)
3087 {
3088 if (! SESSION_FILTERED(s))
3089 return;
3090
3091 report_smtp_protocol_server("smtp-in", s->id, response);
3092 }
3093
3094 static void
smtp_report_filter_response(struct smtp_session * s,int phase,int response,const char * param)3095 smtp_report_filter_response(struct smtp_session *s, int phase, int response, const char *param)
3096 {
3097 if (! SESSION_FILTERED(s))
3098 return;
3099
3100 report_smtp_filter_response("smtp-in", s->id, phase, response, param);
3101 }
3102
3103 static void
smtp_report_timeout(struct smtp_session * s)3104 smtp_report_timeout(struct smtp_session *s)
3105 {
3106 if (! SESSION_FILTERED(s))
3107 return;
3108
3109 report_smtp_timeout("smtp-in", s->id);
3110 }
3111