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 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1369 5129e9c0 2025-04-10 kirill if (f(&session->ctx, line))
1370 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1373 ce062d50 2019-08-21 martijn static void
1374 866e5e0e 2025-02-03 martijn osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1375 866e5e0e 2025-02-03 martijn char *params, char *linedup)
1377 ce062d50 2019-08-21 martijn struct sockaddr_storage ss;
1378 ce062d50 2019-08-21 martijn char *hostname;
1379 ce062d50 2019-08-21 martijn char *address;
1380 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1382 ce062d50 2019-08-21 martijn hostname = params;
1383 ce062d50 2019-08-21 martijn if ((address = strchr(params, '|')) == NULL)
1384 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1385 c6cb29f3 2019-08-22 martijn linedup);
1386 ce062d50 2019-08-21 martijn address++[0] = '\0';
1388 ce062d50 2019-08-21 martijn osmtpd_addrtoss(address, &ss, 0, linedup);
1390 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1391 5129e9c0 2025-04-10 kirill if (f(&session->ctx, hostname, &ss))
1392 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1395 ce062d50 2019-08-21 martijn static void
1396 866e5e0e 2025-02-03 martijn osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1397 6258daeb 2019-11-14 martijn char *identity, __unused char *linedup)
1399 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1401 421c9a86 2019-09-06 martijn if (cb->storereport) {
1402 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1403 866e5e0e 2025-02-03 martijn if ((session->ctx.identity = strdup(identity)) == NULL)
1404 421c9a86 2019-09-06 martijn osmtpd_err(1, "strdup");
1407 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1408 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1409 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1412 421c9a86 2019-09-06 martijn static void
1413 866e5e0e 2025-02-03 martijn osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1414 ce062d50 2019-08-21 martijn char *params, char *linedup)
1416 30f1cbac 2019-08-22 martijn char *end, *rdns;
1417 30f1cbac 2019-08-22 martijn enum osmtpd_status fcrdns;
1418 ce062d50 2019-08-21 martijn struct sockaddr_storage src, dst;
1419 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1420 c6cb29f3 2019-08-22 martijn struct sockaddr_storage *, struct sockaddr_storage *);
1422 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1423 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1424 c6cb29f3 2019-08-22 martijn linedup);
1425 ce062d50 2019-08-21 martijn end++[0] = '\0';
1426 ce062d50 2019-08-21 martijn rdns = params;
1427 ce062d50 2019-08-21 martijn params = end;
1428 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1429 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing src: %s",
1430 c6cb29f3 2019-08-22 martijn linedup);
1431 ce062d50 2019-08-21 martijn end++[0] = '\0';
1432 30f1cbac 2019-08-22 martijn if (strcmp(params, "pass") == 0)
1433 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_OK;
1434 30f1cbac 2019-08-22 martijn else if (strcmp(params, "fail") == 0)
1435 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_PERMFAIL;
1436 30f1cbac 2019-08-22 martijn else if (strcmp(params, "error") == 0)
1437 30f1cbac 2019-08-22 martijn fcrdns = OSMTPD_STATUS_TEMPFAIL;
1439 30f1cbac 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1440 30f1cbac 2019-08-22 martijn linedup);
1441 ce062d50 2019-08-21 martijn params = end;
1442 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1443 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing dst: %s",
1444 c6cb29f3 2019-08-22 martijn linedup);
1445 ce062d50 2019-08-21 martijn end++[0] = '\0';
1446 ce062d50 2019-08-21 martijn osmtpd_addrtoss(params, &src, 1, linedup);
1447 ce062d50 2019-08-21 martijn params = end;
1448 ce062d50 2019-08-21 martijn osmtpd_addrtoss(params, &dst, 1, linedup);
1449 ce062d50 2019-08-21 martijn if (cb->storereport) {
1450 866e5e0e 2025-02-03 martijn if ((session->ctx.rdns = strdup(rdns)) == NULL)
1451 30f1cbac 2019-08-22 martijn osmtpd_err(1, "strdup");
1452 866e5e0e 2025-02-03 martijn session->ctx.fcrdns = fcrdns;
1453 866e5e0e 2025-02-03 martijn memcpy(&session->ctx.src, &src, sizeof(session->ctx.src));
1454 866e5e0e 2025-02-03 martijn memcpy(&session->ctx.dst, &dst, sizeof(session->ctx.dst));
1456 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1457 5129e9c0 2025-04-10 kirill if (f(&session->ctx, rdns, fcrdns, &src, &dst))
1458 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1461 ce062d50 2019-08-21 martijn static void
1462 866e5e0e 2025-02-03 martijn osmtpd_link_disconnect(struct osmtpd_callback *cb,
1463 866e5e0e 2025-02-03 martijn struct osmtpd_session *session, __unused char *param,
1464 866e5e0e 2025-02-03 martijn __unused char *linedup)
1466 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *);
1467 ce062d50 2019-08-21 martijn size_t i;
1469 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1470 5129e9c0 2025-04-10 kirill if (f(&session->ctx))
1471 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1473 866e5e0e 2025-02-03 martijn RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1474 866e5e0e 2025-02-03 martijn if (ondeletecb_session != NULL && session->ctx.local_session != NULL)
1475 866e5e0e 2025-02-03 martijn ondeletecb_session(&session->ctx, session->ctx.local_session);
1476 866e5e0e 2025-02-03 martijn free(session->ctx.rdns);
1477 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1478 866e5e0e 2025-02-03 martijn free(session->ctx.greeting.identity);
1479 866e5e0e 2025-02-03 martijn free(session->ctx.ciphers);
1480 866e5e0e 2025-02-03 martijn free(session->ctx.username);
1481 866e5e0e 2025-02-03 martijn free(session->ctx.mailfrom);
1482 866e5e0e 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1483 866e5e0e 2025-02-03 martijn free(session->ctx.rcptto[i]);
1484 866e5e0e 2025-02-03 martijn free(session->ctx.rcptto);
1485 866e5e0e 2025-02-03 martijn free(session);
1488 866e5e0e 2025-02-03 martijn static void
1489 866e5e0e 2025-02-03 martijn osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_session *session,
1490 866e5e0e 2025-02-03 martijn char *identity, __unused char *linedup)
1492 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1494 866e5e0e 2025-02-03 martijn if (cb->storereport) {
1495 0fb4c799 2019-09-05 martijn free(session->ctx.greeting.identity);
1496 866e5e0e 2025-02-03 martijn if ((session->ctx.greeting.identity = strdup(identity)) == NULL)
1497 a05d5c54 2019-08-28 martijn osmtpd_err(1, NULL);
1500 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1501 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1502 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1505 a05d5c54 2019-08-28 martijn static void
1506 866e5e0e 2025-02-03 martijn osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1507 6258daeb 2019-11-14 martijn char *identity, __unused char *linedup)
1509 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1511 ce062d50 2019-08-21 martijn if (cb->storereport) {
1512 866e5e0e 2025-02-03 martijn free(session->ctx.identity);
1513 866e5e0e 2025-02-03 martijn if ((session->ctx.identity = strdup(identity)) == NULL)
1514 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1517 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1518 5129e9c0 2025-04-10 kirill if (f(&session->ctx, identity))
1519 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1522 ce062d50 2019-08-21 martijn static void
1523 866e5e0e 2025-02-03 martijn osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_session *session,
1524 6258daeb 2019-11-14 martijn char *ciphers, __unused char *linedup)
1526 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *);
1528 ce062d50 2019-08-21 martijn if (cb->storereport) {
1529 866e5e0e 2025-02-03 martijn if ((session->ctx.ciphers = strdup(ciphers)) == NULL)
1530 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1533 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1534 5129e9c0 2025-04-10 kirill if (f(&session->ctx, ciphers))
1535 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1538 ce062d50 2019-08-21 martijn static void
1539 866e5e0e 2025-02-03 martijn osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_session *session,
1540 58a6bc69 2022-12-05 martijn char *username, char *linedup)
1542 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1543 58a6bc69 2022-12-05 martijn char *status;
1544 58a6bc69 2022-12-05 martijn enum osmtpd_auth_status s;
1546 58a6bc69 2022-12-05 martijn if ((status = strrchr(username, '|')) == NULL)
1547 58a6bc69 2022-12-05 martijn osmtpd_errx(1, "Invalid auth received: %s", linedup);
1548 58a6bc69 2022-12-05 martijn status[0] = '\0';
1549 58a6bc69 2022-12-05 martijn status++;
1550 58a6bc69 2022-12-05 martijn if (strcmp(status, "pass") == 0)
1551 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_PASS;
1552 58a6bc69 2022-12-05 martijn else if (strcmp(status, "fail") == 0)
1553 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_FAIL;
1554 58a6bc69 2022-12-05 martijn else if (strcmp(status, "error") == 0)
1555 58a6bc69 2022-12-05 martijn s = OSMTPD_AUTH_ERROR;
1557 58a6bc69 2022-12-05 martijn osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1559 58a6bc69 2022-12-05 martijn if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1560 866e5e0e 2025-02-03 martijn if ((session->ctx.username = strdup(username)) == NULL)
1561 58a6bc69 2022-12-05 martijn osmtpd_err(1, NULL);
1564 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1565 5129e9c0 2025-04-10 kirill if (f(&session->ctx, username, s))
1566 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1569 58a6bc69 2022-12-05 martijn static void
1570 d308c531 2025-02-03 martijn osmtpd_tx_reset(struct osmtpd_callback *cb, struct osmtpd_session *session,
1571 d308c531 2025-02-03 martijn char *params, char *linedup)
1573 d308c531 2025-02-03 martijn char *end;
1574 d308c531 2025-02-03 martijn unsigned long imsgid;
1575 d308c531 2025-02-03 martijn uint32_t msgid;
1576 d308c531 2025-02-03 martijn size_t i;
1577 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1579 d308c531 2025-02-03 martijn errno = 0;
1580 d308c531 2025-02-03 martijn imsgid = strtoul(params, &end, 16);
1581 d308c531 2025-02-03 martijn if ((imsgid == ULONG_MAX && errno != 0))
1582 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1583 d308c531 2025-02-03 martijn linedup);
1584 d308c531 2025-02-03 martijn if (end[0] != '\0')
1585 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1586 d308c531 2025-02-03 martijn linedup);
1587 d308c531 2025-02-03 martijn msgid = imsgid;
1588 d308c531 2025-02-03 martijn if ((unsigned long) msgid != imsgid)
1589 d308c531 2025-02-03 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1590 d308c531 2025-02-03 martijn linedup);
1592 d308c531 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1593 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid))
1594 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1596 d308c531 2025-02-03 martijn if (ondeletecb_message != NULL && session->ctx.local_message != NULL) {
1597 d308c531 2025-02-03 martijn ondeletecb_message(&session->ctx, session->ctx.local_message);
1598 d308c531 2025-02-03 martijn session->ctx.local_message = NULL;
1601 d308c531 2025-02-03 martijn free(session->ctx.mailfrom);
1602 d308c531 2025-02-03 martijn session->ctx.mailfrom = NULL;
1604 d308c531 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1605 d308c531 2025-02-03 martijn free(session->ctx.rcptto[i]);
1606 d308c531 2025-02-03 martijn session->ctx.rcptto[0] = NULL;
1607 d308c531 2025-02-03 martijn session->ctx.evpid = 0;
1608 d308c531 2025-02-03 martijn session->ctx.msgid = 0;
1611 d308c531 2025-02-03 martijn static void
1612 866e5e0e 2025-02-03 martijn osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_session *session,
1613 ce062d50 2019-08-21 martijn char *msgid, char *linedup)
1615 ce062d50 2019-08-21 martijn unsigned long imsgid;
1616 ce062d50 2019-08-21 martijn char *endptr;
1617 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1619 ce062d50 2019-08-21 martijn errno = 0;
1620 ce062d50 2019-08-21 martijn imsgid = strtoul(msgid, &endptr, 16);
1621 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1622 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1623 c6cb29f3 2019-08-22 martijn linedup);
1624 866e5e0e 2025-02-03 martijn session->ctx.msgid = imsgid;
1625 ce062d50 2019-08-21 martijn /* Check if we're in range */
1626 866e5e0e 2025-02-03 martijn if ((unsigned long) session->ctx.msgid != imsgid)
1627 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1628 c6cb29f3 2019-08-22 martijn linedup);
1630 ce062d50 2019-08-21 martijn if (!cb->storereport)
1631 866e5e0e 2025-02-03 martijn session->ctx.msgid = 0;
1633 866e5e0e 2025-02-03 martijn if (oncreatecb_message != NULL) {
1634 866e5e0e 2025-02-03 martijn session->ctx.local_message = oncreatecb_message(&session->ctx);
1635 866e5e0e 2025-02-03 martijn if (session->ctx.local_message == NULL)
1636 866e5e0e 2025-02-03 martijn session->status = SESSION_ERROR;
1639 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1640 5129e9c0 2025-04-10 kirill if (f(&session->ctx, imsgid))
1641 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1644 ce062d50 2019-08-21 martijn static void
1645 866e5e0e 2025-02-03 martijn osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_session *session,
1646 ce062d50 2019-08-21 martijn char *params, char *linedup)
1648 ce062d50 2019-08-21 martijn char *end, *mailfrom;
1649 53b354a9 2020-04-12 martijn enum osmtpd_status status;
1650 ce062d50 2019-08-21 martijn unsigned long imsgid;
1651 ce062d50 2019-08-21 martijn uint32_t msgid;
1652 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1653 ce062d50 2019-08-21 martijn enum osmtpd_status);
1655 ce062d50 2019-08-21 martijn errno = 0;
1656 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1657 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1658 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1659 c6cb29f3 2019-08-22 martijn linedup);
1660 ce062d50 2019-08-21 martijn if (end[0] != '|')
1661 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1662 c6cb29f3 2019-08-22 martijn linedup);
1663 ce062d50 2019-08-21 martijn msgid = imsgid;
1664 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1665 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1666 c6cb29f3 2019-08-22 martijn linedup);
1667 ce062d50 2019-08-21 martijn params = end + 1;
1669 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1670 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing status: %s",
1671 c6cb29f3 2019-08-22 martijn linedup);
1672 ce062d50 2019-08-21 martijn end++[0] = '\0';
1673 866e5e0e 2025-02-03 martijn if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1674 53b354a9 2020-04-12 martijn mailfrom = params;
1675 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(end, linedup);
1676 53b354a9 2020-04-12 martijn } else {
1677 53b354a9 2020-04-12 martijn mailfrom = end;
1678 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(params, linedup);
1680 ce062d50 2019-08-21 martijn if (cb->storereport) {
1681 866e5e0e 2025-02-03 martijn if ((session->ctx.mailfrom = strdup(mailfrom)) == NULL)
1682 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1685 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1686 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, mailfrom, status))
1687 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1690 ce062d50 2019-08-21 martijn static void
1691 866e5e0e 2025-02-03 martijn osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_session *session,
1692 ce062d50 2019-08-21 martijn char *params, char *linedup)
1694 ce062d50 2019-08-21 martijn char *end, *rcptto;
1695 53b354a9 2020-04-12 martijn enum osmtpd_status status;
1696 ce062d50 2019-08-21 martijn unsigned long imsgid;
1697 ce062d50 2019-08-21 martijn uint32_t msgid;
1698 ce062d50 2019-08-21 martijn size_t i;
1699 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1700 ce062d50 2019-08-21 martijn enum osmtpd_status);
1702 ce062d50 2019-08-21 martijn errno = 0;
1703 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1704 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1705 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1706 c6cb29f3 2019-08-22 martijn linedup);
1707 ce062d50 2019-08-21 martijn if (end[0] != '|')
1708 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1709 c6cb29f3 2019-08-22 martijn linedup);
1710 ce062d50 2019-08-21 martijn msgid = imsgid;
1711 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1712 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1713 c6cb29f3 2019-08-22 martijn linedup);
1714 ce062d50 2019-08-21 martijn params = end + 1;
1716 ce062d50 2019-08-21 martijn if ((end = strchr(params, '|')) == NULL)
1717 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing status: %s",
1718 c6cb29f3 2019-08-22 martijn linedup);
1719 ce062d50 2019-08-21 martijn end++[0] = '\0';
1721 866e5e0e 2025-02-03 martijn if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1722 53b354a9 2020-04-12 martijn rcptto = params;
1723 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(end, linedup);
1724 53b354a9 2020-04-12 martijn } else {
1725 53b354a9 2020-04-12 martijn rcptto = end;
1726 53b354a9 2020-04-12 martijn status = osmtpd_strtostatus(params, linedup);
1729 ce062d50 2019-08-21 martijn if (cb->storereport) {
1730 866e5e0e 2025-02-03 martijn for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1732 866e5e0e 2025-02-03 martijn session->ctx.rcptto = reallocarray(session->ctx.rcptto, i + 2,
1733 866e5e0e 2025-02-03 martijn sizeof(*session->ctx.rcptto));
1734 866e5e0e 2025-02-03 martijn if (session->ctx.rcptto == NULL)
1735 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1737 866e5e0e 2025-02-03 martijn if ((session->ctx.rcptto[i] = strdup(rcptto)) == NULL)
1738 27dd1f3b 2019-08-22 martijn osmtpd_err(1, NULL);
1739 866e5e0e 2025-02-03 martijn session->ctx.rcptto[i + 1] = NULL;
1742 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1743 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, rcptto, status))
1744 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1747 ce062d50 2019-08-21 martijn static void
1748 866e5e0e 2025-02-03 martijn osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_session *session,
1749 ce062d50 2019-08-21 martijn char *params, char *linedup)
1751 ce062d50 2019-08-21 martijn unsigned long imsgid;
1752 ce062d50 2019-08-21 martijn uint32_t msgid;
1753 ce062d50 2019-08-21 martijn uint64_t evpid;
1754 ce062d50 2019-08-21 martijn char *end;
1755 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1757 ce062d50 2019-08-21 martijn errno = 0;
1758 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1759 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1760 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1761 c6cb29f3 2019-08-22 martijn linedup);
1762 ce062d50 2019-08-21 martijn if (end[0] != '|')
1763 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1764 c6cb29f3 2019-08-22 martijn linedup);
1765 ce062d50 2019-08-21 martijn msgid = imsgid;
1766 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1767 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1768 c6cb29f3 2019-08-22 martijn linedup);
1769 ce062d50 2019-08-21 martijn params = end + 1;
1771 ce062d50 2019-08-21 martijn evpid = strtoull(params, &end, 16);
1772 866e5e0e 2025-02-03 martijn if ((session->ctx.evpid == ULLONG_MAX && errno != 0) || end[0] != '\0')
1773 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1774 c6cb29f3 2019-08-22 martijn linedup);
1775 ce062d50 2019-08-21 martijn if (cb->storereport)
1776 866e5e0e 2025-02-03 martijn session->ctx.evpid = evpid;
1778 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1779 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, evpid))
1780 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1783 ce062d50 2019-08-21 martijn static void
1784 866e5e0e 2025-02-03 martijn osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_session *session,
1785 ce062d50 2019-08-21 martijn char *params, char *linedup)
1787 ce062d50 2019-08-21 martijn char *end;
1788 ce062d50 2019-08-21 martijn unsigned long imsgid;
1789 ce062d50 2019-08-21 martijn uint32_t msgid;
1790 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1792 ce062d50 2019-08-21 martijn errno = 0;
1793 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1794 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1795 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1796 c6cb29f3 2019-08-22 martijn linedup);
1797 ce062d50 2019-08-21 martijn if (end[0] != '|')
1798 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1799 c6cb29f3 2019-08-22 martijn linedup);
1800 ce062d50 2019-08-21 martijn msgid = imsgid;
1801 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1802 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1803 c6cb29f3 2019-08-22 martijn linedup);
1804 ce062d50 2019-08-21 martijn params = end + 1;
1806 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1807 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, osmtpd_strtostatus(params, linedup)))
1808 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1811 ce062d50 2019-08-21 martijn static void
1812 866e5e0e 2025-02-03 martijn osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_session *session,
1813 ce062d50 2019-08-21 martijn char *params, char *linedup)
1815 ce062d50 2019-08-21 martijn char *end;
1816 332b3141 2019-08-22 martijn const char *errstr = NULL;
1817 ce062d50 2019-08-21 martijn unsigned long imsgid;
1818 ce062d50 2019-08-21 martijn uint32_t msgid;
1819 d308c531 2025-02-03 martijn size_t msgsz;
1820 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1822 ce062d50 2019-08-21 martijn errno = 0;
1823 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1824 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1825 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1826 c6cb29f3 2019-08-22 martijn linedup);
1827 ce062d50 2019-08-21 martijn if (end[0] != '|')
1828 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1829 c6cb29f3 2019-08-22 martijn linedup);
1830 ce062d50 2019-08-21 martijn msgid = imsgid;
1831 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1832 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1833 c6cb29f3 2019-08-22 martijn linedup);
1834 ce062d50 2019-08-21 martijn params = end + 1;
1836 332b3141 2019-08-22 martijn msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1837 ce062d50 2019-08-21 martijn if (errstr != NULL)
1838 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1839 c6cb29f3 2019-08-22 martijn linedup);
1841 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1842 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid, msgsz))
1843 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1846 ce062d50 2019-08-21 martijn static void
1847 866e5e0e 2025-02-03 martijn osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_session *session,
1848 ce062d50 2019-08-21 martijn char *params, char *linedup)
1850 ce062d50 2019-08-21 martijn char *end;
1851 ce062d50 2019-08-21 martijn unsigned long imsgid;
1852 ce062d50 2019-08-21 martijn uint32_t msgid;
1853 5129e9c0 2025-04-10 kirill int (*f)(struct osmtpd_ctx *, uint32_t);
1855 ce062d50 2019-08-21 martijn errno = 0;
1856 ce062d50 2019-08-21 martijn imsgid = strtoul(params, &end, 16);
1857 ce062d50 2019-08-21 martijn if ((imsgid == ULONG_MAX && errno != 0))
1858 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1859 c6cb29f3 2019-08-22 martijn linedup);
1860 ce062d50 2019-08-21 martijn if (end[0] != '\0')
1861 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: missing address: %s",
1862 c6cb29f3 2019-08-22 martijn linedup);
1863 ce062d50 2019-08-21 martijn msgid = imsgid;
1864 ce062d50 2019-08-21 martijn if ((unsigned long) msgid != imsgid)
1865 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1866 c6cb29f3 2019-08-22 martijn linedup);
1868 866e5e0e 2025-02-03 martijn if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1869 5129e9c0 2025-04-10 kirill if (f(&session->ctx, msgid))
1870 5129e9c0 2025-04-10 kirill session->status = SESSION_ERROR;
1874 ce062d50 2019-08-21 martijn osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1876 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1878 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1879 866e5e0e 2025-02-03 martijn return;
1881 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1882 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1883 06220a70 2019-12-06 martijn "proceed\n", ctx->token, ctx->reqid);
1885 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1886 06220a70 2019-12-06 martijn "proceed\n", ctx->reqid, ctx->token);
1890 ce062d50 2019-08-21 martijn osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1892 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1893 ce062d50 2019-08-21 martijn va_list ap;
1895 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1896 866e5e0e 2025-02-03 martijn return;
1898 ce062d50 2019-08-21 martijn if (code < 200 || code > 599)
1899 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid reject code");
1901 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1902 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1903 06220a70 2019-12-06 martijn "reject|%d ", ctx->token, ctx->reqid, code);
1905 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1906 06220a70 2019-12-06 martijn "reject|%d ", ctx->reqid, ctx->token, code);
1907 ce062d50 2019-08-21 martijn va_start(ap, reason);
1908 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, reason, ap);
1909 ce062d50 2019-08-21 martijn va_end(ap);
1910 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
1914 000aebbc 2019-08-23 martijn osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1915 000aebbc 2019-08-23 martijn int subject, int detail, const char *reason, ...)
1917 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1918 000aebbc 2019-08-23 martijn va_list ap;
1920 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1921 866e5e0e 2025-02-03 martijn return;
1923 000aebbc 2019-08-23 martijn if (code < 200 || code > 599)
1924 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid reject code");
1925 2a3d7bdf 2019-08-27 martijn if (class < 2 || class > 5)
1926 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status class");
1927 000aebbc 2019-08-23 martijn if (subject < 0 || subject > 999)
1928 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status subject");
1929 000aebbc 2019-08-23 martijn if (detail < 0 || detail > 999)
1930 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status detail");
1932 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1933 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1934 06220a70 2019-12-06 martijn "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1935 06220a70 2019-12-06 martijn subject, detail);
1937 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1938 06220a70 2019-12-06 martijn "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1939 06220a70 2019-12-06 martijn subject, detail);
1940 000aebbc 2019-08-23 martijn va_start(ap, reason);
1941 000aebbc 2019-08-23 martijn io_vprintf(io_stdout, reason, ap);
1942 000aebbc 2019-08-23 martijn va_end(ap);
1943 000aebbc 2019-08-23 martijn io_printf(io_stdout, "\n");
1947 ce062d50 2019-08-21 martijn osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1949 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1950 ce062d50 2019-08-21 martijn va_list ap;
1952 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1953 866e5e0e 2025-02-03 martijn return;
1955 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1956 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1957 06220a70 2019-12-06 martijn "disconnect|421 ", ctx->token, ctx->reqid);
1959 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1960 06220a70 2019-12-06 martijn "disconnect|421 ", ctx->reqid, ctx->token);
1961 ce062d50 2019-08-21 martijn va_start(ap, reason);
1962 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, reason, ap);
1963 ce062d50 2019-08-21 martijn va_end(ap);
1964 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
1965 866e5e0e 2025-02-03 martijn session->status = SESSION_DISCONNECTED;
1969 000aebbc 2019-08-23 martijn osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1970 000aebbc 2019-08-23 martijn int detail, const char *reason, ...)
1972 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1973 000aebbc 2019-08-23 martijn va_list ap;
1975 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
1976 866e5e0e 2025-02-03 martijn return;
1978 000aebbc 2019-08-23 martijn if (class <= 2 || class >= 5)
1979 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status class");
1980 000aebbc 2019-08-23 martijn if (subject < 0 || subject > 999)
1981 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status subject");
1982 000aebbc 2019-08-23 martijn if (detail < 0 || detail > 999)
1983 000aebbc 2019-08-23 martijn osmtpd_errx(1, "Invalid enhanced status detail");
1984 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
1985 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1986 06220a70 2019-12-06 martijn "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1987 06220a70 2019-12-06 martijn subject, detail);
1989 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1990 06220a70 2019-12-06 martijn "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1991 06220a70 2019-12-06 martijn subject, detail);
1992 000aebbc 2019-08-23 martijn va_start(ap, reason);
1993 000aebbc 2019-08-23 martijn io_vprintf(io_stdout, reason, ap);
1994 000aebbc 2019-08-23 martijn va_end(ap);
1995 000aebbc 2019-08-23 martijn io_printf(io_stdout, "\n");
1996 866e5e0e 2025-02-03 martijn session->status = SESSION_DISCONNECTED;
2000 4fb72612 2019-08-21 martijn osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
2002 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2003 4fb72612 2019-08-21 martijn va_list ap;
2005 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
2006 866e5e0e 2025-02-03 martijn return;
2008 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
2009 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2010 06220a70 2019-12-06 martijn "rewrite|", ctx->token, ctx->reqid);
2012 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2013 06220a70 2019-12-06 martijn "rewrite|", ctx->reqid, ctx->token);
2014 4fb72612 2019-08-21 martijn va_start(ap, value);
2015 4fb72612 2019-08-21 martijn io_vprintf(io_stdout, value, ap);
2016 4fb72612 2019-08-21 martijn va_end(ap);
2017 4fb72612 2019-08-21 martijn io_printf(io_stdout, "\n");
2021 ce062d50 2019-08-21 martijn osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
2023 866e5e0e 2025-02-03 martijn struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2024 ce062d50 2019-08-21 martijn va_list ap;
2026 866e5e0e 2025-02-03 martijn if (session->status == SESSION_DISCONNECTED)
2027 866e5e0e 2025-02-03 martijn return;
2029 06220a70 2019-12-06 martijn if (ctx->version_major == 0 && ctx->version_minor < 5)
2030 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2031 06220a70 2019-12-06 martijn ctx->token, ctx->reqid);
2033 06220a70 2019-12-06 martijn io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2034 06220a70 2019-12-06 martijn ctx->reqid, ctx->token);
2035 ce062d50 2019-08-21 martijn va_start(ap, line);
2036 ce062d50 2019-08-21 martijn io_vprintf(io_stdout, line, ap);
2037 ce062d50 2019-08-21 martijn va_end(ap);
2038 ce062d50 2019-08-21 martijn io_printf(io_stdout, "\n");
2041 ce062d50 2019-08-21 martijn static void
2042 ce062d50 2019-08-21 martijn osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
2043 ce062d50 2019-08-21 martijn int storereport, void *cb)
2045 ce062d50 2019-08-21 martijn size_t i;
2047 ce062d50 2019-08-21 martijn if (ready)
2048 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Can't register when proc is running");
2050 ce062d50 2019-08-21 martijn for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
2051 ce062d50 2019-08-21 martijn if (type == osmtpd_callbacks[i].type &&
2052 ce062d50 2019-08-21 martijn phase == osmtpd_callbacks[i].phase &&
2053 ce062d50 2019-08-21 martijn incoming == osmtpd_callbacks[i].incoming) {
2054 ce062d50 2019-08-21 martijn if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
2055 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Event already registered");
2056 912d0ff2 2019-08-22 martijn if (cb != NULL)
2057 912d0ff2 2019-08-22 martijn osmtpd_callbacks[i].cb = cb;
2058 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].doregister = 1;
2059 ce062d50 2019-08-21 martijn if (storereport)
2060 ce062d50 2019-08-21 martijn osmtpd_callbacks[i].storereport = 1;
2061 ce062d50 2019-08-21 martijn return;
2064 ce062d50 2019-08-21 martijn /* NOT REACHED */
2065 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Trying to register unknown event");
2068 ce062d50 2019-08-21 martijn static enum osmtpd_phase
2069 ce062d50 2019-08-21 martijn osmtpd_strtophase(const char *phase, const char *linedup)
2071 ce062d50 2019-08-21 martijn if (strcmp(phase, "connect") == 0)
2072 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_CONNECT;
2073 ce062d50 2019-08-21 martijn if (strcmp(phase, "helo") == 0)
2074 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_HELO;
2075 ce062d50 2019-08-21 martijn if (strcmp(phase, "ehlo") == 0)
2076 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_EHLO;
2077 ce062d50 2019-08-21 martijn if (strcmp(phase, "starttls") == 0)
2078 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_STARTTLS;
2079 ce062d50 2019-08-21 martijn if (strcmp(phase, "auth") == 0)
2080 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_AUTH;
2081 ce062d50 2019-08-21 martijn if (strcmp(phase, "mail-from") == 0)
2082 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_MAIL_FROM;
2083 ce062d50 2019-08-21 martijn if (strcmp(phase, "rcpt-to") == 0)
2084 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_RCPT_TO;
2085 ce062d50 2019-08-21 martijn if (strcmp(phase, "data") == 0)
2086 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_DATA;
2087 ce062d50 2019-08-21 martijn if (strcmp(phase, "data-line") == 0)
2088 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_DATA_LINE;
2089 ce062d50 2019-08-21 martijn if (strcmp(phase, "rset") == 0)
2090 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_RSET;
2091 ce062d50 2019-08-21 martijn if (strcmp(phase, "quit") == 0)
2092 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_QUIT;
2093 ce062d50 2019-08-21 martijn if (strcmp(phase, "noop") == 0)
2094 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_NOOP;
2095 ce062d50 2019-08-21 martijn if (strcmp(phase, "help") == 0)
2096 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_HELP;
2097 ce062d50 2019-08-21 martijn if (strcmp(phase, "wiz") == 0)
2098 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_WIZ;
2099 ce062d50 2019-08-21 martijn if (strcmp(phase, "commit") == 0)
2100 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_COMMIT;
2101 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-connect") == 0)
2102 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_CONNECT;
2103 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-disconnect") == 0)
2104 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_DISCONNECT;
2105 b52f2785 2019-09-06 martijn if (strcmp(phase, "link-greeting") == 0)
2106 b52f2785 2019-09-06 martijn return OSMTPD_PHASE_LINK_GREETING;
2107 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-identify") == 0)
2108 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_IDENTIFY;
2109 ce062d50 2019-08-21 martijn if (strcmp(phase, "link-tls") == 0)
2110 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_LINK_TLS;
2111 58a6bc69 2022-12-05 martijn if (strcmp(phase, "link-auth") == 0)
2112 58a6bc69 2022-12-05 martijn return OSMTPD_PHASE_LINK_AUTH;
2113 d308c531 2025-02-03 martijn if (strcmp(phase, "tx-reset") == 0)
2114 d308c531 2025-02-03 martijn return OSMTPD_PHASE_TX_RESET;
2115 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-begin") == 0)
2116 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_BEGIN;
2117 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-mail") == 0)
2118 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_MAIL;
2119 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-rcpt") == 0)
2120 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_RCPT;
2121 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-envelope") == 0)
2122 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_ENVELOPE;
2123 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-data") == 0)
2124 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_DATA;
2125 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-commit") == 0)
2126 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_COMMIT;
2127 ce062d50 2019-08-21 martijn if (strcmp(phase, "tx-rollback") == 0)
2128 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TX_ROLLBACK;
2129 ce062d50 2019-08-21 martijn if (strcmp(phase, "protocol-client") == 0)
2130 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_PROTOCOL_CLIENT;
2131 ce062d50 2019-08-21 martijn if (strcmp(phase, "protocol-server") == 0)
2132 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_PROTOCOL_SERVER;
2133 ce062d50 2019-08-21 martijn if (strcmp(phase, "filter-response") == 0)
2134 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_FILTER_RESPONSE;
2135 ce062d50 2019-08-21 martijn if (strcmp(phase, "timeout") == 0)
2136 ce062d50 2019-08-21 martijn return OSMTPD_PHASE_TIMEOUT;
2137 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
2140 ce062d50 2019-08-21 martijn static const char *
2141 ce062d50 2019-08-21 martijn osmtpd_typetostr(enum osmtpd_type type)
2143 ce062d50 2019-08-21 martijn switch (type) {
2144 ce062d50 2019-08-21 martijn case OSMTPD_TYPE_FILTER:
2145 ce062d50 2019-08-21 martijn return "filter";
2146 ce062d50 2019-08-21 martijn case OSMTPD_TYPE_REPORT:
2147 ce062d50 2019-08-21 martijn return "report";
2149 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "In valid type: %d\n", type);
2152 ce062d50 2019-08-21 martijn static const char *
2153 ce062d50 2019-08-21 martijn osmtpd_phasetostr(enum osmtpd_phase phase)
2155 ce062d50 2019-08-21 martijn switch (phase) {
2156 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_CONNECT:
2157 ce062d50 2019-08-21 martijn return "connect";
2158 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_HELO:
2159 ce062d50 2019-08-21 martijn return "helo";
2160 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_EHLO:
2161 ce062d50 2019-08-21 martijn return "ehlo";
2162 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_STARTTLS:
2163 ce062d50 2019-08-21 martijn return "starttls";
2164 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_AUTH:
2165 ce062d50 2019-08-21 martijn return "auth";
2166 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_MAIL_FROM:
2167 ce062d50 2019-08-21 martijn return "mail-from";
2168 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_RCPT_TO:
2169 ce062d50 2019-08-21 martijn return "rcpt-to";
2170 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_DATA:
2171 ce062d50 2019-08-21 martijn return "data";
2172 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_DATA_LINE:
2173 ce062d50 2019-08-21 martijn return "data-line";
2174 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_RSET:
2175 ce062d50 2019-08-21 martijn return "rset";
2176 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_QUIT:
2177 ce062d50 2019-08-21 martijn return "quit";
2178 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_NOOP:
2179 ce062d50 2019-08-21 martijn return "noop";
2180 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_HELP:
2181 ce062d50 2019-08-21 martijn return "help";
2182 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_WIZ:
2183 ce062d50 2019-08-21 martijn return "wiz";
2184 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_COMMIT:
2185 ce062d50 2019-08-21 martijn return "commit";
2186 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_CONNECT:
2187 ce062d50 2019-08-21 martijn return "link-connect";
2188 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_DISCONNECT:
2189 ce062d50 2019-08-21 martijn return "link-disconnect";
2190 a05d5c54 2019-08-28 martijn case OSMTPD_PHASE_LINK_GREETING:
2191 a05d5c54 2019-08-28 martijn return "link-greeting";
2192 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_IDENTIFY:
2193 ce062d50 2019-08-21 martijn return "link-identify";
2194 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_LINK_TLS:
2195 ce062d50 2019-08-21 martijn return "link-tls";
2196 58a6bc69 2022-12-05 martijn case OSMTPD_PHASE_LINK_AUTH:
2197 58a6bc69 2022-12-05 martijn return "link-auth";
2198 d308c531 2025-02-03 martijn case OSMTPD_PHASE_TX_RESET:
2199 d308c531 2025-02-03 martijn return "tx-reset";
2200 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_BEGIN:
2201 ce062d50 2019-08-21 martijn return "tx-begin";
2202 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_MAIL:
2203 ce062d50 2019-08-21 martijn return "tx-mail";
2204 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_RCPT:
2205 ce062d50 2019-08-21 martijn return "tx-rcpt";
2206 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_ENVELOPE:
2207 ce062d50 2019-08-21 martijn return "tx-envelope";
2208 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_DATA:
2209 ce062d50 2019-08-21 martijn return "tx-data";
2210 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_COMMIT:
2211 ce062d50 2019-08-21 martijn return "tx-commit";
2212 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TX_ROLLBACK:
2213 ce062d50 2019-08-21 martijn return "tx-rollback";
2214 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_PROTOCOL_CLIENT:
2215 ce062d50 2019-08-21 martijn return "protocol-client";
2216 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_PROTOCOL_SERVER:
2217 ce062d50 2019-08-21 martijn return "protocol-server";
2218 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_FILTER_RESPONSE:
2219 ce062d50 2019-08-21 martijn return "filter-response";
2220 ce062d50 2019-08-21 martijn case OSMTPD_PHASE_TIMEOUT:
2221 ce062d50 2019-08-21 martijn return "timeout";
2223 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "In valid phase: %d\n", phase);
2226 53b354a9 2020-04-12 martijn static enum osmtpd_status
2227 53b354a9 2020-04-12 martijn osmtpd_strtostatus(const char *status, char *linedup)
2229 ce062d50 2019-08-21 martijn if (strcmp(status, "ok") == 0)
2230 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_OK;
2231 ce062d50 2019-08-21 martijn else if (strcmp(status, "tempfail") == 0)
2232 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_TEMPFAIL;
2233 ce062d50 2019-08-21 martijn else if (strcmp(status, "permfail") == 0)
2234 ce062d50 2019-08-21 martijn return OSMTPD_STATUS_PERMFAIL;
2235 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2238 ce062d50 2019-08-21 martijn static void
2239 ce062d50 2019-08-21 martijn osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2240 ce062d50 2019-08-21 martijn char *linedup)
2242 a37af028 2019-09-17 martijn char *port = NULL;
2243 ce062d50 2019-08-21 martijn const char *errstr = NULL;
2244 ce062d50 2019-08-21 martijn struct sockaddr_in *sin;
2245 ce062d50 2019-08-21 martijn struct sockaddr_in6 *sin6;
2246 ce062d50 2019-08-21 martijn struct sockaddr_un *sun;
2247 4574fbd0 2019-09-26 martijn size_t n;
2249 4574fbd0 2019-09-26 martijn if (addr[0] == '[') {
2250 ce062d50 2019-08-21 martijn sin6 = (struct sockaddr_in6 *)ss;
2251 ce062d50 2019-08-21 martijn sin6->sin6_family = AF_INET6;
2252 ce062d50 2019-08-21 martijn sin6->sin6_port = 0;
2253 ce062d50 2019-08-21 martijn if (hasport) {
2254 ce062d50 2019-08-21 martijn if ((port = strrchr(addr, ':')) == NULL)
2255 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2256 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2257 4574fbd0 2019-09-26 martijn if (port[-1] != ']')
2258 4574fbd0 2019-09-26 martijn osmtpd_errx(1, "Invalid line received: invalid "
2259 4574fbd0 2019-09-26 martijn "address (%s): %s", addr, linedup);
2260 ce062d50 2019-08-21 martijn port++;
2261 ce062d50 2019-08-21 martijn sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2262 ce062d50 2019-08-21 martijn &errstr));
2263 ce062d50 2019-08-21 martijn if (errstr != NULL)
2264 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2265 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2266 4574fbd0 2019-09-26 martijn port[-2] = '\0';
2267 4574fbd0 2019-09-26 martijn } else {
2268 4574fbd0 2019-09-26 martijn n = strlen(addr);
2269 4574fbd0 2019-09-26 martijn if (addr[n - 1] != ']')
2270 4574fbd0 2019-09-26 martijn osmtpd_errx(1, "Invalid line received: invalid "
2271 4574fbd0 2019-09-26 martijn "address (%s): %s", addr, linedup);
2272 4574fbd0 2019-09-26 martijn addr[n - 1] = '\0';
2274 4574fbd0 2019-09-26 martijn switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2275 ce062d50 2019-08-21 martijn case 1:
2277 ce062d50 2019-08-21 martijn case 0:
2278 a37af028 2019-09-17 martijn if (hasport)
2279 4574fbd0 2019-09-26 martijn port[-2] = ']';
2281 4574fbd0 2019-09-26 martijn addr[n - 1] = ']';
2282 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid address "
2283 ce062d50 2019-08-21 martijn "(%s): %s", addr, linedup);
2284 ce062d50 2019-08-21 martijn default:
2285 a37af028 2019-09-17 martijn if (hasport)
2286 4574fbd0 2019-09-26 martijn port[-2] = ']';
2288 4574fbd0 2019-09-26 martijn addr[n - 1] = ']';
2289 c6cb29f3 2019-08-22 martijn osmtpd_err(1, "Can't parse address (%s): %s", addr,
2290 c6cb29f3 2019-08-22 martijn linedup);
2292 ce062d50 2019-08-21 martijn } else if (strncasecmp(addr, "unix:", 5) == 0) {
2293 ce062d50 2019-08-21 martijn sun = (struct sockaddr_un *)ss;
2294 ce062d50 2019-08-21 martijn sun->sun_family = AF_UNIX;
2295 ce062d50 2019-08-21 martijn if (strlcpy(sun->sun_path, addr,
2296 ce062d50 2019-08-21 martijn sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2297 c6cb29f3 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: address too "
2298 c6cb29f3 2019-08-22 martijn "long (%s): %s", addr, linedup);
2300 ce062d50 2019-08-21 martijn } else {
2301 ce062d50 2019-08-21 martijn sin = (struct sockaddr_in *)ss;
2302 ce062d50 2019-08-21 martijn sin->sin_family = AF_INET;
2303 ce062d50 2019-08-21 martijn sin->sin_port = 0;
2304 ce062d50 2019-08-21 martijn if (hasport) {
2305 ce062d50 2019-08-21 martijn if ((port = strrchr(addr, ':')) == NULL)
2306 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2307 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2308 ce062d50 2019-08-21 martijn port++;
2309 ce062d50 2019-08-21 martijn sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2310 ce062d50 2019-08-21 martijn &errstr));
2311 ce062d50 2019-08-21 martijn if (errstr != NULL)
2312 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid "
2313 ce062d50 2019-08-21 martijn "address (%s): %s", addr, linedup);
2314 ce062d50 2019-08-21 martijn port[-1] = '\0';
2316 ce062d50 2019-08-21 martijn switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2317 ce062d50 2019-08-21 martijn case 1:
2319 ce062d50 2019-08-21 martijn case 0:
2320 a37af028 2019-09-17 martijn if (hasport)
2321 a37af028 2019-09-17 martijn port[-1] = ':';
2322 27dd1f3b 2019-08-22 martijn osmtpd_errx(1, "Invalid line received: invalid address "
2323 ce062d50 2019-08-21 martijn "(%s): %s", addr, linedup);
2324 ce062d50 2019-08-21 martijn default:
2325 a37af028 2019-09-17 martijn if (hasport)
2326 a37af028 2019-09-17 martijn port[-1] = ':';
2327 c6cb29f3 2019-08-22 martijn osmtpd_err(1, "Can't parse address (%s): %s", addr,
2328 c6cb29f3 2019-08-22 martijn linedup);
2333 ce062d50 2019-08-21 martijn static int
2334 ce062d50 2019-08-21 martijn osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2336 ce062d50 2019-08-21 martijn return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2339 9e3e8410 2019-08-22 martijn RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);