Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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