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;
587 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
588 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
591 osmtpd_register_conf(void (*cb)(const char *, const char *))
597 osmtpd_register_filter_connect(int (*cb)(struct osmtpd_ctx *, const char *,
598 struct sockaddr_storage *))
600 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
602 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
607 osmtpd_register_filter_helo(int (*cb)(struct osmtpd_ctx *, const char *))
609 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
611 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
616 osmtpd_register_filter_ehlo(int (*cb)(struct osmtpd_ctx *, const char *))
618 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
620 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
625 osmtpd_register_filter_starttls(int (*cb)(struct osmtpd_ctx *))
627 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
629 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
634 osmtpd_register_filter_auth(int (*cb)(struct osmtpd_ctx *, const char *))
636 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
638 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
643 osmtpd_register_filter_mailfrom(int (*cb)(struct osmtpd_ctx *, const char *))
645 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
647 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
652 osmtpd_register_filter_rcptto(int (*cb)(struct osmtpd_ctx *, const char *))
654 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
656 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
661 osmtpd_register_filter_data(int (*cb)(struct osmtpd_ctx *))
663 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
665 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
670 osmtpd_register_filter_dataline(int (*cb)(struct osmtpd_ctx *, const char *))
672 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
674 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
679 osmtpd_register_filter_rset(int (*cb)(struct osmtpd_ctx *))
681 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
683 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
688 osmtpd_register_filter_quit(int (*cb)(struct osmtpd_ctx *))
690 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
692 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
697 osmtpd_register_filter_noop(int (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
701 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
706 osmtpd_register_filter_help(int (*cb)(struct osmtpd_ctx *))
708 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
710 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
715 osmtpd_register_filter_wiz(int (*cb)(struct osmtpd_ctx *))
717 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
724 osmtpd_register_filter_commit(int (*cb)(struct osmtpd_ctx *))
726 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
728 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
733 osmtpd_register_report_connect(int incoming, int (*cb)(struct osmtpd_ctx *,
734 const char *, enum osmtpd_status, struct sockaddr_storage *,
735 struct sockaddr_storage *))
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
739 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
744 osmtpd_register_report_disconnect(int incoming, int (*cb)(struct osmtpd_ctx *))
746 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
747 incoming, 0, (void *)cb);
751 osmtpd_register_report_identify(int incoming, int (*cb)(struct osmtpd_ctx *,
754 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
755 incoming, 0, (void *)cb);
756 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
761 osmtpd_register_report_tls(int incoming, int (*cb)(struct osmtpd_ctx *,
764 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
766 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
771 osmtpd_register_report_auth(int incoming, int (*cb)(struct osmtpd_ctx *,
772 const char *, enum osmtpd_auth_status))
774 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, incoming, 0,
776 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
781 osmtpd_register_report_reset(int incoming, int (*cb)(struct osmtpd_ctx *,
784 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET, incoming, 0,
786 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
791 osmtpd_register_report_begin(int incoming, int (*cb)(struct osmtpd_ctx *,
794 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
796 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
801 osmtpd_register_report_mail(int incoming, int (*cb)(struct osmtpd_ctx *,
802 uint32_t, const char *, enum osmtpd_status))
804 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
806 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
811 osmtpd_register_report_rcpt(int incoming, int (*cb)(struct osmtpd_ctx *,
812 uint32_t, const char *, enum osmtpd_status))
814 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
816 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
821 osmtpd_register_report_envelope(int incoming, int (*cb)(struct osmtpd_ctx *,
824 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
826 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
831 osmtpd_register_report_data(int incoming, int (*cb)(struct osmtpd_ctx *,
832 uint32_t, enum osmtpd_status))
834 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
836 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
841 osmtpd_register_report_commit(int incoming, int (*cb)(struct osmtpd_ctx *,
844 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
846 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
851 osmtpd_register_report_rollback(int incoming, int (*cb)(struct osmtpd_ctx *,
854 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
856 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
861 osmtpd_register_report_client(int incoming, int (*cb)(struct osmtpd_ctx *,
864 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
865 incoming, 0, (void *)cb);
866 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
871 osmtpd_register_report_server(int incoming, int (*cb)(struct osmtpd_ctx *,
874 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
875 incoming, 0, (void *)cb);
876 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
881 osmtpd_register_report_response(int incoming, int (*cb)(struct osmtpd_ctx *,
884 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
885 incoming, 0, (void *)cb);
886 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
891 osmtpd_register_report_timeout(int incoming, int (*cb)(struct osmtpd_ctx *))
893 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
900 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
901 void (*ondelete)(struct osmtpd_ctx *, void *))
903 oncreatecb_session = oncreate;
904 ondeletecb_session = ondelete;
908 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
909 void (*ondelete)(struct osmtpd_ctx *, void *))
911 oncreatecb_message = oncreate;
912 ondeletecb_message = ondelete;
916 osmtpd_need(int lneeds)
922 osmtpd_register_need(int incoming)
924 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
926 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
928 if (needs & OSMTPD_NEED_GREETING)
929 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
931 if (needs & OSMTPD_NEED_IDENTITY)
932 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
934 if (needs & OSMTPD_NEED_CIPHERS)
935 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
937 if (needs & OSMTPD_NEED_USERNAME)
938 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
940 if (needs & OSMTPD_NEED_MSGID) {
941 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
943 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
946 if (needs & OSMTPD_NEED_MAILFROM) {
947 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
949 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
952 if (needs & OSMTPD_NEED_RCPTTO) {
953 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
955 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
958 if (needs & OSMTPD_NEED_EVPID) {
959 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
961 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
965 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
974 struct event_base *evbase;
976 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
977 struct osmtpd_callback *ridentity = NULL;
979 evbase = event_init();
981 if ((io_stdin = io_new()) == NULL ||
982 (io_stdout = io_new()) == NULL)
983 osmtpd_err(1, "io_new");
984 io_set_nonblocking(STDIN_FILENO);
985 io_set_fd(io_stdin, STDIN_FILENO);
986 io_set_callback(io_stdin, osmtpd_newline, NULL);
987 io_set_read(io_stdin);
988 io_set_nonblocking(STDOUT_FILENO);
989 io_set_fd(io_stdout, STDOUT_FILENO);
990 io_set_callback(io_stdout, osmtpd_outevt, NULL);
991 io_set_write(io_stdout);
993 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
994 if (osmtpd_callbacks[i].doregister) {
995 osmtpd_register_need(osmtpd_callbacks[i].incoming);
996 if (oncreatecb_message != NULL) {
997 osmtpd_register(OSMTPD_TYPE_REPORT,
998 OSMTPD_PHASE_TX_BEGIN,
999 osmtpd_callbacks[i].incoming, 0, NULL);
1000 osmtpd_register(OSMTPD_TYPE_REPORT,
1001 OSMTPD_PHASE_TX_RESET,
1002 osmtpd_callbacks[i].incoming, 0, NULL);
1004 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1005 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
1006 hidenity = &(osmtpd_callbacks[i]);
1007 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1008 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
1009 eidentity = &(osmtpd_callbacks[i]);
1010 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
1011 osmtpd_callbacks[i].phase ==
1012 OSMTPD_PHASE_LINK_IDENTIFY &&
1013 osmtpd_callbacks[i].incoming == 1)
1014 ridentity = &(osmtpd_callbacks[i]);
1017 if (ridentity != NULL && ridentity->storereport) {
1018 if (hidenity != NULL && hidenity->doregister)
1019 hidenity->storereport = 1;
1020 if (eidentity != NULL && eidentity->doregister)
1021 eidentity->storereport = 1;
1023 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1024 if (osmtpd_callbacks[i].doregister) {
1025 if (osmtpd_callbacks[i].cb != NULL)
1027 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1028 osmtpd_typetostr(osmtpd_callbacks[i].type),
1029 osmtpd_callbacks[i].incoming ? "in" : "out",
1030 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1035 osmtpd_errx(1, "No events registered");
1036 io_printf(io_stdout, "register|ready\n");
1042 event_base_free(evbase);
1046 osmtpd_warn(struct osmtpd_ctx *ctx, const char *fmt, ...)
1051 fprintf(stderr, "%016"PRIx64, ctx->reqid);
1053 vfprintf(stderr, fmt, ap);
1055 fprintf(stderr, ": %s\n", strerror(errno));
1059 osmtpd_warnx(struct osmtpd_ctx *ctx, const char *fmt, ...)
1064 fprintf(stderr, "%016"PRIx64, ctx->reqid);
1066 vfprintf(stderr, fmt, ap);
1068 fprintf(stderr, "\n");
1072 osmtpd_err(int eval, const char *fmt, ...)
1077 vfprintf(stderr, fmt, ap);
1079 fprintf(stderr, ": %s\n", strerror(errno));
1084 osmtpd_errx(int eval, const char *fmt, ...)
1089 vfprintf(stderr, fmt, ap);
1091 fprintf(stderr, "\n");
1096 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1098 static char *linedup = NULL;
1099 static size_t dupsize = 0;
1100 struct osmtpd_session *ctx, search;
1101 enum osmtpd_type type;
1102 enum osmtpd_phase phase;
1103 int version_major, version_minor, incoming;
1106 const char *errstr = NULL;
1111 if (ev == IO_DISCONNECTED) {
1115 if (ev != IO_DATAIN)
1118 * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1119 * cause a build-up of kevents, because of event_add/event_del loop.
1121 io_pause(io_stdout, IO_OUT);
1122 while ((line = io_getline(io, &linelen)) != NULL) {
1123 if (dupsize < linelen) {
1124 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1125 osmtpd_err(1, NULL);
1126 dupsize = linelen + 1;
1128 strlcpy(linedup, line, dupsize);
1129 if ((end = strchr(line, '|')) == NULL)
1130 osmtpd_errx(1, "Invalid line received: missing "
1131 "version: %s", linedup);
1133 if (strcmp(line, "filter") == 0)
1134 type = OSMTPD_TYPE_FILTER;
1135 else if (strcmp(line, "report") == 0)
1136 type = OSMTPD_TYPE_REPORT;
1137 else if (strcmp(line, "config") == 0) {
1139 if (strcmp(line, "ready") == 0) {
1140 if (conf_cb != NULL)
1141 conf_cb(NULL, NULL);
1144 if ((end = strchr(line, '|')) == NULL)
1145 osmtpd_errx(1, "Invalid line received: missing "
1146 "key: %s", linedup);
1148 if (conf_cb != NULL)
1150 if (strcmp(line, "smtp-session-timeout") == 0) {
1151 session_timeout = strtonum(end, 0, INT_MAX,
1154 osmtpd_errx(1, "Invalid line received: "
1155 "invalid smtp-sesion-timeout: %s",
1161 osmtpd_errx(1, "Invalid line received: unknown message "
1162 "type: %s", linedup);
1164 version_major = strtoul(line, &end, 10);
1165 if (line == end || end[0] != '.')
1166 osmtpd_errx(1, "Invalid protocol received: %s",
1169 version_minor = strtoul(line, &end, 10);
1171 osmtpd_errx(1, "Invalid line received: missing time: "
1173 if (line == end || end[0] != '|')
1174 osmtpd_errx(1, "Invalid protocol received: %s",
1176 if (version_major != 0)
1177 osmtpd_errx(1, "Unsupported protocol received: %s",
1180 if ((end = strchr(line, '.')) == NULL)
1181 osmtpd_errx(1, "Invalid line received: invalid "
1182 "timestamp: %s", linedup);
1184 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1186 osmtpd_errx(1, "Invalid line received: invalid "
1187 "timestamp: %s", linedup);
1189 if ((end = strchr(line, '|')) == NULL)
1190 osmtpd_errx(1, "Invalid line received: missing "
1191 "direction: %s", linedup);
1193 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1195 osmtpd_errx(1, "Invalid line received: invalid "
1196 "timestamp: %s", linedup);
1197 tm.tv_nsec *= 10 * (9 - (end - line));
1199 if ((end = strchr(line, '|')) == NULL)
1200 osmtpd_errx(1, "Invalid line received: missing "
1201 "phase: %s", linedup);
1203 if (strcmp(line, "smtp-in") == 0)
1205 else if (strcmp(line, "smtp-out") == 0)
1208 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1211 if ((end = strchr(line, '|')) == NULL)
1212 osmtpd_errx(1, "Invalid line received: missing reqid: "
1215 phase = osmtpd_strtophase(line, linedup);
1218 search.ctx.reqid = strtoull(line, &end, 16);
1219 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1220 (end[0] != '|' && end[0] != '\0'))
1221 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1224 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1226 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1227 osmtpd_err(1, NULL);
1228 ctx->status = SESSION_OK;
1229 ctx->ctx.reqid = search.ctx.reqid;
1230 ctx->ctx.rdns = NULL;
1231 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1232 ctx->ctx.identity = NULL;
1233 ctx->ctx.greeting.identity = NULL;
1234 ctx->ctx.ciphers = NULL;
1236 ctx->ctx.username = NULL;
1237 ctx->ctx.mailfrom = NULL;
1238 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1239 if (ctx->ctx.rcptto == NULL)
1240 osmtpd_err(1, "malloc");
1241 ctx->ctx.rcptto[0] = NULL;
1242 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1243 ctx->ctx.src.ss_family = AF_UNSPEC;
1244 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1245 ctx->ctx.dst.ss_family = AF_UNSPEC;
1246 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1248 ctx->ctx.local_session = NULL;
1249 ctx->ctx.local_message = NULL;
1250 if (oncreatecb_session != NULL)
1251 if ((ctx->ctx.local_session =
1252 oncreatecb_session(&ctx->ctx)) == NULL)
1253 ctx->status = SESSION_ERROR;
1255 ctx->ctx.type = type;
1256 ctx->ctx.phase = phase;
1257 ctx->ctx.version_major = version_major;
1258 ctx->ctx.version_minor = version_minor;
1259 ctx->ctx.incoming = incoming;
1260 ctx->ctx.tm.tv_sec = tm.tv_sec;
1261 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1264 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1265 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1266 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1267 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1270 if (i == NITEMS(osmtpd_callbacks)) {
1271 osmtpd_errx(1, "Invalid line received: received "
1272 "unregistered line: %s", linedup);
1274 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1275 ctx->ctx.token = strtoull(line, &end, 16);
1276 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1278 osmtpd_errx(1, "Invalid line received: invalid "
1279 "token: %s", linedup);
1281 if (ctx->status == SESSION_ERROR)
1282 osmtpd_filter_disconnect(&ctx->ctx,
1283 "internal server error");
1285 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1286 ctx, line, linedup);
1288 io_resume(io_stdout, IO_OUT);
1292 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1297 case IO_DISCONNECTED:
1300 osmtpd_errx(1, "Unexpectd event");
1305 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_session *session,
1306 __unused char *params, __unused char *linedup)
1308 int (*f)(struct osmtpd_ctx *);
1310 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1311 if (f(&session->ctx))
1312 session->status = SESSION_ERROR;
1316 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_session *session,
1317 char *line, __unused char *linedup)
1319 int (*f)(struct osmtpd_ctx *, const char *);
1321 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1322 if (f(&session->ctx, line))
1323 session->status = SESSION_ERROR;
1327 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1328 char *params, char *linedup)
1330 struct sockaddr_storage ss;
1333 int (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1336 if ((address = strchr(params, '|')) == NULL)
1337 osmtpd_errx(1, "Invalid line received: missing address: %s",
1339 address++[0] = '\0';
1341 osmtpd_addrtoss(address, &ss, 0, linedup);
1343 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1344 if (f(&session->ctx, hostname, &ss))
1345 session->status = SESSION_ERROR;
1349 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1350 char *identity, __unused char *linedup)
1352 int (*f)(struct osmtpd_ctx *, const char *);
1354 if (cb->storereport) {
1355 free(session->ctx.identity);
1356 if ((session->ctx.identity = strdup(identity)) == NULL)
1357 osmtpd_err(1, "strdup");
1360 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1361 if (f(&session->ctx, identity))
1362 session->status = SESSION_ERROR;
1366 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1367 char *params, char *linedup)
1370 enum osmtpd_status fcrdns;
1371 struct sockaddr_storage src, dst;
1372 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1373 struct sockaddr_storage *, struct sockaddr_storage *);
1375 if ((end = strchr(params, '|')) == NULL)
1376 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1381 if ((end = strchr(params, '|')) == NULL)
1382 osmtpd_errx(1, "Invalid line received: missing src: %s",
1385 if (strcmp(params, "pass") == 0)
1386 fcrdns = OSMTPD_STATUS_OK;
1387 else if (strcmp(params, "fail") == 0)
1388 fcrdns = OSMTPD_STATUS_PERMFAIL;
1389 else if (strcmp(params, "error") == 0)
1390 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1392 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1395 if ((end = strchr(params, '|')) == NULL)
1396 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1399 osmtpd_addrtoss(params, &src, 1, linedup);
1401 osmtpd_addrtoss(params, &dst, 1, linedup);
1402 if (cb->storereport) {
1403 if ((session->ctx.rdns = strdup(rdns)) == NULL)
1404 osmtpd_err(1, "strdup");
1405 session->ctx.fcrdns = fcrdns;
1406 memcpy(&session->ctx.src, &src, sizeof(session->ctx.src));
1407 memcpy(&session->ctx.dst, &dst, sizeof(session->ctx.dst));
1409 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1410 if (f(&session->ctx, rdns, fcrdns, &src, &dst))
1411 session->status = SESSION_ERROR;
1415 osmtpd_link_disconnect(struct osmtpd_callback *cb,
1416 struct osmtpd_session *session, __unused char *param,
1417 __unused char *linedup)
1419 int (*f)(struct osmtpd_ctx *);
1422 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1423 if (f(&session->ctx))
1424 session->status = SESSION_ERROR;
1426 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1427 if (ondeletecb_session != NULL && session->ctx.local_session != NULL)
1428 ondeletecb_session(&session->ctx, session->ctx.local_session);
1429 free(session->ctx.rdns);
1430 free(session->ctx.identity);
1431 free(session->ctx.greeting.identity);
1432 free(session->ctx.ciphers);
1433 free(session->ctx.username);
1434 free(session->ctx.mailfrom);
1435 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1436 free(session->ctx.rcptto[i]);
1437 free(session->ctx.rcptto);
1442 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_session *session,
1443 char *identity, __unused char *linedup)
1445 int (*f)(struct osmtpd_ctx *, const char *);
1447 if (cb->storereport) {
1448 free(session->ctx.greeting.identity);
1449 if ((session->ctx.greeting.identity = strdup(identity)) == NULL)
1450 osmtpd_err(1, NULL);
1453 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1454 if (f(&session->ctx, identity))
1455 session->status = SESSION_ERROR;
1459 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1460 char *identity, __unused char *linedup)
1462 int (*f)(struct osmtpd_ctx *, const char *);
1464 if (cb->storereport) {
1465 free(session->ctx.identity);
1466 if ((session->ctx.identity = strdup(identity)) == NULL)
1467 osmtpd_err(1, NULL);
1470 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1471 if (f(&session->ctx, identity))
1472 session->status = SESSION_ERROR;
1476 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_session *session,
1477 char *ciphers, __unused char *linedup)
1479 int (*f)(struct osmtpd_ctx *, const char *);
1481 if (cb->storereport) {
1482 if ((session->ctx.ciphers = strdup(ciphers)) == NULL)
1483 osmtpd_err(1, NULL);
1486 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1487 if (f(&session->ctx, ciphers))
1488 session->status = SESSION_ERROR;
1492 osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_session *session,
1493 char *username, char *linedup)
1495 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1497 enum osmtpd_auth_status s;
1499 if ((status = strrchr(username, '|')) == NULL)
1500 osmtpd_errx(1, "Invalid auth received: %s", linedup);
1503 if (strcmp(status, "pass") == 0)
1504 s = OSMTPD_AUTH_PASS;
1505 else if (strcmp(status, "fail") == 0)
1506 s = OSMTPD_AUTH_FAIL;
1507 else if (strcmp(status, "error") == 0)
1508 s = OSMTPD_AUTH_ERROR;
1510 osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1512 if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1513 if ((session->ctx.username = strdup(username)) == NULL)
1514 osmtpd_err(1, NULL);
1517 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1518 if (f(&session->ctx, username, s))
1519 session->status = SESSION_ERROR;
1523 osmtpd_tx_reset(struct osmtpd_callback *cb, struct osmtpd_session *session,
1524 char *params, char *linedup)
1527 unsigned long imsgid;
1530 int (*f)(struct osmtpd_ctx *, uint32_t);
1533 imsgid = strtoul(params, &end, 16);
1534 if ((imsgid == ULONG_MAX && errno != 0))
1535 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1538 osmtpd_errx(1, "Invalid line received: missing address: %s",
1541 if ((unsigned long) msgid != imsgid)
1542 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1545 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1546 if (f(&session->ctx, msgid))
1547 session->status = SESSION_ERROR;
1549 if (ondeletecb_message != NULL && session->ctx.local_message != NULL) {
1550 ondeletecb_message(&session->ctx, session->ctx.local_message);
1551 session->ctx.local_message = NULL;
1554 free(session->ctx.mailfrom);
1555 session->ctx.mailfrom = NULL;
1557 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1558 free(session->ctx.rcptto[i]);
1559 session->ctx.rcptto[0] = NULL;
1560 session->ctx.evpid = 0;
1561 session->ctx.msgid = 0;
1565 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_session *session,
1566 char *msgid, char *linedup)
1568 unsigned long imsgid;
1570 int (*f)(struct osmtpd_ctx *, uint32_t);
1573 imsgid = strtoul(msgid, &endptr, 16);
1574 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1575 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1577 session->ctx.msgid = imsgid;
1578 /* Check if we're in range */
1579 if ((unsigned long) session->ctx.msgid != imsgid)
1580 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1583 if (!cb->storereport)
1584 session->ctx.msgid = 0;
1586 if (oncreatecb_message != NULL) {
1587 session->ctx.local_message = oncreatecb_message(&session->ctx);
1588 if (session->ctx.local_message == NULL)
1589 session->status = SESSION_ERROR;
1592 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1593 if (f(&session->ctx, imsgid))
1594 session->status = SESSION_ERROR;
1598 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_session *session,
1599 char *params, char *linedup)
1601 char *end, *mailfrom;
1602 enum osmtpd_status status;
1603 unsigned long imsgid;
1605 int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1606 enum osmtpd_status);
1609 imsgid = strtoul(params, &end, 16);
1610 if ((imsgid == ULONG_MAX && errno != 0))
1611 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1614 osmtpd_errx(1, "Invalid line received: missing address: %s",
1617 if ((unsigned long) msgid != imsgid)
1618 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1622 if ((end = strchr(params, '|')) == NULL)
1623 osmtpd_errx(1, "Invalid line received: missing status: %s",
1626 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1628 status = osmtpd_strtostatus(end, linedup);
1631 status = osmtpd_strtostatus(params, linedup);
1633 if (cb->storereport) {
1634 if ((session->ctx.mailfrom = strdup(mailfrom)) == NULL)
1635 osmtpd_err(1, NULL);
1638 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1639 if (f(&session->ctx, msgid, mailfrom, status))
1640 session->status = SESSION_ERROR;
1644 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_session *session,
1645 char *params, char *linedup)
1648 enum osmtpd_status status;
1649 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",
1674 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1676 status = osmtpd_strtostatus(end, linedup);
1679 status = osmtpd_strtostatus(params, linedup);
1682 if (cb->storereport) {
1683 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1685 session->ctx.rcptto = reallocarray(session->ctx.rcptto, i + 2,
1686 sizeof(*session->ctx.rcptto));
1687 if (session->ctx.rcptto == NULL)
1688 osmtpd_err(1, NULL);
1690 if ((session->ctx.rcptto[i] = strdup(rcptto)) == NULL)
1691 osmtpd_err(1, NULL);
1692 session->ctx.rcptto[i + 1] = NULL;
1695 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1696 if (f(&session->ctx, msgid, rcptto, status))
1697 session->status = SESSION_ERROR;
1701 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_session *session,
1702 char *params, char *linedup)
1704 unsigned long imsgid;
1708 int (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1711 imsgid = strtoul(params, &end, 16);
1712 if ((imsgid == ULONG_MAX && errno != 0))
1713 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1716 osmtpd_errx(1, "Invalid line received: missing address: %s",
1719 if ((unsigned long) msgid != imsgid)
1720 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1724 evpid = strtoull(params, &end, 16);
1725 if ((session->ctx.evpid == ULLONG_MAX && errno != 0) || end[0] != '\0')
1726 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1728 if (cb->storereport)
1729 session->ctx.evpid = evpid;
1731 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1732 if (f(&session->ctx, msgid, evpid))
1733 session->status = SESSION_ERROR;
1737 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_session *session,
1738 char *params, char *linedup)
1741 unsigned long imsgid;
1743 int (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1746 imsgid = strtoul(params, &end, 16);
1747 if ((imsgid == ULONG_MAX && errno != 0))
1748 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1751 osmtpd_errx(1, "Invalid line received: missing address: %s",
1754 if ((unsigned long) msgid != imsgid)
1755 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1759 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1760 if (f(&session->ctx, msgid, osmtpd_strtostatus(params, linedup)))
1761 session->status = SESSION_ERROR;
1765 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_session *session,
1766 char *params, char *linedup)
1769 const char *errstr = NULL;
1770 unsigned long imsgid;
1773 int (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1776 imsgid = strtoul(params, &end, 16);
1777 if ((imsgid == ULONG_MAX && errno != 0))
1778 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1781 osmtpd_errx(1, "Invalid line received: missing address: %s",
1784 if ((unsigned long) msgid != imsgid)
1785 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1789 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1791 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1794 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1795 if (f(&session->ctx, msgid, msgsz))
1796 session->status = SESSION_ERROR;
1800 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_session *session,
1801 char *params, char *linedup)
1804 unsigned long imsgid;
1806 int (*f)(struct osmtpd_ctx *, uint32_t);
1809 imsgid = strtoul(params, &end, 16);
1810 if ((imsgid == ULONG_MAX && errno != 0))
1811 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1814 osmtpd_errx(1, "Invalid line received: missing address: %s",
1817 if ((unsigned long) msgid != imsgid)
1818 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1821 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1822 if (f(&session->ctx, msgid))
1823 session->status = SESSION_ERROR;
1827 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1829 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1831 if (session->status == SESSION_DISCONNECTED)
1834 if (ctx->version_major == 0 && ctx->version_minor < 5)
1835 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1836 "proceed\n", ctx->token, ctx->reqid);
1838 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1839 "proceed\n", ctx->reqid, ctx->token);
1843 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1845 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1848 if (session->status == SESSION_DISCONNECTED)
1851 if (code < 200 || code > 599)
1852 osmtpd_errx(1, "Invalid reject code");
1854 if (ctx->version_major == 0 && ctx->version_minor < 5)
1855 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1856 "reject|%d ", ctx->token, ctx->reqid, code);
1858 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1859 "reject|%d ", ctx->reqid, ctx->token, code);
1860 va_start(ap, reason);
1861 io_vprintf(io_stdout, reason, ap);
1863 io_printf(io_stdout, "\n");
1867 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1868 int subject, int detail, const char *reason, ...)
1870 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1873 if (session->status == SESSION_DISCONNECTED)
1876 if (code < 200 || code > 599)
1877 osmtpd_errx(1, "Invalid reject code");
1878 if (class < 2 || class > 5)
1879 osmtpd_errx(1, "Invalid enhanced status class");
1880 if (subject < 0 || subject > 999)
1881 osmtpd_errx(1, "Invalid enhanced status subject");
1882 if (detail < 0 || detail > 999)
1883 osmtpd_errx(1, "Invalid enhanced status detail");
1885 if (ctx->version_major == 0 && ctx->version_minor < 5)
1886 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1887 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1890 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1891 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1893 va_start(ap, reason);
1894 io_vprintf(io_stdout, reason, ap);
1896 io_printf(io_stdout, "\n");
1900 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1902 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1905 if (session->status == SESSION_DISCONNECTED)
1908 if (ctx->version_major == 0 && ctx->version_minor < 5)
1909 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1910 "disconnect|421 ", ctx->token, ctx->reqid);
1912 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1913 "disconnect|421 ", ctx->reqid, ctx->token);
1914 va_start(ap, reason);
1915 io_vprintf(io_stdout, reason, ap);
1917 io_printf(io_stdout, "\n");
1918 session->status = SESSION_DISCONNECTED;
1922 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1923 int detail, const char *reason, ...)
1925 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1928 if (session->status == SESSION_DISCONNECTED)
1931 if (class <= 2 || class >= 5)
1932 osmtpd_errx(1, "Invalid enhanced status class");
1933 if (subject < 0 || subject > 999)
1934 osmtpd_errx(1, "Invalid enhanced status subject");
1935 if (detail < 0 || detail > 999)
1936 osmtpd_errx(1, "Invalid enhanced status detail");
1937 if (ctx->version_major == 0 && ctx->version_minor < 5)
1938 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1939 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1942 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1943 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1945 va_start(ap, reason);
1946 io_vprintf(io_stdout, reason, ap);
1948 io_printf(io_stdout, "\n");
1949 session->status = SESSION_DISCONNECTED;
1953 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1955 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1958 if (session->status == SESSION_DISCONNECTED)
1961 if (ctx->version_major == 0 && ctx->version_minor < 5)
1962 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1963 "rewrite|", ctx->token, ctx->reqid);
1965 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1966 "rewrite|", ctx->reqid, ctx->token);
1967 va_start(ap, value);
1968 io_vprintf(io_stdout, value, ap);
1970 io_printf(io_stdout, "\n");
1974 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1976 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1979 if (session->status == SESSION_DISCONNECTED)
1982 if (ctx->version_major == 0 && ctx->version_minor < 5)
1983 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1984 ctx->token, ctx->reqid);
1986 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1987 ctx->reqid, ctx->token);
1989 io_vprintf(io_stdout, line, ap);
1991 io_printf(io_stdout, "\n");
1995 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1996 int storereport, void *cb)
2001 osmtpd_errx(1, "Can't register when proc is running");
2003 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
2004 if (type == osmtpd_callbacks[i].type &&
2005 phase == osmtpd_callbacks[i].phase &&
2006 incoming == osmtpd_callbacks[i].incoming) {
2007 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
2008 osmtpd_errx(1, "Event already registered");
2010 osmtpd_callbacks[i].cb = cb;
2011 osmtpd_callbacks[i].doregister = 1;
2013 osmtpd_callbacks[i].storereport = 1;
2018 osmtpd_errx(1, "Trying to register unknown event");
2021 static enum osmtpd_phase
2022 osmtpd_strtophase(const char *phase, const char *linedup)
2024 if (strcmp(phase, "connect") == 0)
2025 return OSMTPD_PHASE_CONNECT;
2026 if (strcmp(phase, "helo") == 0)
2027 return OSMTPD_PHASE_HELO;
2028 if (strcmp(phase, "ehlo") == 0)
2029 return OSMTPD_PHASE_EHLO;
2030 if (strcmp(phase, "starttls") == 0)
2031 return OSMTPD_PHASE_STARTTLS;
2032 if (strcmp(phase, "auth") == 0)
2033 return OSMTPD_PHASE_AUTH;
2034 if (strcmp(phase, "mail-from") == 0)
2035 return OSMTPD_PHASE_MAIL_FROM;
2036 if (strcmp(phase, "rcpt-to") == 0)
2037 return OSMTPD_PHASE_RCPT_TO;
2038 if (strcmp(phase, "data") == 0)
2039 return OSMTPD_PHASE_DATA;
2040 if (strcmp(phase, "data-line") == 0)
2041 return OSMTPD_PHASE_DATA_LINE;
2042 if (strcmp(phase, "rset") == 0)
2043 return OSMTPD_PHASE_RSET;
2044 if (strcmp(phase, "quit") == 0)
2045 return OSMTPD_PHASE_QUIT;
2046 if (strcmp(phase, "noop") == 0)
2047 return OSMTPD_PHASE_NOOP;
2048 if (strcmp(phase, "help") == 0)
2049 return OSMTPD_PHASE_HELP;
2050 if (strcmp(phase, "wiz") == 0)
2051 return OSMTPD_PHASE_WIZ;
2052 if (strcmp(phase, "commit") == 0)
2053 return OSMTPD_PHASE_COMMIT;
2054 if (strcmp(phase, "link-connect") == 0)
2055 return OSMTPD_PHASE_LINK_CONNECT;
2056 if (strcmp(phase, "link-disconnect") == 0)
2057 return OSMTPD_PHASE_LINK_DISCONNECT;
2058 if (strcmp(phase, "link-greeting") == 0)
2059 return OSMTPD_PHASE_LINK_GREETING;
2060 if (strcmp(phase, "link-identify") == 0)
2061 return OSMTPD_PHASE_LINK_IDENTIFY;
2062 if (strcmp(phase, "link-tls") == 0)
2063 return OSMTPD_PHASE_LINK_TLS;
2064 if (strcmp(phase, "link-auth") == 0)
2065 return OSMTPD_PHASE_LINK_AUTH;
2066 if (strcmp(phase, "tx-reset") == 0)
2067 return OSMTPD_PHASE_TX_RESET;
2068 if (strcmp(phase, "tx-begin") == 0)
2069 return OSMTPD_PHASE_TX_BEGIN;
2070 if (strcmp(phase, "tx-mail") == 0)
2071 return OSMTPD_PHASE_TX_MAIL;
2072 if (strcmp(phase, "tx-rcpt") == 0)
2073 return OSMTPD_PHASE_TX_RCPT;
2074 if (strcmp(phase, "tx-envelope") == 0)
2075 return OSMTPD_PHASE_TX_ENVELOPE;
2076 if (strcmp(phase, "tx-data") == 0)
2077 return OSMTPD_PHASE_TX_DATA;
2078 if (strcmp(phase, "tx-commit") == 0)
2079 return OSMTPD_PHASE_TX_COMMIT;
2080 if (strcmp(phase, "tx-rollback") == 0)
2081 return OSMTPD_PHASE_TX_ROLLBACK;
2082 if (strcmp(phase, "protocol-client") == 0)
2083 return OSMTPD_PHASE_PROTOCOL_CLIENT;
2084 if (strcmp(phase, "protocol-server") == 0)
2085 return OSMTPD_PHASE_PROTOCOL_SERVER;
2086 if (strcmp(phase, "filter-response") == 0)
2087 return OSMTPD_PHASE_FILTER_RESPONSE;
2088 if (strcmp(phase, "timeout") == 0)
2089 return OSMTPD_PHASE_TIMEOUT;
2090 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
2094 osmtpd_typetostr(enum osmtpd_type type)
2097 case OSMTPD_TYPE_FILTER:
2099 case OSMTPD_TYPE_REPORT:
2102 osmtpd_errx(1, "In valid type: %d\n", type);
2106 osmtpd_phasetostr(enum osmtpd_phase phase)
2109 case OSMTPD_PHASE_CONNECT:
2111 case OSMTPD_PHASE_HELO:
2113 case OSMTPD_PHASE_EHLO:
2115 case OSMTPD_PHASE_STARTTLS:
2117 case OSMTPD_PHASE_AUTH:
2119 case OSMTPD_PHASE_MAIL_FROM:
2121 case OSMTPD_PHASE_RCPT_TO:
2123 case OSMTPD_PHASE_DATA:
2125 case OSMTPD_PHASE_DATA_LINE:
2127 case OSMTPD_PHASE_RSET:
2129 case OSMTPD_PHASE_QUIT:
2131 case OSMTPD_PHASE_NOOP:
2133 case OSMTPD_PHASE_HELP:
2135 case OSMTPD_PHASE_WIZ:
2137 case OSMTPD_PHASE_COMMIT:
2139 case OSMTPD_PHASE_LINK_CONNECT:
2140 return "link-connect";
2141 case OSMTPD_PHASE_LINK_DISCONNECT:
2142 return "link-disconnect";
2143 case OSMTPD_PHASE_LINK_GREETING:
2144 return "link-greeting";
2145 case OSMTPD_PHASE_LINK_IDENTIFY:
2146 return "link-identify";
2147 case OSMTPD_PHASE_LINK_TLS:
2149 case OSMTPD_PHASE_LINK_AUTH:
2151 case OSMTPD_PHASE_TX_RESET:
2153 case OSMTPD_PHASE_TX_BEGIN:
2155 case OSMTPD_PHASE_TX_MAIL:
2157 case OSMTPD_PHASE_TX_RCPT:
2159 case OSMTPD_PHASE_TX_ENVELOPE:
2160 return "tx-envelope";
2161 case OSMTPD_PHASE_TX_DATA:
2163 case OSMTPD_PHASE_TX_COMMIT:
2165 case OSMTPD_PHASE_TX_ROLLBACK:
2166 return "tx-rollback";
2167 case OSMTPD_PHASE_PROTOCOL_CLIENT:
2168 return "protocol-client";
2169 case OSMTPD_PHASE_PROTOCOL_SERVER:
2170 return "protocol-server";
2171 case OSMTPD_PHASE_FILTER_RESPONSE:
2172 return "filter-response";
2173 case OSMTPD_PHASE_TIMEOUT:
2176 osmtpd_errx(1, "In valid phase: %d\n", phase);
2179 static enum osmtpd_status
2180 osmtpd_strtostatus(const char *status, char *linedup)
2182 if (strcmp(status, "ok") == 0)
2183 return OSMTPD_STATUS_OK;
2184 else if (strcmp(status, "tempfail") == 0)
2185 return OSMTPD_STATUS_TEMPFAIL;
2186 else if (strcmp(status, "permfail") == 0)
2187 return OSMTPD_STATUS_PERMFAIL;
2188 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2192 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2196 const char *errstr = NULL;
2197 struct sockaddr_in *sin;
2198 struct sockaddr_in6 *sin6;
2199 struct sockaddr_un *sun;
2202 if (addr[0] == '[') {
2203 sin6 = (struct sockaddr_in6 *)ss;
2204 sin6->sin6_family = AF_INET6;
2205 sin6->sin6_port = 0;
2207 if ((port = strrchr(addr, ':')) == NULL)
2208 osmtpd_errx(1, "Invalid line received: invalid "
2209 "address (%s): %s", addr, linedup);
2210 if (port[-1] != ']')
2211 osmtpd_errx(1, "Invalid line received: invalid "
2212 "address (%s): %s", addr, linedup);
2214 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2217 osmtpd_errx(1, "Invalid line received: invalid "
2218 "address (%s): %s", addr, linedup);
2222 if (addr[n - 1] != ']')
2223 osmtpd_errx(1, "Invalid line received: invalid "
2224 "address (%s): %s", addr, linedup);
2227 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2235 osmtpd_errx(1, "Invalid line received: invalid address "
2236 "(%s): %s", addr, linedup);
2242 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2245 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2246 sun = (struct sockaddr_un *)ss;
2247 sun->sun_family = AF_UNIX;
2248 if (strlcpy(sun->sun_path, addr,
2249 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2250 osmtpd_errx(1, "Invalid line received: address too "
2251 "long (%s): %s", addr, linedup);
2254 sin = (struct sockaddr_in *)ss;
2255 sin->sin_family = AF_INET;
2258 if ((port = strrchr(addr, ':')) == NULL)
2259 osmtpd_errx(1, "Invalid line received: invalid "
2260 "address (%s): %s", addr, linedup);
2262 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2265 osmtpd_errx(1, "Invalid line received: invalid "
2266 "address (%s): %s", addr, linedup);
2269 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2275 osmtpd_errx(1, "Invalid line received: invalid address "
2276 "(%s): %s", addr, linedup);
2280 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2287 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2289 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2292 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);