Bug Summary

File:src/usr.sbin/smtpd/smtpd/../smtp_session.c
Warning:line 393, column 38
Although the value stored to 'pos_component_beg' is used in the enclosing expression, the value is never actually read from 'pos_component_beg'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name smtp_session.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/smtpd/smtpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/smtpd/smtpd/.. -D IO_TLS -D QUEUE_PROFILING -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/smtpd/smtpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/smtpd/smtpd/../smtp_session.c
1/* $OpenBSD: smtp_session.c,v 1.439 2024/01/03 08:11:15 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(*__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_MAX65535 65535
37#define DATA_HIWAT65535 65535
38#define APPEND_DOMAIN_BUFFER_SIZE65535 SMTP_LINE_MAX65535
39
40enum 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
53enum 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
63enum {
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
74enum 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
90struct smtp_rcpt {
91 TAILQ_ENTRY(smtp_rcpt)struct { struct smtp_rcpt *tqe_next; struct smtp_rcpt **tqe_prev
; }
entry;
92 uint64_t evpid;
93 struct mailaddr maddr;
94 size_t destcount;
95};
96
97struct 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)struct { struct smtp_rcpt *tqh_first; struct smtp_rcpt **tqh_last
; }
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
120struct 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_MAX255+1];
127 char smtpname[HOST_NAME_MAX255+1];
128 int fcrdns;
129
130 int flags;
131 enum smtp_state state;
132
133 uint8_t banner_sent;
134 char helo[LINE_MAX2048];
135 char cmd[LINE_MAX2048];
136 char username[SMTPD_MAXMAILADDRSIZE(255 + 1)];
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)((s)->listener->flags & 0x01 && !((s)->flags
& SF_SECURE))
\
151 ((s)->listener->flags & F_STARTTLS0x01 && !((s)->flags & SF_SECURE))
152
153#define ADVERTISE_AUTH(s)((s)->listener->flags & 0x08 && (s)->flags
& SF_SECURE && !((s)->flags & SF_AUTHENTICATED
))
\
154 ((s)->listener->flags & F_AUTH0x08 && (s)->flags & SF_SECURE && \
155 !((s)->flags & SF_AUTHENTICATED))
156
157#define ADVERTISE_EXT_DSN(s)((s)->listener->flags & 0x400) \
158 ((s)->listener->flags & F_EXT_DSN0x400)
159
160#define SESSION_FILTERED(s)((s)->listener->flags & 0x2000) \
161 ((s)->listener->flags & F_FILTERED0x2000)
162
163#define SESSION_DATA_FILTERED(s)((s)->listener->flags & 0x2000) \
164 ((s)->listener->flags & F_FILTERED0x2000)
165
166
167static int smtp_mailaddr(struct mailaddr *, char *, int, char **, const char *);
168static void smtp_session_init(void);
169static void smtp_lookup_servername(struct smtp_session *);
170static void smtp_getnameinfo_cb(void *, int, const char *, const char *);
171static void smtp_getaddrinfo_cb(void *, int, struct addrinfo *);
172static void smtp_connected(struct smtp_session *);
173static void smtp_send_banner(struct smtp_session *);
174static void smtp_tls_init(struct smtp_session *);
175static void smtp_tls_started(struct smtp_session *);
176static void smtp_io(struct io *, int, void *);
177static void smtp_enter_state(struct smtp_session *, int);
178static void smtp_reply(struct smtp_session *, char *, ...);
179static void smtp_command(struct smtp_session *, char *);
180static void smtp_rfc4954_auth_plain(struct smtp_session *, char *);
181static void smtp_rfc4954_auth_login(struct smtp_session *, char *);
182static void smtp_free(struct smtp_session *, const char *);
183static const char *smtp_strstate(int);
184static void smtp_auth_failure_pause(struct smtp_session *);
185static void smtp_auth_failure_resume(int, short, void *);
186
187static int smtp_tx(struct smtp_session *);
188static void smtp_tx_free(struct smtp_tx *);
189static void smtp_tx_create_message(struct smtp_tx *);
190static void smtp_tx_mail_from(struct smtp_tx *, const char *);
191static void smtp_tx_rcpt_to(struct smtp_tx *, const char *);
192static void smtp_tx_open_message(struct smtp_tx *);
193static void smtp_tx_commit(struct smtp_tx *);
194static void smtp_tx_rollback(struct smtp_tx *);
195static int smtp_tx_dataline(struct smtp_tx *, const char *);
196static int smtp_tx_filtered_dataline(struct smtp_tx *, const char *);
197static void smtp_tx_eom(struct smtp_tx *);
198static void smtp_filter_fd(struct smtp_tx *, int);
199static int smtp_message_fd(struct smtp_tx *, int);
200static void smtp_message_begin(struct smtp_tx *);
201static void smtp_message_end(struct smtp_tx *);
202static int smtp_filter_printf(struct smtp_tx *, const char *, ...)
203 __attribute__((__format__ (printf, 2, 3)));
204static int smtp_message_printf(struct smtp_tx *, const char *, ...)
205 __attribute__((__format__ (printf, 2, 3)));
206
207static int smtp_check_rset(struct smtp_session *, const char *);
208static int smtp_check_helo(struct smtp_session *, const char *);
209static int smtp_check_ehlo(struct smtp_session *, const char *);
210static int smtp_check_auth(struct smtp_session *s, const char *);
211static int smtp_check_starttls(struct smtp_session *, const char *);
212static int smtp_check_mail_from(struct smtp_session *, const char *);
213static int smtp_check_rcpt_to(struct smtp_session *, const char *);
214static int smtp_check_data(struct smtp_session *, const char *);
215static int smtp_check_noop(struct smtp_session *, const char *);
216static int smtp_check_noparam(struct smtp_session *, const char *);
217
218static void smtp_filter_phase(enum filter_phase, struct smtp_session *, const char *);
219
220static void smtp_proceed_connected(struct smtp_session *);
221static void smtp_proceed_rset(struct smtp_session *, const char *);
222static void smtp_proceed_helo(struct smtp_session *, const char *);
223static void smtp_proceed_ehlo(struct smtp_session *, const char *);
224static void smtp_proceed_auth(struct smtp_session *, const char *);
225static void smtp_proceed_starttls(struct smtp_session *, const char *);
226static void smtp_proceed_mail_from(struct smtp_session *, const char *);
227static void smtp_proceed_rcpt_to(struct smtp_session *, const char *);
228static void smtp_proceed_data(struct smtp_session *, const char *);
229static void smtp_proceed_noop(struct smtp_session *, const char *);
230static void smtp_proceed_help(struct smtp_session *, const char *);
231static void smtp_proceed_wiz(struct smtp_session *, const char *);
232static void smtp_proceed_quit(struct smtp_session *, const char *);
233static void smtp_proceed_commit(struct smtp_session *, const char *);
234static void smtp_proceed_rollback(struct smtp_session *, const char *);
235
236static void smtp_filter_begin(struct smtp_session *);
237static void smtp_filter_end(struct smtp_session *);
238static void smtp_filter_data_begin(struct smtp_session *);
239static void smtp_filter_data_end(struct smtp_session *);
240
241static void smtp_report_link_connect(struct smtp_session *, const char *, int,
242 const struct sockaddr_storage *,
243 const struct sockaddr_storage *);
244static void smtp_report_link_greeting(struct smtp_session *, const char *);
245static void smtp_report_link_identify(struct smtp_session *, const char *, const char *);
246static void smtp_report_link_tls(struct smtp_session *, const char *);
247static void smtp_report_link_disconnect(struct smtp_session *);
248static void smtp_report_link_auth(struct smtp_session *, const char *, const char *);
249static void smtp_report_tx_reset(struct smtp_session *, uint32_t);
250static void smtp_report_tx_begin(struct smtp_session *, uint32_t);
251static void smtp_report_tx_mail(struct smtp_session *, uint32_t, const char *, int);
252static void smtp_report_tx_rcpt(struct smtp_session *, uint32_t, const char *, int);
253static void smtp_report_tx_envelope(struct smtp_session *, uint32_t, uint64_t);
254static void smtp_report_tx_data(struct smtp_session *, uint32_t, int);
255static void smtp_report_tx_commit(struct smtp_session *, uint32_t, size_t);
256static void smtp_report_tx_rollback(struct smtp_session *, uint32_t);
257static void smtp_report_protocol_client(struct smtp_session *, const char *);
258static void smtp_report_protocol_server(struct smtp_session *, const char *);
259static void smtp_report_filter_response(struct smtp_session *, int, int, const char *);
260static void smtp_report_timeout(struct smtp_session *);
261
262
263static 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((void *)0), NULL((void *)0) },
285};
286
287static struct tree wait_lka_helo;
288static struct tree wait_lka_mail;
289static struct tree wait_lka_rcpt;
290static struct tree wait_parent_auth;
291static struct tree wait_queue_msg;
292static struct tree wait_queue_fd;
293static struct tree wait_queue_commit;
294static struct tree wait_ssl_init;
295static struct tree wait_ssl_verify;
296static struct tree wait_filters;
297static struct tree wait_filter_fd;
298
299static void
300header_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_SIZE65535];
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
380static void
381header_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_SIZE65535];
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;
Although the value stored to 'pos_component_beg' is used in the enclosing expression, the value is never actually read from 'pos_component_beg'
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
460static void
461header_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_SIZE65535];
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 && !quote)
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_MASQUERADE0x1000 &&
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_MASQUERADE0x1000 &&
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
562static void
563smtp_session_init(void)
564{
565 static int init = 0;
566
567 if (!init) {
568 tree_init(&wait_lka_helo)do { do { (&((&wait_lka_helo)->tree))->sph_root
= ((void *)0); } while (0); (&wait_lka_helo)->count =
0; } while(0)
;
569 tree_init(&wait_lka_mail)do { do { (&((&wait_lka_mail)->tree))->sph_root
= ((void *)0); } while (0); (&wait_lka_mail)->count =
0; } while(0)
;
570 tree_init(&wait_lka_rcpt)do { do { (&((&wait_lka_rcpt)->tree))->sph_root
= ((void *)0); } while (0); (&wait_lka_rcpt)->count =
0; } while(0)
;
571 tree_init(&wait_parent_auth)do { do { (&((&wait_parent_auth)->tree))->sph_root
= ((void *)0); } while (0); (&wait_parent_auth)->count
= 0; } while(0)
;
572 tree_init(&wait_queue_msg)do { do { (&((&wait_queue_msg)->tree))->sph_root
= ((void *)0); } while (0); (&wait_queue_msg)->count =
0; } while(0)
;
573 tree_init(&wait_queue_fd)do { do { (&((&wait_queue_fd)->tree))->sph_root
= ((void *)0); } while (0); (&wait_queue_fd)->count =
0; } while(0)
;
574 tree_init(&wait_queue_commit)do { do { (&((&wait_queue_commit)->tree))->sph_root
= ((void *)0); } while (0); (&wait_queue_commit)->count
= 0; } while(0)
;
575 tree_init(&wait_ssl_init)do { do { (&((&wait_ssl_init)->tree))->sph_root
= ((void *)0); } while (0); (&wait_ssl_init)->count =
0; } while(0)
;
576 tree_init(&wait_ssl_verify)do { do { (&((&wait_ssl_verify)->tree))->sph_root
= ((void *)0); } while (0); (&wait_ssl_verify)->count
= 0; } while(0)
;
577 tree_init(&wait_filters)do { do { (&((&wait_filters)->tree))->sph_root =
((void *)0); } while (0); (&wait_filters)->count = 0;
} while(0)
;
578 tree_init(&wait_filter_fd)do { do { (&((&wait_filter_fd)->tree))->sph_root
= ((void *)0); } while (0); (&wait_filter_fd)->count =
0; } while(0)
;
579 init = 1;
580 }
581}
582
583int
584smtp_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((void *)0))
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((void *)0))
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_TIMEOUT300 * 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 "do { if (tracing & (0x0008)) log_trace0("smtp: %p: connected to listener %p "
"[hostname=%s, port=%d, tag=%s]", s, listener, listener->
hostname, (__uint16_t)(__builtin_constant_p(listener->port
) ? (__uint16_t)(((__uint16_t)(listener->port) & 0xffU
) << 8 | ((__uint16_t)(listener->port) & 0xff00U
) >> 8) : __swap16md(listener->port)), listener->
tag); } while (0)
612 "[hostname=%s, port=%d, tag=%s]", s, listener,do { if (tracing & (0x0008)) log_trace0("smtp: %p: connected to listener %p "
"[hostname=%s, port=%d, tag=%s]", s, listener, listener->
hostname, (__uint16_t)(__builtin_constant_p(listener->port
) ? (__uint16_t)(((__uint16_t)(listener->port) & 0xffU
) << 8 | ((__uint16_t)(listener->port) & 0xff00U
) >> 8) : __swap16md(listener->port)), listener->
tag); } while (0)
613 listener->hostname, ntohs(listener->port), listener->tag)do { if (tracing & (0x0008)) log_trace0("smtp: %p: connected to listener %p "
"[hostname=%s, port=%d, tag=%s]", s, listener, listener->
hostname, (__uint16_t)(__builtin_constant_p(listener->port
) ? (__uint16_t)(((__uint16_t)(listener->port) & 0xffU
) << 8 | ((__uint16_t)(listener->port) & 0xff00U
) >> 8) : __swap16md(listener->port)), listener->
tag); } while (0)
;
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_NAMEREQD8 | NI_NUMERICSERV2, smtp_getnameinfo_cb, s);
627 }
628
629 /* session may have been freed by now */
630
631 return (0);
632}
633
634static void
635smtp_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-5 || gaierrno == EAI_NONAME-2)
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_STREAM1;
660 resolver_getaddrinfo(s->rdns, NULL((void *)0), &hints, smtp_getaddrinfo_cb, s);
661}
662
663static void
664smtp_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-5 || gaierrno == EAI_NONAME-2)
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
694void
695smtp_session_imsg(struct mproc *p, struct imsg *imsg)
696{
697 struct smtp_session *s;
698 struct smtp_rcpt *rcpt;
699 char user[SMTPD_MAXMAILADDRSIZE(255 + 1)];
700 char tmp[SMTP_LINE_MAX65535];
701 struct msg m;
702 const char *line, *helo;
703 uint64_t reqid, evpid;
704 uint32_t msgid;
705 int status, success;
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 s = tree_xpop(&wait_queue_fd, reqid);
806 if (!success || imsg->fd == -1) {
807 if (imsg->fd != -1)
808 close(imsg->fd);
809 smtp_reply(s, "421 %s Temporary Error",
810 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
811 smtp_enter_state(s, STATE_QUIT);
812 return;
813 }
814
815 log_debug("smtp: %p: fd %d from queue", s, imsg->fd);
816
817 if (smtp_message_fd(s->tx, imsg->fd)) {
818 if (!SESSION_DATA_FILTERED(s)((s)->listener->flags & 0x2000))
819 smtp_message_begin(s->tx);
820 else
821 smtp_filter_data_begin(s);
822 }
823 return;
824
825 case IMSG_FILTER_SMTP_DATA_BEGIN:
826 m_msg(&m, imsg);
827 m_get_id(&m, &reqid);
828 m_get_int(&m, &success);
829 m_end(&m);
830
831 s = tree_xpop(&wait_filter_fd, reqid);
832 if (!success || imsg->fd == -1) {
833 if (imsg->fd != -1)
834 close(imsg->fd);
835 smtp_reply(s, "421 %s Temporary Error",
836 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
837 smtp_enter_state(s, STATE_QUIT);
838 return;
839 }
840
841 log_debug("smtp: %p: fd %d from lka", s, imsg->fd);
842
843 smtp_filter_fd(s->tx, imsg->fd);
844 smtp_message_begin(s->tx);
845 return;
846
847 case IMSG_QUEUE_ENVELOPE_SUBMIT:
848 m_msg(&m, imsg);
849 m_get_id(&m, &reqid);
850 m_get_int(&m, &success);
851 s = tree_xget(&wait_lka_rcpt, reqid);
852 if (success) {
853 m_get_evpid(&m, &evpid);
854 s->tx->evp.id = evpid;
855 s->tx->destcount++;
856 smtp_report_tx_envelope(s, s->tx->msgid, evpid);
857 }
858 else
859 s->tx->error = TX_ERROR_ENVELOPE;
860 m_end(&m);
861 return;
862
863 case IMSG_QUEUE_ENVELOPE_COMMIT:
864 m_msg(&m, imsg);
865 m_get_id(&m, &reqid);
866 m_get_int(&m, &success);
867 m_end(&m);
868 if (!success)
869 fatalx("commit evp failed: not supposed to happen");
870 s = tree_xpop(&wait_lka_rcpt, reqid);
871 if (s->tx->error) {
872 /*
873 * If an envelope failed, we can't cancel the last
874 * RCPT only so we must cancel the whole transaction
875 * and close the connection.
876 */
877 smtp_reply(s, "421 %s Temporary failure",
878 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
879 smtp_enter_state(s, STATE_QUIT);
880 }
881 else {
882 rcpt = xcalloc(1, sizeof(*rcpt));
883 rcpt->evpid = s->tx->evp.id;
884 rcpt->destcount = s->tx->destcount;
885 rcpt->maddr = s->tx->evp.rcpt;
886 TAILQ_INSERT_TAIL(&s->tx->rcpts, rcpt, entry)do { (rcpt)->entry.tqe_next = ((void *)0); (rcpt)->entry
.tqe_prev = (&s->tx->rcpts)->tqh_last; *(&s->
tx->rcpts)->tqh_last = (rcpt); (&s->tx->rcpts
)->tqh_last = &(rcpt)->entry.tqe_next; } while (0)
;
887
888 s->tx->destcount = 0;
889 s->tx->rcptcount++;
890 smtp_reply(s, "250 %s %s: Recipient ok",
891 esc_code(ESC_STATUS_OK, ESC_DESTINATION_ADDRESS_VALID),
892 esc_description(ESC_DESTINATION_ADDRESS_VALID));
893 }
894 return;
895
896 case IMSG_SMTP_MESSAGE_COMMIT:
897 m_msg(&m, imsg);
898 m_get_id(&m, &reqid);
899 m_get_int(&m, &success);
900 m_end(&m);
901 s = tree_xpop(&wait_queue_commit, reqid);
902 if (!success) {
903 smtp_reply(s, "421 %s Temporary failure",
904 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
905 smtp_tx_free(s->tx);
906 smtp_enter_state(s, STATE_QUIT);
907 return;
908 }
909
910 smtp_reply(s, "250 %s %08x Message accepted for delivery",
911 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS),
912 s->tx->msgid);
913 smtp_report_tx_commit(s, s->tx->msgid, s->tx->odatalen);
914 smtp_report_tx_reset(s, s->tx->msgid);
915
916 log_info("%016"PRIx64"llx"" smtp message "
917 "msgid=%08x size=%zu nrcpt=%zu proto=%s",
918 s->id,
919 s->tx->msgid,
920 s->tx->odatalen,
921 s->tx->rcptcount,
922 s->flags & SF_EHLO ? "ESMTP" : "SMTP");
923 TAILQ_FOREACH(rcpt, &s->tx->rcpts, entry)for((rcpt) = ((&s->tx->rcpts)->tqh_first); (rcpt
) != ((void *)0); (rcpt) = ((rcpt)->entry.tqe_next))
{
924 log_info("%016"PRIx64"llx"" smtp envelope "
925 "evpid=%016"PRIx64"llx"" from=<%s%s%s> to=<%s%s%s>",
926 s->id,
927 rcpt->evpid,
928 s->tx->evp.sender.user,
929 s->tx->evp.sender.user[0] == '\0' ? "" : "@",
930 s->tx->evp.sender.domain,
931 rcpt->maddr.user,
932 rcpt->maddr.user[0] == '\0' ? "" : "@",
933 rcpt->maddr.domain);
934 }
935 smtp_tx_free(s->tx);
936 s->mailcount++;
937 smtp_enter_state(s, STATE_HELO);
938 return;
939
940 case IMSG_SMTP_AUTHENTICATE:
941 m_msg(&m, imsg);
942 m_get_id(&m, &reqid);
943 m_get_int(&m, &success);
944 m_end(&m);
945
946 s = tree_xpop(&wait_parent_auth, reqid);
947 strnvis(user, s->username, sizeof user, VIS_WHITE(0x04 | 0x08 | 0x10) | VIS_SAFE0x20);
948 if (success == LKA_OK) {
949 log_info("%016"PRIx64"llx"" smtp "
950 "authentication user=%s "
951 "result=ok",
952 s->id, user);
953 s->flags |= SF_AUTHENTICATED;
954 smtp_report_link_auth(s, user, "pass");
955 smtp_reply(s, "235 %s Authentication succeeded",
956 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
957 }
958 else if (success == LKA_PERMFAIL) {
959 log_info("%016"PRIx64"llx"" smtp "
960 "authentication user=%s "
961 "result=permfail",
962 s->id, user);
963 smtp_report_link_auth(s, user, "fail");
964 smtp_auth_failure_pause(s);
965 return;
966 }
967 else if (success == LKA_TEMPFAIL) {
968 log_info("%016"PRIx64"llx"" smtp "
969 "authentication user=%s "
970 "result=tempfail",
971 s->id, user);
972 smtp_report_link_auth(s, user, "error");
973 smtp_reply(s, "421 %s Temporary failure",
974 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
975 }
976 else
977 fatalx("bad lka response");
978
979 smtp_enter_state(s, STATE_HELO);
980 return;
981
982 case IMSG_FILTER_SMTP_PROTOCOL:
983 m_msg(&m, imsg);
984 m_get_id(&m, &reqid);
985 m_get_int(&m, &filter_response);
986 if (filter_response != FILTER_PROCEED &&
987 filter_response != FILTER_JUNK)
988 m_get_string(&m, &filter_param);
989 else
990 filter_param = NULL((void *)0);
991 m_end(&m);
992
993 s = tree_xpop(&wait_filters, reqid);
994
995 switch (filter_response) {
996 case FILTER_REJECT:
997 case FILTER_DISCONNECT:
998 if (!valid_smtp_response(filter_param) ||
999 (filter_param[0] != '4' && filter_param[0] != '5'))
1000 filter_param = "421 Internal server error";
1001 if (!strncmp(filter_param, "421", 3))
1002 filter_response = FILTER_DISCONNECT;
1003
1004 smtp_report_filter_response(s, s->filter_phase,
1005 filter_response, filter_param);
1006
1007 smtp_reply(s, "%s", filter_param);
1008
1009 if (filter_response == FILTER_DISCONNECT)
1010 smtp_enter_state(s, STATE_QUIT);
1011 else if (s->filter_phase == FILTER_COMMIT)
1012 smtp_proceed_rollback(s, NULL((void *)0));
1013 break;
1014
1015
1016 case FILTER_JUNK:
1017 if (s->tx)
1018 s->tx->junk = 1;
1019 else
1020 s->junk = 1;
1021 /* fallthrough */
1022
1023 case FILTER_PROCEED:
1024 filter_param = s->filter_param;
1025 /* fallthrough */
1026
1027 case FILTER_REWRITE:
1028 smtp_report_filter_response(s, s->filter_phase,
1029 filter_response,
1030 filter_param == s->filter_param ? NULL((void *)0) : filter_param);
1031 if (s->filter_phase == FILTER_CONNECT) {
1032 smtp_proceed_connected(s);
1033 return;
1034 }
1035 for (i = 0; i < nitems(commands)(sizeof((commands)) / sizeof((commands)[0])); ++i)
1036 if (commands[i].filter_phase == s->filter_phase) {
1037 if (filter_response == FILTER_REWRITE)
1038 if (!commands[i].check(s, filter_param))
1039 break;
1040 commands[i].proceed(s, filter_param);
1041 break;
1042 }
1043 break;
1044 }
1045 return;
1046 }
1047
1048 log_warnx("smtp_session_imsg: unexpected %s imsg",
1049 imsg_to_str(imsg->hdr.type));
1050 fatalx(NULL((void *)0));
1051}
1052
1053static void
1054smtp_tls_init(struct smtp_session *s)
1055{
1056 io_set_read(s->io);
1057 if (io_accept_tls(s->io, s->listener->tls) == -1) {
1058 log_info("%016"PRIx64"llx"" smtp disconnected "
1059 "reason=tls-accept-failed",
1060 s->id);
1061 smtp_free(s, "accept failed");
1062 }
1063}
1064
1065static void
1066smtp_tls_started(struct smtp_session *s)
1067{
1068 if (tls_peer_cert_provided(io_tls(s->io))) {
1069 log_info("%016"PRIx64"llx"" smtp "
1070 "cert-check result=\"%s\" fingerprint=\"%s\"",
1071 s->id,
1072 (s->flags & SF_VERIFIED) ? "verified" : "unchecked",
1073 tls_peer_cert_hash(io_tls(s->io)));
1074 }
1075
1076 if (s->listener->flags & F_SMTPS0x02) {
1077 stat_increment("smtp.smtps", 1);
1078 io_set_write(s->io);
1079 smtp_send_banner(s);
1080 }
1081 else {
1082 stat_increment("smtp.tls", 1);
1083 smtp_enter_state(s, STATE_HELO);
1084 }
1085}
1086
1087static void
1088smtp_io(struct io *io, int evt, void *arg)
1089{
1090 struct smtp_session *s = arg;
1091 char *line;
1092 size_t len;
1093 int eom;
1094
1095 log_trace(TRACE_IO, "smtp: %p: %s %s", s, io_strevent(evt),do { if (tracing & (0x0004)) log_trace0("smtp: %p: %s %s"
, s, io_strevent(evt), io_strio(io)); } while (0)
1096 io_strio(io))do { if (tracing & (0x0004)) log_trace0("smtp: %p: %s %s"
, s, io_strevent(evt), io_strio(io)); } while (0)
;
1097
1098 switch (evt) {
1099
1100 case IO_TLSREADY:
1101 log_info("%016"PRIx64"llx"" smtp tls ciphers=%s",
1102 s->id, tls_to_text(io_tls(s->io)));
1103
1104 smtp_report_link_tls(s, tls_to_text(io_tls(s->io)));
1105
1106 s->flags |= SF_SECURE;
1107 if (s->listener->flags & F_TLS_VERIFY0x200)
1108 s->flags |= SF_VERIFIED;
1109 s->helo[0] = '\0';
1110
1111 smtp_tls_started(s);
1112 break;
1113
1114 case IO_DATAIN:
1115 nextline:
1116 line = io_getline(s->io, &len);
1117 if ((line == NULL((void *)0) && io_datalen(s->io) >= SMTP_LINE_MAX65535) ||
1118 (line && len >= SMTP_LINE_MAX65535)) {
1119 s->flags |= SF_BADINPUT;
1120 smtp_reply(s, "500 %s Line too long",
1121 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1122 smtp_enter_state(s, STATE_QUIT);
1123 io_set_write(io);
1124 return;
1125 }
1126
1127 /* No complete line received */
1128 if (line == NULL((void *)0))
1129 return;
1130
1131 /* Strip trailing '\r' */
1132 if (len && line[len - 1] == '\r')
1133 line[--len] = '\0';
1134
1135 /* Message body */
1136 eom = 0;
1137 if (s->state == STATE_BODY) {
1138 if (strcmp(line, ".")) {
1139 s->tx->datain += strlen(line) + 1;
1140 if (s->tx->datain > env->sc_maxsize)
1141 s->tx->error = TX_ERROR_SIZE;
1142 }
1143 eom = (s->tx->filter == NULL((void *)0)) ?
1144 smtp_tx_dataline(s->tx, line) :
1145 smtp_tx_filtered_dataline(s->tx, line);
1146 if (eom == 0)
1147 goto nextline;
1148 }
1149
1150 /* Pipelining not supported */
1151 if (io_datalen(s->io)) {
1152 s->flags |= SF_BADINPUT;
1153 smtp_reply(s, "500 %s %s: Pipelining not supported",
1154 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1155 esc_description(ESC_INVALID_COMMAND));
1156 smtp_enter_state(s, STATE_QUIT);
1157 io_set_write(io);
1158 return;
1159 }
1160
1161 if (eom) {
1162 io_set_write(io);
1163 if (s->tx->filter == NULL((void *)0))
1164 smtp_tx_eom(s->tx);
1165 return;
1166 }
1167
1168 /* Must be a command */
1169 if (strlcpy(s->cmd, line, sizeof(s->cmd)) >= sizeof(s->cmd)) {
1170 s->flags |= SF_BADINPUT;
1171 smtp_reply(s, "500 %s Command line too long",
1172 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
1173 smtp_enter_state(s, STATE_QUIT);
1174 io_set_write(io);
1175 return;
1176 }
1177 io_set_write(io);
1178 smtp_command(s, line);
1179 break;
1180
1181 case IO_LOWAT:
1182 if (s->state == STATE_QUIT) {
1183 log_info("%016"PRIx64"llx"" smtp disconnected "
1184 "reason=quit",
1185 s->id);
1186 smtp_free(s, "done");
1187 break;
1188 }
1189
1190 /* Wait for the client to start tls */
1191 if (s->state == STATE_TLS) {
1192 smtp_tls_init(s);
1193 break;
1194 }
1195
1196 io_set_read(io);
1197 break;
1198
1199 case IO_TIMEOUT:
1200 log_info("%016"PRIx64"llx"" smtp disconnected "
1201 "reason=timeout",
1202 s->id);
1203 smtp_report_timeout(s);
1204 smtp_free(s, "timeout");
1205 break;
1206
1207 case IO_DISCONNECTED:
1208 log_info("%016"PRIx64"llx"" smtp disconnected "
1209 "reason=disconnect",
1210 s->id);
1211 smtp_free(s, "disconnected");
1212 break;
1213
1214 case IO_ERROR:
1215 log_info("%016"PRIx64"llx"" smtp disconnected "
1216 "reason=\"io-error: %s\"",
1217 s->id, io_error(io));
1218 smtp_free(s, "IO error");
1219 break;
1220
1221 default:
1222 fatalx("smtp_io()");
1223 }
1224}
1225
1226static void
1227smtp_command(struct smtp_session *s, char *line)
1228{
1229 char *args;
1230 int cmd, i;
1231
1232 log_trace(TRACE_SMTP, "smtp: %p: <<< %s", s, line)do { if (tracing & (0x0008)) log_trace0("smtp: %p: <<< %s"
, s, line); } while (0)
;
1233
1234 /*
1235 * These states are special.
1236 */
1237 if (s->state == STATE_AUTH_INIT) {
1238 smtp_report_protocol_client(s, "********");
1239 smtp_rfc4954_auth_plain(s, line);
1240 return;
1241 }
1242 if (s->state == STATE_AUTH_USERNAME || s->state == STATE_AUTH_PASSWORD) {
1243 smtp_report_protocol_client(s, "********");
1244 smtp_rfc4954_auth_login(s, line);
1245 return;
1246 }
1247
1248 if (s->state == STATE_HELO && strncasecmp(line, "AUTH PLAIN ", 11) == 0)
1249 smtp_report_protocol_client(s, "AUTH PLAIN ********");
1250 else
1251 smtp_report_protocol_client(s, line);
1252
1253
1254 /*
1255 * Unlike other commands, "mail from" and "rcpt to" contain a
1256 * space in the command name.
1257 */
1258 if (strncasecmp("mail from:", line, 10) == 0 ||
1259 strncasecmp("rcpt to:", line, 8) == 0)
1260 args = strchr(line, ':');
1261 else
1262 args = strchr(line, ' ');
1263
1264 if (args) {
1265 *args++ = '\0';
1266 while (isspace((unsigned char)*args))
1267 args++;
1268 }
1269
1270 cmd = -1;
1271 for (i = 0; commands[i].code != -1; i++)
1272 if (!strcasecmp(line, commands[i].cmd)) {
1273 cmd = commands[i].code;
1274 break;
1275 }
1276
1277 s->last_cmd = cmd;
1278 switch (cmd) {
1279 /*
1280 * INIT
1281 */
1282 case CMD_HELO:
1283 if (!smtp_check_helo(s, args))
1284 break;
1285 smtp_filter_phase(FILTER_HELO, s, args);
1286 break;
1287
1288 case CMD_EHLO:
1289 if (!smtp_check_ehlo(s, args))
1290 break;
1291 smtp_filter_phase(FILTER_EHLO, s, args);
1292 break;
1293
1294 /*
1295 * SETUP
1296 */
1297 case CMD_STARTTLS:
1298 if (!smtp_check_starttls(s, args))
1299 break;
1300
1301 smtp_filter_phase(FILTER_STARTTLS, s, NULL((void *)0));
1302 break;
1303
1304 case CMD_AUTH:
1305 if (!smtp_check_auth(s, args))
1306 break;
1307 smtp_filter_phase(FILTER_AUTH, s, args);
1308 break;
1309
1310 case CMD_MAIL_FROM:
1311 if (!smtp_check_mail_from(s, args))
1312 break;
1313 smtp_filter_phase(FILTER_MAIL_FROM, s, args);
1314 break;
1315
1316 /*
1317 * TRANSACTION
1318 */
1319 case CMD_RCPT_TO:
1320 if (!smtp_check_rcpt_to(s, args))
1321 break;
1322 smtp_filter_phase(FILTER_RCPT_TO, s, args);
1323 break;
1324
1325 case CMD_RSET:
1326 if (!smtp_check_rset(s, args))
1327 break;
1328 smtp_filter_phase(FILTER_RSET, s, NULL((void *)0));
1329 break;
1330
1331 case CMD_DATA:
1332 if (!smtp_check_data(s, args))
1333 break;
1334 smtp_filter_phase(FILTER_DATA, s, NULL((void *)0));
1335 break;
1336
1337 /*
1338 * ANY
1339 */
1340 case CMD_QUIT:
1341 if (!smtp_check_noparam(s, args))
1342 break;
1343 smtp_filter_phase(FILTER_QUIT, s, NULL((void *)0));
1344 break;
1345
1346 case CMD_NOOP:
1347 if (!smtp_check_noop(s, args))
1348 break;
1349 smtp_filter_phase(FILTER_NOOP, s, NULL((void *)0));
1350 break;
1351
1352 case CMD_HELP:
1353 if (!smtp_check_noparam(s, args))
1354 break;
1355 smtp_proceed_help(s, NULL((void *)0));
1356 break;
1357
1358 case CMD_WIZ:
1359 if (!smtp_check_noparam(s, args))
1360 break;
1361 smtp_proceed_wiz(s, NULL((void *)0));
1362 break;
1363
1364 default:
1365 smtp_reply(s, "500 %s %s: Command unrecognized",
1366 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1367 esc_description(ESC_INVALID_COMMAND));
1368 break;
1369 }
1370}
1371
1372static int
1373smtp_check_rset(struct smtp_session *s, const char *args)
1374{
1375 if (!smtp_check_noparam(s, args))
1376 return 0;
1377
1378 if (s->helo[0] == '\0') {
1379 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1380 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1381 esc_description(ESC_INVALID_COMMAND));
1382 return 0;
1383 }
1384 return 1;
1385}
1386
1387static int
1388smtp_check_helo(struct smtp_session *s, const char *args)
1389{
1390 if (!s->banner_sent) {
1391 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1392 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1393 esc_description(ESC_INVALID_COMMAND));
1394 return 0;
1395 }
1396
1397 if (s->helo[0]) {
1398 smtp_reply(s, "503 %s %s: Already identified",
1399 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1400 esc_description(ESC_INVALID_COMMAND));
1401 return 0;
1402 }
1403
1404 if (args == NULL((void *)0)) {
1405 smtp_reply(s, "501 %s %s: HELO requires domain name",
1406 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1407 esc_description(ESC_INVALID_COMMAND));
1408 return 0;
1409 }
1410
1411 if (!valid_domainpart(args)) {
1412 smtp_reply(s, "501 %s %s: Invalid domain name",
1413 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1414 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1415 return 0;
1416 }
1417
1418 return 1;
1419}
1420
1421static int
1422smtp_check_ehlo(struct smtp_session *s, const char *args)
1423{
1424 if (!s->banner_sent) {
1425 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1426 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1427 esc_description(ESC_INVALID_COMMAND));
1428 return 0;
1429 }
1430
1431 if (s->helo[0]) {
1432 smtp_reply(s, "503 %s %s: Already identified",
1433 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1434 esc_description(ESC_INVALID_COMMAND));
1435 return 0;
1436 }
1437
1438 if (args == NULL((void *)0)) {
1439 smtp_reply(s, "501 %s %s: EHLO requires domain name",
1440 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1441 esc_description(ESC_INVALID_COMMAND));
1442 return 0;
1443 }
1444
1445 if (!valid_domainpart(args)) {
1446 smtp_reply(s, "501 %s %s: Invalid domain name",
1447 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1448 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1449 return 0;
1450 }
1451
1452 return 1;
1453}
1454
1455static int
1456smtp_check_auth(struct smtp_session *s, const char *args)
1457{
1458 if (s->helo[0] == '\0' || s->tx) {
1459 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1460 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1461 esc_description(ESC_INVALID_COMMAND));
1462 return 0;
1463 }
1464
1465 if (s->flags & SF_AUTHENTICATED) {
1466 smtp_reply(s, "503 %s %s: Already authenticated",
1467 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1468 esc_description(ESC_INVALID_COMMAND));
1469 return 0;
1470 }
1471
1472 if (!ADVERTISE_AUTH(s)((s)->listener->flags & 0x08 && (s)->flags
& SF_SECURE && !((s)->flags & SF_AUTHENTICATED
))
) {
1473 smtp_reply(s, "503 %s %s: Command not supported",
1474 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1475 esc_description(ESC_INVALID_COMMAND));
1476 return 0;
1477 }
1478
1479 if (args == NULL((void *)0)) {
1480 smtp_reply(s, "501 %s %s: No parameters given",
1481 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1482 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1483 return 0;
1484 }
1485
1486 return 1;
1487}
1488
1489static int
1490smtp_check_starttls(struct smtp_session *s, const char *args)
1491{
1492 if (s->helo[0] == '\0' || s->tx) {
1493 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1494 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1495 esc_description(ESC_INVALID_COMMAND));
1496 return 0;
1497 }
1498
1499 if (!(s->listener->flags & F_STARTTLS0x01)) {
1500 smtp_reply(s, "503 %s %s: Command not supported",
1501 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1502 esc_description(ESC_INVALID_COMMAND));
1503 return 0;
1504 }
1505
1506 if (s->flags & SF_SECURE) {
1507 smtp_reply(s, "503 %s %s: Channel already secured",
1508 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1509 esc_description(ESC_INVALID_COMMAND));
1510 return 0;
1511 }
1512
1513 if (args != NULL((void *)0)) {
1514 smtp_reply(s, "501 %s %s: No parameters allowed",
1515 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1516 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1517 return 0;
1518 }
1519
1520 return 1;
1521}
1522
1523static int
1524smtp_check_mail_from(struct smtp_session *s, const char *args)
1525{
1526 char *copy;
1527 char tmp[SMTP_LINE_MAX65535];
1528 struct mailaddr sender;
1529
1530 (void)strlcpy(tmp, args, sizeof tmp);
1531 copy = tmp;
1532
1533 if (s->helo[0] == '\0' || s->tx) {
1534 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1535 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1536 esc_description(ESC_INVALID_COMMAND));
1537 return 0;
1538 }
1539
1540 if (s->listener->flags & F_STARTTLS_REQUIRE0x20 &&
1541 !(s->flags & SF_SECURE)) {
1542 smtp_reply(s,
1543 "530 %s %s: Must issue a STARTTLS command first",
1544 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1545 esc_description(ESC_INVALID_COMMAND));
1546 return 0;
1547 }
1548
1549 if (s->listener->flags & F_AUTH_REQUIRE0x40 &&
1550 !(s->flags & SF_AUTHENTICATED)) {
1551 smtp_reply(s,
1552 "530 %s %s: Must issue an AUTH command first",
1553 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1554 esc_description(ESC_INVALID_COMMAND));
1555 return 0;
1556 }
1557
1558 if (s->mailcount >= env->sc_session_max_mails) {
1559 /* we can pretend we had too many recipients */
1560 smtp_reply(s, "452 %s %s: Too many messages sent",
1561 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1562 esc_description(ESC_TOO_MANY_RECIPIENTS));
1563 return 0;
1564 }
1565
1566 if (smtp_mailaddr(&sender, copy, 1, &copy,
1567 s->smtpname) == 0) {
1568 smtp_reply(s, "553 %s Sender address syntax error",
1569 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1570 return 0;
1571 }
1572
1573 return 1;
1574}
1575
1576static int
1577smtp_check_rcpt_to(struct smtp_session *s, const char *args)
1578{
1579 char *copy;
1580 char tmp[SMTP_LINE_MAX65535];
1581
1582 (void)strlcpy(tmp, args, sizeof tmp);
1583 copy = tmp;
1584
1585 if (s->tx == NULL((void *)0)) {
1586 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1587 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1588 esc_description(ESC_INVALID_COMMAND));
1589 return 0;
1590 }
1591
1592 if (s->tx->rcptcount >= env->sc_session_max_rcpt) {
1593 smtp_reply(s->tx->session, "451 %s %s: Too many recipients",
1594 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
1595 esc_description(ESC_TOO_MANY_RECIPIENTS));
1596 return 0;
1597 }
1598
1599 if (smtp_mailaddr(&s->tx->evp.rcpt, copy, 0, &copy,
1600 s->tx->session->smtpname) == 0) {
1601 smtp_reply(s->tx->session,
1602 "501 %s Recipient address syntax error",
1603 esc_code(ESC_STATUS_PERMFAIL,
1604 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
1605 return 0;
1606 }
1607
1608 return 1;
1609}
1610
1611static int
1612smtp_check_data(struct smtp_session *s, const char *args)
1613{
1614 if (!smtp_check_noparam(s, args))
1615 return 0;
1616
1617 if (s->tx == NULL((void *)0)) {
1618 smtp_reply(s, "503 %s %s: Command not allowed at this point.",
1619 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1620 esc_description(ESC_INVALID_COMMAND));
1621 return 0;
1622 }
1623
1624 if (s->tx->rcptcount == 0) {
1625 smtp_reply(s, "503 %s %s: No recipient specified",
1626 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1627 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1628 return 0;
1629 }
1630
1631 return 1;
1632}
1633
1634static int
1635smtp_check_noop(struct smtp_session *s, const char *args)
1636{
1637 return 1;
1638}
1639
1640static int
1641smtp_check_noparam(struct smtp_session *s, const char *args)
1642{
1643 if (args != NULL((void *)0)) {
1644 smtp_reply(s, "500 %s %s: command does not accept arguments.",
1645 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
1646 esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
1647 return 0;
1648 }
1649 return 1;
1650}
1651
1652static void
1653smtp_query_filters(enum filter_phase phase, struct smtp_session *s, const char *args)
1654{
1655 m_create(p_lka, IMSG_FILTER_SMTP_PROTOCOL, 0, 0, -1);
1656 m_add_id(p_lka, s->id);
1657 m_add_int(p_lka, phase);
1658 m_add_string(p_lka, args);
1659 m_close(p_lka);
1660 tree_xset(&wait_filters, s->id, s);
1661}
1662
1663static void
1664smtp_filter_begin(struct smtp_session *s)
1665{
1666 if (!SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
1667 return;
1668
1669 m_create(p_lka, IMSG_FILTER_SMTP_BEGIN, 0, 0, -1);
1670 m_add_id(p_lka, s->id);
1671 m_add_string(p_lka, s->listener->filter_name);
1672 m_close(p_lka);
1673}
1674
1675static void
1676smtp_filter_end(struct smtp_session *s)
1677{
1678 if (!SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
1679 return;
1680
1681 m_create(p_lka, IMSG_FILTER_SMTP_END, 0, 0, -1);
1682 m_add_id(p_lka, s->id);
1683 m_close(p_lka);
1684}
1685
1686static void
1687smtp_filter_data_begin(struct smtp_session *s)
1688{
1689 if (!SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
1690 return;
1691
1692 m_create(p_lka, IMSG_FILTER_SMTP_DATA_BEGIN, 0, 0, -1);
1693 m_add_id(p_lka, s->id);
1694 m_close(p_lka);
1695 tree_xset(&wait_filter_fd, s->id, s);
1696}
1697
1698static void
1699smtp_filter_data_end(struct smtp_session *s)
1700{
1701 if (!SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
1702 return;
1703
1704 if (s->tx->filter == NULL((void *)0))
1705 return;
1706
1707 io_free(s->tx->filter);
1708 s->tx->filter = NULL((void *)0);
1709
1710 m_create(p_lka, IMSG_FILTER_SMTP_DATA_END, 0, 0, -1);
1711 m_add_id(p_lka, s->id);
1712 m_close(p_lka);
1713}
1714
1715static void
1716smtp_filter_phase(enum filter_phase phase, struct smtp_session *s, const char *param)
1717{
1718 uint8_t i;
1719
1720 s->filter_phase = phase;
1721 s->filter_param = param;
1722
1723 if (SESSION_FILTERED(s)((s)->listener->flags & 0x2000)) {
1724 smtp_query_filters(phase, s, param ? param : "");
1725 return;
1726 }
1727
1728 if (s->filter_phase == FILTER_CONNECT) {
1729 smtp_proceed_connected(s);
1730 return;
1731 }
1732
1733 for (i = 0; i < nitems(commands)(sizeof((commands)) / sizeof((commands)[0])); ++i)
1734 if (commands[i].filter_phase == s->filter_phase) {
1735 commands[i].proceed(s, param);
1736 break;
1737 }
1738}
1739
1740static void
1741smtp_proceed_rset(struct smtp_session *s, const char *args)
1742{
1743 smtp_reply(s, "250 %s Reset state",
1744 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1745
1746 if (s->tx) {
1747 if (s->tx->msgid)
1748 smtp_tx_rollback(s->tx);
1749 smtp_tx_free(s->tx);
1750 }
1751}
1752
1753static void
1754smtp_proceed_helo(struct smtp_session *s, const char *args)
1755{
1756 (void)strlcpy(s->helo, args, sizeof(s->helo));
1757 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1758
1759 smtp_report_link_identify(s, "HELO", s->helo);
1760
1761 smtp_enter_state(s, STATE_HELO);
1762
1763 smtp_reply(s, "250 %s Hello %s %s%s%s, pleased to meet you",
1764 s->smtpname,
1765 s->helo,
1766 s->ss.ss_family == AF_INET624 ? "" : "[",
1767 ss_to_text(&s->ss),
1768 s->ss.ss_family == AF_INET624 ? "" : "]");
1769}
1770
1771static void
1772smtp_proceed_ehlo(struct smtp_session *s, const char *args)
1773{
1774 (void)strlcpy(s->helo, args, sizeof(s->helo));
1775 s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
1776 s->flags |= SF_EHLO;
1777 s->flags |= SF_8BITMIME;
1778
1779 smtp_report_link_identify(s, "EHLO", s->helo);
1780
1781 smtp_enter_state(s, STATE_HELO);
1782 smtp_reply(s, "250-%s Hello %s %s%s%s, pleased to meet you",
1783 s->smtpname,
1784 s->helo,
1785 s->ss.ss_family == AF_INET624 ? "" : "[",
1786 ss_to_text(&s->ss),
1787 s->ss.ss_family == AF_INET624 ? "" : "]");
1788
1789 smtp_reply(s, "250-8BITMIME");
1790 smtp_reply(s, "250-ENHANCEDSTATUSCODES");
1791 smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
1792 if (ADVERTISE_EXT_DSN(s)((s)->listener->flags & 0x400))
1793 smtp_reply(s, "250-DSN");
1794 if (ADVERTISE_TLS(s)((s)->listener->flags & 0x01 && !((s)->flags
& SF_SECURE))
)
1795 smtp_reply(s, "250-STARTTLS");
1796 if (ADVERTISE_AUTH(s)((s)->listener->flags & 0x08 && (s)->flags
& SF_SECURE && !((s)->flags & SF_AUTHENTICATED
))
)
1797 smtp_reply(s, "250-AUTH PLAIN LOGIN");
1798 smtp_reply(s, "250 HELP");
1799}
1800
1801static void
1802smtp_proceed_auth(struct smtp_session *s, const char *args)
1803{
1804 char tmp[SMTP_LINE_MAX65535];
1805 char *eom, *method;
1806
1807 (void)strlcpy(tmp, args, sizeof tmp);
1808
1809 method = tmp;
1810 eom = strchr(tmp, ' ');
1811 if (eom == NULL((void *)0))
1812 eom = strchr(tmp, '\t');
1813 if (eom != NULL((void *)0))
1814 *eom++ = '\0';
1815 if (strcasecmp(method, "PLAIN") == 0)
1816 smtp_rfc4954_auth_plain(s, eom);
1817 else if (strcasecmp(method, "LOGIN") == 0)
1818 smtp_rfc4954_auth_login(s, eom);
1819 else
1820 smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
1821 esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1822 esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
1823 method);
1824}
1825
1826static void
1827smtp_proceed_starttls(struct smtp_session *s, const char *args)
1828{
1829 smtp_reply(s, "220 %s Ready to start TLS",
1830 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1831 smtp_enter_state(s, STATE_TLS);
1832}
1833
1834static void
1835smtp_proceed_mail_from(struct smtp_session *s, const char *args)
1836{
1837 char *copy;
1838 char tmp[SMTP_LINE_MAX65535];
1839
1840 (void)strlcpy(tmp, args, sizeof tmp);
1841 copy = tmp;
1842
1843 if (!smtp_tx(s)) {
1844 smtp_reply(s, "421 %s Temporary Error",
1845 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
1846 smtp_enter_state(s, STATE_QUIT);
1847 return;
1848 }
1849
1850 if (smtp_mailaddr(&s->tx->evp.sender, copy, 1, &copy,
1851 s->smtpname) == 0) {
1852 smtp_reply(s, "553 %s Sender address syntax error",
1853 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
1854 smtp_tx_free(s->tx);
1855 return;
1856 }
1857
1858 smtp_tx_mail_from(s->tx, args);
1859}
1860
1861static void
1862smtp_proceed_rcpt_to(struct smtp_session *s, const char *args)
1863{
1864 smtp_tx_rcpt_to(s->tx, args);
1865}
1866
1867static void
1868smtp_proceed_data(struct smtp_session *s, const char *args)
1869{
1870 smtp_tx_open_message(s->tx);
1871}
1872
1873static void
1874smtp_proceed_quit(struct smtp_session *s, const char *args)
1875{
1876 smtp_reply(s, "221 %s Bye",
1877 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1878 smtp_enter_state(s, STATE_QUIT);
1879}
1880
1881static void
1882smtp_proceed_noop(struct smtp_session *s, const char *args)
1883{
1884 smtp_reply(s, "250 %s Ok",
1885 esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
1886}
1887
1888static void
1889smtp_proceed_help(struct smtp_session *s, const char *args)
1890{
1891 const char *code = esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS);
1892
1893 smtp_reply(s, "214-%s This is " SMTPD_NAME"OpenSMTPD", code);
1894 smtp_reply(s, "214-%s To report bugs in the implementation, "
1895 "please contact bugs@openbsd.org", code);
1896 smtp_reply(s, "214-%s with full details", code);
1897 smtp_reply(s, "214 %s End of HELP info", code);
1898}
1899
1900static void
1901smtp_proceed_wiz(struct smtp_session *s, const char *args)
1902{
1903 smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
1904 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
1905 esc_description(ESC_INVALID_COMMAND));
1906}
1907
1908static void
1909smtp_proceed_commit(struct smtp_session *s, const char *args)
1910{
1911 smtp_message_end(s->tx);
1912}
1913
1914static void
1915smtp_proceed_rollback(struct smtp_session *s, const char *args)
1916{
1917 struct smtp_tx *tx;
1918
1919 tx = s->tx;
1920
1921 fclose(tx->ofile);
1922 tx->ofile = NULL((void *)0);
1923
1924 smtp_tx_rollback(tx);
1925 smtp_tx_free(tx);
1926 smtp_enter_state(s, STATE_HELO);
1927}
1928
1929static void
1930smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg)
1931{
1932 char buf[1024], *user, *pass;
1933 int len;
1934
1935 switch (s->state) {
1936 case STATE_HELO:
1937 if (arg == NULL((void *)0)) {
1938 smtp_enter_state(s, STATE_AUTH_INIT);
1939 smtp_reply(s, "334 ");
1940 return;
1941 }
1942 smtp_enter_state(s, STATE_AUTH_INIT);
1943 /* FALLTHROUGH */
1944
1945 case STATE_AUTH_INIT:
1946 /* String is not NUL terminated, leave room. */
1947 if ((len = base64_decode(arg, (unsigned char *)buf,
1948 sizeof(buf) - 1)) == -1)
1949 goto abort;
1950 /* buf is a byte string, NUL terminate. */
1951 buf[len] = '\0';
1952
1953 /*
1954 * Skip "foo" in "foo\0user\0pass", if present.
1955 */
1956 user = memchr(buf, '\0', len);
1957 if (user == NULL((void *)0) || user >= buf + len - 2)
1958 goto abort;
1959 user++; /* skip NUL */
1960 if (strlcpy(s->username, user, sizeof(s->username))
1961 >= sizeof(s->username))
1962 goto abort;
1963
1964 pass = memchr(user, '\0', len - (user - buf));
1965 if (pass == NULL((void *)0) || pass >= buf + len - 2)
1966 goto abort;
1967 pass++; /* skip NUL */
1968
1969 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
1970 m_add_id(p_lka, s->id);
1971 m_add_string(p_lka, s->listener->authtable);
1972 m_add_string(p_lka, user);
1973 m_add_string(p_lka, pass);
1974 m_close(p_lka);
1975 tree_xset(&wait_parent_auth, s->id, s);
1976 return;
1977
1978 default:
1979 fatal("smtp_rfc4954_auth_plain: unknown state");
1980 }
1981
1982abort:
1983 smtp_reply(s, "501 %s %s: Syntax error",
1984 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
1985 esc_description(ESC_SYNTAX_ERROR));
1986 smtp_enter_state(s, STATE_HELO);
1987}
1988
1989static void
1990smtp_rfc4954_auth_login(struct smtp_session *s, char *arg)
1991{
1992 char buf[LINE_MAX2048];
1993
1994 switch (s->state) {
1995 case STATE_HELO:
1996 smtp_enter_state(s, STATE_AUTH_USERNAME);
1997 if (arg != NULL((void *)0) && *arg != '\0') {
1998 smtp_rfc4954_auth_login(s, arg);
1999 return;
2000 }
2001 smtp_reply(s, "334 VXNlcm5hbWU6");
2002 return;
2003
2004 case STATE_AUTH_USERNAME:
2005 memset(s->username, 0, sizeof(s->username));
2006 if (base64_decode(arg, (unsigned char *)s->username,
2007 sizeof(s->username) - 1) == -1)
2008 goto abort;
2009
2010 smtp_enter_state(s, STATE_AUTH_PASSWORD);
2011 smtp_reply(s, "334 UGFzc3dvcmQ6");
2012 return;
2013
2014 case STATE_AUTH_PASSWORD:
2015 memset(buf, 0, sizeof(buf));
2016 if (base64_decode(arg, (unsigned char *)buf,
2017 sizeof(buf)-1) == -1)
2018 goto abort;
2019
2020 m_create(p_lka, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
2021 m_add_id(p_lka, s->id);
2022 m_add_string(p_lka, s->listener->authtable);
2023 m_add_string(p_lka, s->username);
2024 m_add_string(p_lka, buf);
2025 m_close(p_lka);
2026 tree_xset(&wait_parent_auth, s->id, s);
2027 return;
2028
2029 default:
2030 fatal("smtp_rfc4954_auth_login: unknown state");
2031 }
2032
2033abort:
2034 smtp_reply(s, "501 %s %s: Syntax error",
2035 esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
2036 esc_description(ESC_SYNTAX_ERROR));
2037 smtp_enter_state(s, STATE_HELO);
2038}
2039
2040static void
2041smtp_lookup_servername(struct smtp_session *s)
2042{
2043 if (s->listener->hostnametable[0]) {
2044 m_create(p_lka, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
2045 m_add_id(p_lka, s->id);
2046 m_add_string(p_lka, s->listener->hostnametable);
2047 m_add_sockaddr(p_lka, (struct sockaddr*)&s->listener->ss);
2048 m_close(p_lka);
2049 tree_xset(&wait_lka_helo, s->id, s);
2050 return;
2051 }
2052
2053 smtp_connected(s);
2054}
2055
2056static void
2057smtp_connected(struct smtp_session *s)
2058{
2059 smtp_enter_state(s, STATE_CONNECTED);
2060
2061 log_info("%016"PRIx64"llx"" smtp connected address=%s host=%s",
2062 s->id, ss_to_text(&s->ss), s->rdns);
2063
2064 smtp_filter_begin(s);
2065
2066 smtp_report_link_connect(s, s->rdns, s->fcrdns, &s->ss,
2067 &s->listener->ss);
2068
2069 smtp_filter_phase(FILTER_CONNECT, s, ss_to_text(&s->ss));
2070}
2071
2072static void
2073smtp_proceed_connected(struct smtp_session *s)
2074{
2075 if (s->listener->flags & F_SMTPS0x02)
2076 smtp_tls_init(s);
2077 else
2078 smtp_send_banner(s);
2079}
2080
2081static void
2082smtp_send_banner(struct smtp_session *s)
2083{
2084 smtp_reply(s, "220 %s ESMTP %s", s->smtpname, SMTPD_NAME"OpenSMTPD");
2085 s->banner_sent = 1;
2086 smtp_report_link_greeting(s, s->smtpname);
2087}
2088
2089void
2090smtp_enter_state(struct smtp_session *s, int newstate)
2091{
2092 log_trace(TRACE_SMTP, "smtp: %p: %s -> %s", s,do { if (tracing & (0x0008)) log_trace0("smtp: %p: %s -> %s"
, s, smtp_strstate(s->state), smtp_strstate(newstate)); } while
(0)
2093 smtp_strstate(s->state),do { if (tracing & (0x0008)) log_trace0("smtp: %p: %s -> %s"
, s, smtp_strstate(s->state), smtp_strstate(newstate)); } while
(0)
2094 smtp_strstate(newstate))do { if (tracing & (0x0008)) log_trace0("smtp: %p: %s -> %s"
, s, smtp_strstate(s->state), smtp_strstate(newstate)); } while
(0)
;
2095
2096 s->state = newstate;
2097}
2098
2099static void
2100smtp_reply(struct smtp_session *s, char *fmt, ...)
2101{
2102 va_list ap;
2103 int n;
2104 char buf[LINE_MAX2048*2], tmp[LINE_MAX2048*2];
2105
2106 va_start(ap, fmt)__builtin_va_start((ap), fmt);
2107 n = vsnprintf(buf, sizeof buf, fmt, ap);
2108 va_end(ap)__builtin_va_end((ap));
2109 if (n < 0)
2110 fatalx("smtp_reply: response format error");
2111 if (n < 4)
2112 fatalx("smtp_reply: response too short");
2113 if (n >= (int)sizeof buf) {
2114 /* only first three bytes are used by SMTP logic,
2115 * so if _our_ reply does not fit entirely in the
2116 * buffer, it's ok to truncate.
2117 */
2118 }
2119
2120 log_trace(TRACE_SMTP, "smtp: %p: >>> %s", s, buf)do { if (tracing & (0x0008)) log_trace0("smtp: %p: >>> %s"
, s, buf); } while (0)
;
2121 smtp_report_protocol_server(s, buf);
2122
2123 switch (buf[0]) {
2124 case '2':
2125 if (s->tx) {
2126 if (s->last_cmd == CMD_MAIL_FROM) {
2127 smtp_report_tx_begin(s, s->tx->msgid);
2128 smtp_report_tx_mail(s, s->tx->msgid, s->cmd + 10, 1);
2129 }
2130 else if (s->last_cmd == CMD_RCPT_TO)
2131 smtp_report_tx_rcpt(s, s->tx->msgid, s->cmd + 8, 1);
2132 }
2133 break;
2134 case '3':
2135 if (s->tx) {
2136 if (s->last_cmd == CMD_DATA)
2137 smtp_report_tx_data(s, s->tx->msgid, 1);
2138 }
2139 break;
2140 case '5':
2141 case '4':
2142 /* do not report smtp_tx_mail/smtp_tx_rcpt errors
2143 * if they happened outside of a transaction.
2144 */
2145 if (s->tx) {
2146 if (s->last_cmd == CMD_MAIL_FROM)
2147 smtp_report_tx_mail(s, s->tx->msgid,
2148 s->cmd + 10, buf[0] == '4' ? -1 : 0);
2149 else if (s->last_cmd == CMD_RCPT_TO)
2150 smtp_report_tx_rcpt(s,
2151 s->tx->msgid, s->cmd + 8, buf[0] == '4' ? -1 : 0);
2152 else if (s->last_cmd == CMD_DATA && s->tx->rcptcount)
2153 smtp_report_tx_data(s, s->tx->msgid,
2154 buf[0] == '4' ? -1 : 0);
2155 }
2156
2157 if (s->flags & SF_BADINPUT) {
2158 log_info("%016"PRIx64"llx"" smtp "
2159 "bad-input result=\"%.*s\"",
2160 s->id, n, buf);
2161 }
2162 else if (s->state == STATE_AUTH_INIT) {
2163 log_info("%016"PRIx64"llx"" smtp "
2164 "failed-command "
2165 "command=\"AUTH PLAIN (...)\" result=\"%.*s\"",
2166 s->id, n, buf);
2167 }
2168 else if (s->state == STATE_AUTH_USERNAME) {
2169 log_info("%016"PRIx64"llx"" smtp "
2170 "failed-command "
2171 "command=\"AUTH LOGIN (username)\" result=\"%.*s\"",
2172 s->id, n, buf);
2173 }
2174 else if (s->state == STATE_AUTH_PASSWORD) {
2175 log_info("%016"PRIx64"llx"" smtp "
2176 "failed-command "
2177 "command=\"AUTH LOGIN (password)\" result=\"%.*s\"",
2178 s->id, n, buf);
2179 }
2180 else {
2181 strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE0x20 | VIS_CSTYLE0x02);
2182 log_info("%016"PRIx64"llx"" smtp "
2183 "failed-command command=\"%s\" "
2184 "result=\"%.*s\"",
2185 s->id, tmp, n, buf);
2186 }
2187 break;
2188 }
2189
2190 io_xprintf(s->io, "%s\r\n", buf);
2191}
2192
2193static void
2194smtp_free(struct smtp_session *s, const char * reason)
2195{
2196 if (s->tx) {
2197 if (s->tx->msgid)
2198 smtp_tx_rollback(s->tx);
2199 smtp_tx_free(s->tx);
2200 }
2201
2202 smtp_report_link_disconnect(s);
2203 smtp_filter_end(s);
2204
2205 if (s->flags & SF_SECURE && s->listener->flags & F_SMTPS0x02)
2206 stat_decrement("smtp.smtps", 1);
2207 if (s->flags & SF_SECURE && s->listener->flags & F_STARTTLS0x01)
2208 stat_decrement("smtp.tls", 1);
2209
2210 io_free(s->io);
2211 free(s);
2212
2213 smtp_collect();
2214}
2215
2216static int
2217smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args,
2218 const char *domain)
2219{
2220 char *p, *e;
2221
2222 if (line == NULL((void *)0))
2223 return (0);
2224
2225 if (*line != '<')
2226 return (0);
2227
2228 e = strchr(line, '>');
2229 if (e == NULL((void *)0))
2230 return (0);
2231 *e++ = '\0';
2232 while (*e == ' ')
2233 e++;
2234 *args = e;
2235
2236 if (!text_to_mailaddr(maddr, line + 1))
2237 return (0);
2238
2239 p = strchr(maddr->user, ':');
2240 if (p != NULL((void *)0)) {
2241 p++;
2242 memmove(maddr->user, p, strlen(p) + 1);
2243 }
2244
2245 /* accept empty return-path in MAIL FROM, required for bounces */
2246 if (mailfrom && maddr->user[0] == '\0' && maddr->domain[0] == '\0')
2247 return (1);
2248
2249 /* no or invalid user-part, reject */
2250 if (maddr->user[0] == '\0' || !valid_localpart(maddr->user))
2251 return (0);
2252
2253 /* no domain part, local user */
2254 if (maddr->domain[0] == '\0') {
2255 (void)strlcpy(maddr->domain, domain,
2256 sizeof(maddr->domain));
2257 }
2258
2259 if (!valid_domainpart(maddr->domain))
2260 return (0);
2261
2262 return (1);
2263}
2264
2265static void
2266smtp_auth_failure_resume(int fd, short event, void *p)
2267{
2268 struct smtp_session *s = p;
2269
2270 smtp_reply(s, "535 Authentication failed");
2271 smtp_enter_state(s, STATE_HELO);
2272}
2273
2274static void
2275smtp_auth_failure_pause(struct smtp_session *s)
2276{
2277 struct timeval tv;
2278
2279 tv.tv_sec = 0;
2280 tv.tv_usec = arc4random_uniform(1000000);
2281 log_trace(TRACE_SMTP, "smtp: timing-attack protection triggered, "do { if (tracing & (0x0008)) log_trace0("smtp: timing-attack protection triggered, "
"will defer answer for %lu microseconds", (long)tv.tv_usec);
} while (0)
2282 "will defer answer for %lu microseconds", (long)tv.tv_usec)do { if (tracing & (0x0008)) log_trace0("smtp: timing-attack protection triggered, "
"will defer answer for %lu microseconds", (long)tv.tv_usec);
} while (0)
;
2283 evtimer_set(&s->pause, smtp_auth_failure_resume, s)event_set(&s->pause, -1, 0, smtp_auth_failure_resume, s
)
;
2284 evtimer_add(&s->pause, &tv)event_add(&s->pause, &tv);
2285}
2286
2287static int
2288smtp_tx(struct smtp_session *s)
2289{
2290 struct smtp_tx *tx;
2291
2292 tx = calloc(1, sizeof(*tx));
2293 if (tx == NULL((void *)0))
2294 return 0;
2295
2296 TAILQ_INIT(&tx->rcpts)do { (&tx->rcpts)->tqh_first = ((void *)0); (&tx
->rcpts)->tqh_last = &(&tx->rcpts)->tqh_first
; } while (0)
;
2297
2298 s->tx = tx;
2299 tx->session = s;
2300
2301 /* setup the envelope */
2302 tx->evp.ss = s->ss;
2303 (void)strlcpy(tx->evp.tag, s->listener->tag, sizeof(tx->evp.tag));
2304 (void)strlcpy(tx->evp.smtpname, s->smtpname, sizeof(tx->evp.smtpname));
2305 (void)strlcpy(tx->evp.hostname, s->rdns, sizeof tx->evp.hostname);
2306 (void)strlcpy(tx->evp.helo, s->helo, sizeof(tx->evp.helo));
2307 (void)strlcpy(tx->evp.username, s->username, sizeof(tx->evp.username));
2308
2309 if (s->flags & SF_BOUNCE)
2310 tx->evp.flags |= EF_BOUNCE;
2311 if (s->flags & SF_AUTHENTICATED)
2312 tx->evp.flags |= EF_AUTHENTICATED;
2313
2314 if ((tx->parser = rfc5322_parser_new()) == NULL((void *)0)) {
2315 free(tx);
2316 return 0;
2317 }
2318
2319 return 1;
2320}
2321
2322static void
2323smtp_tx_free(struct smtp_tx *tx)
2324{
2325 struct smtp_rcpt *rcpt;
2326
2327 rfc5322_free(tx->parser);
2328
2329 while ((rcpt = TAILQ_FIRST(&tx->rcpts)((&tx->rcpts)->tqh_first))) {
2330 TAILQ_REMOVE(&tx->rcpts, rcpt, entry)do { if (((rcpt)->entry.tqe_next) != ((void *)0)) (rcpt)->
entry.tqe_next->entry.tqe_prev = (rcpt)->entry.tqe_prev
; else (&tx->rcpts)->tqh_last = (rcpt)->entry.tqe_prev
; *(rcpt)->entry.tqe_prev = (rcpt)->entry.tqe_next; ; ;
} while (0)
;
2331 free(rcpt);
2332 }
2333
2334 if (tx->ofile)
2335 fclose(tx->ofile);
2336
2337 tx->session->tx = NULL((void *)0);
2338
2339 free(tx);
2340}
2341
2342static void
2343smtp_tx_mail_from(struct smtp_tx *tx, const char *line)
2344{
2345 char *opt;
2346 char *copy;
2347 char tmp[SMTP_LINE_MAX65535];
2348
2349 (void)strlcpy(tmp, line, sizeof tmp);
2350 copy = tmp;
2351
2352 if (smtp_mailaddr(&tx->evp.sender, copy, 1, &copy,
2353 tx->session->smtpname) == 0) {
2354 smtp_reply(tx->session, "553 %s Sender address syntax error",
2355 esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
2356 smtp_tx_free(tx);
2357 return;
2358 }
2359
2360 while ((opt = strsep(&copy, " "))) {
2361 if (*opt == '\0')
2362 continue;
2363
2364 if (strncasecmp(opt, "AUTH=", 5) == 0)
2365 log_debug("debug: smtp: AUTH in MAIL FROM command");
2366 else if (strncasecmp(opt, "SIZE=", 5) == 0)
2367 log_debug("debug: smtp: SIZE in MAIL FROM command");
2368 else if (strcasecmp(opt, "BODY=7BIT") == 0)
2369 /* XXX only for this transaction */
2370 tx->session->flags &= ~SF_8BITMIME;
2371 else if (strcasecmp(opt, "BODY=8BITMIME") == 0)
2372 ;
2373 else if (ADVERTISE_EXT_DSN(tx->session)((tx->session)->listener->flags & 0x400) && strncasecmp(opt, "RET=", 4) == 0) {
2374 opt += 4;
2375 if (strcasecmp(opt, "HDRS") == 0)
2376 tx->evp.dsn_ret = DSN_RETHDRS;
2377 else if (strcasecmp(opt, "FULL") == 0)
2378 tx->evp.dsn_ret = DSN_RETFULL;
2379 } else if (ADVERTISE_EXT_DSN(tx->session)((tx->session)->listener->flags & 0x400) && strncasecmp(opt, "ENVID=", 6) == 0) {
2380 opt += 6;
2381 if (strlcpy(tx->evp.dsn_envid, opt, sizeof(tx->evp.dsn_envid))
2382 >= sizeof(tx->evp.dsn_envid)) {
2383 smtp_reply(tx->session,
2384 "503 %s %s: option too large, truncated: %s",
2385 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2386 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2387 smtp_tx_free(tx);
2388 return;
2389 }
2390 } else {
2391 smtp_reply(tx->session, "503 %s %s: Unsupported option %s",
2392 esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
2393 esc_description(ESC_INVALID_COMMAND_ARGUMENTS), opt);
2394 smtp_tx_free(tx);
2395 return;
2396 }
2397 }
2398
2399 /* only check sendertable if defined and user has authenticated */
2400 if (tx->session->flags & SF_AUTHENTICATED &&
2401 tx->session->listener->sendertable[0]) {
2402 m_create(p_lka, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
2403 m_add_id(p_lka, tx->session->id);
2404 m_add_string(p_lka, tx->session->listener->sendertable);
2405 m_add_string(p_lka, tx->session->username);
2406 m_add_mailaddr(p_lka, &tx->evp.sender);
2407 m_close(p_lka);
2408 tree_xset(&wait_lka_mail, tx->session->id, tx->session);
2409 }
2410 else
2411 smtp_tx_create_message(tx);
2412}
2413
2414static void
2415smtp_tx_create_message(struct smtp_tx *tx)
2416{
2417 m_create(p_queue, IMSG_SMTP_MESSAGE_CREATE, 0, 0, -1);
2418 m_add_id(p_queue, tx->session->id);
2419 m_close(p_queue);
2420 tree_xset(&wait_queue_msg, tx->session->id, tx->session);
2421}
2422
2423static void
2424smtp_tx_rcpt_to(struct smtp_tx *tx, const char *line)
2425{
2426 char *opt, *p;
2427 char *copy;
2428 char tmp[SMTP_LINE_MAX65535];
2429
2430 (void)strlcpy(tmp, line, sizeof tmp);
2431 copy = tmp;
2432
2433 if (tx->rcptcount >= env->sc_session_max_rcpt) {
2434 smtp_reply(tx->session, "451 %s %s: Too many recipients",
2435 esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
2436 esc_description(ESC_TOO_MANY_RECIPIENTS));
2437 return;
2438 }
2439
2440 if (smtp_mailaddr(&tx->evp.rcpt, copy, 0, &copy,
2441 tx->session->smtpname) == 0) {
2442 smtp_reply(tx->session,
2443 "501 %s Recipient address syntax error",
2444 esc_code(ESC_STATUS_PERMFAIL,
2445 ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
2446 return;
2447 }
2448
2449 while ((opt = strsep(&copy, " "))) {
2450 if (*opt == '\0')
2451 continue;
2452
2453 if (ADVERTISE_EXT_DSN(tx->session)((tx->session)->listener->flags & 0x400) && strncasecmp(opt, "NOTIFY=", 7) == 0) {
2454 opt += 7;
2455 while ((p = strsep(&opt, ","))) {
2456 if (strcasecmp(p, "SUCCESS") == 0)
2457 tx->evp.dsn_notify |= DSN_SUCCESS0x01;
2458 else if (strcasecmp(p, "FAILURE") == 0)
2459 tx->evp.dsn_notify |= DSN_FAILURE0x02;
2460 else if (strcasecmp(p, "DELAY") == 0)
2461 tx->evp.dsn_notify |= DSN_DELAY0x04;
2462 else if (strcasecmp(p, "NEVER") == 0)
2463 tx->evp.dsn_notify |= DSN_NEVER0x08;
2464 }
2465
2466 if (tx->evp.dsn_notify & DSN_NEVER0x08 &&
2467 tx->evp.dsn_notify & (DSN_SUCCESS0x01 | DSN_FAILURE0x02 |
2468 DSN_DELAY0x04)) {
2469 smtp_reply(tx->session,
2470 "553 NOTIFY option NEVER cannot be"
2471 " combined with other options");
2472 return;
2473 }
2474 } else if (ADVERTISE_EXT_DSN(tx->session)((tx->session)->listener->flags & 0x400) &&
2475 strncasecmp(opt, "ORCPT=", 6) == 0) {
2476 size_t len = sizeof(tx->evp.dsn_orcpt);
2477
2478 opt += 6;
2479
2480 if ((p = strchr(opt, ';')) == NULL((void *)0) ||
2481 !valid_xtext(p + 1) ||
2482 strlcpy(opt, tx->evp.dsn_orcpt, len) >= len) {
2483 smtp_reply(tx->session,
2484 "553 ORCPT address syntax error");
2485 return;
2486 }
2487 } else {
2488 smtp_reply(tx->session, "503 Unsupported option %s", opt);
2489 return;
2490 }
2491 }
2492
2493 m_create(p_lka, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1);
2494 m_add_id(p_lka, tx->session->id);
2495 m_add_envelope(p_lka, &tx->evp);
2496 m_close(p_lka);
2497 tree_xset(&wait_lka_rcpt, tx->session->id, tx->session);
2498}
2499
2500static void
2501smtp_tx_open_message(struct smtp_tx *tx)
2502{
2503 m_create(p_queue, IMSG_SMTP_MESSAGE_OPEN, 0, 0, -1);
2504 m_add_id(p_queue, tx->session->id);
2505 m_add_msgid(p_queue, tx->msgid);
2506 m_close(p_queue);
2507 tree_xset(&wait_queue_fd, tx->session->id, tx->session);
2508}
2509
2510static void
2511smtp_tx_commit(struct smtp_tx *tx)
2512{
2513 m_create(p_queue, IMSG_SMTP_MESSAGE_COMMIT, 0, 0, -1);
2514 m_add_id(p_queue, tx->session->id);
2515 m_add_msgid(p_queue, tx->msgid);
2516 m_close(p_queue);
2517 tree_xset(&wait_queue_commit, tx->session->id, tx->session);
2518 smtp_filter_data_end(tx->session);
2519}
2520
2521static void
2522smtp_tx_rollback(struct smtp_tx *tx)
2523{
2524 m_create(p_queue, IMSG_SMTP_MESSAGE_ROLLBACK, 0, 0, -1);
2525 m_add_msgid(p_queue, tx->msgid);
2526 m_close(p_queue);
2527 smtp_report_tx_rollback(tx->session, tx->msgid);
2528 smtp_report_tx_reset(tx->session, tx->msgid);
2529 smtp_filter_data_end(tx->session);
2530}
2531
2532static int
2533smtp_tx_dataline(struct smtp_tx *tx, const char *line)
2534{
2535 struct rfc5322_result res;
2536 int r;
2537
2538 log_trace(TRACE_SMTP, "<<< [MSG] %s", line)do { if (tracing & (0x0008)) log_trace0("<<< [MSG] %s"
, line); } while (0)
;
2539
2540 if (!strcmp(line, ".")) {
2541 smtp_report_protocol_client(tx->session, ".");
2542 log_trace(TRACE_SMTP, "<<< [EOM]")do { if (tracing & (0x0008)) log_trace0("<<< [EOM]"
); } while (0)
;
2543 if (tx->error)
2544 return 1;
2545 line = NULL((void *)0);
2546 }
2547 else {
2548 /* ignore data line if an error is set */
2549 if (tx->error)
2550 return 0;
2551
2552 /* escape lines starting with a '.' */
2553 if (line[0] == '.')
2554 line += 1;
2555 }
2556
2557 if (rfc5322_push(tx->parser, line) == -1) {
2558 log_warnx("failed to push dataline");
2559 tx->error = TX_ERROR_INTERNAL;
2560 return 0;
2561 }
2562
2563 for(;;) {
2564 r = rfc5322_next(tx->parser, &res);
2565 switch (r) {
2566 case -1:
2567 if (errno(*__errno()) == ENOMEM12)
2568 tx->error = TX_ERROR_INTERNAL;
2569 else
2570 tx->error = TX_ERROR_MALFORMED;
2571 return 0;
2572
2573 case RFC5322_NONE0:
2574 /* Need more data */
2575 return 0;
2576
2577 case RFC5322_HEADER_START1:
2578 /* ignore bcc */
2579 if (!strcasecmp("Bcc", res.hdr))
2580 continue;
2581
2582 if (!strcasecmp("To", res.hdr) ||
2583 !strcasecmp("Cc", res.hdr) ||
2584 !strcasecmp("From", res.hdr)) {
2585 rfc5322_unfold_header(tx->parser);
2586 continue;
2587 }
2588
2589 if (!strcasecmp("Received", res.hdr)) {
2590 if (++tx->rcvcount >= MAX_HOPS_COUNT100) {
2591 log_warnx("warn: loop detected");
2592 tx->error = TX_ERROR_LOOP;
2593 return 0;
2594 }
2595 }
2596 else if (!tx->has_date && !strcasecmp("Date", res.hdr))
2597 tx->has_date = 1;
2598 else if (!tx->has_message_id &&
2599 !strcasecmp("Message-Id", res.hdr))
2600 tx->has_message_id = 1;
2601
2602 smtp_message_printf(tx, "%s:%s\n", res.hdr, res.value);
2603 break;
2604
2605 case RFC5322_HEADER_CONT2:
2606
2607 if (!strcasecmp("Bcc", res.hdr) ||
2608 !strcasecmp("To", res.hdr) ||
2609 !strcasecmp("Cc", res.hdr) ||
2610 !strcasecmp("From", res.hdr))
2611 continue;
2612
2613 smtp_message_printf(tx, "%s\n", res.value);
2614 break;
2615
2616 case RFC5322_HEADER_END3:
2617 if (!strcasecmp("To", res.hdr) ||
2618 !strcasecmp("Cc", res.hdr) ||
2619 !strcasecmp("From", res.hdr))
2620 header_domain_append_callback(tx, res.hdr,
2621 res.value);
2622 break;
2623
2624 case RFC5322_END_OF_HEADERS4:
2625 if (tx->session->listener->local ||
2626 tx->session->listener->port == htons(587)(__uint16_t)(__builtin_constant_p(587) ? (__uint16_t)(((__uint16_t
)(587) & 0xffU) << 8 | ((__uint16_t)(587) & 0xff00U
) >> 8) : __swap16md(587))
) {
2627
2628 if (!tx->has_date) {
2629 log_debug("debug: %p: adding Date", tx);
2630 smtp_message_printf(tx, "Date: %s\n",
2631 time_to_text(tx->time));
2632 }
2633
2634 if (!tx->has_message_id) {
2635 log_debug("debug: %p: adding Message-ID", tx);
2636 smtp_message_printf(tx,
2637 "Message-ID: <%016"PRIx64"llx""@%s>\n",
2638 generate_uid(),
2639 tx->session->listener->hostname);
2640 }
2641 }
2642 break;
2643
2644 case RFC5322_BODY_START5:
2645 case RFC5322_BODY6:
2646 smtp_message_printf(tx, "%s\n", res.value);
2647 break;
2648
2649 case RFC5322_END_OF_MESSAGE7:
2650 return 1;
2651
2652 default:
2653 fatalx("%s", __func__);
2654 }
2655 }
2656}
2657
2658static int
2659smtp_tx_filtered_dataline(struct smtp_tx *tx, const char *line)
2660{
2661 if (!strcmp(line, "."))
2662 line = NULL((void *)0);
2663 else {
2664 /* ignore data line if an error is set */
2665 if (tx->error)
2666 return 0;
2667 }
2668 io_printf(tx->filter, "%s\n", line ? line : ".");
2669 return line ? 0 : 1;
2670}
2671
2672static void
2673smtp_tx_eom(struct smtp_tx *tx)
2674{
2675 smtp_filter_phase(FILTER_COMMIT, tx->session, NULL((void *)0));
2676}
2677
2678static int
2679smtp_message_fd(struct smtp_tx *tx, int fd)
2680{
2681 struct smtp_session *s;
2682
2683 s = tx->session;
2684
2685 log_debug("smtp: %p: message fd %d", s, fd);
2686
2687 if ((tx->ofile = fdopen(fd, "w")) == NULL((void *)0)) {
2688 close(fd);
2689 smtp_reply(s, "421 %s Temporary Error",
2690 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2691 smtp_enter_state(s, STATE_QUIT);
2692 return 0;
2693 }
2694 return 1;
2695}
2696
2697static void
2698filter_session_io(struct io *io, int evt, void *arg)
2699{
2700 struct smtp_tx*tx = arg;
2701 char*line = NULL((void *)0);
2702 ssize_t len;
2703
2704 log_trace(TRACE_IO, "filter session io (smtp): %p: %s %s", tx, io_strevent(evt),do { if (tracing & (0x0004)) log_trace0("filter session io (smtp): %p: %s %s"
, tx, io_strevent(evt), io_strio(io)); } while (0)
2705 io_strio(io))do { if (tracing & (0x0004)) log_trace0("filter session io (smtp): %p: %s %s"
, tx, io_strevent(evt), io_strio(io)); } while (0)
;
2706
2707 switch (evt) {
2708 case IO_DATAIN:
2709 nextline:
2710 line = io_getline(tx->filter, &len);
2711 /* No complete line received */
2712 if (line == NULL((void *)0))
2713 return;
2714
2715 if (smtp_tx_dataline(tx, line)) {
2716 smtp_tx_eom(tx);
2717 return;
2718 }
2719
2720 goto nextline;
2721 }
2722}
2723
2724static void
2725smtp_filter_fd(struct smtp_tx *tx, int fd)
2726{
2727 struct smtp_session *s;
2728
2729 s = tx->session;
2730
2731 log_debug("smtp: %p: filter fd %d", s, fd);
2732
2733 tx->filter = io_new();
2734 io_set_fd(tx->filter, fd);
2735 io_set_callback(tx->filter, filter_session_io, tx);
2736}
2737
2738static void
2739smtp_message_begin(struct smtp_tx *tx)
2740{
2741 struct smtp_session *s;
2742 struct smtp_rcpt *rcpt;
2743 int (*m_printf)(struct smtp_tx *, const char *, ...);
2744
2745 m_printf = smtp_message_printf;
2746 if (tx->filter)
2747 m_printf = smtp_filter_printf;
2748
2749 s = tx->session;
2750
2751 log_debug("smtp: %p: message begin", s);
2752
2753 smtp_reply(s, "354 Enter mail, end with \".\""
2754 " on a line by itself");
2755
2756 if (s->junk || (s->tx && s->tx->junk))
2757 m_printf(tx, "X-Spam: Yes\n");
2758
2759 m_printf(tx, "Received: ");
2760 if (!(s->listener->flags & F_MASK_SOURCE0x100)) {
2761 m_printf(tx, "from %s (%s %s%s%s)",
2762 s->helo,
2763 s->rdns,
2764 s->ss.ss_family == AF_INET624 ? "" : "[",
2765 ss_to_text(&s->ss),
2766 s->ss.ss_family == AF_INET624 ? "" : "]");
2767 }
2768 m_printf(tx, "\n\tby %s (%s) with %sSMTP%s%s id %08x",
2769 s->smtpname,
2770 SMTPD_NAME"OpenSMTPD",
2771 s->flags & SF_EHLO ? "E" : "",
2772 s->flags & SF_SECURE ? "S" : "",
2773 s->flags & SF_AUTHENTICATED ? "A" : "",
2774 tx->msgid);
2775
2776 if (s->flags & SF_SECURE) {
2777 m_printf(tx, " (%s:%s:%d:%s)",
2778 tls_conn_version(io_tls(s->io)),
2779 tls_conn_cipher(io_tls(s->io)),
2780 tls_conn_cipher_strength(io_tls(s->io)),
2781 (s->flags & SF_VERIFIED) ? "YES" : "NO");
2782
2783 if (s->listener->flags & F_RECEIVEDAUTH0x800) {
2784 m_printf(tx, " auth=%s",
2785 s->username[0] ? "yes" : "no");
2786 if (s->username[0])
2787 m_printf(tx, " user=%s", s->username);
2788 }
2789 }
2790
2791 if (tx->rcptcount == 1) {
2792 rcpt = TAILQ_FIRST(&tx->rcpts)((&tx->rcpts)->tqh_first);
2793 m_printf(tx, "\n\tfor <%s@%s>",
2794 rcpt->maddr.user,
2795 rcpt->maddr.domain);
2796 }
2797
2798 m_printf(tx, ";\n\t%s\n", time_to_text(time(&tx->time)));
2799
2800 smtp_enter_state(s, STATE_BODY);
2801}
2802
2803static void
2804smtp_message_end(struct smtp_tx *tx)
2805{
2806 struct smtp_session *s;
2807
2808 s = tx->session;
2809
2810 log_debug("debug: %p: end of message, error=%d", s, tx->error);
2811
2812 fclose(tx->ofile);
2813 tx->ofile = NULL((void *)0);
2814
2815 switch(tx->error) {
2816 case TX_OK:
2817 smtp_tx_commit(tx);
2818 return;
2819
2820 case TX_ERROR_SIZE:
2821 smtp_reply(s, "554 %s %s: Transaction failed, message too big",
2822 esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM),
2823 esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM));
2824 break;
2825
2826 case TX_ERROR_LOOP:
2827 smtp_reply(s, "500 %s %s: Loop detected",
2828 esc_code(ESC_STATUS_PERMFAIL, ESC_ROUTING_LOOP_DETECTED),
2829 esc_description(ESC_ROUTING_LOOP_DETECTED));
2830 break;
2831
2832 case TX_ERROR_MALFORMED:
2833 smtp_reply(s, "550 %s %s: Message is not RFC 2822 compliant",
2834 esc_code(ESC_STATUS_PERMFAIL, ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED),
2835 esc_description(ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED));
2836 break;
2837
2838 case TX_ERROR_IO:
2839 case TX_ERROR_RESOURCES:
2840 smtp_reply(s, "421 %s Temporary Error",
2841 esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
2842 break;
2843
2844 default:
2845 /* fatal? */
2846 smtp_reply(s, "421 Internal server error");
2847 }
2848
2849 smtp_tx_rollback(tx);
2850 smtp_tx_free(tx);
2851 smtp_enter_state(s, STATE_HELO);
2852}
2853
2854static int
2855smtp_filter_printf(struct smtp_tx *tx, const char *fmt, ...)
2856{
2857 va_list ap;
2858 int len;
2859
2860 if (tx->error)
2861 return -1;
2862
2863 va_start(ap, fmt)__builtin_va_start((ap), fmt);
2864 len = io_vprintf(tx->filter, fmt, ap);
2865 va_end(ap)__builtin_va_end((ap));
2866
2867 if (len < 0) {
2868 log_warn("smtp-in: session %016"PRIx64"llx"": vfprintf", tx->session->id);
2869 tx->error = TX_ERROR_IO;
2870 }
2871 else
2872 tx->odatalen += len;
2873
2874 return len;
2875}
2876
2877static int
2878smtp_message_printf(struct smtp_tx *tx, const char *fmt, ...)
2879{
2880 va_list ap;
2881 int len;
2882
2883 if (tx->error)
2884 return -1;
2885
2886 va_start(ap, fmt)__builtin_va_start((ap), fmt);
2887 len = vfprintf(tx->ofile, fmt, ap);
2888 va_end(ap)__builtin_va_end((ap));
2889
2890 if (len == -1) {
2891 log_warn("smtp-in: session %016"PRIx64"llx"": vfprintf", tx->session->id);
2892 tx->error = TX_ERROR_IO;
2893 }
2894 else
2895 tx->odatalen += len;
2896
2897 return len;
2898}
2899
2900#define CASE(x)case x : return "x" case x : return #x
2901
2902const char *
2903smtp_strstate(int state)
2904{
2905 static char buf[32];
2906
2907 switch (state) {
2908 CASE(STATE_NEW)case STATE_NEW : return "STATE_NEW";
2909 CASE(STATE_CONNECTED)case STATE_CONNECTED : return "STATE_CONNECTED";
2910 CASE(STATE_TLS)case STATE_TLS : return "STATE_TLS";
2911 CASE(STATE_HELO)case STATE_HELO : return "STATE_HELO";
2912 CASE(STATE_AUTH_INIT)case STATE_AUTH_INIT : return "STATE_AUTH_INIT";
2913 CASE(STATE_AUTH_USERNAME)case STATE_AUTH_USERNAME : return "STATE_AUTH_USERNAME";
2914 CASE(STATE_AUTH_PASSWORD)case STATE_AUTH_PASSWORD : return "STATE_AUTH_PASSWORD";
2915 CASE(STATE_AUTH_FINALIZE)case STATE_AUTH_FINALIZE : return "STATE_AUTH_FINALIZE";
2916 CASE(STATE_BODY)case STATE_BODY : return "STATE_BODY";
2917 CASE(STATE_QUIT)case STATE_QUIT : return "STATE_QUIT";
2918 default:
2919 (void)snprintf(buf, sizeof(buf), "STATE_??? (%d)", state);
2920 return (buf);
2921 }
2922}
2923
2924
2925static void
2926smtp_report_link_connect(struct smtp_session *s, const char *rdns, int fcrdns,
2927 const struct sockaddr_storage *ss_src,
2928 const struct sockaddr_storage *ss_dest)
2929{
2930 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2931 return;
2932
2933 report_smtp_link_connect("smtp-in", s->id, rdns, fcrdns, ss_src, ss_dest);
2934}
2935
2936static void
2937smtp_report_link_greeting(struct smtp_session *s,
2938 const char *domain)
2939{
2940 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2941 return;
2942
2943 report_smtp_link_greeting("smtp-in", s->id, domain);
2944}
2945
2946static void
2947smtp_report_link_identify(struct smtp_session *s, const char *method, const char *identity)
2948{
2949 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2950 return;
2951
2952 report_smtp_link_identify("smtp-in", s->id, method, identity);
2953}
2954
2955static void
2956smtp_report_link_tls(struct smtp_session *s, const char *ssl)
2957{
2958 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2959 return;
2960
2961 report_smtp_link_tls("smtp-in", s->id, ssl);
2962}
2963
2964static void
2965smtp_report_link_disconnect(struct smtp_session *s)
2966{
2967 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2968 return;
2969
2970 report_smtp_link_disconnect("smtp-in", s->id);
2971}
2972
2973static void
2974smtp_report_link_auth(struct smtp_session *s, const char *user, const char *result)
2975{
2976 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2977 return;
2978
2979 report_smtp_link_auth("smtp-in", s->id, user, result);
2980}
2981
2982static void
2983smtp_report_tx_reset(struct smtp_session *s, uint32_t msgid)
2984{
2985 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2986 return;
2987
2988 report_smtp_tx_reset("smtp-in", s->id, msgid);
2989}
2990
2991static void
2992smtp_report_tx_begin(struct smtp_session *s, uint32_t msgid)
2993{
2994 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
2995 return;
2996
2997 report_smtp_tx_begin("smtp-in", s->id, msgid);
2998}
2999
3000static void
3001smtp_report_tx_mail(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3002{
3003 char mailaddr[SMTPD_MAXMAILADDRSIZE(255 + 1)];
3004 char *p;
3005
3006 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3007 return;
3008
3009 if ((p = strchr(address, '<')) == NULL((void *)0))
3010 return;
3011 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3012 if ((p = strchr(mailaddr, '>')) == NULL((void *)0))
3013 return;
3014 *p = '\0';
3015
3016 report_smtp_tx_mail("smtp-in", s->id, msgid, mailaddr, ok);
3017}
3018
3019static void
3020smtp_report_tx_rcpt(struct smtp_session *s, uint32_t msgid, const char *address, int ok)
3021{
3022 char mailaddr[SMTPD_MAXMAILADDRSIZE(255 + 1)];
3023 char *p;
3024
3025 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3026 return;
3027
3028 if ((p = strchr(address, '<')) == NULL((void *)0))
3029 return;
3030 (void)strlcpy(mailaddr, p + 1, sizeof mailaddr);
3031 if ((p = strchr(mailaddr, '>')) == NULL((void *)0))
3032 return;
3033 *p = '\0';
3034
3035 report_smtp_tx_rcpt("smtp-in", s->id, msgid, mailaddr, ok);
3036}
3037
3038static void
3039smtp_report_tx_envelope(struct smtp_session *s, uint32_t msgid, uint64_t evpid)
3040{
3041 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3042 return;
3043
3044 report_smtp_tx_envelope("smtp-in", s->id, msgid, evpid);
3045}
3046
3047static void
3048smtp_report_tx_data(struct smtp_session *s, uint32_t msgid, int ok)
3049{
3050 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3051 return;
3052
3053 report_smtp_tx_data("smtp-in", s->id, msgid, ok);
3054}
3055
3056static void
3057smtp_report_tx_commit(struct smtp_session *s, uint32_t msgid, size_t msgsz)
3058{
3059 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3060 return;
3061
3062 report_smtp_tx_commit("smtp-in", s->id, msgid, msgsz);
3063}
3064
3065static void
3066smtp_report_tx_rollback(struct smtp_session *s, uint32_t msgid)
3067{
3068 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3069 return;
3070
3071 report_smtp_tx_rollback("smtp-in", s->id, msgid);
3072}
3073
3074static void
3075smtp_report_protocol_client(struct smtp_session *s, const char *command)
3076{
3077 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3078 return;
3079
3080 report_smtp_protocol_client("smtp-in", s->id, command);
3081}
3082
3083static void
3084smtp_report_protocol_server(struct smtp_session *s, const char *response)
3085{
3086 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3087 return;
3088
3089 report_smtp_protocol_server("smtp-in", s->id, response);
3090}
3091
3092static void
3093smtp_report_filter_response(struct smtp_session *s, int phase, int response, const char *param)
3094{
3095 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3096 return;
3097
3098 report_smtp_filter_response("smtp-in", s->id, phase, response, param);
3099}
3100
3101static void
3102smtp_report_timeout(struct smtp_session *s)
3103{
3104 if (! SESSION_FILTERED(s)((s)->listener->flags & 0x2000))
3105 return;
3106
3107 report_smtp_timeout("smtp-in", s->id);
3108}