2 ce062d50 2019-08-21 martijn * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
4 ce062d50 2019-08-21 martijn * Permission to use, copy, modify, and distribute this software for any
5 ce062d50 2019-08-21 martijn * purpose with or without fee is hereby granted, provided that the above
6 ce062d50 2019-08-21 martijn * copyright notice and this permission notice appear in all copies.
8 ce062d50 2019-08-21 martijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 ce062d50 2019-08-21 martijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 ce062d50 2019-08-21 martijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ce062d50 2019-08-21 martijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 ce062d50 2019-08-21 martijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ce062d50 2019-08-21 martijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 ce062d50 2019-08-21 martijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 957c2372 2019-11-14 martijn #define _GNU_SOURCE 1
18 ce062d50 2019-08-21 martijn #include <sys/time.h>
19 ce062d50 2019-08-21 martijn #include <sys/tree.h>
20 ce062d50 2019-08-21 martijn #include <sys/socket.h>
21 ce062d50 2019-08-21 martijn #include <sys/un.h>
23 ce062d50 2019-08-21 martijn #include <arpa/inet.h>
24 078ff8cf 2019-08-21 martijn #include <netinet/in.h>
26 ce062d50 2019-08-21 martijn #include <errno.h>
27 ce062d50 2019-08-21 martijn #include <event.h>
28 ce062d50 2019-08-21 martijn #include <fcntl.h>
29 ce062d50 2019-08-21 martijn #include <inttypes.h>
30 ce062d50 2019-08-21 martijn #include <limits.h>
31 ce062d50 2019-08-21 martijn #include <stdarg.h>
32 ce062d50 2019-08-21 martijn #include <stdio.h>
33 ce062d50 2019-08-21 martijn #include <stdlib.h>
34 ce062d50 2019-08-21 martijn #include <string.h>
35 ce062d50 2019-08-21 martijn #include <syslog.h>
36 ce062d50 2019-08-21 martijn #include <unistd.h>
38 957c2372 2019-11-14 martijn #include "openbsd-compat.h"
39 ce062d50 2019-08-21 martijn #include "opensmtpd.h"
40 ce062d50 2019-08-21 martijn #include "ioev.h"
42 ce062d50 2019-08-21 martijn #define NITEMS(x) (sizeof(x) / sizeof(*x))
44 866e5e0e 2025-02-03 martijn enum osmtpd_session_status {
45 866e5e0e 2025-02-03 martijn SESSION_OK = 0,
46 866e5e0e 2025-02-03 martijn SESSION_ERROR,
47 866e5e0e 2025-02-03 martijn SESSION_DISCONNECTED
50 866e5e0e 2025-02-03 martijn struct osmtpd_session {
51 866e5e0e 2025-02-03 martijn struct osmtpd_ctx ctx; /* Must remain first element */
52 866e5e0e 2025-02-03 martijn enum osmtpd_session_status status;
53 866e5e0e 2025-02-03 martijn RB_ENTRY(osmtpd_session) entry;
56 d229c123 2019-08-22 martijn struct osmtpd_callback {
57 d229c123 2019-08-22 martijn enum osmtpd_type type;
58 d229c123 2019-08-22 martijn enum osmtpd_phase phase;
59 d229c123 2019-08-22 martijn int incoming;
60 866e5e0e 2025-02-03 martijn void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_session *,
61 866e5e0e 2025-02-03 martijn char *, char *);
62 d229c123 2019-08-22 martijn void *cb;
63 d229c123 2019-08-22 martijn int doregister;
64 d229c123 2019-08-22 martijn int storereport;
67 d229c123 2019-08-22 martijn static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
69 d229c123 2019-08-22 martijn static const char *osmtpd_typetostr(enum osmtpd_type);
70 d229c123 2019-08-22 martijn static const char *osmtpd_phasetostr(enum osmtpd_phase);
71 d229c123 2019-08-22 martijn static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
72 d229c123 2019-08-22 martijn static void osmtpd_newline(struct io *, int, void *);
73 d229c123 2019-08-22 martijn static void osmtpd_outevt(struct io *, int, void *);
74 866e5e0e 2025-02-03 martijn static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_session *,
75 d229c123 2019-08-22 martijn char *, char *);
76 866e5e0e 2025-02-03 martijn static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_session *,
77 d229c123 2019-08-22 martijn char *, char *);
78 866e5e0e 2025-02-03 martijn static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_session *,
79 d229c123 2019-08-22 martijn char *, char *);
80 866e5e0e 2025-02-03 martijn static void osmtpd_identify(struct osmtpd_callback *, struct osmtpd_session *,
81 421c9a86 2019-09-06 martijn char *, char *);
82 866e5e0e 2025-02-03 martijn static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_session *,
83 d229c123 2019-08-22 martijn char *, char *);
84 d229c123 2019-08-22 martijn static void osmtpd_link_disconnect(struct osmtpd_callback *,
85 866e5e0e 2025-02-03 martijn struct osmtpd_session *, char *, char *);
86 866e5e0e 2025-02-03 martijn static void osmtpd_link_greeting(struct osmtpd_callback *, struct osmtpd_session *,
87 a05d5c54 2019-08-28 martijn char *, char *);
88 866e5e0e 2025-02-03 martijn static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_session *,
89 d229c123 2019-08-22 martijn char *, char *);
90 866e5e0e 2025-02-03 martijn static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_session *,
91 d229c123 2019-08-22 martijn char *, char *);
92 866e5e0e 2025-02-03 martijn static void osmtpd_link_auth(struct osmtpd_callback *, struct osmtpd_session *,
93 58a6bc69 2022-12-05 martijn char *, char *);
94 d308c531 2025-02-03 martijn static void osmtpd_tx_reset(struct osmtpd_callback *, struct osmtpd_session *,
95 d308c531 2025-02-03 martijn char *, char *);
96 866e5e0e 2025-02-03 martijn static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_session *,
97 d229c123 2019-08-22 martijn char *, char *);
98 866e5e0e 2025-02-03 martijn static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_session *,
99 d229c123 2019-08-22 martijn char *, char *);
100 866e5e0e 2025-02-03 martijn static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_session *,
101 d229c123 2019-08-22 martijn char *, char *);
102 866e5e0e 2025-02-03 martijn static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_session *,
103 d229c123 2019-08-22 martijn char *, char *);
104 866e5e0e 2025-02-03 martijn static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_session *,
105 d229c123 2019-08-22 martijn char *, char *);
106 866e5e0e 2025-02-03 martijn static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_session *,
107 d229c123 2019-08-22 martijn char *, char *);
108 866e5e0e 2025-02-03 martijn static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_session *,
109 d229c123 2019-08-22 martijn char *, char *);
110 d229c123 2019-08-22 martijn static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
111 d229c123 2019-08-22 martijn static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
112 d229c123 2019-08-22 martijn static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
113 912d0ff2 2019-08-22 martijn static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
114 912d0ff2 2019-08-22 martijn static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
115 912d0ff2 2019-08-22 martijn static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
116 912d0ff2 2019-08-22 martijn static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
117 2029083f 2020-10-15 martijn static void (*conf_cb)(const char *, const char *);
119 d229c123 2019-08-22 martijn static struct osmtpd_callback osmtpd_callbacks[] = {
121 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
122 d229c123 2019-08-22 martijn OSMTPD_PHASE_CONNECT,
124 d229c123 2019-08-22 martijn osmtpd_connect,
130 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
131 d229c123 2019-08-22 martijn OSMTPD_PHASE_HELO,
133 421c9a86 2019-09-06 martijn osmtpd_identify,
139 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
140 d229c123 2019-08-22 martijn OSMTPD_PHASE_EHLO,
142 421c9a86 2019-09-06 martijn osmtpd_identify,
148 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
149 d229c123 2019-08-22 martijn OSMTPD_PHASE_STARTTLS,
151 d229c123 2019-08-22 martijn osmtpd_noargs,
157 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
158 d229c123 2019-08-22 martijn OSMTPD_PHASE_AUTH,
160 d229c123 2019-08-22 martijn osmtpd_onearg,
166 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
167 d229c123 2019-08-22 martijn OSMTPD_PHASE_MAIL_FROM,
169 d229c123 2019-08-22 martijn osmtpd_onearg,
175 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
176 d229c123 2019-08-22 martijn OSMTPD_PHASE_RCPT_TO,
178 d229c123 2019-08-22 martijn osmtpd_onearg,
184 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
185 d229c123 2019-08-22 martijn OSMTPD_PHASE_DATA,
187 d229c123 2019-08-22 martijn osmtpd_noargs,
193 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
194 d229c123 2019-08-22 martijn OSMTPD_PHASE_DATA_LINE,
196 d229c123 2019-08-22 martijn osmtpd_onearg,
202 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
203 d229c123 2019-08-22 martijn OSMTPD_PHASE_RSET,
205 d229c123 2019-08-22 martijn osmtpd_noargs,
211 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
212 d229c123 2019-08-22 martijn OSMTPD_PHASE_QUIT,
214 d229c123 2019-08-22 martijn osmtpd_noargs,
220 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
221 d229c123 2019-08-22 martijn OSMTPD_PHASE_NOOP,
223 d229c123 2019-08-22 martijn osmtpd_noargs,
229 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
230 d229c123 2019-08-22 martijn OSMTPD_PHASE_HELP,
232 d229c123 2019-08-22 martijn osmtpd_noargs,
238 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
239 d229c123 2019-08-22 martijn OSMTPD_PHASE_WIZ,
241 d229c123 2019-08-22 martijn osmtpd_noargs,
247 d229c123 2019-08-22 martijn OSMTPD_TYPE_FILTER,
248 d229c123 2019-08-22 martijn OSMTPD_PHASE_COMMIT,
250 d229c123 2019-08-22 martijn osmtpd_noargs,
256 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
257 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_CONNECT,
259 d229c123 2019-08-22 martijn osmtpd_link_connect,
265 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
266 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_DISCONNECT,
268 d229c123 2019-08-22 martijn osmtpd_link_disconnect,
274 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
275 a05d5c54 2019-08-28 martijn OSMTPD_PHASE_LINK_GREETING,
277 a05d5c54 2019-08-28 martijn osmtpd_link_greeting,
283 a05d5c54 2019-08-28 martijn OSMTPD_TYPE_REPORT,
284 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_IDENTIFY,
286 d229c123 2019-08-22 martijn osmtpd_link_identify,
292 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
293 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_TLS,
295 d229c123 2019-08-22 martijn osmtpd_link_tls,
301 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
302 58a6bc69 2022-12-05 martijn OSMTPD_PHASE_LINK_AUTH,
304 58a6bc69 2022-12-05 martijn osmtpd_link_auth,
310 58a6bc69 2022-12-05 martijn OSMTPD_TYPE_REPORT,
311 d308c531 2025-02-03 martijn OSMTPD_PHASE_TX_RESET,
313 d308c531 2025-02-03 martijn osmtpd_tx_reset,
319 d308c531 2025-02-03 martijn OSMTPD_TYPE_REPORT,
320 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_BEGIN,
322 d229c123 2019-08-22 martijn osmtpd_tx_begin,
328 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
329 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_MAIL,
331 d229c123 2019-08-22 martijn osmtpd_tx_mail,
337 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
338 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_RCPT,
340 d229c123 2019-08-22 martijn osmtpd_tx_rcpt,
346 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
347 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_ENVELOPE,
349 d229c123 2019-08-22 martijn osmtpd_tx_envelope,
355 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
356 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_DATA,
358 d229c123 2019-08-22 martijn osmtpd_tx_data,
364 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
365 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_COMMIT,
367 d229c123 2019-08-22 martijn osmtpd_tx_commit,
373 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
374 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_ROLLBACK,
376 d229c123 2019-08-22 martijn osmtpd_tx_rollback,
382 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
383 d229c123 2019-08-22 martijn OSMTPD_PHASE_PROTOCOL_CLIENT,
385 d229c123 2019-08-22 martijn osmtpd_onearg,
391 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
392 d229c123 2019-08-22 martijn OSMTPD_PHASE_PROTOCOL_SERVER,
394 d229c123 2019-08-22 martijn osmtpd_onearg,
400 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
401 d229c123 2019-08-22 martijn OSMTPD_PHASE_FILTER_RESPONSE,
403 d229c123 2019-08-22 martijn osmtpd_onearg,
409 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
410 d229c123 2019-08-22 martijn OSMTPD_PHASE_TIMEOUT,
412 d229c123 2019-08-22 martijn osmtpd_noargs,
418 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
419 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_CONNECT,
421 d229c123 2019-08-22 martijn osmtpd_link_connect,
427 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
428 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_DISCONNECT,
430 d229c123 2019-08-22 martijn osmtpd_link_disconnect,
436 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
437 a05d5c54 2019-08-28 martijn OSMTPD_PHASE_LINK_GREETING,
439 a05d5c54 2019-08-28 martijn osmtpd_link_greeting,
445 a05d5c54 2019-08-28 martijn OSMTPD_TYPE_REPORT,
446 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_IDENTIFY,
448 d229c123 2019-08-22 martijn osmtpd_link_identify,
454 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
455 d229c123 2019-08-22 martijn OSMTPD_PHASE_LINK_TLS,
457 d229c123 2019-08-22 martijn osmtpd_link_tls,
463 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
464 58a6bc69 2022-12-05 martijn OSMTPD_PHASE_LINK_AUTH,
466 58a6bc69 2022-12-05 martijn osmtpd_link_auth,
472 58a6bc69 2022-12-05 martijn OSMTPD_TYPE_REPORT,
473 d308c531 2025-02-03 martijn OSMTPD_PHASE_TX_RESET,
475 d308c531 2025-02-03 martijn osmtpd_tx_reset,
481 d308c531 2025-02-03 martijn OSMTPD_TYPE_REPORT,
482 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_BEGIN,
484 d229c123 2019-08-22 martijn osmtpd_tx_begin,
490 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
491 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_MAIL,
493 d229c123 2019-08-22 martijn osmtpd_tx_mail,
499 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
500 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_RCPT,
502 d229c123 2019-08-22 martijn osmtpd_tx_rcpt,
508 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
509 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_ENVELOPE,
511 d229c123 2019-08-22 martijn osmtpd_tx_envelope,
517 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
518 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_DATA,
520 d229c123 2019-08-22 martijn osmtpd_tx_data,
526 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
527 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_COMMIT,
529 d229c123 2019-08-22 martijn osmtpd_tx_commit,
535 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
536 d229c123 2019-08-22 martijn OSMTPD_PHASE_TX_ROLLBACK,
538 d229c123 2019-08-22 martijn osmtpd_tx_rollback,
544 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
545 d229c123 2019-08-22 martijn OSMTPD_PHASE_PROTOCOL_CLIENT,
547 d229c123 2019-08-22 martijn osmtpd_onearg,
553 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
554 d229c123 2019-08-22 martijn OSMTPD_PHASE_PROTOCOL_SERVER,
556 d229c123 2019-08-22 martijn osmtpd_onearg,
562 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
563 d229c123 2019-08-22 martijn OSMTPD_PHASE_FILTER_RESPONSE,
565 d229c123 2019-08-22 martijn osmtpd_onearg,
571 d229c123 2019-08-22 martijn OSMTPD_TYPE_REPORT,
572 d229c123 2019-08-22 martijn OSMTPD_PHASE_TIMEOUT,
574 d229c123 2019-08-22 martijn osmtpd_noargs,
581 ce062d50 2019-08-21 martijn static struct io *io_stdout;
582 09816288 2019-08-22 martijn static int needs;
583 ce062d50 2019-08-21 martijn static int ready = 0;
584 ce062d50 2019-08-21 martijn /* Default from smtpd */
585 ce062d50 2019-08-21 martijn static int session_timeout = 300;
586 1a5c543c 2026-03-19 martijn int version_major, version_minor;
588 d229c123 2019-08-22 martijn RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
589 9e3e8410 2019-08-22 martijn RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
592 2029083f 2020-10-15 martijn osmtpd_register_conf(void (*cb)(const char *, const char *))
594 2029083f 2020-10-15 martijn conf_cb = cb;
598 5129e9c0 2025-04-10 kirill osmtpd_register_filter_connect(int (*cb)(struct osmtpd_ctx *, const char *,
599 ce062d50 2019-08-21 martijn struct sockaddr_storage *))
601 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
602 ce062d50 2019-08-21 martijn (void *)cb);
603 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
608 5129e9c0 2025-04-10 kirill osmtpd_register_filter_helo(int (*cb)(struct osmtpd_ctx *, const char *))
610 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
611 ce062d50 2019-08-21 martijn (void *)cb);
612 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
617 5129e9c0 2025-04-10 kirill osmtpd_register_filter_ehlo(int (*cb)(struct osmtpd_ctx *, const char *))
619 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
620 ce062d50 2019-08-21 martijn (void *)cb);
621 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
626 5129e9c0 2025-04-10 kirill osmtpd_register_filter_starttls(int (*cb)(struct osmtpd_ctx *))
628 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
629 ce062d50 2019-08-21 martijn (void *)cb);
630 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
635 5129e9c0 2025-04-10 kirill osmtpd_register_filter_auth(int (*cb)(struct osmtpd_ctx *, const char *))
637 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
638 ce062d50 2019-08-21 martijn (void *)cb);
639 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
644 5129e9c0 2025-04-10 kirill osmtpd_register_filter_mailfrom(int (*cb)(struct osmtpd_ctx *, const char *))
646 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
647 ce062d50 2019-08-21 martijn (void *)cb);
648 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
653 5129e9c0 2025-04-10 kirill osmtpd_register_filter_rcptto(int (*cb)(struct osmtpd_ctx *, const char *))
655 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
656 ce062d50 2019-08-21 martijn (void *)cb);
657 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
662 5129e9c0 2025-04-10 kirill osmtpd_register_filter_data(int (*cb)(struct osmtpd_ctx *))
664 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
665 ce062d50 2019-08-21 martijn (void *)cb);
666 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
671 5129e9c0 2025-04-10 kirill osmtpd_register_filter_dataline(int (*cb)(struct osmtpd_ctx *, const char *))
673 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
674 ce062d50 2019-08-21 martijn (void *)cb);
675 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
680 5129e9c0 2025-04-10 kirill osmtpd_register_filter_rset(int (*cb)(struct osmtpd_ctx *))
682 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
683 ce062d50 2019-08-21 martijn (void *)cb);
684 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
689 5129e9c0 2025-04-10 kirill osmtpd_register_filter_quit(int (*cb)(struct osmtpd_ctx *))
691 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
692 ce062d50 2019-08-21 martijn (void *)cb);
693 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
698 5129e9c0 2025-04-10 kirill osmtpd_register_filter_noop(int (*cb)(struct osmtpd_ctx *))
700 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
701 ce062d50 2019-08-21 martijn (void *)cb);
702 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
707 5129e9c0 2025-04-10 kirill osmtpd_register_filter_help(int (*cb)(struct osmtpd_ctx *))
709 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
710 ce062d50 2019-08-21 martijn (void *)cb);
711 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
716 5129e9c0 2025-04-10 kirill osmtpd_register_filter_wiz(int (*cb)(struct osmtpd_ctx *))
718 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
719 ce062d50 2019-08-21 martijn (void *)cb);
720 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
725 5129e9c0 2025-04-10 kirill osmtpd_register_filter_commit(int (*cb)(struct osmtpd_ctx *))
727 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
728 ce062d50 2019-08-21 martijn (void *)cb);
729 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
734 5129e9c0 2025-04-10 kirill osmtpd_register_report_connect(int incoming, int (*cb)(struct osmtpd_ctx *,
735 30f1cbac 2019-08-22 martijn const char *, enum osmtpd_status, struct sockaddr_storage *,
736 ce062d50 2019-08-21 martijn struct sockaddr_storage *))
738 3fd8a04a 2021-04-18 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
739 ce062d50 2019-08-21 martijn 0, (void *)cb);
740 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
741 ce062d50 2019-08-21 martijn incoming, 0, NULL);
745 5129e9c0 2025-04-10 kirill osmtpd_register_report_disconnect(int incoming, int (*cb)(struct osmtpd_ctx *))
747 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
748 ce062d50 2019-08-21 martijn incoming, 0, (void *)cb);
752 5129e9c0 2025-04-10 kirill osmtpd_register_report_identify(int incoming, int (*cb)(struct osmtpd_ctx *,
753 ce062d50 2019-08-21 martijn const char *))
755 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
756 ce062d50 2019-08-21 martijn incoming, 0, (void *)cb);
757 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
758 ce062d50 2019-08-21 martijn incoming, 0, NULL);
762 5129e9c0 2025-04-10 kirill osmtpd_register_report_tls(int incoming, int (*cb)(struct osmtpd_ctx *,
763 ce062d50 2019-08-21 martijn const char *))
765 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
766 ce062d50 2019-08-21 martijn (void *)cb);
767 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
768 ce062d50 2019-08-21 martijn incoming, 0, NULL);
772 5129e9c0 2025-04-10 kirill osmtpd_register_report_auth(int incoming, int (*cb)(struct osmtpd_ctx *,
773 58a6bc69 2022-12-05 martijn const char *, enum osmtpd_auth_status))
775 58a6bc69 2022-12-05 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, incoming, 0,
776 58a6bc69 2022-12-05 martijn (void *)cb);
777 58a6bc69 2022-12-05 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
778 58a6bc69 2022-12-05 martijn incoming, 0, NULL);
782 5129e9c0 2025-04-10 kirill osmtpd_register_report_reset(int incoming, int (*cb)(struct osmtpd_ctx *,
783 d308c531 2025-02-03 martijn uint32_t))
785 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET, incoming, 0,
786 d308c531 2025-02-03 martijn (void *)cb);
787 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
788 d308c531 2025-02-03 martijn incoming, 0, NULL);
792 5129e9c0 2025-04-10 kirill osmtpd_register_report_begin(int incoming, int (*cb)(struct osmtpd_ctx *,
793 ce062d50 2019-08-21 martijn uint32_t))
795 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
796 ce062d50 2019-08-21 martijn (void *)cb);
797 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
798 ce062d50 2019-08-21 martijn incoming, 0, NULL);
802 5129e9c0 2025-04-10 kirill osmtpd_register_report_mail(int incoming, int (*cb)(struct osmtpd_ctx *,
803 ce062d50 2019-08-21 martijn uint32_t, const char *, enum osmtpd_status))
805 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
806 ce062d50 2019-08-21 martijn (void *)cb);
807 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
808 ce062d50 2019-08-21 martijn incoming, 0, NULL);
812 5129e9c0 2025-04-10 kirill osmtpd_register_report_rcpt(int incoming, int (*cb)(struct osmtpd_ctx *,
813 ce062d50 2019-08-21 martijn uint32_t, const char *, enum osmtpd_status))
815 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
816 ce062d50 2019-08-21 martijn (void *)cb);
817 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
818 ce062d50 2019-08-21 martijn incoming, 0, NULL);
822 5129e9c0 2025-04-10 kirill osmtpd_register_report_envelope(int incoming, int (*cb)(struct osmtpd_ctx *,
823 ce062d50 2019-08-21 martijn uint32_t, uint64_t))
825 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
826 ce062d50 2019-08-21 martijn 0, (void *)cb);
827 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
828 ce062d50 2019-08-21 martijn incoming, 0, NULL);
832 5129e9c0 2025-04-10 kirill osmtpd_register_report_data(int incoming, int (*cb)(struct osmtpd_ctx *,
833 ce062d50 2019-08-21 martijn uint32_t, enum osmtpd_status))
835 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
836 ce062d50 2019-08-21 martijn (void *)cb);
837 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
838 ce062d50 2019-08-21 martijn incoming, 0, NULL);
842 5129e9c0 2025-04-10 kirill osmtpd_register_report_commit(int incoming, int (*cb)(struct osmtpd_ctx *,
843 ce062d50 2019-08-21 martijn uint32_t, size_t))
845 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
846 ce062d50 2019-08-21 martijn (void *)cb);
847 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
848 ce062d50 2019-08-21 martijn incoming, 0, NULL);
852 5129e9c0 2025-04-10 kirill osmtpd_register_report_rollback(int incoming, int (*cb)(struct osmtpd_ctx *,
853 ce062d50 2019-08-21 martijn uint32_t))
855 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
856 ce062d50 2019-08-21 martijn 0, (void *)cb);
857 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
858 ce062d50 2019-08-21 martijn incoming, 0, NULL);
862 5129e9c0 2025-04-10 kirill osmtpd_register_report_client(int incoming, int (*cb)(struct osmtpd_ctx *,
863 ce062d50 2019-08-21 martijn const char *))
865 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
866 ce062d50 2019-08-21 martijn incoming, 0, (void *)cb);
867 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
868 ce062d50 2019-08-21 martijn incoming, 0, NULL);
872 5129e9c0 2025-04-10 kirill osmtpd_register_report_server(int incoming, int (*cb)(struct osmtpd_ctx *,
873 ce062d50 2019-08-21 martijn const char *))
875 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
876 ce062d50 2019-08-21 martijn incoming, 0, (void *)cb);
877 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
878 ce062d50 2019-08-21 martijn incoming, 0, NULL);
882 5129e9c0 2025-04-10 kirill osmtpd_register_report_response(int incoming, int (*cb)(struct osmtpd_ctx *,
883 ce062d50 2019-08-21 martijn const char *))
885 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
886 ce062d50 2019-08-21 martijn incoming, 0, (void *)cb);
887 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
888 ce062d50 2019-08-21 martijn incoming, 0, NULL);
892 5129e9c0 2025-04-10 kirill osmtpd_register_report_timeout(int incoming, int (*cb)(struct osmtpd_ctx *))
894 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
895 ce062d50 2019-08-21 martijn (void *)cb);
896 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
897 ce062d50 2019-08-21 martijn incoming, 0, NULL);
901 912d0ff2 2019-08-22 martijn osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
902 ce062d50 2019-08-21 martijn void (*ondelete)(struct osmtpd_ctx *, void *))
904 912d0ff2 2019-08-22 martijn oncreatecb_session = oncreate;
905 912d0ff2 2019-08-22 martijn ondeletecb_session = ondelete;
909 912d0ff2 2019-08-22 martijn osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
910 912d0ff2 2019-08-22 martijn void (*ondelete)(struct osmtpd_ctx *, void *))
912 912d0ff2 2019-08-22 martijn oncreatecb_message = oncreate;
913 912d0ff2 2019-08-22 martijn ondeletecb_message = ondelete;
917 09816288 2019-08-22 martijn osmtpd_need(int lneeds)
919 09816288 2019-08-22 martijn needs |= lneeds;
922 09816288 2019-08-22 martijn static void
923 09816288 2019-08-22 martijn osmtpd_register_need(int incoming)
925 ce062d50 2019-08-21 martijn if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
926 09816288 2019-08-22 martijn OSMTPD_NEED_FCRDNS))
927 705cd566 2019-08-23 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
928 ce062d50 2019-08-21 martijn incoming, 1, NULL);
929 0fb4c799 2019-09-05 martijn if (needs & OSMTPD_NEED_GREETING)
930 a05d5c54 2019-08-28 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
931 a05d5c54 2019-08-28 martijn incoming, 1, NULL);
932 0fb4c799 2019-09-05 martijn if (needs & OSMTPD_NEED_IDENTITY)
933 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
934 ce062d50 2019-08-21 martijn incoming, 1, NULL);
935 ce062d50 2019-08-21 martijn if (needs & OSMTPD_NEED_CIPHERS)
936 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
937 ce062d50 2019-08-21 martijn incoming, 1, NULL);
938 58a6bc69 2022-12-05 martijn if (needs & OSMTPD_NEED_USERNAME)
939 58a6bc69 2022-12-05 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
940 58a6bc69 2022-12-05 martijn incoming, 1, NULL);
941 ce062d50 2019-08-21 martijn if (needs & OSMTPD_NEED_MSGID) {
942 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
943 ce062d50 2019-08-21 martijn incoming, 1, NULL);
944 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
945 ce062d50 2019-08-21 martijn incoming, 0, NULL);
947 ce062d50 2019-08-21 martijn if (needs & OSMTPD_NEED_MAILFROM) {
948 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
949 ce062d50 2019-08-21 martijn incoming, 1, NULL);
950 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
951 ce062d50 2019-08-21 martijn incoming, 0, NULL);
953 ce062d50 2019-08-21 martijn if (needs & OSMTPD_NEED_RCPTTO) {
954 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
955 ce062d50 2019-08-21 martijn incoming, 1, NULL);
956 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
957 ce062d50 2019-08-21 martijn incoming, 0, NULL);
959 ce062d50 2019-08-21 martijn if (needs & OSMTPD_NEED_EVPID) {
960 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
961 ce062d50 2019-08-21 martijn incoming, 1, NULL);
962 d308c531 2025-02-03 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
963 ce062d50 2019-08-21 martijn incoming, 0, NULL);
966 ce062d50 2019-08-21 martijn osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
967 ce062d50 2019-08-21 martijn incoming, 0, NULL);
971 ce062d50 2019-08-21 martijn osmtpd_run(void)
973 ce062d50 2019-08-21 martijn size_t i = 0;
974 ce062d50 2019-08-21 martijn int registered = 0;
975 adebfe7c 2021-03-21 martijn struct event_base *evbase;
976 ce062d50 2019-08-21 martijn struct io *io_stdin;
977 a37af028 2019-09-17 martijn struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
978 a37af028 2019-09-17 martijn struct osmtpd_callback *ridentity = NULL;
980 adebfe7c 2021-03-21 martijn evbase = event_init();
982 ce062d50 2019-08-21 martijn if ((io_stdin = io_new()) == NULL ||
983 ce062d50 2019-08-21 martijn (io_stdout = io_new()) == NULL)
984 27dd1f3b 2019-08-22 martijn osmtpd_err(1, "io_new");
985 ce062d50 2019-08-21 martijn io_set_nonblocking(STDIN_FILENO);
986 ce062d50 2019-08-21 martijn io_set_fd(io_stdin, STDIN_FILENO);
987 ce062d50 2019-08-21 martijn io_set_callback(io_stdin, osmtpd_newline, NULL);
988 ce062d50 2019-08-21 martijn io_set_read(io_stdin);
989 ce062d50 2019-08-21 martijn io_set_nonblocking(STDOUT_FILENO);
990 ce062d50 2019-08-21 martijn io_set_fd(io_stdout, STDOUT_FILENO);
991 ce062d50 2019-08-21 martijn io_set_callback(io_stdout, osmtpd_outevt, NULL);
992 ce062d50 2019-08-21 martijn io_set_write(io_stdout);
994 ce062d50 2019-08-21 martijn for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
995 912d0ff2 2019-08-22 martijn if (osmtpd_callbacks[i].doregister) {
996 09816288 2019-08-22 martijn osmtpd_register_need(osmtpd_callbacks[i].incoming);
997 912d0ff2 2019-08-22 martijn if (oncreatecb_message != NULL) {
998 912d0ff2 2019-08-22 martijn osmtpd_register(OSMTPD_TYPE_REPORT,
999 912d0ff2 2019-08-22 martijn OSMTPD_PHASE_TX_BEGIN,
1000 912d0ff2 2019-08-22 martijn osmtpd_callbacks[i].incoming, 0, NULL);
1001 912d0ff2 2019-08-22 martijn osmtpd_register(OSMTPD_TYPE_REPORT,
1002 d308c531 2025-02-03 martijn OSMTPD_PHASE_TX_RESET,
1003 912d0ff2 2019-08-22 martijn osmtpd_callbacks[i].incoming, 0, NULL);
1005 421c9a86 2019-09-06 martijn if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1006 421c9a86 2019-09-06 martijn osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
1007 421c9a86 2019-09-06 martijn hidenity = &(osmtpd_callbacks[i]);
1008 421c9a86 2019-09-06 martijn if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1009 421c9a86 2019-09-06 martijn osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
1010 421c9a86 2019-09-06 martijn eidentity = &(osmtpd_callbacks[i]);
1011 421c9a86 2019-09-06 martijn if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
1012 421c9a86 2019-09-06 martijn osmtpd_callbacks[i].phase ==
1013 421c9a86 2019-09-06 martijn OSMTPD_PHASE_LINK_IDENTIFY &&
1014 421c9a86 2019-09-06 martijn osmtpd_callbacks[i].incoming == 1)
1015 421c9a86 2019-09-06 martijn ridentity = &(osmtpd_callbacks[i]);
1018 a37af028 2019-09-17 martijn if (ridentity != NULL && ridentity->storereport) {
1019 a37af028 2019-09-17 martijn if (hidenity != NULL && hidenity->doregister)
1020 421c9a86 2019-09-06 martijn hidenity->storereport = 1;
1021 a37af028 2019-09-17 martijn if (eidentity != NULL && eidentity->doregister)
1022 421c9a86 2019-09-06 martijn eidentity->storereport = 1;
1024 09816288 2019-08-22 martijn for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1025 ce062d50 2019-08-21 martijn if (osmtpd_callbacks[i].doregister) {
1026 ce062d50 2019-08-21 martijn if (osmtpd_callbacks[i].cb != NULL)
1027 ce062d50 2019-08-21 martijn registered = 1;
1028 ce062d50 2019-08-21 martijn io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1029 ce062d50 2019-08-21 martijn osmtpd_typetostr(osmtpd_callbacks[i].type),
1030 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].incoming ? "in" : "out",
1031 ce062d50 2019-08-21 martijn osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1035 ce062d50 2019-08-21 martijn if (!registered)
1036 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "No events registered");
1037 ce062d50 2019-08-21 martijn io_printf(io_stdout, "register|ready\n");
1038 ce062d50 2019-08-21 martijn ready = 1;
1040 ce062d50 2019-08-21 martijn event_dispatch();
1041 adebfe7c 2021-03-21 martijn io_free(io_stdin);
1042 adebfe7c 2021-03-21 martijn io_free(io_stdout);
1043 adebfe7c 2021-03-21 martijn event_base_free(evbase);
1046 27dd1f3b 2019-08-22 martijn __dead void
1047 27dd1f3b 2019-08-22 martijn osmtpd_err(int eval, const char *fmt, ...)
1049 27dd1f3b 2019-08-22 martijn va_list ap;
1051 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1052 1a5c543c 2026-03-19 martijn fprintf(stderr, "FATAL|");
1053 27dd1f3b 2019-08-22 martijn va_start(ap, fmt);
1054 27dd1f3b 2019-08-22 martijn vfprintf(stderr, fmt, ap);
1055 27dd1f3b 2019-08-22 martijn va_end(ap);
1056 67cd1323 2019-08-22 martijn fprintf(stderr, ": %s\n", strerror(errno));
1057 27dd1f3b 2019-08-22 martijn exit(eval);
1060 27dd1f3b 2019-08-22 martijn __dead void
1061 27dd1f3b 2019-08-22 martijn osmtpd_errx(int eval, const char *fmt, ...)
1063 27dd1f3b 2019-08-22 martijn va_list ap;
1065 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1066 1a5c543c 2026-03-19 martijn fprintf(stderr, "FATAL|");
1067 27dd1f3b 2019-08-22 martijn va_start(ap, fmt);
1068 27dd1f3b 2019-08-22 martijn vfprintf(stderr, fmt, ap);
1069 27dd1f3b 2019-08-22 martijn va_end(ap);
1070 27dd1f3b 2019-08-22 martijn fprintf(stderr, "\n");
1071 27dd1f3b 2019-08-22 martijn exit(eval);
1075 1a5c543c 2026-03-19 martijn osmtpd_warn(struct osmtpd_ctx *ctx, const char *fmt, ...)
1077 1a5c543c 2026-03-19 martijn va_list ap;
1079 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1080 1a5c543c 2026-03-19 martijn fprintf(stderr, "WARN|");
1081 1a5c543c 2026-03-19 martijn if (ctx)
1082 1a5c543c 2026-03-19 martijn fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1083 1a5c543c 2026-03-19 martijn va_start(ap, fmt);
1084 1a5c543c 2026-03-19 martijn vfprintf(stderr, fmt, ap);
1085 1a5c543c 2026-03-19 martijn va_end(ap);
1086 1a5c543c 2026-03-19 martijn fprintf(stderr, ": %s\n", strerror(errno));
1090 1a5c543c 2026-03-19 martijn osmtpd_warnx(struct osmtpd_ctx *ctx, const char *fmt, ...)
1092 1a5c543c 2026-03-19 martijn va_list ap;
1094 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1095 1a5c543c 2026-03-19 martijn fprintf(stderr, "WARN|");
1096 1a5c543c 2026-03-19 martijn if (ctx)
1097 1a5c543c 2026-03-19 martijn fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1098 1a5c543c 2026-03-19 martijn va_start(ap, fmt);
1099 1a5c543c 2026-03-19 martijn vfprintf(stderr, fmt, ap);
1100 1a5c543c 2026-03-19 martijn va_end(ap);
1101 1a5c543c 2026-03-19 martijn fprintf(stderr, "\n");
1105 1a5c543c 2026-03-19 martijn osmtpd_info(struct osmtpd_ctx *ctx, const char *fmt, ...)
1107 1a5c543c 2026-03-19 martijn va_list ap;
1109 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1110 1a5c543c 2026-03-19 martijn fprintf(stderr, "INFO|");
1111 1a5c543c 2026-03-19 martijn if (ctx)
1112 1a5c543c 2026-03-19 martijn fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1113 1a5c543c 2026-03-19 martijn va_start(ap, fmt);
1114 1a5c543c 2026-03-19 martijn vfprintf(stderr, fmt, ap);
1115 1a5c543c 2026-03-19 martijn va_end(ap);
1116 1a5c543c 2026-03-19 martijn fprintf(stderr, "\n");
1120 1a5c543c 2026-03-19 martijn osmtpd_debug(struct osmtpd_ctx *ctx, const char *fmt, ...)
1122 1a5c543c 2026-03-19 martijn va_list ap;
1124 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor >= 8)
1125 1a5c543c 2026-03-19 martijn fprintf(stderr, "DEBUG|");
1126 1a5c543c 2026-03-19 martijn if (ctx)
1127 1a5c543c 2026-03-19 martijn fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1128 1a5c543c 2026-03-19 martijn va_start(ap, fmt);
1129 1a5c543c 2026-03-19 martijn vfprintf(stderr, fmt, ap);
1130 1a5c543c 2026-03-19 martijn va_end(ap);
1131 1a5c543c 2026-03-19 martijn fprintf(stderr, "\n");
1134 ce062d50 2019-08-21 martijn static void
1135 6258daeb 2019-11-14 martijn osmtpd_newline(struct io *io, int ev, __unused void *arg)
1137 ce062d50 2019-08-21 martijn static char *linedup = NULL;
1138 ce062d50 2019-08-21 martijn static size_t dupsize = 0;
1139 ce062d50 2019-08-21 martijn struct osmtpd_session *ctx, search;
1140 ce062d50 2019-08-21 martijn enum osmtpd_type type;
1141 ce062d50 2019-08-21 martijn enum osmtpd_phase phase;
1142 1a5c543c 2026-03-19 martijn int major, minor, incoming;
1143 ce062d50 2019-08-21 martijn struct timespec tm;
1144 ce062d50 2019-08-21 martijn char *line = NULL;
1145 ce062d50 2019-08-21 martijn const char *errstr = NULL;
1146 ce062d50 2019-08-21 martijn size_t linelen;
1147 ce062d50 2019-08-21 martijn char *end;
1148 ce062d50 2019-08-21 martijn size_t i;
1150 adebfe7c 2021-03-21 martijn if (ev == IO_DISCONNECTED) {
1151 adebfe7c 2021-03-21 martijn event_loopexit(0);
1152 adebfe7c 2021-03-21 martijn return;
1154 ce062d50 2019-08-21 martijn if (ev != IO_DATAIN)
1155 ce062d50 2019-08-21 martijn return;
1157 5f7c62fa 2022-03-28 martijn * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1158 5f7c62fa 2022-03-28 martijn * cause a build-up of kevents, because of event_add/event_del loop.
1160 5f7c62fa 2022-03-28 martijn io_pause(io_stdout, IO_OUT);
1161 24d62a97 2019-08-23 martijn while ((line = io_getline(io, &linelen)) != NULL) {
1162 ce062d50 2019-08-21 martijn if (dupsize < linelen) {
1163 ce062d50 2019-08-21 martijn if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1164 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1165 ce062d50 2019-08-21 martijn dupsize = linelen + 1;
1167 ce062d50 2019-08-21 martijn strlcpy(linedup, line, dupsize);
1168 ce062d50 2019-08-21 martijn if ((end = strchr(line, '|')) == NULL)
1169 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing "
1170 c6cb29f3 2019-08-22 martijn "version: %s", linedup);
1171 ce062d50 2019-08-21 martijn end++[0] = '\0';
1172 ce062d50 2019-08-21 martijn if (strcmp(line, "filter") == 0)
1173 ce062d50 2019-08-21 martijn type = OSMTPD_TYPE_FILTER;
1174 ce062d50 2019-08-21 martijn else if (strcmp(line, "report") == 0)
1175 ce062d50 2019-08-21 martijn type = OSMTPD_TYPE_REPORT;
1176 ce062d50 2019-08-21 martijn else if (strcmp(line, "config") == 0) {
1177 ce062d50 2019-08-21 martijn line = end;
1178 2029083f 2020-10-15 martijn if (strcmp(line, "ready") == 0) {
1179 34f87d66 2020-12-20 martijn if (conf_cb != NULL)
1180 34f87d66 2020-12-20 martijn conf_cb(NULL, NULL);
1181 ce062d50 2019-08-21 martijn continue;
1183 ce062d50 2019-08-21 martijn if ((end = strchr(line, '|')) == NULL)
1184 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing "
1185 c6cb29f3 2019-08-22 martijn "key: %s", linedup);
1186 ce062d50 2019-08-21 martijn end++[0] = '\0';
1187 34f87d66 2020-12-20 martijn if (conf_cb != NULL)
1188 34f87d66 2020-12-20 martijn conf_cb(line, end);
1189 ce062d50 2019-08-21 martijn if (strcmp(line, "smtp-session-timeout") == 0) {
1190 ce062d50 2019-08-21 martijn session_timeout = strtonum(end, 0, INT_MAX,
1191 ce062d50 2019-08-21 martijn &errstr);
1192 ce062d50 2019-08-21 martijn if (errstr != NULL)
1193 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: "
1194 ce062d50 2019-08-21 martijn "invalid smtp-sesion-timeout: %s",
1195 ce062d50 2019-08-21 martijn linedup);
1197 ce062d50 2019-08-21 martijn continue;
1200 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: unknown message "
1201 c6cb29f3 2019-08-22 martijn "type: %s", linedup);
1202 ce062d50 2019-08-21 martijn line = end;
1203 1a5c543c 2026-03-19 martijn major = strtoul(line, &end, 10);
1204 183acf20 2019-08-28 martijn if (line == end || end[0] != '.')
1205 183acf20 2019-08-28 martijn osmtpd_errx(1, "Invalid protocol received: %s",
1206 183acf20 2019-08-28 martijn linedup);
1207 183acf20 2019-08-28 martijn line = end + 1;
1208 1a5c543c 2026-03-19 martijn minor = strtoul(line, &end, 10);
1209 183acf20 2019-08-28 martijn if (end[0] == '\0')
1210 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing time: "
1211 c6cb29f3 2019-08-22 martijn "%s", linedup);
1212 183acf20 2019-08-28 martijn if (line == end || end[0] != '|')
1213 183acf20 2019-08-28 martijn osmtpd_errx(1, "Invalid protocol received: %s",
1214 183acf20 2019-08-28 martijn linedup);
1215 1a5c543c 2026-03-19 martijn if (major != 0)
1216 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Unsupported protocol received: %s",
1217 c6cb29f3 2019-08-22 martijn linedup);
1218 1a5c543c 2026-03-19 martijn if (version_major == 0 && version_minor == 0) {
1219 1a5c543c 2026-03-19 martijn version_major = major;
1220 1a5c543c 2026-03-19 martijn version_minor = minor;
1221 1a5c543c 2026-03-19 martijn } else {
1222 1a5c543c 2026-03-19 martijn if (version_major != major && version_minor != minor)
1223 1a5c543c 2026-03-19 martijn osmtpd_errx(1, "Unexpected protocol version "
1224 1a5c543c 2026-03-19 martijn "change: %s", linedup);
1226 183acf20 2019-08-28 martijn line = end + 1;
1227 ce062d50 2019-08-21 martijn if ((end = strchr(line, '.')) == NULL)
1228 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
1229 c6cb29f3 2019-08-22 martijn "timestamp: %s", linedup);
1230 ce062d50 2019-08-21 martijn end++[0] = '\0';
1231 ce062d50 2019-08-21 martijn tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1232 ce062d50 2019-08-21 martijn if (errstr != NULL)
1233 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
1234 c6cb29f3 2019-08-22 martijn "timestamp: %s", linedup);
1235 ce062d50 2019-08-21 martijn line = end;
1236 ce062d50 2019-08-21 martijn if ((end = strchr(line, '|')) == NULL)
1237 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing "
1238 c6cb29f3 2019-08-22 martijn "direction: %s", linedup);
1239 ce062d50 2019-08-21 martijn end++[0] = '\0';
1240 ce062d50 2019-08-21 martijn tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1241 ce062d50 2019-08-21 martijn if (errstr != NULL)
1242 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
1243 c6cb29f3 2019-08-22 martijn "timestamp: %s", linedup);
1244 ce062d50 2019-08-21 martijn tm.tv_nsec *= 10 * (9 - (end - line));
1245 ce062d50 2019-08-21 martijn line = end;
1246 ce062d50 2019-08-21 martijn if ((end = strchr(line, '|')) == NULL)
1247 e5f09156 2021-06-01 martijn osmtpd_errx(1, "Invalid line received: missing "
1248 c6cb29f3 2019-08-22 martijn "phase: %s", linedup);
1249 ce062d50 2019-08-21 martijn end++[0] = '\0';
1250 ce062d50 2019-08-21 martijn if (strcmp(line, "smtp-in") == 0)
1251 ce062d50 2019-08-21 martijn incoming = 1;
1252 ce062d50 2019-08-21 martijn else if (strcmp(line, "smtp-out") == 0)
1253 ce062d50 2019-08-21 martijn incoming = 0;
1255 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line: invalid direction: %s",
1256 c6cb29f3 2019-08-22 martijn linedup);
1257 ce062d50 2019-08-21 martijn line = end;
1258 ce062d50 2019-08-21 martijn if ((end = strchr(line, '|')) == NULL)
1259 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing reqid: "
1260 c6cb29f3 2019-08-22 martijn "%s", linedup);
1261 ce062d50 2019-08-21 martijn end++[0] = '\0';
1262 ce062d50 2019-08-21 martijn phase = osmtpd_strtophase(line, linedup);
1263 ce062d50 2019-08-21 martijn line = end;
1264 ce062d50 2019-08-21 martijn errno = 0;
1265 ce062d50 2019-08-21 martijn search.ctx.reqid = strtoull(line, &end, 16);
1266 ce062d50 2019-08-21 martijn if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1267 ce062d50 2019-08-21 martijn (end[0] != '|' && end[0] != '\0'))
1268 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid reqid: "
1269 c6cb29f3 2019-08-22 martijn "%s", linedup);
1270 ce062d50 2019-08-21 martijn line = end + 1;
1271 ce062d50 2019-08-21 martijn ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1272 ce062d50 2019-08-21 martijn if (ctx == NULL) {
1273 ce062d50 2019-08-21 martijn if ((ctx = malloc(sizeof(*ctx))) == NULL)
1274 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1275 d308c531 2025-02-03 martijn ctx->status = SESSION_OK;
1276 ce062d50 2019-08-21 martijn ctx->ctx.reqid = search.ctx.reqid;
1277 ce062d50 2019-08-21 martijn ctx->ctx.rdns = NULL;
1278 30f1cbac 2019-08-22 martijn ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1279 0fb4c799 2019-09-05 martijn ctx->ctx.identity = NULL;
1280 0fb4c799 2019-09-05 martijn ctx->ctx.greeting.identity = NULL;
1281 ce062d50 2019-08-21 martijn ctx->ctx.ciphers = NULL;
1282 ce062d50 2019-08-21 martijn ctx->ctx.msgid = 0;
1283 58a6bc69 2022-12-05 martijn ctx->ctx.username = NULL;
1284 ce062d50 2019-08-21 martijn ctx->ctx.mailfrom = NULL;
1285 ce062d50 2019-08-21 martijn ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1286 ce062d50 2019-08-21 martijn if (ctx->ctx.rcptto == NULL)
1287 27dd1f3b 2019-08-22 martijn osmtpd_err(1, "malloc");
1288 ce062d50 2019-08-21 martijn ctx->ctx.rcptto[0] = NULL;
1289 ce062d50 2019-08-21 martijn memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1290 ce062d50 2019-08-21 martijn ctx->ctx.src.ss_family = AF_UNSPEC;
1291 ce062d50 2019-08-21 martijn memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1292 ce062d50 2019-08-21 martijn ctx->ctx.dst.ss_family = AF_UNSPEC;
1293 ce062d50 2019-08-21 martijn RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1294 ce062d50 2019-08-21 martijn ctx->ctx.evpid = 0;
1295 912d0ff2 2019-08-22 martijn ctx->ctx.local_session = NULL;
1296 912d0ff2 2019-08-22 martijn ctx->ctx.local_message = NULL;
1297 912d0ff2 2019-08-22 martijn if (oncreatecb_session != NULL)
1298 866e5e0e 2025-02-03 martijn if ((ctx->ctx.local_session =
1299 866e5e0e 2025-02-03 martijn oncreatecb_session(&ctx->ctx)) == NULL)
1300 866e5e0e 2025-02-03 martijn ctx->status = SESSION_ERROR;
1302 ce062d50 2019-08-21 martijn ctx->ctx.type = type;
1303 ce062d50 2019-08-21 martijn ctx->ctx.phase = phase;
1304 1a5c543c 2026-03-19 martijn ctx->ctx.version_major = major;
1305 1a5c543c 2026-03-19 martijn ctx->ctx.version_minor = minor;
1306 ce062d50 2019-08-21 martijn ctx->ctx.incoming = incoming;
1307 ce062d50 2019-08-21 martijn ctx->ctx.tm.tv_sec = tm.tv_sec;
1308 ce062d50 2019-08-21 martijn ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1309 ce062d50 2019-08-21 martijn ctx->ctx.token = 0;
1311 ce062d50 2019-08-21 martijn for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1312 ce062d50 2019-08-21 martijn if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1313 ce062d50 2019-08-21 martijn ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1314 ce062d50 2019-08-21 martijn ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1317 ce062d50 2019-08-21 martijn if (i == NITEMS(osmtpd_callbacks)) {
1318 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: received "
1319 c6cb29f3 2019-08-22 martijn "unregistered line: %s", linedup);
1321 ce062d50 2019-08-21 martijn if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1322 ce062d50 2019-08-21 martijn ctx->ctx.token = strtoull(line, &end, 16);
1323 c6cb29f3 2019-08-22 martijn if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1324 ce062d50 2019-08-21 martijn end[0] != '|')
1325 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
1326 c6cb29f3 2019-08-22 martijn "token: %s", linedup);
1327 ce062d50 2019-08-21 martijn line = end + 1;
1328 866e5e0e 2025-02-03 martijn if (ctx->status == SESSION_ERROR)
1329 866e5e0e 2025-02-03 martijn osmtpd_filter_disconnect(&ctx->ctx,
1330 866e5e0e 2025-02-03 martijn "internal server error");
1332 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1333 866e5e0e 2025-02-03 martijn ctx, line, linedup);
1335 5f7c62fa 2022-03-28 martijn io_resume(io_stdout, IO_OUT);
1338 ce062d50 2019-08-21 martijn static void
1339 6258daeb 2019-11-14 martijn osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1341 ce062d50 2019-08-21 martijn switch (evt) {
1342 ce062d50 2019-08-21 martijn case IO_LOWAT:
1343 ce062d50 2019-08-21 martijn return;
1344 ce062d50 2019-08-21 martijn case IO_DISCONNECTED:
1345 ce062d50 2019-08-21 martijn exit(0);
1346 ce062d50 2019-08-21 martijn default:
1347 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Unexpectd event");
1351 ce062d50 2019-08-21 martijn static void
1352 866e5e0e 2025-02-03 martijn osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_session *session,
1353 6258daeb 2019-11-14 martijn __unused char *params, __unused char *linedup)
1355 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *);
1357 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1358 5129e9c0 2025-04-10 kirill if (f(&session->ctx))
1359 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1362 ce062d50 2019-08-21 martijn static void
1363 866e5e0e 2025-02-03 martijn osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_session *session,
1364 866e5e0e 2025-02-03 martijn char *line, __unused char *linedup)
1366 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1368 7bb76d65 2026-03-20 op if (oncreatecb_message != NULL && cb->phase == OSMTPD_PHASE_MAIL_FROM) {
1369 7bb76d65 2026-03-20 op session->ctx.local_message = oncreatecb_message(&session->ctx);
1370 7bb76d65 2026-03-20 op if (session->ctx.local_message == NULL)
1371 7bb76d65 2026-03-20 op session->status = SESSION_ERROR;
1373 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1374 5129e9c0 2025-04-10 kirill if (f(&session->ctx, line))
1375 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1378 ce062d50 2019-08-21 martijn static void
1379 866e5e0e 2025-02-03 martijn osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1380 866e5e0e 2025-02-03 martijn char *params, char *linedup)
1382 ce062d50 2019-08-21 martijn struct sockaddr_storage ss;
1383 ce062d50 2019-08-21 martijn char *hostname;
1384 ce062d50 2019-08-21 martijn char *address;
1385 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1387 ce062d50 2019-08-21 martijn hostname = params;
1388 ce062d50 2019-08-21 martijn if ((address = strchr(params, '|')) == NULL)
1389 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1390 c6cb29f3 2019-08-22 martijn linedup);
1391 ce062d50 2019-08-21 martijn address++[0] = '\0';
1393 ce062d50 2019-08-21 martijn osmtpd_addrtoss(address, &ss, 0, linedup);
1395 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1396 5129e9c0 2025-04-10 kirill if (f(&session->ctx, hostname, &ss))
1397 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1400 ce062d50 2019-08-21 martijn static void
1401 866e5e0e 2025-02-03 martijn osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1402 6258daeb 2019-11-14 martijn char *identity, __unused char *linedup)
1404 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1406 421c9a86 2019-09-06 martijn if (cb->storereport) {
1407 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1408 866e5e0e 2025-02-03 martijn if ((session->ctx.identity = strdup(identity)) == NULL)
1409 421c9a86 2019-09-06 martijn osmtpd_err(1, "strdup");
1412 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1413 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1414 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1417 421c9a86 2019-09-06 martijn static void
1418 866e5e0e 2025-02-03 martijn osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1419 ce062d50 2019-08-21 martijn char *params, char *linedup)
1421 30f1cbac 2019-08-22 martijn char *end, *rdns;
1422 30f1cbac 2019-08-22 martijn enum osmtpd_status fcrdns;
1423 ce062d50 2019-08-21 martijn struct sockaddr_storage src, dst;
1424 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1425 c6cb29f3 2019-08-22 martijn struct sockaddr_storage *, struct sockaddr_storage *);
1427 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1428 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1429 c6cb29f3 2019-08-22 martijn linedup);
1430 ce062d50 2019-08-21 martijn end++[0] = '\0';
1431 ce062d50 2019-08-21 martijn rdns = params;
1432 ce062d50 2019-08-21 martijn params = end;
1433 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1434 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing src: %s",
1435 c6cb29f3 2019-08-22 martijn linedup);
1436 ce062d50 2019-08-21 martijn end++[0] = '\0';
1437 30f1cbac 2019-08-22 martijn if (strcmp(params, "pass") == 0)
1438 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_OK;
1439 30f1cbac 2019-08-22 martijn else if (strcmp(params, "fail") == 0)
1440 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_PERMFAIL;
1441 30f1cbac 2019-08-22 martijn else if (strcmp(params, "error") == 0)
1442 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_TEMPFAIL;
1444 30f1cbac 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1445 30f1cbac 2019-08-22 martijn linedup);
1446 ce062d50 2019-08-21 martijn params = end;
1447 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1448 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing dst: %s",
1449 c6cb29f3 2019-08-22 martijn linedup);
1450 ce062d50 2019-08-21 martijn end++[0] = '\0';
1451 ce062d50 2019-08-21 martijn osmtpd_addrtoss(params, &src, 1, linedup);
1452 ce062d50 2019-08-21 martijn params = end;
1453 ce062d50 2019-08-21 martijn osmtpd_addrtoss(params, &dst, 1, linedup);
1454 ce062d50 2019-08-21 martijn if (cb->storereport) {
1455 866e5e0e 2025-02-03 martijn if ((session->ctx.rdns = strdup(rdns)) == NULL)
1456 30f1cbac 2019-08-22 martijn osmtpd_err(1, "strdup");
1457 866e5e0e 2025-02-03 martijn session->ctx.fcrdns = fcrdns;
1458 866e5e0e 2025-02-03 martijn memcpy(&session->ctx.src, &src, sizeof(session->ctx.src));
1459 866e5e0e 2025-02-03 martijn memcpy(&session->ctx.dst, &dst, sizeof(session->ctx.dst));
1461 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1462 5129e9c0 2025-04-10 kirill if (f(&session->ctx, rdns, fcrdns, &src, &dst))
1463 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1466 ce062d50 2019-08-21 martijn static void
1467 866e5e0e 2025-02-03 martijn osmtpd_link_disconnect(struct osmtpd_callback *cb,
1468 866e5e0e 2025-02-03 martijn struct osmtpd_session *session, __unused char *param,
1469 866e5e0e 2025-02-03 martijn __unused char *linedup)
1471 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *);
1472 ce062d50 2019-08-21 martijn size_t i;
1474 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1475 5129e9c0 2025-04-10 kirill if (f(&session->ctx))
1476 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1478 866e5e0e 2025-02-03 martijn RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1479 866e5e0e 2025-02-03 martijn if (ondeletecb_session != NULL && session->ctx.local_session != NULL)
1480 866e5e0e 2025-02-03 martijn ondeletecb_session(&session->ctx, session->ctx.local_session);
1481 866e5e0e 2025-02-03 martijn free(session->ctx.rdns);
1482 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1483 866e5e0e 2025-02-03 martijn free(session->ctx.greeting.identity);
1484 866e5e0e 2025-02-03 martijn free(session->ctx.ciphers);
1485 866e5e0e 2025-02-03 martijn free(session->ctx.username);
1486 866e5e0e 2025-02-03 martijn free(session->ctx.mailfrom);
1487 866e5e0e 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1488 866e5e0e 2025-02-03 martijn free(session->ctx.rcptto[i]);
1489 866e5e0e 2025-02-03 martijn free(session->ctx.rcptto);
1490 866e5e0e 2025-02-03 martijn free(session);
1493 866e5e0e 2025-02-03 martijn static void
1494 866e5e0e 2025-02-03 martijn osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_session *session,
1495 866e5e0e 2025-02-03 martijn char *identity, __unused char *linedup)
1497 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1499 866e5e0e 2025-02-03 martijn if (cb->storereport) {
1500 0fb4c799 2019-09-05 martijn free(session->ctx.greeting.identity);
1501 866e5e0e 2025-02-03 martijn if ((session->ctx.greeting.identity = strdup(identity)) == NULL)
1502 a05d5c54 2019-08-28 martijn osmtpd_err(1, NULL);
1505 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1506 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1507 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1510 a05d5c54 2019-08-28 martijn static void
1511 866e5e0e 2025-02-03 martijn osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1512 6258daeb 2019-11-14 martijn char *identity, __unused char *linedup)
1514 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1516 ce062d50 2019-08-21 martijn if (cb->storereport) {
1517 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1518 866e5e0e 2025-02-03 martijn if ((session->ctx.identity = strdup(identity)) == NULL)
1519 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1522 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1523 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1524 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1527 ce062d50 2019-08-21 martijn static void
1528 866e5e0e 2025-02-03 martijn osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_session *session,
1529 6258daeb 2019-11-14 martijn char *ciphers, __unused char *linedup)
1531 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1533 ce062d50 2019-08-21 martijn if (cb->storereport) {
1534 866e5e0e 2025-02-03 martijn if ((session->ctx.ciphers = strdup(ciphers)) == NULL)
1535 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1538 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1539 5129e9c0 2025-04-10 kirill if (f(&session->ctx, ciphers))
1540 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1543 ce062d50 2019-08-21 martijn static void
1544 866e5e0e 2025-02-03 martijn osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_session *session,
1545 58a6bc69 2022-12-05 martijn char *username, char *linedup)
1547 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1548 58a6bc69 2022-12-05 martijn char *status;
1549 58a6bc69 2022-12-05 martijn enum osmtpd_auth_status s;
1551 58a6bc69 2022-12-05 martijn if ((status = strrchr(username, '|')) == NULL)
1552 58a6bc69 2022-12-05 martijn osmtpd_errx(1, "Invalid auth received: %s", linedup);
1553 58a6bc69 2022-12-05 martijn status[0] = '\0';
1554 58a6bc69 2022-12-05 martijn status++;
1555 58a6bc69 2022-12-05 martijn if (strcmp(status, "pass") == 0)
1556 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_PASS;
1557 58a6bc69 2022-12-05 martijn else if (strcmp(status, "fail") == 0)
1558 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_FAIL;
1559 58a6bc69 2022-12-05 martijn else if (strcmp(status, "error") == 0)
1560 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_ERROR;
1562 58a6bc69 2022-12-05 martijn osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1564 58a6bc69 2022-12-05 martijn if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1565 866e5e0e 2025-02-03 martijn if ((session->ctx.username = strdup(username)) == NULL)
1566 58a6bc69 2022-12-05 martijn osmtpd_err(1, NULL);
1569 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1570 5129e9c0 2025-04-10 kirill if (f(&session->ctx, username, s))
1571 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1574 58a6bc69 2022-12-05 martijn static void
1575 d308c531 2025-02-03 martijn osmtpd_tx_reset(struct osmtpd_callback *cb, struct osmtpd_session *session,
1576 d308c531 2025-02-03 martijn char *params, char *linedup)
1578 d308c531 2025-02-03 martijn char *end;
1579 d308c531 2025-02-03 martijn unsigned long imsgid;
1580 d308c531 2025-02-03 martijn uint32_t msgid;
1581 d308c531 2025-02-03 martijn size_t i;
1582 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1584 d308c531 2025-02-03 martijn errno = 0;
1585 d308c531 2025-02-03 martijn imsgid = strtoul(params, &end, 16);
1586 d308c531 2025-02-03 martijn if ((imsgid == ULONG_MAX && errno != 0))
1587 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1588 d308c531 2025-02-03 martijn linedup);
1589 d308c531 2025-02-03 martijn if (end[0] != '\0')
1590 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1591 d308c531 2025-02-03 martijn linedup);
1592 d308c531 2025-02-03 martijn msgid = imsgid;
1593 d308c531 2025-02-03 martijn if ((unsigned long) msgid != imsgid)
1594 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1595 d308c531 2025-02-03 martijn linedup);
1597 d308c531 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1598 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid))
1599 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1601 d308c531 2025-02-03 martijn if (ondeletecb_message != NULL && session->ctx.local_message != NULL) {
1602 d308c531 2025-02-03 martijn ondeletecb_message(&session->ctx, session->ctx.local_message);
1603 d308c531 2025-02-03 martijn session->ctx.local_message = NULL;
1606 d308c531 2025-02-03 martijn free(session->ctx.mailfrom);
1607 d308c531 2025-02-03 martijn session->ctx.mailfrom = NULL;
1609 d308c531 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1610 d308c531 2025-02-03 martijn free(session->ctx.rcptto[i]);
1611 d308c531 2025-02-03 martijn session->ctx.rcptto[0] = NULL;
1612 d308c531 2025-02-03 martijn session->ctx.evpid = 0;
1613 d308c531 2025-02-03 martijn session->ctx.msgid = 0;
1616 d308c531 2025-02-03 martijn static void
1617 866e5e0e 2025-02-03 martijn osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_session *session,
1618 ce062d50 2019-08-21 martijn char *msgid, char *linedup)
1620 ce062d50 2019-08-21 martijn unsigned long imsgid;
1621 ce062d50 2019-08-21 martijn char *endptr;
1622 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1624 ce062d50 2019-08-21 martijn errno = 0;
1625 ce062d50 2019-08-21 martijn imsgid = strtoul(msgid, &endptr, 16);
1626 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1627 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1628 c6cb29f3 2019-08-22 martijn linedup);
1629 866e5e0e 2025-02-03 martijn session->ctx.msgid = imsgid;
1630 ce062d50 2019-08-21 martijn /* Check if we're in range */
1631 866e5e0e 2025-02-03 martijn if ((unsigned long) session->ctx.msgid != imsgid)
1632 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1633 c6cb29f3 2019-08-22 martijn linedup);
1635 ce062d50 2019-08-21 martijn if (!cb->storereport)
1636 866e5e0e 2025-02-03 martijn session->ctx.msgid = 0;
1638 7bb76d65 2026-03-20 op if (oncreatecb_message != NULL && session->ctx.local_message == NULL) {
1639 866e5e0e 2025-02-03 martijn session->ctx.local_message = oncreatecb_message(&session->ctx);
1640 866e5e0e 2025-02-03 martijn if (session->ctx.local_message == NULL)
1641 866e5e0e 2025-02-03 martijn session->status = SESSION_ERROR;
1644 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1645 5129e9c0 2025-04-10 kirill if (f(&session->ctx, imsgid))
1646 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1649 ce062d50 2019-08-21 martijn static void
1650 866e5e0e 2025-02-03 martijn osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_session *session,
1651 ce062d50 2019-08-21 martijn char *params, char *linedup)
1653 ce062d50 2019-08-21 martijn char *end, *mailfrom;
1654 53b354a9 2020-04-12 martijn enum osmtpd_status status;
1655 ce062d50 2019-08-21 martijn unsigned long imsgid;
1656 ce062d50 2019-08-21 martijn uint32_t msgid;
1657 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1658 ce062d50 2019-08-21 martijn enum osmtpd_status);
1660 ce062d50 2019-08-21 martijn errno = 0;
1661 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1662 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1663 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1664 c6cb29f3 2019-08-22 martijn linedup);
1665 ce062d50 2019-08-21 martijn if (end[0] != '|')
1666 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1667 c6cb29f3 2019-08-22 martijn linedup);
1668 ce062d50 2019-08-21 martijn msgid = imsgid;
1669 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1670 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1671 c6cb29f3 2019-08-22 martijn linedup);
1672 ce062d50 2019-08-21 martijn params = end + 1;
1674 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1675 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing status: %s",
1676 c6cb29f3 2019-08-22 martijn linedup);
1677 ce062d50 2019-08-21 martijn end++[0] = '\0';
1678 866e5e0e 2025-02-03 martijn if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1679 53b354a9 2020-04-12 martijn mailfrom = params;
1680 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(end, linedup);
1681 53b354a9 2020-04-12 martijn } else {
1682 53b354a9 2020-04-12 martijn mailfrom = end;
1683 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(params, linedup);
1685 ce062d50 2019-08-21 martijn if (cb->storereport) {
1686 866e5e0e 2025-02-03 martijn if ((session->ctx.mailfrom = strdup(mailfrom)) == NULL)
1687 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1690 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1691 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, mailfrom, status))
1692 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1695 ce062d50 2019-08-21 martijn static void
1696 866e5e0e 2025-02-03 martijn osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_session *session,
1697 ce062d50 2019-08-21 martijn char *params, char *linedup)
1699 ce062d50 2019-08-21 martijn char *end, *rcptto;
1700 53b354a9 2020-04-12 martijn enum osmtpd_status status;
1701 ce062d50 2019-08-21 martijn unsigned long imsgid;
1702 ce062d50 2019-08-21 martijn uint32_t msgid;
1703 ce062d50 2019-08-21 martijn size_t i;
1704 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1705 ce062d50 2019-08-21 martijn enum osmtpd_status);
1707 ce062d50 2019-08-21 martijn errno = 0;
1708 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1709 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1710 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1711 c6cb29f3 2019-08-22 martijn linedup);
1712 ce062d50 2019-08-21 martijn if (end[0] != '|')
1713 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1714 c6cb29f3 2019-08-22 martijn linedup);
1715 ce062d50 2019-08-21 martijn msgid = imsgid;
1716 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1717 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1718 c6cb29f3 2019-08-22 martijn linedup);
1719 ce062d50 2019-08-21 martijn params = end + 1;
1721 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1722 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing status: %s",
1723 c6cb29f3 2019-08-22 martijn linedup);
1724 ce062d50 2019-08-21 martijn end++[0] = '\0';
1726 866e5e0e 2025-02-03 martijn if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1727 53b354a9 2020-04-12 martijn rcptto = params;
1728 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(end, linedup);
1729 53b354a9 2020-04-12 martijn } else {
1730 53b354a9 2020-04-12 martijn rcptto = end;
1731 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(params, linedup);
1734 ce062d50 2019-08-21 martijn if (cb->storereport) {
1735 866e5e0e 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1737 866e5e0e 2025-02-03 martijn session->ctx.rcptto = reallocarray(session->ctx.rcptto, i + 2,
1738 866e5e0e 2025-02-03 martijn sizeof(*session->ctx.rcptto));
1739 866e5e0e 2025-02-03 martijn if (session->ctx.rcptto == NULL)
1740 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1742 866e5e0e 2025-02-03 martijn if ((session->ctx.rcptto[i] = strdup(rcptto)) == NULL)
1743 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1744 866e5e0e 2025-02-03 martijn session->ctx.rcptto[i + 1] = NULL;
1747 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1748 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, rcptto, status))
1749 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1752 ce062d50 2019-08-21 martijn static void
1753 866e5e0e 2025-02-03 martijn osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_session *session,
1754 ce062d50 2019-08-21 martijn char *params, char *linedup)
1756 ce062d50 2019-08-21 martijn unsigned long imsgid;
1757 ce062d50 2019-08-21 martijn uint32_t msgid;
1758 ce062d50 2019-08-21 martijn uint64_t evpid;
1759 ce062d50 2019-08-21 martijn char *end;
1760 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1762 ce062d50 2019-08-21 martijn errno = 0;
1763 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1764 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1765 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1766 c6cb29f3 2019-08-22 martijn linedup);
1767 ce062d50 2019-08-21 martijn if (end[0] != '|')
1768 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1769 c6cb29f3 2019-08-22 martijn linedup);
1770 ce062d50 2019-08-21 martijn msgid = imsgid;
1771 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1772 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1773 c6cb29f3 2019-08-22 martijn linedup);
1774 ce062d50 2019-08-21 martijn params = end + 1;
1776 ce062d50 2019-08-21 martijn evpid = strtoull(params, &end, 16);
1777 866e5e0e 2025-02-03 martijn if ((session->ctx.evpid == ULLONG_MAX && errno != 0) || end[0] != '\0')
1778 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1779 c6cb29f3 2019-08-22 martijn linedup);
1780 ce062d50 2019-08-21 martijn if (cb->storereport)
1781 866e5e0e 2025-02-03 martijn session->ctx.evpid = evpid;
1783 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1784 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, evpid))
1785 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1788 ce062d50 2019-08-21 martijn static void
1789 866e5e0e 2025-02-03 martijn osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_session *session,
1790 ce062d50 2019-08-21 martijn char *params, char *linedup)
1792 ce062d50 2019-08-21 martijn char *end;
1793 ce062d50 2019-08-21 martijn unsigned long imsgid;
1794 ce062d50 2019-08-21 martijn uint32_t msgid;
1795 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1797 ce062d50 2019-08-21 martijn errno = 0;
1798 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1799 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1800 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1801 c6cb29f3 2019-08-22 martijn linedup);
1802 ce062d50 2019-08-21 martijn if (end[0] != '|')
1803 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1804 c6cb29f3 2019-08-22 martijn linedup);
1805 ce062d50 2019-08-21 martijn msgid = imsgid;
1806 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1807 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1808 c6cb29f3 2019-08-22 martijn linedup);
1809 ce062d50 2019-08-21 martijn params = end + 1;
1811 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1812 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, osmtpd_strtostatus(params, linedup)))
1813 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1816 ce062d50 2019-08-21 martijn static void
1817 866e5e0e 2025-02-03 martijn osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_session *session,
1818 ce062d50 2019-08-21 martijn char *params, char *linedup)
1820 ce062d50 2019-08-21 martijn char *end;
1821 332b3141 2019-08-22 martijn const char *errstr = NULL;
1822 ce062d50 2019-08-21 martijn unsigned long imsgid;
1823 ce062d50 2019-08-21 martijn uint32_t msgid;
1824 d308c531 2025-02-03 martijn size_t msgsz;
1825 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1827 ce062d50 2019-08-21 martijn errno = 0;
1828 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1829 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1830 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1831 c6cb29f3 2019-08-22 martijn linedup);
1832 ce062d50 2019-08-21 martijn if (end[0] != '|')
1833 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1834 c6cb29f3 2019-08-22 martijn linedup);
1835 ce062d50 2019-08-21 martijn msgid = imsgid;
1836 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1837 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1838 c6cb29f3 2019-08-22 martijn linedup);
1839 ce062d50 2019-08-21 martijn params = end + 1;
1841 332b3141 2019-08-22 martijn msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1842 ce062d50 2019-08-21 martijn if (errstr != NULL)
1843 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1844 c6cb29f3 2019-08-22 martijn linedup);
1846 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1847 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, msgsz))
1848 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1851 ce062d50 2019-08-21 martijn static void
1852 866e5e0e 2025-02-03 martijn osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_session *session,
1853 ce062d50 2019-08-21 martijn char *params, char *linedup)
1855 ce062d50 2019-08-21 martijn char *end;
1856 ce062d50 2019-08-21 martijn unsigned long imsgid;
1857 ce062d50 2019-08-21 martijn uint32_t msgid;
1858 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1860 ce062d50 2019-08-21 martijn errno = 0;
1861 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1862 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1863 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1864 c6cb29f3 2019-08-22 martijn linedup);
1865 ce062d50 2019-08-21 martijn if (end[0] != '\0')
1866 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1867 c6cb29f3 2019-08-22 martijn linedup);
1868 ce062d50 2019-08-21 martijn msgid = imsgid;
1869 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1870 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1871 c6cb29f3 2019-08-22 martijn linedup);
1873 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1874 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid))
1875 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1879 ce062d50 2019-08-21 martijn osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1881 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1883 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1884 866e5e0e 2025-02-03 martijn return;
1886 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1887 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1888 06220a70 2019-12-06 martijn "proceed\n", ctx->token, ctx->reqid);
1890 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1891 06220a70 2019-12-06 martijn "proceed\n", ctx->reqid, ctx->token);
1895 ce062d50 2019-08-21 martijn osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1897 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1898 ce062d50 2019-08-21 martijn va_list ap;
1900 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1901 866e5e0e 2025-02-03 martijn return;
1903 ce062d50 2019-08-21 martijn if (code < 200 || code > 599)
1904 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid reject code");
1906 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1907 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1908 06220a70 2019-12-06 martijn "reject|%d ", ctx->token, ctx->reqid, code);
1910 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1911 06220a70 2019-12-06 martijn "reject|%d ", ctx->reqid, ctx->token, code);
1912 ce062d50 2019-08-21 martijn va_start(ap, reason);
1913 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, reason, ap);
1914 ce062d50 2019-08-21 martijn va_end(ap);
1915 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
1919 000aebbc 2019-08-23 martijn osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1920 000aebbc 2019-08-23 martijn int subject, int detail, const char *reason, ...)
1922 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1923 000aebbc 2019-08-23 martijn va_list ap;
1925 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1926 866e5e0e 2025-02-03 martijn return;
1928 000aebbc 2019-08-23 martijn if (code < 200 || code > 599)
1929 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid reject code");
1930 2a3d7bdf 2019-08-27 martijn if (class < 2 || class > 5)
1931 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status class");
1932 000aebbc 2019-08-23 martijn if (subject < 0 || subject > 999)
1933 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status subject");
1934 000aebbc 2019-08-23 martijn if (detail < 0 || detail > 999)
1935 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status detail");
1937 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1938 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1939 06220a70 2019-12-06 martijn "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1940 06220a70 2019-12-06 martijn subject, detail);
1942 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1943 06220a70 2019-12-06 martijn "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1944 06220a70 2019-12-06 martijn subject, detail);
1945 000aebbc 2019-08-23 martijn va_start(ap, reason);
1946 000aebbc 2019-08-23 martijn io_vprintf(io_stdout, reason, ap);
1947 000aebbc 2019-08-23 martijn va_end(ap);
1948 000aebbc 2019-08-23 martijn io_printf(io_stdout, "\n");
1952 ce062d50 2019-08-21 martijn osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1954 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1955 ce062d50 2019-08-21 martijn va_list ap;
1957 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1958 866e5e0e 2025-02-03 martijn return;
1960 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1961 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1962 06220a70 2019-12-06 martijn "disconnect|421 ", ctx->token, ctx->reqid);
1964 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1965 06220a70 2019-12-06 martijn "disconnect|421 ", ctx->reqid, ctx->token);
1966 ce062d50 2019-08-21 martijn va_start(ap, reason);
1967 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, reason, ap);
1968 ce062d50 2019-08-21 martijn va_end(ap);
1969 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
1970 866e5e0e 2025-02-03 martijn session->status = SESSION_DISCONNECTED;
1974 000aebbc 2019-08-23 martijn osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1975 000aebbc 2019-08-23 martijn int detail, const char *reason, ...)
1977 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1978 000aebbc 2019-08-23 martijn va_list ap;
1980 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1981 866e5e0e 2025-02-03 martijn return;
1983 000aebbc 2019-08-23 martijn if (class <= 2 || class >= 5)
1984 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status class");
1985 000aebbc 2019-08-23 martijn if (subject < 0 || subject > 999)
1986 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status subject");
1987 000aebbc 2019-08-23 martijn if (detail < 0 || detail > 999)
1988 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status detail");
1989 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1990 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1991 06220a70 2019-12-06 martijn "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1992 06220a70 2019-12-06 martijn subject, detail);
1994 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1995 06220a70 2019-12-06 martijn "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1996 06220a70 2019-12-06 martijn subject, detail);
1997 000aebbc 2019-08-23 martijn va_start(ap, reason);
1998 000aebbc 2019-08-23 martijn io_vprintf(io_stdout, reason, ap);
1999 000aebbc 2019-08-23 martijn va_end(ap);
2000 000aebbc 2019-08-23 martijn io_printf(io_stdout, "\n");
2001 866e5e0e 2025-02-03 martijn session->status = SESSION_DISCONNECTED;
2005 4fb72612 2019-08-21 martijn osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
2007 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2008 4fb72612 2019-08-21 martijn va_list ap;
2010 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
2011 866e5e0e 2025-02-03 martijn return;
2013 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
2014 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2015 06220a70 2019-12-06 martijn "rewrite|", ctx->token, ctx->reqid);
2017 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2018 06220a70 2019-12-06 martijn "rewrite|", ctx->reqid, ctx->token);
2019 4fb72612 2019-08-21 martijn va_start(ap, value);
2020 4fb72612 2019-08-21 martijn io_vprintf(io_stdout, value, ap);
2021 4fb72612 2019-08-21 martijn va_end(ap);
2022 4fb72612 2019-08-21 martijn io_printf(io_stdout, "\n");
2026 ce062d50 2019-08-21 martijn osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
2028 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2029 ce062d50 2019-08-21 martijn va_list ap;
2031 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
2032 866e5e0e 2025-02-03 martijn return;
2034 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
2035 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2036 06220a70 2019-12-06 martijn ctx->token, ctx->reqid);
2038 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2039 06220a70 2019-12-06 martijn ctx->reqid, ctx->token);
2040 ce062d50 2019-08-21 martijn va_start(ap, line);
2041 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, line, ap);
2042 ce062d50 2019-08-21 martijn va_end(ap);
2043 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
2046 ce062d50 2019-08-21 martijn static void
2047 ce062d50 2019-08-21 martijn osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
2048 ce062d50 2019-08-21 martijn int storereport, void *cb)
2050 ce062d50 2019-08-21 martijn size_t i;
2052 ce062d50 2019-08-21 martijn if (ready)
2053 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Can't register when proc is running");
2055 ce062d50 2019-08-21 martijn for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
2056 ce062d50 2019-08-21 martijn if (type == osmtpd_callbacks[i].type &&
2057 ce062d50 2019-08-21 martijn phase == osmtpd_callbacks[i].phase &&
2058 ce062d50 2019-08-21 martijn incoming == osmtpd_callbacks[i].incoming) {
2059 ce062d50 2019-08-21 martijn if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
2060 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Event already registered");
2061 912d0ff2 2019-08-22 martijn if (cb != NULL)
2062 912d0ff2 2019-08-22 martijn osmtpd_callbacks[i].cb = cb;
2063 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].doregister = 1;
2064 ce062d50 2019-08-21 martijn if (storereport)
2065 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].storereport = 1;
2066 ce062d50 2019-08-21 martijn return;
2069 ce062d50 2019-08-21 martijn /* NOT REACHED */
2070 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Trying to register unknown event");
2073 ce062d50 2019-08-21 martijn static enum osmtpd_phase
2074 ce062d50 2019-08-21 martijn osmtpd_strtophase(const char *phase, const char *linedup)
2076 ce062d50 2019-08-21 martijn if (strcmp(phase, "connect") == 0)
2077 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_CONNECT;
2078 ce062d50 2019-08-21 martijn if (strcmp(phase, "helo") == 0)
2079 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_HELO;
2080 ce062d50 2019-08-21 martijn if (strcmp(phase, "ehlo") == 0)
2081 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_EHLO;
2082 ce062d50 2019-08-21 martijn if (strcmp(phase, "starttls") == 0)
2083 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_STARTTLS;
2084 ce062d50 2019-08-21 martijn if (strcmp(phase, "auth") == 0)
2085 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_AUTH;
2086 ce062d50 2019-08-21 martijn if (strcmp(phase, "mail-from") == 0)
2087 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_MAIL_FROM;
2088 ce062d50 2019-08-21 martijn if (strcmp(phase, "rcpt-to") == 0)
2089 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_RCPT_TO;
2090 ce062d50 2019-08-21 martijn if (strcmp(phase, "data") == 0)
2091 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_DATA;
2092 ce062d50 2019-08-21 martijn if (strcmp(phase, "data-line") == 0)
2093 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_DATA_LINE;
2094 ce062d50 2019-08-21 martijn if (strcmp(phase, "rset") == 0)
2095 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_RSET;
2096 ce062d50 2019-08-21 martijn if (strcmp(phase, "quit") == 0)
2097 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_QUIT;
2098 ce062d50 2019-08-21 martijn if (strcmp(phase, "noop") == 0)
2099 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_NOOP;
2100 ce062d50 2019-08-21 martijn if (strcmp(phase, "help") == 0)
2101 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_HELP;
2102 ce062d50 2019-08-21 martijn if (strcmp(phase, "wiz") == 0)
2103 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_WIZ;
2104 ce062d50 2019-08-21 martijn if (strcmp(phase, "commit") == 0)
2105 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_COMMIT;
2106 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-connect") == 0)
2107 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_CONNECT;
2108 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-disconnect") == 0)
2109 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_DISCONNECT;
2110 b52f2785 2019-09-06 martijn if (strcmp(phase, "link-greeting") == 0)
2111 b52f2785 2019-09-06 martijn return OSMTPD_PHASE_LINK_GREETING;
2112 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-identify") == 0)
2113 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_IDENTIFY;
2114 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-tls") == 0)
2115 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_TLS;
2116 58a6bc69 2022-12-05 martijn if (strcmp(phase, "link-auth") == 0)
2117 58a6bc69 2022-12-05 martijn return OSMTPD_PHASE_LINK_AUTH;
2118 d308c531 2025-02-03 martijn if (strcmp(phase, "tx-reset") == 0)
2119 d308c531 2025-02-03 martijn return OSMTPD_PHASE_TX_RESET;
2120 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-begin") == 0)
2121 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_BEGIN;
2122 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-mail") == 0)
2123 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_MAIL;
2124 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-rcpt") == 0)
2125 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_RCPT;
2126 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-envelope") == 0)
2127 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_ENVELOPE;
2128 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-data") == 0)
2129 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_DATA;
2130 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-commit") == 0)
2131 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_COMMIT;
2132 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-rollback") == 0)
2133 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_ROLLBACK;
2134 ce062d50 2019-08-21 martijn if (strcmp(phase, "protocol-client") == 0)
2135 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_PROTOCOL_CLIENT;
2136 ce062d50 2019-08-21 martijn if (strcmp(phase, "protocol-server") == 0)
2137 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_PROTOCOL_SERVER;
2138 ce062d50 2019-08-21 martijn if (strcmp(phase, "filter-response") == 0)
2139 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_FILTER_RESPONSE;
2140 ce062d50 2019-08-21 martijn if (strcmp(phase, "timeout") == 0)
2141 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TIMEOUT;
2142 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
2145 ce062d50 2019-08-21 martijn static const char *
2146 ce062d50 2019-08-21 martijn osmtpd_typetostr(enum osmtpd_type type)
2148 ce062d50 2019-08-21 martijn switch (type) {
2149 ce062d50 2019-08-21 martijn case OSMTPD_TYPE_FILTER:
2150 ce062d50 2019-08-21 martijn return "filter";
2151 ce062d50 2019-08-21 martijn case OSMTPD_TYPE_REPORT:
2152 ce062d50 2019-08-21 martijn return "report";
2154 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "In valid type: %d\n", type);
2157 ce062d50 2019-08-21 martijn static const char *
2158 ce062d50 2019-08-21 martijn osmtpd_phasetostr(enum osmtpd_phase phase)
2160 ce062d50 2019-08-21 martijn switch (phase) {
2161 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_CONNECT:
2162 ce062d50 2019-08-21 martijn return "connect";
2163 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_HELO:
2164 ce062d50 2019-08-21 martijn return "helo";
2165 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_EHLO:
2166 ce062d50 2019-08-21 martijn return "ehlo";
2167 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_STARTTLS:
2168 ce062d50 2019-08-21 martijn return "starttls";
2169 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_AUTH:
2170 ce062d50 2019-08-21 martijn return "auth";
2171 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_MAIL_FROM:
2172 ce062d50 2019-08-21 martijn return "mail-from";
2173 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_RCPT_TO:
2174 ce062d50 2019-08-21 martijn return "rcpt-to";
2175 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_DATA:
2176 ce062d50 2019-08-21 martijn return "data";
2177 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_DATA_LINE:
2178 ce062d50 2019-08-21 martijn return "data-line";
2179 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_RSET:
2180 ce062d50 2019-08-21 martijn return "rset";
2181 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_QUIT:
2182 ce062d50 2019-08-21 martijn return "quit";
2183 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_NOOP:
2184 ce062d50 2019-08-21 martijn return "noop";
2185 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_HELP:
2186 ce062d50 2019-08-21 martijn return "help";
2187 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_WIZ:
2188 ce062d50 2019-08-21 martijn return "wiz";
2189 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_COMMIT:
2190 ce062d50 2019-08-21 martijn return "commit";
2191 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_CONNECT:
2192 ce062d50 2019-08-21 martijn return "link-connect";
2193 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_DISCONNECT:
2194 ce062d50 2019-08-21 martijn return "link-disconnect";
2195 a05d5c54 2019-08-28 martijn case OSMTPD_PHASE_LINK_GREETING:
2196 a05d5c54 2019-08-28 martijn return "link-greeting";
2197 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_IDENTIFY:
2198 ce062d50 2019-08-21 martijn return "link-identify";
2199 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_TLS:
2200 ce062d50 2019-08-21 martijn return "link-tls";
2201 58a6bc69 2022-12-05 martijn case OSMTPD_PHASE_LINK_AUTH:
2202 58a6bc69 2022-12-05 martijn return "link-auth";
2203 d308c531 2025-02-03 martijn case OSMTPD_PHASE_TX_RESET:
2204 d308c531 2025-02-03 martijn return "tx-reset";
2205 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_BEGIN:
2206 ce062d50 2019-08-21 martijn return "tx-begin";
2207 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_MAIL:
2208 ce062d50 2019-08-21 martijn return "tx-mail";
2209 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_RCPT:
2210 ce062d50 2019-08-21 martijn return "tx-rcpt";
2211 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_ENVELOPE:
2212 ce062d50 2019-08-21 martijn return "tx-envelope";
2213 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_DATA:
2214 ce062d50 2019-08-21 martijn return "tx-data";
2215 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_COMMIT:
2216 ce062d50 2019-08-21 martijn return "tx-commit";
2217 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_ROLLBACK:
2218 ce062d50 2019-08-21 martijn return "tx-rollback";
2219 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_PROTOCOL_CLIENT:
2220 ce062d50 2019-08-21 martijn return "protocol-client";
2221 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_PROTOCOL_SERVER:
2222 ce062d50 2019-08-21 martijn return "protocol-server";
2223 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_FILTER_RESPONSE:
2224 ce062d50 2019-08-21 martijn return "filter-response";
2225 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TIMEOUT:
2226 ce062d50 2019-08-21 martijn return "timeout";
2228 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "In valid phase: %d\n", phase);
2231 53b354a9 2020-04-12 martijn static enum osmtpd_status
2232 53b354a9 2020-04-12 martijn osmtpd_strtostatus(const char *status, char *linedup)
2234 ce062d50 2019-08-21 martijn if (strcmp(status, "ok") == 0)
2235 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_OK;
2236 ce062d50 2019-08-21 martijn else if (strcmp(status, "tempfail") == 0)
2237 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_TEMPFAIL;
2238 ce062d50 2019-08-21 martijn else if (strcmp(status, "permfail") == 0)
2239 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_PERMFAIL;
2240 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2243 ce062d50 2019-08-21 martijn static void
2244 ce062d50 2019-08-21 martijn osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2245 ce062d50 2019-08-21 martijn char *linedup)
2247 a37af028 2019-09-17 martijn char *port = NULL;
2248 ce062d50 2019-08-21 martijn const char *errstr = NULL;
2249 ce062d50 2019-08-21 martijn struct sockaddr_in *sin;
2250 ce062d50 2019-08-21 martijn struct sockaddr_in6 *sin6;
2251 ce062d50 2019-08-21 martijn struct sockaddr_un *sun;
2252 4574fbd0 2019-09-26 martijn size_t n;
2254 4574fbd0 2019-09-26 martijn if (addr[0] == '[') {
2255 ce062d50 2019-08-21 martijn sin6 = (struct sockaddr_in6 *)ss;
2256 ce062d50 2019-08-21 martijn sin6->sin6_family = AF_INET6;
2257 ce062d50 2019-08-21 martijn sin6->sin6_port = 0;
2258 ce062d50 2019-08-21 martijn if (hasport) {
2259 ce062d50 2019-08-21 martijn if ((port = strrchr(addr, ':')) == NULL)
2260 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2261 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2262 4574fbd0 2019-09-26 martijn if (port[-1] != ']')
2263 4574fbd0 2019-09-26 martijn osmtpd_errx(1, "Invalid line received: invalid "
2264 4574fbd0 2019-09-26 martijn "address (%s): %s", addr, linedup);
2265 ce062d50 2019-08-21 martijn port++;
2266 ce062d50 2019-08-21 martijn sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2267 ce062d50 2019-08-21 martijn &errstr));
2268 ce062d50 2019-08-21 martijn if (errstr != NULL)
2269 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2270 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2271 4574fbd0 2019-09-26 martijn port[-2] = '\0';
2272 4574fbd0 2019-09-26 martijn } else {
2273 4574fbd0 2019-09-26 martijn n = strlen(addr);
2274 4574fbd0 2019-09-26 martijn if (addr[n - 1] != ']')
2275 4574fbd0 2019-09-26 martijn osmtpd_errx(1, "Invalid line received: invalid "
2276 4574fbd0 2019-09-26 martijn "address (%s): %s", addr, linedup);
2277 4574fbd0 2019-09-26 martijn addr[n - 1] = '\0';
2279 4574fbd0 2019-09-26 martijn switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2280 ce062d50 2019-08-21 martijn case 1:
2282 ce062d50 2019-08-21 martijn case 0:
2283 a37af028 2019-09-17 martijn if (hasport)
2284 4574fbd0 2019-09-26 martijn port[-2] = ']';
2286 4574fbd0 2019-09-26 martijn addr[n - 1] = ']';
2287 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid address "
2288 ce062d50 2019-08-21 martijn "(%s): %s", addr, linedup);
2289 ce062d50 2019-08-21 martijn default:
2290 a37af028 2019-09-17 martijn if (hasport)
2291 4574fbd0 2019-09-26 martijn port[-2] = ']';
2293 4574fbd0 2019-09-26 martijn addr[n - 1] = ']';
2294 c6cb29f3 2019-08-22 martijn osmtpd_err(1, "Can't parse address (%s): %s", addr,
2295 c6cb29f3 2019-08-22 martijn linedup);
2297 ce062d50 2019-08-21 martijn } else if (strncasecmp(addr, "unix:", 5) == 0) {
2298 ce062d50 2019-08-21 martijn sun = (struct sockaddr_un *)ss;
2299 ce062d50 2019-08-21 martijn sun->sun_family = AF_UNIX;
2300 ce062d50 2019-08-21 martijn if (strlcpy(sun->sun_path, addr,
2301 ce062d50 2019-08-21 martijn sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2302 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: address too "
2303 c6cb29f3 2019-08-22 martijn "long (%s): %s", addr, linedup);
2305 ce062d50 2019-08-21 martijn } else {
2306 ce062d50 2019-08-21 martijn sin = (struct sockaddr_in *)ss;
2307 ce062d50 2019-08-21 martijn sin->sin_family = AF_INET;
2308 ce062d50 2019-08-21 martijn sin->sin_port = 0;
2309 ce062d50 2019-08-21 martijn if (hasport) {
2310 ce062d50 2019-08-21 martijn if ((port = strrchr(addr, ':')) == NULL)
2311 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2312 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2313 ce062d50 2019-08-21 martijn port++;
2314 ce062d50 2019-08-21 martijn sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2315 ce062d50 2019-08-21 martijn &errstr));
2316 ce062d50 2019-08-21 martijn if (errstr != NULL)
2317 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2318 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2319 ce062d50 2019-08-21 martijn port[-1] = '\0';
2321 ce062d50 2019-08-21 martijn switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2322 ce062d50 2019-08-21 martijn case 1:
2324 ce062d50 2019-08-21 martijn case 0:
2325 a37af028 2019-09-17 martijn if (hasport)
2326 a37af028 2019-09-17 martijn port[-1] = ':';
2327 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid address "
2328 ce062d50 2019-08-21 martijn "(%s): %s", addr, linedup);
2329 ce062d50 2019-08-21 martijn default:
2330 a37af028 2019-09-17 martijn if (hasport)
2331 a37af028 2019-09-17 martijn port[-1] = ':';
2332 c6cb29f3 2019-08-22 martijn osmtpd_err(1, "Can't parse address (%s): %s", addr,
2333 c6cb29f3 2019-08-22 martijn linedup);
2338 ce062d50 2019-08-21 martijn static int
2339 ce062d50 2019-08-21 martijn osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2341 ce062d50 2019-08-21 martijn return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2344 9e3e8410 2019-08-22 martijn RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);