2 * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/socket.h>
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
38 #include "openbsd-compat.h"
39 #include "opensmtpd.h"
42 #define NITEMS(x) (sizeof(x) / sizeof(*x))
44 enum osmtpd_session_status {
50 struct osmtpd_session {
51 struct osmtpd_ctx ctx; /* Must remain first element */
52 enum osmtpd_session_status status;
53 RB_ENTRY(osmtpd_session) entry;
56 struct osmtpd_callback {
57 enum osmtpd_type type;
58 enum osmtpd_phase phase;
60 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_session *,
67 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
69 static const char *osmtpd_typetostr(enum osmtpd_type);
70 static const char *osmtpd_phasetostr(enum osmtpd_phase);
71 static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
72 static void osmtpd_newline(struct io *, int, void *);
73 static void osmtpd_outevt(struct io *, int, void *);
74 static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_session *,
76 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_session *,
78 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_session *,
80 static void osmtpd_identify(struct osmtpd_callback *, struct osmtpd_session *,
82 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_session *,
84 static void osmtpd_link_disconnect(struct osmtpd_callback *,
85 struct osmtpd_session *, char *, char *);
86 static void osmtpd_link_greeting(struct osmtpd_callback *, struct osmtpd_session *,
88 static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_session *,
90 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_session *,
92 static void osmtpd_link_auth(struct osmtpd_callback *, struct osmtpd_session *,
94 static void osmtpd_tx_reset(struct osmtpd_callback *, struct osmtpd_session *,
96 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_session *,
98 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_session *,
100 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_session *,
102 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_session *,
104 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_session *,
106 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_session *,
108 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_session *,
110 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
111 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
112 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
113 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
114 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
115 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
116 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
117 static void (*conf_cb)(const char *, const char *);
119 static struct osmtpd_callback osmtpd_callbacks[] = {
122 OSMTPD_PHASE_CONNECT,
149 OSMTPD_PHASE_STARTTLS,
167 OSMTPD_PHASE_MAIL_FROM,
176 OSMTPD_PHASE_RCPT_TO,
194 OSMTPD_PHASE_DATA_LINE,
257 OSMTPD_PHASE_LINK_CONNECT,
266 OSMTPD_PHASE_LINK_DISCONNECT,
268 osmtpd_link_disconnect,
275 OSMTPD_PHASE_LINK_GREETING,
277 osmtpd_link_greeting,
284 OSMTPD_PHASE_LINK_IDENTIFY,
286 osmtpd_link_identify,
293 OSMTPD_PHASE_LINK_TLS,
302 OSMTPD_PHASE_LINK_AUTH,
311 OSMTPD_PHASE_TX_RESET,
320 OSMTPD_PHASE_TX_BEGIN,
329 OSMTPD_PHASE_TX_MAIL,
338 OSMTPD_PHASE_TX_RCPT,
347 OSMTPD_PHASE_TX_ENVELOPE,
356 OSMTPD_PHASE_TX_DATA,
365 OSMTPD_PHASE_TX_COMMIT,
374 OSMTPD_PHASE_TX_ROLLBACK,
383 OSMTPD_PHASE_PROTOCOL_CLIENT,
392 OSMTPD_PHASE_PROTOCOL_SERVER,
401 OSMTPD_PHASE_FILTER_RESPONSE,
410 OSMTPD_PHASE_TIMEOUT,
419 OSMTPD_PHASE_LINK_CONNECT,
428 OSMTPD_PHASE_LINK_DISCONNECT,
430 osmtpd_link_disconnect,
437 OSMTPD_PHASE_LINK_GREETING,
439 osmtpd_link_greeting,
446 OSMTPD_PHASE_LINK_IDENTIFY,
448 osmtpd_link_identify,
455 OSMTPD_PHASE_LINK_TLS,
464 OSMTPD_PHASE_LINK_AUTH,
473 OSMTPD_PHASE_TX_RESET,
482 OSMTPD_PHASE_TX_BEGIN,
491 OSMTPD_PHASE_TX_MAIL,
500 OSMTPD_PHASE_TX_RCPT,
509 OSMTPD_PHASE_TX_ENVELOPE,
518 OSMTPD_PHASE_TX_DATA,
527 OSMTPD_PHASE_TX_COMMIT,
536 OSMTPD_PHASE_TX_ROLLBACK,
545 OSMTPD_PHASE_PROTOCOL_CLIENT,
554 OSMTPD_PHASE_PROTOCOL_SERVER,
563 OSMTPD_PHASE_FILTER_RESPONSE,
572 OSMTPD_PHASE_TIMEOUT,
581 static struct io *io_stdout;
583 static int ready = 0;
584 /* Default from smtpd */
585 static int session_timeout = 300;
586 int version_major, version_minor;
588 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
589 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
592 osmtpd_register_conf(void (*cb)(const char *, const char *))
598 osmtpd_register_filter_connect(int (*cb)(struct osmtpd_ctx *, const char *,
599 struct sockaddr_storage *))
601 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
603 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
608 osmtpd_register_filter_helo(int (*cb)(struct osmtpd_ctx *, const char *))
610 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
612 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
617 osmtpd_register_filter_ehlo(int (*cb)(struct osmtpd_ctx *, const char *))
619 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
621 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
626 osmtpd_register_filter_starttls(int (*cb)(struct osmtpd_ctx *))
628 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
630 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
635 osmtpd_register_filter_auth(int (*cb)(struct osmtpd_ctx *, const char *))
637 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
639 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
644 osmtpd_register_filter_mailfrom(int (*cb)(struct osmtpd_ctx *, const char *))
646 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
648 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
653 osmtpd_register_filter_rcptto(int (*cb)(struct osmtpd_ctx *, const char *))
655 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
657 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
662 osmtpd_register_filter_data(int (*cb)(struct osmtpd_ctx *))
664 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
666 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
671 osmtpd_register_filter_dataline(int (*cb)(struct osmtpd_ctx *, const char *))
673 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
675 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
680 osmtpd_register_filter_rset(int (*cb)(struct osmtpd_ctx *))
682 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
684 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
689 osmtpd_register_filter_quit(int (*cb)(struct osmtpd_ctx *))
691 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
693 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
698 osmtpd_register_filter_noop(int (*cb)(struct osmtpd_ctx *))
700 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
702 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
707 osmtpd_register_filter_help(int (*cb)(struct osmtpd_ctx *))
709 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
711 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
716 osmtpd_register_filter_wiz(int (*cb)(struct osmtpd_ctx *))
718 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
720 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
725 osmtpd_register_filter_commit(int (*cb)(struct osmtpd_ctx *))
727 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
729 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
734 osmtpd_register_report_connect(int incoming, int (*cb)(struct osmtpd_ctx *,
735 const char *, enum osmtpd_status, struct sockaddr_storage *,
736 struct sockaddr_storage *))
738 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
740 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
745 osmtpd_register_report_disconnect(int incoming, int (*cb)(struct osmtpd_ctx *))
747 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
748 incoming, 0, (void *)cb);
752 osmtpd_register_report_identify(int incoming, int (*cb)(struct osmtpd_ctx *,
755 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
756 incoming, 0, (void *)cb);
757 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
762 osmtpd_register_report_tls(int incoming, int (*cb)(struct osmtpd_ctx *,
765 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
767 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
772 osmtpd_register_report_auth(int incoming, int (*cb)(struct osmtpd_ctx *,
773 const char *, enum osmtpd_auth_status))
775 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, incoming, 0,
777 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
782 osmtpd_register_report_reset(int incoming, int (*cb)(struct osmtpd_ctx *,
785 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET, incoming, 0,
787 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
792 osmtpd_register_report_begin(int incoming, int (*cb)(struct osmtpd_ctx *,
795 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
797 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
802 osmtpd_register_report_mail(int incoming, int (*cb)(struct osmtpd_ctx *,
803 uint32_t, const char *, enum osmtpd_status))
805 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
807 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
812 osmtpd_register_report_rcpt(int incoming, int (*cb)(struct osmtpd_ctx *,
813 uint32_t, const char *, enum osmtpd_status))
815 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
817 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
822 osmtpd_register_report_envelope(int incoming, int (*cb)(struct osmtpd_ctx *,
825 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
827 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
832 osmtpd_register_report_data(int incoming, int (*cb)(struct osmtpd_ctx *,
833 uint32_t, enum osmtpd_status))
835 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
837 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
842 osmtpd_register_report_commit(int incoming, int (*cb)(struct osmtpd_ctx *,
845 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
847 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
852 osmtpd_register_report_rollback(int incoming, int (*cb)(struct osmtpd_ctx *,
855 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
857 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
862 osmtpd_register_report_client(int incoming, int (*cb)(struct osmtpd_ctx *,
865 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
866 incoming, 0, (void *)cb);
867 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
872 osmtpd_register_report_server(int incoming, int (*cb)(struct osmtpd_ctx *,
875 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
876 incoming, 0, (void *)cb);
877 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
882 osmtpd_register_report_response(int incoming, int (*cb)(struct osmtpd_ctx *,
885 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
886 incoming, 0, (void *)cb);
887 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
892 osmtpd_register_report_timeout(int incoming, int (*cb)(struct osmtpd_ctx *))
894 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
896 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
901 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
902 void (*ondelete)(struct osmtpd_ctx *, void *))
904 oncreatecb_session = oncreate;
905 ondeletecb_session = ondelete;
909 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
910 void (*ondelete)(struct osmtpd_ctx *, void *))
912 oncreatecb_message = oncreate;
913 ondeletecb_message = ondelete;
917 osmtpd_need(int lneeds)
923 osmtpd_register_need(int incoming)
925 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
927 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
929 if (needs & OSMTPD_NEED_GREETING)
930 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
932 if (needs & OSMTPD_NEED_IDENTITY)
933 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
935 if (needs & OSMTPD_NEED_CIPHERS)
936 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
938 if (needs & OSMTPD_NEED_USERNAME)
939 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
941 if (needs & OSMTPD_NEED_MSGID) {
942 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
944 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
947 if (needs & OSMTPD_NEED_MAILFROM) {
948 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
950 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
953 if (needs & OSMTPD_NEED_RCPTTO) {
954 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
956 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
959 if (needs & OSMTPD_NEED_EVPID) {
960 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
962 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
966 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
975 struct event_base *evbase;
977 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
978 struct osmtpd_callback *ridentity = NULL;
980 evbase = event_init();
982 if ((io_stdin = io_new()) == NULL ||
983 (io_stdout = io_new()) == NULL)
984 osmtpd_err(1, "io_new");
985 io_set_nonblocking(STDIN_FILENO);
986 io_set_fd(io_stdin, STDIN_FILENO);
987 io_set_callback(io_stdin, osmtpd_newline, NULL);
988 io_set_read(io_stdin);
989 io_set_nonblocking(STDOUT_FILENO);
990 io_set_fd(io_stdout, STDOUT_FILENO);
991 io_set_callback(io_stdout, osmtpd_outevt, NULL);
992 io_set_write(io_stdout);
994 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
995 if (osmtpd_callbacks[i].doregister) {
996 osmtpd_register_need(osmtpd_callbacks[i].incoming);
997 if (oncreatecb_message != NULL) {
998 osmtpd_register(OSMTPD_TYPE_REPORT,
999 OSMTPD_PHASE_TX_BEGIN,
1000 osmtpd_callbacks[i].incoming, 0, NULL);
1001 osmtpd_register(OSMTPD_TYPE_REPORT,
1002 OSMTPD_PHASE_TX_RESET,
1003 osmtpd_callbacks[i].incoming, 0, NULL);
1005 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1006 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
1007 hidenity = &(osmtpd_callbacks[i]);
1008 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1009 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
1010 eidentity = &(osmtpd_callbacks[i]);
1011 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
1012 osmtpd_callbacks[i].phase ==
1013 OSMTPD_PHASE_LINK_IDENTIFY &&
1014 osmtpd_callbacks[i].incoming == 1)
1015 ridentity = &(osmtpd_callbacks[i]);
1018 if (ridentity != NULL && ridentity->storereport) {
1019 if (hidenity != NULL && hidenity->doregister)
1020 hidenity->storereport = 1;
1021 if (eidentity != NULL && eidentity->doregister)
1022 eidentity->storereport = 1;
1024 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1025 if (osmtpd_callbacks[i].doregister) {
1026 if (osmtpd_callbacks[i].cb != NULL)
1028 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1029 osmtpd_typetostr(osmtpd_callbacks[i].type),
1030 osmtpd_callbacks[i].incoming ? "in" : "out",
1031 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1036 osmtpd_errx(1, "No events registered");
1037 io_printf(io_stdout, "register|ready\n");
1043 event_base_free(evbase);
1047 osmtpd_err(int eval, const char *fmt, ...)
1051 if (version_major == 0 && version_minor >= 8)
1052 fprintf(stderr, "FATAL|");
1054 vfprintf(stderr, fmt, ap);
1056 fprintf(stderr, ": %s\n", strerror(errno));
1061 osmtpd_errx(int eval, const char *fmt, ...)
1065 if (version_major == 0 && version_minor >= 8)
1066 fprintf(stderr, "FATAL|");
1068 vfprintf(stderr, fmt, ap);
1070 fprintf(stderr, "\n");
1075 osmtpd_warn(struct osmtpd_ctx *ctx, const char *fmt, ...)
1079 if (version_major == 0 && version_minor >= 8)
1080 fprintf(stderr, "WARN|");
1082 fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1084 vfprintf(stderr, fmt, ap);
1086 fprintf(stderr, ": %s\n", strerror(errno));
1090 osmtpd_warnx(struct osmtpd_ctx *ctx, const char *fmt, ...)
1094 if (version_major == 0 && version_minor >= 8)
1095 fprintf(stderr, "WARN|");
1097 fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1099 vfprintf(stderr, fmt, ap);
1101 fprintf(stderr, "\n");
1105 osmtpd_info(struct osmtpd_ctx *ctx, const char *fmt, ...)
1109 if (version_major == 0 && version_minor >= 8)
1110 fprintf(stderr, "INFO|");
1112 fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1114 vfprintf(stderr, fmt, ap);
1116 fprintf(stderr, "\n");
1120 osmtpd_debug(struct osmtpd_ctx *ctx, const char *fmt, ...)
1124 if (version_major == 0 && version_minor >= 8)
1125 fprintf(stderr, "DEBUG|");
1127 fprintf(stderr, "%016"PRIx64" ", ctx->reqid);
1129 vfprintf(stderr, fmt, ap);
1131 fprintf(stderr, "\n");
1135 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1137 static char *linedup = NULL;
1138 static size_t dupsize = 0;
1139 struct osmtpd_session *ctx, search;
1140 enum osmtpd_type type;
1141 enum osmtpd_phase phase;
1142 int major, minor, incoming;
1145 const char *errstr = NULL;
1150 if (ev == IO_DISCONNECTED) {
1154 if (ev != IO_DATAIN)
1157 * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1158 * cause a build-up of kevents, because of event_add/event_del loop.
1160 io_pause(io_stdout, IO_OUT);
1161 while ((line = io_getline(io, &linelen)) != NULL) {
1162 if (dupsize < linelen) {
1163 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1164 osmtpd_err(1, NULL);
1165 dupsize = linelen + 1;
1167 strlcpy(linedup, line, dupsize);
1168 if ((end = strchr(line, '|')) == NULL)
1169 osmtpd_errx(1, "Invalid line received: missing "
1170 "version: %s", linedup);
1172 if (strcmp(line, "filter") == 0)
1173 type = OSMTPD_TYPE_FILTER;
1174 else if (strcmp(line, "report") == 0)
1175 type = OSMTPD_TYPE_REPORT;
1176 else if (strcmp(line, "config") == 0) {
1178 if (strcmp(line, "ready") == 0) {
1179 if (conf_cb != NULL)
1180 conf_cb(NULL, NULL);
1183 if ((end = strchr(line, '|')) == NULL)
1184 osmtpd_errx(1, "Invalid line received: missing "
1185 "key: %s", linedup);
1187 if (conf_cb != NULL)
1189 if (strcmp(line, "smtp-session-timeout") == 0) {
1190 session_timeout = strtonum(end, 0, INT_MAX,
1193 osmtpd_errx(1, "Invalid line received: "
1194 "invalid smtp-sesion-timeout: %s",
1200 osmtpd_errx(1, "Invalid line received: unknown message "
1201 "type: %s", linedup);
1203 major = strtoul(line, &end, 10);
1204 if (line == end || end[0] != '.')
1205 osmtpd_errx(1, "Invalid protocol received: %s",
1208 minor = strtoul(line, &end, 10);
1210 osmtpd_errx(1, "Invalid line received: missing time: "
1212 if (line == end || end[0] != '|')
1213 osmtpd_errx(1, "Invalid protocol received: %s",
1216 osmtpd_errx(1, "Unsupported protocol received: %s",
1218 if (version_major == 0 && version_minor == 0) {
1219 version_major = major;
1220 version_minor = minor;
1222 if (version_major != major && version_minor != minor)
1223 osmtpd_errx(1, "Unexpected protocol version "
1224 "change: %s", linedup);
1227 if ((end = strchr(line, '.')) == NULL)
1228 osmtpd_errx(1, "Invalid line received: invalid "
1229 "timestamp: %s", linedup);
1231 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1233 osmtpd_errx(1, "Invalid line received: invalid "
1234 "timestamp: %s", linedup);
1236 if ((end = strchr(line, '|')) == NULL)
1237 osmtpd_errx(1, "Invalid line received: missing "
1238 "direction: %s", linedup);
1240 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1242 osmtpd_errx(1, "Invalid line received: invalid "
1243 "timestamp: %s", linedup);
1244 tm.tv_nsec *= 10 * (9 - (end - line));
1246 if ((end = strchr(line, '|')) == NULL)
1247 osmtpd_errx(1, "Invalid line received: missing "
1248 "phase: %s", linedup);
1250 if (strcmp(line, "smtp-in") == 0)
1252 else if (strcmp(line, "smtp-out") == 0)
1255 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1258 if ((end = strchr(line, '|')) == NULL)
1259 osmtpd_errx(1, "Invalid line received: missing reqid: "
1262 phase = osmtpd_strtophase(line, linedup);
1265 search.ctx.reqid = strtoull(line, &end, 16);
1266 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1267 (end[0] != '|' && end[0] != '\0'))
1268 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1271 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1273 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1274 osmtpd_err(1, NULL);
1275 ctx->status = SESSION_OK;
1276 ctx->ctx.reqid = search.ctx.reqid;
1277 ctx->ctx.rdns = NULL;
1278 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1279 ctx->ctx.identity = NULL;
1280 ctx->ctx.greeting.identity = NULL;
1281 ctx->ctx.ciphers = NULL;
1283 ctx->ctx.username = NULL;
1284 ctx->ctx.mailfrom = NULL;
1285 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1286 if (ctx->ctx.rcptto == NULL)
1287 osmtpd_err(1, "malloc");
1288 ctx->ctx.rcptto[0] = NULL;
1289 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1290 ctx->ctx.src.ss_family = AF_UNSPEC;
1291 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1292 ctx->ctx.dst.ss_family = AF_UNSPEC;
1293 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1295 ctx->ctx.local_session = NULL;
1296 ctx->ctx.local_message = NULL;
1297 if (oncreatecb_session != NULL)
1298 if ((ctx->ctx.local_session =
1299 oncreatecb_session(&ctx->ctx)) == NULL)
1300 ctx->status = SESSION_ERROR;
1302 ctx->ctx.type = type;
1303 ctx->ctx.phase = phase;
1304 ctx->ctx.version_major = major;
1305 ctx->ctx.version_minor = minor;
1306 ctx->ctx.incoming = incoming;
1307 ctx->ctx.tm.tv_sec = tm.tv_sec;
1308 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1311 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1312 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1313 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1314 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1317 if (i == NITEMS(osmtpd_callbacks)) {
1318 osmtpd_errx(1, "Invalid line received: received "
1319 "unregistered line: %s", linedup);
1321 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1322 ctx->ctx.token = strtoull(line, &end, 16);
1323 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1325 osmtpd_errx(1, "Invalid line received: invalid "
1326 "token: %s", linedup);
1328 if (ctx->status == SESSION_ERROR)
1329 osmtpd_filter_disconnect(&ctx->ctx,
1330 "internal server error");
1332 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1333 ctx, line, linedup);
1335 io_resume(io_stdout, IO_OUT);
1339 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1344 case IO_DISCONNECTED:
1347 osmtpd_errx(1, "Unexpectd event");
1352 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_session *session,
1353 __unused char *params, __unused char *linedup)
1355 int (*f)(struct osmtpd_ctx *);
1357 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1358 if (f(&session->ctx))
1359 session->status = SESSION_ERROR;
1363 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_session *session,
1364 char *line, __unused char *linedup)
1366 int (*f)(struct osmtpd_ctx *, const char *);
1368 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1369 if (f(&session->ctx, line))
1370 session->status = SESSION_ERROR;
1374 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1375 char *params, char *linedup)
1377 struct sockaddr_storage ss;
1380 int (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1383 if ((address = strchr(params, '|')) == NULL)
1384 osmtpd_errx(1, "Invalid line received: missing address: %s",
1386 address++[0] = '\0';
1388 osmtpd_addrtoss(address, &ss, 0, linedup);
1390 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1391 if (f(&session->ctx, hostname, &ss))
1392 session->status = SESSION_ERROR;
1396 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1397 char *identity, __unused char *linedup)
1399 int (*f)(struct osmtpd_ctx *, const char *);
1401 if (cb->storereport) {
1402 free(session->ctx.identity);
1403 if ((session->ctx.identity = strdup(identity)) == NULL)
1404 osmtpd_err(1, "strdup");
1407 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1408 if (f(&session->ctx, identity))
1409 session->status = SESSION_ERROR;
1413 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1414 char *params, char *linedup)
1417 enum osmtpd_status fcrdns;
1418 struct sockaddr_storage src, dst;
1419 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1420 struct sockaddr_storage *, struct sockaddr_storage *);
1422 if ((end = strchr(params, '|')) == NULL)
1423 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1428 if ((end = strchr(params, '|')) == NULL)
1429 osmtpd_errx(1, "Invalid line received: missing src: %s",
1432 if (strcmp(params, "pass") == 0)
1433 fcrdns = OSMTPD_STATUS_OK;
1434 else if (strcmp(params, "fail") == 0)
1435 fcrdns = OSMTPD_STATUS_PERMFAIL;
1436 else if (strcmp(params, "error") == 0)
1437 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1439 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1442 if ((end = strchr(params, '|')) == NULL)
1443 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1446 osmtpd_addrtoss(params, &src, 1, linedup);
1448 osmtpd_addrtoss(params, &dst, 1, linedup);
1449 if (cb->storereport) {
1450 if ((session->ctx.rdns = strdup(rdns)) == NULL)
1451 osmtpd_err(1, "strdup");
1452 session->ctx.fcrdns = fcrdns;
1453 memcpy(&session->ctx.src, &src, sizeof(session->ctx.src));
1454 memcpy(&session->ctx.dst, &dst, sizeof(session->ctx.dst));
1456 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1457 if (f(&session->ctx, rdns, fcrdns, &src, &dst))
1458 session->status = SESSION_ERROR;
1462 osmtpd_link_disconnect(struct osmtpd_callback *cb,
1463 struct osmtpd_session *session, __unused char *param,
1464 __unused char *linedup)
1466 int (*f)(struct osmtpd_ctx *);
1469 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1470 if (f(&session->ctx))
1471 session->status = SESSION_ERROR;
1473 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1474 if (ondeletecb_session != NULL && session->ctx.local_session != NULL)
1475 ondeletecb_session(&session->ctx, session->ctx.local_session);
1476 free(session->ctx.rdns);
1477 free(session->ctx.identity);
1478 free(session->ctx.greeting.identity);
1479 free(session->ctx.ciphers);
1480 free(session->ctx.username);
1481 free(session->ctx.mailfrom);
1482 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1483 free(session->ctx.rcptto[i]);
1484 free(session->ctx.rcptto);
1489 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_session *session,
1490 char *identity, __unused char *linedup)
1492 int (*f)(struct osmtpd_ctx *, const char *);
1494 if (cb->storereport) {
1495 free(session->ctx.greeting.identity);
1496 if ((session->ctx.greeting.identity = strdup(identity)) == NULL)
1497 osmtpd_err(1, NULL);
1500 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1501 if (f(&session->ctx, identity))
1502 session->status = SESSION_ERROR;
1506 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1507 char *identity, __unused char *linedup)
1509 int (*f)(struct osmtpd_ctx *, const char *);
1511 if (cb->storereport) {
1512 free(session->ctx.identity);
1513 if ((session->ctx.identity = strdup(identity)) == NULL)
1514 osmtpd_err(1, NULL);
1517 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1518 if (f(&session->ctx, identity))
1519 session->status = SESSION_ERROR;
1523 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_session *session,
1524 char *ciphers, __unused char *linedup)
1526 int (*f)(struct osmtpd_ctx *, const char *);
1528 if (cb->storereport) {
1529 if ((session->ctx.ciphers = strdup(ciphers)) == NULL)
1530 osmtpd_err(1, NULL);
1533 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1534 if (f(&session->ctx, ciphers))
1535 session->status = SESSION_ERROR;
1539 osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_session *session,
1540 char *username, char *linedup)
1542 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1544 enum osmtpd_auth_status s;
1546 if ((status = strrchr(username, '|')) == NULL)
1547 osmtpd_errx(1, "Invalid auth received: %s", linedup);
1550 if (strcmp(status, "pass") == 0)
1551 s = OSMTPD_AUTH_PASS;
1552 else if (strcmp(status, "fail") == 0)
1553 s = OSMTPD_AUTH_FAIL;
1554 else if (strcmp(status, "error") == 0)
1555 s = OSMTPD_AUTH_ERROR;
1557 osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1559 if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1560 if ((session->ctx.username = strdup(username)) == NULL)
1561 osmtpd_err(1, NULL);
1564 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1565 if (f(&session->ctx, username, s))
1566 session->status = SESSION_ERROR;
1570 osmtpd_tx_reset(struct osmtpd_callback *cb, struct osmtpd_session *session,
1571 char *params, char *linedup)
1574 unsigned long imsgid;
1577 int (*f)(struct osmtpd_ctx *, uint32_t);
1580 imsgid = strtoul(params, &end, 16);
1581 if ((imsgid == ULONG_MAX && errno != 0))
1582 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1585 osmtpd_errx(1, "Invalid line received: missing address: %s",
1588 if ((unsigned long) msgid != imsgid)
1589 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1592 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1593 if (f(&session->ctx, msgid))
1594 session->status = SESSION_ERROR;
1596 if (ondeletecb_message != NULL && session->ctx.local_message != NULL) {
1597 ondeletecb_message(&session->ctx, session->ctx.local_message);
1598 session->ctx.local_message = NULL;
1601 free(session->ctx.mailfrom);
1602 session->ctx.mailfrom = NULL;
1604 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1605 free(session->ctx.rcptto[i]);
1606 session->ctx.rcptto[0] = NULL;
1607 session->ctx.evpid = 0;
1608 session->ctx.msgid = 0;
1612 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_session *session,
1613 char *msgid, char *linedup)
1615 unsigned long imsgid;
1617 int (*f)(struct osmtpd_ctx *, uint32_t);
1620 imsgid = strtoul(msgid, &endptr, 16);
1621 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1622 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1624 session->ctx.msgid = imsgid;
1625 /* Check if we're in range */
1626 if ((unsigned long) session->ctx.msgid != imsgid)
1627 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1630 if (!cb->storereport)
1631 session->ctx.msgid = 0;
1633 if (oncreatecb_message != NULL) {
1634 session->ctx.local_message = oncreatecb_message(&session->ctx);
1635 if (session->ctx.local_message == NULL)
1636 session->status = SESSION_ERROR;
1639 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1640 if (f(&session->ctx, imsgid))
1641 session->status = SESSION_ERROR;
1645 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_session *session,
1646 char *params, char *linedup)
1648 char *end, *mailfrom;
1649 enum osmtpd_status status;
1650 unsigned long imsgid;
1652 int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1653 enum osmtpd_status);
1656 imsgid = strtoul(params, &end, 16);
1657 if ((imsgid == ULONG_MAX && errno != 0))
1658 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1661 osmtpd_errx(1, "Invalid line received: missing address: %s",
1664 if ((unsigned long) msgid != imsgid)
1665 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1669 if ((end = strchr(params, '|')) == NULL)
1670 osmtpd_errx(1, "Invalid line received: missing status: %s",
1673 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1675 status = osmtpd_strtostatus(end, linedup);
1678 status = osmtpd_strtostatus(params, linedup);
1680 if (cb->storereport) {
1681 if ((session->ctx.mailfrom = strdup(mailfrom)) == NULL)
1682 osmtpd_err(1, NULL);
1685 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1686 if (f(&session->ctx, msgid, mailfrom, status))
1687 session->status = SESSION_ERROR;
1691 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_session *session,
1692 char *params, char *linedup)
1695 enum osmtpd_status status;
1696 unsigned long imsgid;
1699 int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1700 enum osmtpd_status);
1703 imsgid = strtoul(params, &end, 16);
1704 if ((imsgid == ULONG_MAX && errno != 0))
1705 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1708 osmtpd_errx(1, "Invalid line received: missing address: %s",
1711 if ((unsigned long) msgid != imsgid)
1712 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1716 if ((end = strchr(params, '|')) == NULL)
1717 osmtpd_errx(1, "Invalid line received: missing status: %s",
1721 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1723 status = osmtpd_strtostatus(end, linedup);
1726 status = osmtpd_strtostatus(params, linedup);
1729 if (cb->storereport) {
1730 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1732 session->ctx.rcptto = reallocarray(session->ctx.rcptto, i + 2,
1733 sizeof(*session->ctx.rcptto));
1734 if (session->ctx.rcptto == NULL)
1735 osmtpd_err(1, NULL);
1737 if ((session->ctx.rcptto[i] = strdup(rcptto)) == NULL)
1738 osmtpd_err(1, NULL);
1739 session->ctx.rcptto[i + 1] = NULL;
1742 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1743 if (f(&session->ctx, msgid, rcptto, status))
1744 session->status = SESSION_ERROR;
1748 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_session *session,
1749 char *params, char *linedup)
1751 unsigned long imsgid;
1755 int (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1758 imsgid = strtoul(params, &end, 16);
1759 if ((imsgid == ULONG_MAX && errno != 0))
1760 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1763 osmtpd_errx(1, "Invalid line received: missing address: %s",
1766 if ((unsigned long) msgid != imsgid)
1767 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1771 evpid = strtoull(params, &end, 16);
1772 if ((session->ctx.evpid == ULLONG_MAX && errno != 0) || end[0] != '\0')
1773 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1775 if (cb->storereport)
1776 session->ctx.evpid = evpid;
1778 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1779 if (f(&session->ctx, msgid, evpid))
1780 session->status = SESSION_ERROR;
1784 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_session *session,
1785 char *params, char *linedup)
1788 unsigned long imsgid;
1790 int (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1793 imsgid = strtoul(params, &end, 16);
1794 if ((imsgid == ULONG_MAX && errno != 0))
1795 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1798 osmtpd_errx(1, "Invalid line received: missing address: %s",
1801 if ((unsigned long) msgid != imsgid)
1802 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1806 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1807 if (f(&session->ctx, msgid, osmtpd_strtostatus(params, linedup)))
1808 session->status = SESSION_ERROR;
1812 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_session *session,
1813 char *params, char *linedup)
1816 const char *errstr = NULL;
1817 unsigned long imsgid;
1820 int (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1823 imsgid = strtoul(params, &end, 16);
1824 if ((imsgid == ULONG_MAX && errno != 0))
1825 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1828 osmtpd_errx(1, "Invalid line received: missing address: %s",
1831 if ((unsigned long) msgid != imsgid)
1832 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1836 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1838 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1841 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1842 if (f(&session->ctx, msgid, msgsz))
1843 session->status = SESSION_ERROR;
1847 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_session *session,
1848 char *params, char *linedup)
1851 unsigned long imsgid;
1853 int (*f)(struct osmtpd_ctx *, uint32_t);
1856 imsgid = strtoul(params, &end, 16);
1857 if ((imsgid == ULONG_MAX && errno != 0))
1858 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1861 osmtpd_errx(1, "Invalid line received: missing address: %s",
1864 if ((unsigned long) msgid != imsgid)
1865 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1868 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1869 if (f(&session->ctx, msgid))
1870 session->status = SESSION_ERROR;
1874 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1876 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1878 if (session->status == SESSION_DISCONNECTED)
1881 if (ctx->version_major == 0 && ctx->version_minor < 5)
1882 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1883 "proceed\n", ctx->token, ctx->reqid);
1885 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1886 "proceed\n", ctx->reqid, ctx->token);
1890 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1892 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1895 if (session->status == SESSION_DISCONNECTED)
1898 if (code < 200 || code > 599)
1899 osmtpd_errx(1, "Invalid reject code");
1901 if (ctx->version_major == 0 && ctx->version_minor < 5)
1902 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1903 "reject|%d ", ctx->token, ctx->reqid, code);
1905 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1906 "reject|%d ", ctx->reqid, ctx->token, code);
1907 va_start(ap, reason);
1908 io_vprintf(io_stdout, reason, ap);
1910 io_printf(io_stdout, "\n");
1914 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1915 int subject, int detail, const char *reason, ...)
1917 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1920 if (session->status == SESSION_DISCONNECTED)
1923 if (code < 200 || code > 599)
1924 osmtpd_errx(1, "Invalid reject code");
1925 if (class < 2 || class > 5)
1926 osmtpd_errx(1, "Invalid enhanced status class");
1927 if (subject < 0 || subject > 999)
1928 osmtpd_errx(1, "Invalid enhanced status subject");
1929 if (detail < 0 || detail > 999)
1930 osmtpd_errx(1, "Invalid enhanced status detail");
1932 if (ctx->version_major == 0 && ctx->version_minor < 5)
1933 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1934 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1937 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1938 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1940 va_start(ap, reason);
1941 io_vprintf(io_stdout, reason, ap);
1943 io_printf(io_stdout, "\n");
1947 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1949 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1952 if (session->status == SESSION_DISCONNECTED)
1955 if (ctx->version_major == 0 && ctx->version_minor < 5)
1956 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1957 "disconnect|421 ", ctx->token, ctx->reqid);
1959 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1960 "disconnect|421 ", ctx->reqid, ctx->token);
1961 va_start(ap, reason);
1962 io_vprintf(io_stdout, reason, ap);
1964 io_printf(io_stdout, "\n");
1965 session->status = SESSION_DISCONNECTED;
1969 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1970 int detail, const char *reason, ...)
1972 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1975 if (session->status == SESSION_DISCONNECTED)
1978 if (class <= 2 || class >= 5)
1979 osmtpd_errx(1, "Invalid enhanced status class");
1980 if (subject < 0 || subject > 999)
1981 osmtpd_errx(1, "Invalid enhanced status subject");
1982 if (detail < 0 || detail > 999)
1983 osmtpd_errx(1, "Invalid enhanced status detail");
1984 if (ctx->version_major == 0 && ctx->version_minor < 5)
1985 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1986 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1989 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1990 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1992 va_start(ap, reason);
1993 io_vprintf(io_stdout, reason, ap);
1995 io_printf(io_stdout, "\n");
1996 session->status = SESSION_DISCONNECTED;
2000 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
2002 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2005 if (session->status == SESSION_DISCONNECTED)
2008 if (ctx->version_major == 0 && ctx->version_minor < 5)
2009 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2010 "rewrite|", ctx->token, ctx->reqid);
2012 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
2013 "rewrite|", ctx->reqid, ctx->token);
2014 va_start(ap, value);
2015 io_vprintf(io_stdout, value, ap);
2017 io_printf(io_stdout, "\n");
2021 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
2023 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
2026 if (session->status == SESSION_DISCONNECTED)
2029 if (ctx->version_major == 0 && ctx->version_minor < 5)
2030 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2031 ctx->token, ctx->reqid);
2033 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
2034 ctx->reqid, ctx->token);
2036 io_vprintf(io_stdout, line, ap);
2038 io_printf(io_stdout, "\n");
2042 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
2043 int storereport, void *cb)
2048 osmtpd_errx(1, "Can't register when proc is running");
2050 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
2051 if (type == osmtpd_callbacks[i].type &&
2052 phase == osmtpd_callbacks[i].phase &&
2053 incoming == osmtpd_callbacks[i].incoming) {
2054 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
2055 osmtpd_errx(1, "Event already registered");
2057 osmtpd_callbacks[i].cb = cb;
2058 osmtpd_callbacks[i].doregister = 1;
2060 osmtpd_callbacks[i].storereport = 1;
2065 osmtpd_errx(1, "Trying to register unknown event");
2068 static enum osmtpd_phase
2069 osmtpd_strtophase(const char *phase, const char *linedup)
2071 if (strcmp(phase, "connect") == 0)
2072 return OSMTPD_PHASE_CONNECT;
2073 if (strcmp(phase, "helo") == 0)
2074 return OSMTPD_PHASE_HELO;
2075 if (strcmp(phase, "ehlo") == 0)
2076 return OSMTPD_PHASE_EHLO;
2077 if (strcmp(phase, "starttls") == 0)
2078 return OSMTPD_PHASE_STARTTLS;
2079 if (strcmp(phase, "auth") == 0)
2080 return OSMTPD_PHASE_AUTH;
2081 if (strcmp(phase, "mail-from") == 0)
2082 return OSMTPD_PHASE_MAIL_FROM;
2083 if (strcmp(phase, "rcpt-to") == 0)
2084 return OSMTPD_PHASE_RCPT_TO;
2085 if (strcmp(phase, "data") == 0)
2086 return OSMTPD_PHASE_DATA;
2087 if (strcmp(phase, "data-line") == 0)
2088 return OSMTPD_PHASE_DATA_LINE;
2089 if (strcmp(phase, "rset") == 0)
2090 return OSMTPD_PHASE_RSET;
2091 if (strcmp(phase, "quit") == 0)
2092 return OSMTPD_PHASE_QUIT;
2093 if (strcmp(phase, "noop") == 0)
2094 return OSMTPD_PHASE_NOOP;
2095 if (strcmp(phase, "help") == 0)
2096 return OSMTPD_PHASE_HELP;
2097 if (strcmp(phase, "wiz") == 0)
2098 return OSMTPD_PHASE_WIZ;
2099 if (strcmp(phase, "commit") == 0)
2100 return OSMTPD_PHASE_COMMIT;
2101 if (strcmp(phase, "link-connect") == 0)
2102 return OSMTPD_PHASE_LINK_CONNECT;
2103 if (strcmp(phase, "link-disconnect") == 0)
2104 return OSMTPD_PHASE_LINK_DISCONNECT;
2105 if (strcmp(phase, "link-greeting") == 0)
2106 return OSMTPD_PHASE_LINK_GREETING;
2107 if (strcmp(phase, "link-identify") == 0)
2108 return OSMTPD_PHASE_LINK_IDENTIFY;
2109 if (strcmp(phase, "link-tls") == 0)
2110 return OSMTPD_PHASE_LINK_TLS;
2111 if (strcmp(phase, "link-auth") == 0)
2112 return OSMTPD_PHASE_LINK_AUTH;
2113 if (strcmp(phase, "tx-reset") == 0)
2114 return OSMTPD_PHASE_TX_RESET;
2115 if (strcmp(phase, "tx-begin") == 0)
2116 return OSMTPD_PHASE_TX_BEGIN;
2117 if (strcmp(phase, "tx-mail") == 0)
2118 return OSMTPD_PHASE_TX_MAIL;
2119 if (strcmp(phase, "tx-rcpt") == 0)
2120 return OSMTPD_PHASE_TX_RCPT;
2121 if (strcmp(phase, "tx-envelope") == 0)
2122 return OSMTPD_PHASE_TX_ENVELOPE;
2123 if (strcmp(phase, "tx-data") == 0)
2124 return OSMTPD_PHASE_TX_DATA;
2125 if (strcmp(phase, "tx-commit") == 0)
2126 return OSMTPD_PHASE_TX_COMMIT;
2127 if (strcmp(phase, "tx-rollback") == 0)
2128 return OSMTPD_PHASE_TX_ROLLBACK;
2129 if (strcmp(phase, "protocol-client") == 0)
2130 return OSMTPD_PHASE_PROTOCOL_CLIENT;
2131 if (strcmp(phase, "protocol-server") == 0)
2132 return OSMTPD_PHASE_PROTOCOL_SERVER;
2133 if (strcmp(phase, "filter-response") == 0)
2134 return OSMTPD_PHASE_FILTER_RESPONSE;
2135 if (strcmp(phase, "timeout") == 0)
2136 return OSMTPD_PHASE_TIMEOUT;
2137 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
2141 osmtpd_typetostr(enum osmtpd_type type)
2144 case OSMTPD_TYPE_FILTER:
2146 case OSMTPD_TYPE_REPORT:
2149 osmtpd_errx(1, "In valid type: %d\n", type);
2153 osmtpd_phasetostr(enum osmtpd_phase phase)
2156 case OSMTPD_PHASE_CONNECT:
2158 case OSMTPD_PHASE_HELO:
2160 case OSMTPD_PHASE_EHLO:
2162 case OSMTPD_PHASE_STARTTLS:
2164 case OSMTPD_PHASE_AUTH:
2166 case OSMTPD_PHASE_MAIL_FROM:
2168 case OSMTPD_PHASE_RCPT_TO:
2170 case OSMTPD_PHASE_DATA:
2172 case OSMTPD_PHASE_DATA_LINE:
2174 case OSMTPD_PHASE_RSET:
2176 case OSMTPD_PHASE_QUIT:
2178 case OSMTPD_PHASE_NOOP:
2180 case OSMTPD_PHASE_HELP:
2182 case OSMTPD_PHASE_WIZ:
2184 case OSMTPD_PHASE_COMMIT:
2186 case OSMTPD_PHASE_LINK_CONNECT:
2187 return "link-connect";
2188 case OSMTPD_PHASE_LINK_DISCONNECT:
2189 return "link-disconnect";
2190 case OSMTPD_PHASE_LINK_GREETING:
2191 return "link-greeting";
2192 case OSMTPD_PHASE_LINK_IDENTIFY:
2193 return "link-identify";
2194 case OSMTPD_PHASE_LINK_TLS:
2196 case OSMTPD_PHASE_LINK_AUTH:
2198 case OSMTPD_PHASE_TX_RESET:
2200 case OSMTPD_PHASE_TX_BEGIN:
2202 case OSMTPD_PHASE_TX_MAIL:
2204 case OSMTPD_PHASE_TX_RCPT:
2206 case OSMTPD_PHASE_TX_ENVELOPE:
2207 return "tx-envelope";
2208 case OSMTPD_PHASE_TX_DATA:
2210 case OSMTPD_PHASE_TX_COMMIT:
2212 case OSMTPD_PHASE_TX_ROLLBACK:
2213 return "tx-rollback";
2214 case OSMTPD_PHASE_PROTOCOL_CLIENT:
2215 return "protocol-client";
2216 case OSMTPD_PHASE_PROTOCOL_SERVER:
2217 return "protocol-server";
2218 case OSMTPD_PHASE_FILTER_RESPONSE:
2219 return "filter-response";
2220 case OSMTPD_PHASE_TIMEOUT:
2223 osmtpd_errx(1, "In valid phase: %d\n", phase);
2226 static enum osmtpd_status
2227 osmtpd_strtostatus(const char *status, char *linedup)
2229 if (strcmp(status, "ok") == 0)
2230 return OSMTPD_STATUS_OK;
2231 else if (strcmp(status, "tempfail") == 0)
2232 return OSMTPD_STATUS_TEMPFAIL;
2233 else if (strcmp(status, "permfail") == 0)
2234 return OSMTPD_STATUS_PERMFAIL;
2235 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2239 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2243 const char *errstr = NULL;
2244 struct sockaddr_in *sin;
2245 struct sockaddr_in6 *sin6;
2246 struct sockaddr_un *sun;
2249 if (addr[0] == '[') {
2250 sin6 = (struct sockaddr_in6 *)ss;
2251 sin6->sin6_family = AF_INET6;
2252 sin6->sin6_port = 0;
2254 if ((port = strrchr(addr, ':')) == NULL)
2255 osmtpd_errx(1, "Invalid line received: invalid "
2256 "address (%s): %s", addr, linedup);
2257 if (port[-1] != ']')
2258 osmtpd_errx(1, "Invalid line received: invalid "
2259 "address (%s): %s", addr, linedup);
2261 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2264 osmtpd_errx(1, "Invalid line received: invalid "
2265 "address (%s): %s", addr, linedup);
2269 if (addr[n - 1] != ']')
2270 osmtpd_errx(1, "Invalid line received: invalid "
2271 "address (%s): %s", addr, linedup);
2274 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2282 osmtpd_errx(1, "Invalid line received: invalid address "
2283 "(%s): %s", addr, linedup);
2289 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2292 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2293 sun = (struct sockaddr_un *)ss;
2294 sun->sun_family = AF_UNIX;
2295 if (strlcpy(sun->sun_path, addr,
2296 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2297 osmtpd_errx(1, "Invalid line received: address too "
2298 "long (%s): %s", addr, linedup);
2301 sin = (struct sockaddr_in *)ss;
2302 sin->sin_family = AF_INET;
2305 if ((port = strrchr(addr, ':')) == NULL)
2306 osmtpd_errx(1, "Invalid line received: invalid "
2307 "address (%s): %s", addr, linedup);
2309 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2312 osmtpd_errx(1, "Invalid line received: invalid "
2313 "address (%s): %s", addr, linedup);
2316 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2322 osmtpd_errx(1, "Invalid line received: invalid address "
2323 "(%s): %s", addr, linedup);
2327 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2334 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2336 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2339 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);