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 struct osmtpd_callback {
45 enum osmtpd_type type;
46 enum osmtpd_phase phase;
48 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_ctx *, char *,
55 struct osmtpd_session {
56 struct osmtpd_ctx ctx;
57 RB_ENTRY(osmtpd_session) entry;
60 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
62 static const char *osmtpd_typetostr(enum osmtpd_type);
63 static const char *osmtpd_phasetostr(enum osmtpd_phase);
64 static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
65 static void osmtpd_newline(struct io *, int, void *);
66 static void osmtpd_outevt(struct io *, int, void *);
67 static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_ctx *,
69 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_ctx *,
71 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
73 static void osmtpd_identify(struct osmtpd_callback *, struct osmtpd_ctx *,
75 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
77 static void osmtpd_link_disconnect(struct osmtpd_callback *,
78 struct osmtpd_ctx *, char *, char *);
79 static void osmtpd_link_greeting(struct osmtpd_callback *, struct osmtpd_ctx *,
81 static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_ctx *,
83 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_ctx *,
85 static void osmtpd_link_auth(struct osmtpd_callback *, struct osmtpd_ctx *,
87 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
89 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
91 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
93 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
95 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
97 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
99 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
101 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
102 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
103 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
104 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
105 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
106 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
107 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
108 static void (*conf_cb)(const char *, const char *);
110 static struct osmtpd_callback osmtpd_callbacks[] = {
113 OSMTPD_PHASE_CONNECT,
140 OSMTPD_PHASE_STARTTLS,
158 OSMTPD_PHASE_MAIL_FROM,
167 OSMTPD_PHASE_RCPT_TO,
185 OSMTPD_PHASE_DATA_LINE,
248 OSMTPD_PHASE_LINK_CONNECT,
257 OSMTPD_PHASE_LINK_DISCONNECT,
259 osmtpd_link_disconnect,
266 OSMTPD_PHASE_LINK_GREETING,
268 osmtpd_link_greeting,
275 OSMTPD_PHASE_LINK_IDENTIFY,
277 osmtpd_link_identify,
284 OSMTPD_PHASE_LINK_TLS,
293 OSMTPD_PHASE_LINK_AUTH,
302 OSMTPD_PHASE_TX_BEGIN,
311 OSMTPD_PHASE_TX_MAIL,
320 OSMTPD_PHASE_TX_RCPT,
329 OSMTPD_PHASE_TX_ENVELOPE,
338 OSMTPD_PHASE_TX_DATA,
347 OSMTPD_PHASE_TX_COMMIT,
356 OSMTPD_PHASE_TX_ROLLBACK,
365 OSMTPD_PHASE_PROTOCOL_CLIENT,
374 OSMTPD_PHASE_PROTOCOL_SERVER,
383 OSMTPD_PHASE_FILTER_RESPONSE,
392 OSMTPD_PHASE_TIMEOUT,
401 OSMTPD_PHASE_LINK_CONNECT,
410 OSMTPD_PHASE_LINK_DISCONNECT,
412 osmtpd_link_disconnect,
419 OSMTPD_PHASE_LINK_GREETING,
421 osmtpd_link_greeting,
428 OSMTPD_PHASE_LINK_IDENTIFY,
430 osmtpd_link_identify,
437 OSMTPD_PHASE_LINK_TLS,
446 OSMTPD_PHASE_LINK_AUTH,
455 OSMTPD_PHASE_TX_BEGIN,
464 OSMTPD_PHASE_TX_MAIL,
473 OSMTPD_PHASE_TX_RCPT,
482 OSMTPD_PHASE_TX_ENVELOPE,
491 OSMTPD_PHASE_TX_DATA,
500 OSMTPD_PHASE_TX_COMMIT,
509 OSMTPD_PHASE_TX_ROLLBACK,
518 OSMTPD_PHASE_PROTOCOL_CLIENT,
527 OSMTPD_PHASE_PROTOCOL_SERVER,
536 OSMTPD_PHASE_FILTER_RESPONSE,
545 OSMTPD_PHASE_TIMEOUT,
554 static struct io *io_stdout;
556 static int ready = 0;
557 /* Default from smtpd */
558 static int session_timeout = 300;
560 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
561 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
564 osmtpd_register_conf(void (*cb)(const char *, const char *))
570 osmtpd_register_filter_connect(void (*cb)(struct osmtpd_ctx *, const char *,
571 struct sockaddr_storage *))
573 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
575 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
580 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
582 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
584 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
589 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
591 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
593 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
598 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
600 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
602 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
607 osmtpd_register_filter_auth(void (*cb)(struct osmtpd_ctx *, const char *))
609 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
611 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
616 osmtpd_register_filter_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
618 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
620 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
625 osmtpd_register_filter_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
627 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
629 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
634 osmtpd_register_filter_data(void (*cb)(struct osmtpd_ctx *))
636 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
638 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
643 osmtpd_register_filter_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
645 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
647 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
652 osmtpd_register_filter_rset(void (*cb)(struct osmtpd_ctx *))
654 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
656 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
661 osmtpd_register_filter_quit(void (*cb)(struct osmtpd_ctx *))
663 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
665 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
670 osmtpd_register_filter_noop(void (*cb)(struct osmtpd_ctx *))
672 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
674 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
679 osmtpd_register_filter_help(void (*cb)(struct osmtpd_ctx *))
681 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
683 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
688 osmtpd_register_filter_wiz(void (*cb)(struct osmtpd_ctx *))
690 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
692 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
697 osmtpd_register_filter_commit(void (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
701 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
706 osmtpd_register_report_connect(int incoming, void (*cb)(struct osmtpd_ctx *,
707 const char *, enum osmtpd_status, struct sockaddr_storage *,
708 struct sockaddr_storage *))
710 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
712 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
717 osmtpd_register_report_disconnect(int incoming, void (*cb)(struct osmtpd_ctx *))
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
720 incoming, 0, (void *)cb);
724 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
727 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
728 incoming, 0, (void *)cb);
729 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
734 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
739 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
744 osmtpd_register_report_auth(int incoming, void (*cb)(struct osmtpd_ctx *,
745 const char *, enum osmtpd_auth_status))
747 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, incoming, 0,
749 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
754 osmtpd_register_report_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
757 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
759 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
764 osmtpd_register_report_mail(int incoming, void (*cb)(struct osmtpd_ctx *,
765 uint32_t, const char *, enum osmtpd_status))
767 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
769 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
774 osmtpd_register_report_rcpt(int incoming, void (*cb)(struct osmtpd_ctx *,
775 uint32_t, const char *, enum osmtpd_status))
777 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
779 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
784 osmtpd_register_report_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
787 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
789 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
794 osmtpd_register_report_data(int incoming, void (*cb)(struct osmtpd_ctx *,
795 uint32_t, enum osmtpd_status))
797 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
799 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
804 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
807 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
809 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
814 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
817 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
819 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
824 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
827 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
828 incoming, 0, (void *)cb);
829 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
834 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
837 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
838 incoming, 0, (void *)cb);
839 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
844 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
847 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
848 incoming, 0, (void *)cb);
849 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
854 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
856 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
858 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
863 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
864 void (*ondelete)(struct osmtpd_ctx *, void *))
866 oncreatecb_session = oncreate;
867 ondeletecb_session = ondelete;
871 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
872 void (*ondelete)(struct osmtpd_ctx *, void *))
874 oncreatecb_message = oncreate;
875 ondeletecb_message = ondelete;
879 osmtpd_need(int lneeds)
885 osmtpd_register_need(int incoming)
887 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
889 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
891 if (needs & OSMTPD_NEED_GREETING)
892 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
894 if (needs & OSMTPD_NEED_IDENTITY)
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
897 if (needs & OSMTPD_NEED_CIPHERS)
898 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
900 if (needs & OSMTPD_NEED_USERNAME)
901 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
903 if (needs & OSMTPD_NEED_MSGID) {
904 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
906 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
908 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
911 if (needs & OSMTPD_NEED_MAILFROM) {
912 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
914 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
916 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
919 if (needs & OSMTPD_NEED_RCPTTO) {
920 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
922 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
924 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
927 if (needs & OSMTPD_NEED_EVPID) {
928 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
930 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
932 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
936 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
945 struct event_base *evbase;
947 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
948 struct osmtpd_callback *ridentity = NULL;
950 evbase = event_init();
952 if ((io_stdin = io_new()) == NULL ||
953 (io_stdout = io_new()) == NULL)
954 osmtpd_err(1, "io_new");
955 io_set_nonblocking(STDIN_FILENO);
956 io_set_fd(io_stdin, STDIN_FILENO);
957 io_set_callback(io_stdin, osmtpd_newline, NULL);
958 io_set_read(io_stdin);
959 io_set_nonblocking(STDOUT_FILENO);
960 io_set_fd(io_stdout, STDOUT_FILENO);
961 io_set_callback(io_stdout, osmtpd_outevt, NULL);
962 io_set_write(io_stdout);
964 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
965 if (osmtpd_callbacks[i].doregister) {
966 osmtpd_register_need(osmtpd_callbacks[i].incoming);
967 if (oncreatecb_message != NULL) {
968 osmtpd_register(OSMTPD_TYPE_REPORT,
969 OSMTPD_PHASE_TX_BEGIN,
970 osmtpd_callbacks[i].incoming, 0, NULL);
971 osmtpd_register(OSMTPD_TYPE_REPORT,
972 OSMTPD_PHASE_TX_ROLLBACK,
973 osmtpd_callbacks[i].incoming, 0, NULL);
974 osmtpd_register(OSMTPD_TYPE_REPORT,
975 OSMTPD_PHASE_TX_COMMIT,
976 osmtpd_callbacks[i].incoming, 0, NULL);
978 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
979 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
980 hidenity = &(osmtpd_callbacks[i]);
981 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
982 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
983 eidentity = &(osmtpd_callbacks[i]);
984 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
985 osmtpd_callbacks[i].phase ==
986 OSMTPD_PHASE_LINK_IDENTIFY &&
987 osmtpd_callbacks[i].incoming == 1)
988 ridentity = &(osmtpd_callbacks[i]);
991 if (ridentity != NULL && ridentity->storereport) {
992 if (hidenity != NULL && hidenity->doregister)
993 hidenity->storereport = 1;
994 if (eidentity != NULL && eidentity->doregister)
995 eidentity->storereport = 1;
997 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
998 if (osmtpd_callbacks[i].doregister) {
999 if (osmtpd_callbacks[i].cb != NULL)
1001 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1002 osmtpd_typetostr(osmtpd_callbacks[i].type),
1003 osmtpd_callbacks[i].incoming ? "in" : "out",
1004 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1009 osmtpd_errx(1, "No events registered");
1010 io_printf(io_stdout, "register|ready\n");
1016 event_base_free(evbase);
1020 osmtpd_err(int eval, const char *fmt, ...)
1025 vfprintf(stderr, fmt, ap);
1027 fprintf(stderr, ": %s\n", strerror(errno));
1032 osmtpd_errx(int eval, const char *fmt, ...)
1037 vfprintf(stderr, fmt, ap);
1039 fprintf(stderr, "\n");
1044 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1046 static char *linedup = NULL;
1047 static size_t dupsize = 0;
1048 struct osmtpd_session *ctx, search;
1049 enum osmtpd_type type;
1050 enum osmtpd_phase phase;
1051 int version_major, version_minor, incoming;
1054 const char *errstr = NULL;
1059 if (ev == IO_DISCONNECTED) {
1063 if (ev != IO_DATAIN)
1066 * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1067 * cause a build-up of kevents, because of event_add/event_del loop.
1069 io_pause(io_stdout, IO_OUT);
1070 while ((line = io_getline(io, &linelen)) != NULL) {
1071 if (dupsize < linelen) {
1072 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1073 osmtpd_err(1, NULL);
1074 dupsize = linelen + 1;
1076 strlcpy(linedup, line, dupsize);
1077 if ((end = strchr(line, '|')) == NULL)
1078 osmtpd_errx(1, "Invalid line received: missing "
1079 "version: %s", linedup);
1081 if (strcmp(line, "filter") == 0)
1082 type = OSMTPD_TYPE_FILTER;
1083 else if (strcmp(line, "report") == 0)
1084 type = OSMTPD_TYPE_REPORT;
1085 else if (strcmp(line, "config") == 0) {
1087 if (strcmp(line, "ready") == 0) {
1088 if (conf_cb != NULL)
1089 conf_cb(NULL, NULL);
1092 if ((end = strchr(line, '|')) == NULL)
1093 osmtpd_errx(1, "Invalid line received: missing "
1094 "key: %s", linedup);
1096 if (conf_cb != NULL)
1098 if (strcmp(line, "smtp-session-timeout") == 0) {
1099 session_timeout = strtonum(end, 0, INT_MAX,
1102 osmtpd_errx(1, "Invalid line received: "
1103 "invalid smtp-sesion-timeout: %s",
1109 osmtpd_errx(1, "Invalid line received: unknown message "
1110 "type: %s", linedup);
1112 version_major = strtoul(line, &end, 10);
1113 if (line == end || end[0] != '.')
1114 osmtpd_errx(1, "Invalid protocol received: %s",
1117 version_minor = strtoul(line, &end, 10);
1119 osmtpd_errx(1, "Invalid line received: missing time: "
1121 if (line == end || end[0] != '|')
1122 osmtpd_errx(1, "Invalid protocol received: %s",
1124 if (version_major != 0)
1125 osmtpd_errx(1, "Unsupported protocol received: %s",
1128 if ((end = strchr(line, '.')) == NULL)
1129 osmtpd_errx(1, "Invalid line received: invalid "
1130 "timestamp: %s", linedup);
1132 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1134 osmtpd_errx(1, "Invalid line received: invalid "
1135 "timestamp: %s", linedup);
1137 if ((end = strchr(line, '|')) == NULL)
1138 osmtpd_errx(1, "Invalid line received: missing "
1139 "direction: %s", linedup);
1141 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1143 osmtpd_errx(1, "Invalid line received: invalid "
1144 "timestamp: %s", linedup);
1145 tm.tv_nsec *= 10 * (9 - (end - line));
1147 if ((end = strchr(line, '|')) == NULL)
1148 osmtpd_errx(1, "Invalid line received: missing "
1149 "phase: %s", linedup);
1151 if (strcmp(line, "smtp-in") == 0)
1153 else if (strcmp(line, "smtp-out") == 0)
1156 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1159 if ((end = strchr(line, '|')) == NULL)
1160 osmtpd_errx(1, "Invalid line received: missing reqid: "
1163 phase = osmtpd_strtophase(line, linedup);
1166 search.ctx.reqid = strtoull(line, &end, 16);
1167 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1168 (end[0] != '|' && end[0] != '\0'))
1169 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1172 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1174 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1175 osmtpd_err(1, NULL);
1176 ctx->ctx.reqid = search.ctx.reqid;
1177 ctx->ctx.rdns = NULL;
1178 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1179 ctx->ctx.identity = NULL;
1180 ctx->ctx.greeting.identity = NULL;
1181 ctx->ctx.ciphers = NULL;
1183 ctx->ctx.username = NULL;
1184 ctx->ctx.mailfrom = NULL;
1185 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1186 if (ctx->ctx.rcptto == NULL)
1187 osmtpd_err(1, "malloc");
1188 ctx->ctx.rcptto[0] = NULL;
1189 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1190 ctx->ctx.src.ss_family = AF_UNSPEC;
1191 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1192 ctx->ctx.dst.ss_family = AF_UNSPEC;
1193 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1195 ctx->ctx.local_session = NULL;
1196 ctx->ctx.local_message = NULL;
1197 if (oncreatecb_session != NULL)
1198 ctx->ctx.local_session =
1199 oncreatecb_session(&ctx->ctx);
1201 ctx->ctx.type = type;
1202 ctx->ctx.phase = phase;
1203 ctx->ctx.version_major = version_major;
1204 ctx->ctx.version_minor = version_minor;
1205 ctx->ctx.incoming = incoming;
1206 ctx->ctx.tm.tv_sec = tm.tv_sec;
1207 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1210 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1211 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1212 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1213 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1216 if (i == NITEMS(osmtpd_callbacks)) {
1217 osmtpd_errx(1, "Invalid line received: received "
1218 "unregistered line: %s", linedup);
1220 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1221 ctx->ctx.token = strtoull(line, &end, 16);
1222 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1224 osmtpd_errx(1, "Invalid line received: invalid "
1225 "token: %s", linedup);
1228 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1229 &(ctx->ctx), line, linedup);
1231 io_resume(io_stdout, IO_OUT);
1235 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1240 case IO_DISCONNECTED:
1243 osmtpd_errx(1, "Unexpectd event");
1248 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1249 __unused char *params, __unused char *linedup)
1251 void (*f)(struct osmtpd_ctx *);
1258 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1259 __unused char *linedup)
1261 void (*f)(struct osmtpd_ctx *, const char *);
1268 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1271 struct sockaddr_storage ss;
1274 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1277 if ((address = strchr(params, '|')) == NULL)
1278 osmtpd_errx(1, "Invalid line received: missing address: %s",
1280 address++[0] = '\0';
1282 osmtpd_addrtoss(address, &ss, 0, linedup);
1285 f(ctx, hostname, &ss);
1289 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1290 char *identity, __unused char *linedup)
1292 void (*f)(struct osmtpd_ctx *, const char *);
1294 if (cb->storereport) {
1295 free(ctx->identity);
1296 if ((ctx->identity = strdup(identity)) == NULL)
1297 osmtpd_err(1, "strdup");
1305 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1306 char *params, char *linedup)
1309 enum osmtpd_status fcrdns;
1310 struct sockaddr_storage src, dst;
1311 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1312 struct sockaddr_storage *, struct sockaddr_storage *);
1314 if ((end = strchr(params, '|')) == NULL)
1315 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1320 if ((end = strchr(params, '|')) == NULL)
1321 osmtpd_errx(1, "Invalid line received: missing src: %s",
1324 if (strcmp(params, "pass") == 0)
1325 fcrdns = OSMTPD_STATUS_OK;
1326 else if (strcmp(params, "fail") == 0)
1327 fcrdns = OSMTPD_STATUS_PERMFAIL;
1328 else if (strcmp(params, "error") == 0)
1329 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1331 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1334 if ((end = strchr(params, '|')) == NULL)
1335 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1338 osmtpd_addrtoss(params, &src, 1, linedup);
1340 osmtpd_addrtoss(params, &dst, 1, linedup);
1341 if (cb->storereport) {
1342 if ((ctx->rdns = strdup(rdns)) == NULL)
1343 osmtpd_err(1, "strdup");
1344 ctx->fcrdns = fcrdns;
1345 memcpy(&(ctx->src), &src, sizeof(ctx->src));
1346 memcpy(&(ctx->dst), &dst, sizeof(ctx->dst));
1348 if ((f = cb->cb) != NULL)
1349 f(ctx, rdns, fcrdns, &src, &dst);
1353 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1354 __unused char *param, __unused char *linedup)
1356 void (*f)(struct osmtpd_ctx *);
1358 struct osmtpd_session *session, search;
1360 if ((f = cb->cb) != NULL)
1363 search.ctx.reqid = ctx->reqid;
1364 session = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1365 if (session != NULL) {
1366 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1367 if (ondeletecb_session != NULL)
1368 ondeletecb_session(ctx, session->ctx.local_session);
1369 free(session->ctx.rdns);
1370 free(session->ctx.identity);
1371 free(session->ctx.greeting.identity);
1372 free(session->ctx.ciphers);
1373 free(session->ctx.username);
1374 free(session->ctx.mailfrom);
1375 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1376 free(session->ctx.rcptto[i]);
1377 free(session->ctx.rcptto);
1383 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1384 char *identity, __unused char *linedup)
1386 void (*f)(struct osmtpd_ctx *, const char *);
1388 if (cb->storereport) {
1389 free(ctx->greeting.identity);
1390 if ((ctx->greeting.identity = strdup(identity)) == NULL)
1391 osmtpd_err(1, NULL);
1394 if ((f = cb->cb) != NULL)
1399 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1400 char *identity, __unused char *linedup)
1402 void (*f)(struct osmtpd_ctx *, const char *);
1404 if (cb->storereport) {
1405 free(ctx->identity);
1406 if ((ctx->identity = strdup(identity)) == NULL)
1407 osmtpd_err(1, NULL);
1410 if ((f = cb->cb) != NULL)
1415 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1416 char *ciphers, __unused char *linedup)
1418 void (*f)(struct osmtpd_ctx *, const char *);
1420 if (cb->storereport) {
1421 if ((ctx->ciphers = strdup(ciphers)) == NULL)
1422 osmtpd_err(1, NULL);
1425 if ((f = cb->cb) != NULL)
1430 osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1431 char *username, char *linedup)
1433 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1435 enum osmtpd_auth_status s;
1437 if ((status = strrchr(username, '|')) == NULL)
1438 osmtpd_errx(1, "Invalid auth received: %s", linedup);
1441 if (strcmp(status, "pass") == 0)
1442 s = OSMTPD_AUTH_PASS;
1443 else if (strcmp(status, "fail") == 0)
1444 s = OSMTPD_AUTH_FAIL;
1445 else if (strcmp(status, "error") == 0)
1446 s = OSMTPD_AUTH_ERROR;
1448 osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1450 if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1451 if ((ctx->username = strdup(username)) == NULL)
1452 osmtpd_err(1, NULL);
1455 if ((f = cb->cb) != NULL)
1456 f(ctx, username, s);
1460 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1461 char *msgid, char *linedup)
1463 unsigned long imsgid;
1465 void (*f)(struct osmtpd_ctx *, uint32_t);
1468 imsgid = strtoul(msgid, &endptr, 16);
1469 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1470 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1472 ctx->msgid = imsgid;
1473 /* Check if we're in range */
1474 if ((unsigned long) ctx->msgid != imsgid)
1475 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1478 if (!cb->storereport)
1481 if (oncreatecb_message != NULL)
1482 ctx->local_message = oncreatecb_message(ctx);
1484 if ((f = cb->cb) != NULL)
1489 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1490 char *params, char *linedup)
1492 char *end, *mailfrom;
1493 enum osmtpd_status status;
1494 unsigned long imsgid;
1496 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1497 enum osmtpd_status);
1500 imsgid = strtoul(params, &end, 16);
1501 if ((imsgid == ULONG_MAX && errno != 0))
1502 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1505 osmtpd_errx(1, "Invalid line received: missing address: %s",
1508 if ((unsigned long) msgid != imsgid)
1509 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1513 if ((end = strchr(params, '|')) == NULL)
1514 osmtpd_errx(1, "Invalid line received: missing status: %s",
1517 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1519 status = osmtpd_strtostatus(end, linedup);
1522 status = osmtpd_strtostatus(params, linedup);
1524 if (cb->storereport) {
1525 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1526 osmtpd_err(1, NULL);
1529 if ((f = cb->cb) != NULL)
1530 f(ctx, msgid, mailfrom, status);
1534 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1535 char *params, char *linedup)
1538 enum osmtpd_status status;
1539 unsigned long imsgid;
1542 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1543 enum osmtpd_status);
1546 imsgid = strtoul(params, &end, 16);
1547 if ((imsgid == ULONG_MAX && errno != 0))
1548 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1551 osmtpd_errx(1, "Invalid line received: missing address: %s",
1554 if ((unsigned long) msgid != imsgid)
1555 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1559 if ((end = strchr(params, '|')) == NULL)
1560 osmtpd_errx(1, "Invalid line received: missing status: %s",
1564 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1566 status = osmtpd_strtostatus(end, linedup);
1569 status = osmtpd_strtostatus(params, linedup);
1572 if (cb->storereport) {
1573 for (i = 0; ctx->rcptto[i] != NULL; i++)
1575 ctx->rcptto = reallocarray(ctx->rcptto, i + 2,
1576 sizeof(*(ctx->rcptto)));
1577 if (ctx->rcptto == NULL)
1578 osmtpd_err(1, NULL);
1580 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1581 osmtpd_err(1, NULL);
1582 ctx->rcptto[i + 1] = NULL;
1585 if ((f = cb->cb) != NULL)
1586 f(ctx, msgid, rcptto, status);
1590 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1591 char *params, char *linedup)
1593 unsigned long imsgid;
1597 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1600 imsgid = strtoul(params, &end, 16);
1601 if ((imsgid == ULONG_MAX && errno != 0))
1602 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1605 osmtpd_errx(1, "Invalid line received: missing address: %s",
1608 if ((unsigned long) msgid != imsgid)
1609 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1613 evpid = strtoull(params, &end, 16);
1614 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1616 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1618 if (cb->storereport)
1621 if ((f = cb->cb) != NULL)
1622 f(ctx, msgid, evpid);
1626 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1627 char *params, char *linedup)
1630 unsigned long imsgid;
1632 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1635 imsgid = strtoul(params, &end, 16);
1636 if ((imsgid == ULONG_MAX && errno != 0))
1637 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1640 osmtpd_errx(1, "Invalid line received: missing address: %s",
1643 if ((unsigned long) msgid != imsgid)
1644 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1648 if ((f = cb->cb) != NULL)
1649 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1653 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1654 char *params, char *linedup)
1657 const char *errstr = NULL;
1658 unsigned long imsgid;
1661 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1664 imsgid = strtoul(params, &end, 16);
1665 if ((imsgid == ULONG_MAX && errno != 0))
1666 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1669 osmtpd_errx(1, "Invalid line received: missing address: %s",
1672 if ((unsigned long) msgid != imsgid)
1673 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1677 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1679 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1682 if ((f = cb->cb) != NULL)
1683 f(ctx, msgid, msgsz);
1685 if (ondeletecb_message != NULL) {
1686 ondeletecb_message(ctx, ctx->local_message);
1687 ctx->local_message = NULL;
1690 free(ctx->mailfrom);
1691 ctx->mailfrom = NULL;
1693 for (i = 0; ctx->rcptto[i] != NULL; i++)
1694 free(ctx->rcptto[i]);
1695 ctx->rcptto[0] = NULL;
1701 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1702 char *params, char *linedup)
1705 unsigned long imsgid;
1708 void (*f)(struct osmtpd_ctx *, uint32_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",
1723 if ((f = cb->cb) != NULL)
1726 if (ondeletecb_message != NULL) {
1727 ondeletecb_message(ctx, ctx->local_message);
1728 ctx->local_message = NULL;
1731 free(ctx->mailfrom);
1732 ctx->mailfrom = NULL;
1734 for (i = 0; ctx->rcptto[i] != NULL; i++)
1735 free(ctx->rcptto[i]);
1736 ctx->rcptto[0] = NULL;
1742 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1744 if (ctx->version_major == 0 && ctx->version_minor < 5)
1745 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1746 "proceed\n", ctx->token, ctx->reqid);
1748 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1749 "proceed\n", ctx->reqid, ctx->token);
1753 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1757 if (code < 200 || code > 599)
1758 osmtpd_errx(1, "Invalid reject code");
1760 if (ctx->version_major == 0 && ctx->version_minor < 5)
1761 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1762 "reject|%d ", ctx->token, ctx->reqid, code);
1764 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1765 "reject|%d ", ctx->reqid, ctx->token, code);
1766 va_start(ap, reason);
1767 io_vprintf(io_stdout, reason, ap);
1769 io_printf(io_stdout, "\n");
1773 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1774 int subject, int detail, const char *reason, ...)
1778 if (code < 200 || code > 599)
1779 osmtpd_errx(1, "Invalid reject code");
1780 if (class < 2 || class > 5)
1781 osmtpd_errx(1, "Invalid enhanced status class");
1782 if (subject < 0 || subject > 999)
1783 osmtpd_errx(1, "Invalid enhanced status subject");
1784 if (detail < 0 || detail > 999)
1785 osmtpd_errx(1, "Invalid enhanced status detail");
1787 if (ctx->version_major == 0 && ctx->version_minor < 5)
1788 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1789 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1792 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1793 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1795 va_start(ap, reason);
1796 io_vprintf(io_stdout, reason, ap);
1798 io_printf(io_stdout, "\n");
1802 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1806 if (ctx->version_major == 0 && ctx->version_minor < 5)
1807 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1808 "disconnect|421 ", ctx->token, ctx->reqid);
1810 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1811 "disconnect|421 ", ctx->reqid, ctx->token);
1812 va_start(ap, reason);
1813 io_vprintf(io_stdout, reason, ap);
1815 io_printf(io_stdout, "\n");
1819 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1820 int detail, const char *reason, ...)
1824 if (class <= 2 || class >= 5)
1825 osmtpd_errx(1, "Invalid enhanced status class");
1826 if (subject < 0 || subject > 999)
1827 osmtpd_errx(1, "Invalid enhanced status subject");
1828 if (detail < 0 || detail > 999)
1829 osmtpd_errx(1, "Invalid enhanced status detail");
1830 if (ctx->version_major == 0 && ctx->version_minor < 5)
1831 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1832 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1835 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1836 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1838 va_start(ap, reason);
1839 io_vprintf(io_stdout, reason, ap);
1841 io_printf(io_stdout, "\n");
1845 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1849 if (ctx->version_major == 0 && ctx->version_minor < 5)
1850 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1851 "rewrite|", ctx->token, ctx->reqid);
1853 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1854 "rewrite|", ctx->reqid, ctx->token);
1855 va_start(ap, value);
1856 io_vprintf(io_stdout, value, ap);
1858 io_printf(io_stdout, "\n");
1862 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1866 if (ctx->version_major == 0 && ctx->version_minor < 5)
1867 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1868 ctx->token, ctx->reqid);
1870 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1871 ctx->reqid, ctx->token);
1873 io_vprintf(io_stdout, line, ap);
1875 io_printf(io_stdout, "\n");
1879 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1880 int storereport, void *cb)
1885 osmtpd_errx(1, "Can't register when proc is running");
1887 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1888 if (type == osmtpd_callbacks[i].type &&
1889 phase == osmtpd_callbacks[i].phase &&
1890 incoming == osmtpd_callbacks[i].incoming) {
1891 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
1892 osmtpd_errx(1, "Event already registered");
1894 osmtpd_callbacks[i].cb = cb;
1895 osmtpd_callbacks[i].doregister = 1;
1897 osmtpd_callbacks[i].storereport = 1;
1902 osmtpd_errx(1, "Trying to register unknown event");
1905 static enum osmtpd_phase
1906 osmtpd_strtophase(const char *phase, const char *linedup)
1908 if (strcmp(phase, "connect") == 0)
1909 return OSMTPD_PHASE_CONNECT;
1910 if (strcmp(phase, "helo") == 0)
1911 return OSMTPD_PHASE_HELO;
1912 if (strcmp(phase, "ehlo") == 0)
1913 return OSMTPD_PHASE_EHLO;
1914 if (strcmp(phase, "starttls") == 0)
1915 return OSMTPD_PHASE_STARTTLS;
1916 if (strcmp(phase, "auth") == 0)
1917 return OSMTPD_PHASE_AUTH;
1918 if (strcmp(phase, "mail-from") == 0)
1919 return OSMTPD_PHASE_MAIL_FROM;
1920 if (strcmp(phase, "rcpt-to") == 0)
1921 return OSMTPD_PHASE_RCPT_TO;
1922 if (strcmp(phase, "data") == 0)
1923 return OSMTPD_PHASE_DATA;
1924 if (strcmp(phase, "data-line") == 0)
1925 return OSMTPD_PHASE_DATA_LINE;
1926 if (strcmp(phase, "rset") == 0)
1927 return OSMTPD_PHASE_RSET;
1928 if (strcmp(phase, "quit") == 0)
1929 return OSMTPD_PHASE_QUIT;
1930 if (strcmp(phase, "noop") == 0)
1931 return OSMTPD_PHASE_NOOP;
1932 if (strcmp(phase, "help") == 0)
1933 return OSMTPD_PHASE_HELP;
1934 if (strcmp(phase, "wiz") == 0)
1935 return OSMTPD_PHASE_WIZ;
1936 if (strcmp(phase, "commit") == 0)
1937 return OSMTPD_PHASE_COMMIT;
1938 if (strcmp(phase, "link-connect") == 0)
1939 return OSMTPD_PHASE_LINK_CONNECT;
1940 if (strcmp(phase, "link-disconnect") == 0)
1941 return OSMTPD_PHASE_LINK_DISCONNECT;
1942 if (strcmp(phase, "link-greeting") == 0)
1943 return OSMTPD_PHASE_LINK_GREETING;
1944 if (strcmp(phase, "link-identify") == 0)
1945 return OSMTPD_PHASE_LINK_IDENTIFY;
1946 if (strcmp(phase, "link-tls") == 0)
1947 return OSMTPD_PHASE_LINK_TLS;
1948 if (strcmp(phase, "link-auth") == 0)
1949 return OSMTPD_PHASE_LINK_AUTH;
1950 if (strcmp(phase, "tx-begin") == 0)
1951 return OSMTPD_PHASE_TX_BEGIN;
1952 if (strcmp(phase, "tx-mail") == 0)
1953 return OSMTPD_PHASE_TX_MAIL;
1954 if (strcmp(phase, "tx-rcpt") == 0)
1955 return OSMTPD_PHASE_TX_RCPT;
1956 if (strcmp(phase, "tx-envelope") == 0)
1957 return OSMTPD_PHASE_TX_ENVELOPE;
1958 if (strcmp(phase, "tx-data") == 0)
1959 return OSMTPD_PHASE_TX_DATA;
1960 if (strcmp(phase, "tx-commit") == 0)
1961 return OSMTPD_PHASE_TX_COMMIT;
1962 if (strcmp(phase, "tx-rollback") == 0)
1963 return OSMTPD_PHASE_TX_ROLLBACK;
1964 if (strcmp(phase, "protocol-client") == 0)
1965 return OSMTPD_PHASE_PROTOCOL_CLIENT;
1966 if (strcmp(phase, "protocol-server") == 0)
1967 return OSMTPD_PHASE_PROTOCOL_SERVER;
1968 if (strcmp(phase, "filter-response") == 0)
1969 return OSMTPD_PHASE_FILTER_RESPONSE;
1970 if (strcmp(phase, "timeout") == 0)
1971 return OSMTPD_PHASE_TIMEOUT;
1972 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
1976 osmtpd_typetostr(enum osmtpd_type type)
1979 case OSMTPD_TYPE_FILTER:
1981 case OSMTPD_TYPE_REPORT:
1984 osmtpd_errx(1, "In valid type: %d\n", type);
1988 osmtpd_phasetostr(enum osmtpd_phase phase)
1991 case OSMTPD_PHASE_CONNECT:
1993 case OSMTPD_PHASE_HELO:
1995 case OSMTPD_PHASE_EHLO:
1997 case OSMTPD_PHASE_STARTTLS:
1999 case OSMTPD_PHASE_AUTH:
2001 case OSMTPD_PHASE_MAIL_FROM:
2003 case OSMTPD_PHASE_RCPT_TO:
2005 case OSMTPD_PHASE_DATA:
2007 case OSMTPD_PHASE_DATA_LINE:
2009 case OSMTPD_PHASE_RSET:
2011 case OSMTPD_PHASE_QUIT:
2013 case OSMTPD_PHASE_NOOP:
2015 case OSMTPD_PHASE_HELP:
2017 case OSMTPD_PHASE_WIZ:
2019 case OSMTPD_PHASE_COMMIT:
2021 case OSMTPD_PHASE_LINK_CONNECT:
2022 return "link-connect";
2023 case OSMTPD_PHASE_LINK_DISCONNECT:
2024 return "link-disconnect";
2025 case OSMTPD_PHASE_LINK_GREETING:
2026 return "link-greeting";
2027 case OSMTPD_PHASE_LINK_IDENTIFY:
2028 return "link-identify";
2029 case OSMTPD_PHASE_LINK_TLS:
2031 case OSMTPD_PHASE_LINK_AUTH:
2033 case OSMTPD_PHASE_TX_BEGIN:
2035 case OSMTPD_PHASE_TX_MAIL:
2037 case OSMTPD_PHASE_TX_RCPT:
2039 case OSMTPD_PHASE_TX_ENVELOPE:
2040 return "tx-envelope";
2041 case OSMTPD_PHASE_TX_DATA:
2043 case OSMTPD_PHASE_TX_COMMIT:
2045 case OSMTPD_PHASE_TX_ROLLBACK:
2046 return "tx-rollback";
2047 case OSMTPD_PHASE_PROTOCOL_CLIENT:
2048 return "protocol-client";
2049 case OSMTPD_PHASE_PROTOCOL_SERVER:
2050 return "protocol-server";
2051 case OSMTPD_PHASE_FILTER_RESPONSE:
2052 return "filter-response";
2053 case OSMTPD_PHASE_TIMEOUT:
2056 osmtpd_errx(1, "In valid phase: %d\n", phase);
2059 static enum osmtpd_status
2060 osmtpd_strtostatus(const char *status, char *linedup)
2062 if (strcmp(status, "ok") == 0)
2063 return OSMTPD_STATUS_OK;
2064 else if (strcmp(status, "tempfail") == 0)
2065 return OSMTPD_STATUS_TEMPFAIL;
2066 else if (strcmp(status, "permfail") == 0)
2067 return OSMTPD_STATUS_PERMFAIL;
2068 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2072 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2076 const char *errstr = NULL;
2077 struct sockaddr_in *sin;
2078 struct sockaddr_in6 *sin6;
2079 struct sockaddr_un *sun;
2082 if (addr[0] == '[') {
2083 sin6 = (struct sockaddr_in6 *)ss;
2084 sin6->sin6_family = AF_INET6;
2085 sin6->sin6_port = 0;
2087 if ((port = strrchr(addr, ':')) == NULL)
2088 osmtpd_errx(1, "Invalid line received: invalid "
2089 "address (%s): %s", addr, linedup);
2090 if (port[-1] != ']')
2091 osmtpd_errx(1, "Invalid line received: invalid "
2092 "address (%s): %s", addr, linedup);
2094 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2097 osmtpd_errx(1, "Invalid line received: invalid "
2098 "address (%s): %s", addr, linedup);
2102 if (addr[n - 1] != ']')
2103 osmtpd_errx(1, "Invalid line received: invalid "
2104 "address (%s): %s", addr, linedup);
2107 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2115 osmtpd_errx(1, "Invalid line received: invalid address "
2116 "(%s): %s", addr, linedup);
2122 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2125 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2126 sun = (struct sockaddr_un *)ss;
2127 sun->sun_family = AF_UNIX;
2128 if (strlcpy(sun->sun_path, addr,
2129 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2130 osmtpd_errx(1, "Invalid line received: address too "
2131 "long (%s): %s", addr, linedup);
2134 sin = (struct sockaddr_in *)ss;
2135 sin->sin_family = AF_INET;
2138 if ((port = strrchr(addr, ':')) == NULL)
2139 osmtpd_errx(1, "Invalid line received: invalid "
2140 "address (%s): %s", addr, linedup);
2142 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2145 osmtpd_errx(1, "Invalid line received: invalid "
2146 "address (%s): %s", addr, linedup);
2149 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2155 osmtpd_errx(1, "Invalid line received: invalid address "
2156 "(%s): %s", addr, linedup);
2160 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2167 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2169 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2172 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);