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_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
87 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
89 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
91 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
93 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
95 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
97 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
99 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
100 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
101 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
102 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
103 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
104 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
105 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
106 static void (*conf_cb)(const char *, const char *);
108 static struct osmtpd_callback osmtpd_callbacks[] = {
111 OSMTPD_PHASE_CONNECT,
138 OSMTPD_PHASE_STARTTLS,
156 OSMTPD_PHASE_MAIL_FROM,
165 OSMTPD_PHASE_RCPT_TO,
183 OSMTPD_PHASE_DATA_LINE,
246 OSMTPD_PHASE_LINK_CONNECT,
255 OSMTPD_PHASE_LINK_DISCONNECT,
257 osmtpd_link_disconnect,
264 OSMTPD_PHASE_LINK_GREETING,
266 osmtpd_link_greeting,
273 OSMTPD_PHASE_LINK_IDENTIFY,
275 osmtpd_link_identify,
282 OSMTPD_PHASE_LINK_TLS,
291 OSMTPD_PHASE_TX_BEGIN,
300 OSMTPD_PHASE_TX_MAIL,
309 OSMTPD_PHASE_TX_RCPT,
318 OSMTPD_PHASE_TX_ENVELOPE,
327 OSMTPD_PHASE_TX_DATA,
336 OSMTPD_PHASE_TX_COMMIT,
345 OSMTPD_PHASE_TX_ROLLBACK,
354 OSMTPD_PHASE_PROTOCOL_CLIENT,
363 OSMTPD_PHASE_PROTOCOL_SERVER,
372 OSMTPD_PHASE_FILTER_RESPONSE,
381 OSMTPD_PHASE_TIMEOUT,
390 OSMTPD_PHASE_LINK_CONNECT,
399 OSMTPD_PHASE_LINK_DISCONNECT,
401 osmtpd_link_disconnect,
408 OSMTPD_PHASE_LINK_GREETING,
410 osmtpd_link_greeting,
417 OSMTPD_PHASE_LINK_IDENTIFY,
419 osmtpd_link_identify,
426 OSMTPD_PHASE_LINK_TLS,
435 OSMTPD_PHASE_TX_BEGIN,
444 OSMTPD_PHASE_TX_MAIL,
453 OSMTPD_PHASE_TX_RCPT,
462 OSMTPD_PHASE_TX_ENVELOPE,
471 OSMTPD_PHASE_TX_DATA,
480 OSMTPD_PHASE_TX_COMMIT,
489 OSMTPD_PHASE_TX_ROLLBACK,
498 OSMTPD_PHASE_PROTOCOL_CLIENT,
507 OSMTPD_PHASE_PROTOCOL_SERVER,
516 OSMTPD_PHASE_FILTER_RESPONSE,
525 OSMTPD_PHASE_TIMEOUT,
534 static struct io *io_stdout;
536 static int ready = 0;
537 /* Default from smtpd */
538 static int session_timeout = 300;
540 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
541 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
544 osmtpd_register_conf(void (*cb)(const char *, const char *))
550 osmtpd_register_filter_connect(void (*cb)(struct osmtpd_ctx *, const char *,
551 struct sockaddr_storage *))
553 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
555 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
560 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
562 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
564 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
569 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
571 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
573 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
578 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
580 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
582 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
587 osmtpd_register_filter_auth(void (*cb)(struct osmtpd_ctx *, const char *))
589 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
591 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
596 osmtpd_register_filter_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
598 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
600 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
605 osmtpd_register_filter_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
607 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
609 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
614 osmtpd_register_filter_data(void (*cb)(struct osmtpd_ctx *))
616 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
618 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
623 osmtpd_register_filter_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
625 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
627 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
632 osmtpd_register_filter_rset(void (*cb)(struct osmtpd_ctx *))
634 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
636 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
641 osmtpd_register_filter_quit(void (*cb)(struct osmtpd_ctx *))
643 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
645 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
650 osmtpd_register_filter_noop(void (*cb)(struct osmtpd_ctx *))
652 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
654 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
659 osmtpd_register_filter_help(void (*cb)(struct osmtpd_ctx *))
661 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
663 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
668 osmtpd_register_filter_wiz(void (*cb)(struct osmtpd_ctx *))
670 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
672 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
677 osmtpd_register_filter_commit(void (*cb)(struct osmtpd_ctx *))
679 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
681 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
686 osmtpd_register_report_connect(int incoming, void (*cb)(struct osmtpd_ctx *,
687 const char *, enum osmtpd_status, struct sockaddr_storage *,
688 struct sockaddr_storage *))
690 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
692 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
697 osmtpd_register_report_disconnect(int incoming, void (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
700 incoming, 0, (void *)cb);
704 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
707 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
708 incoming, 0, (void *)cb);
709 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
714 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
717 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
724 osmtpd_register_report_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
727 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
729 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
734 osmtpd_register_report_mail(int incoming, void (*cb)(struct osmtpd_ctx *,
735 uint32_t, const char *, enum osmtpd_status))
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
739 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
744 osmtpd_register_report_rcpt(int incoming, void (*cb)(struct osmtpd_ctx *,
745 uint32_t, const char *, enum osmtpd_status))
747 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
749 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
754 osmtpd_register_report_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
757 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
759 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
764 osmtpd_register_report_data(int incoming, void (*cb)(struct osmtpd_ctx *,
765 uint32_t, enum osmtpd_status))
767 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
769 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
774 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
777 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
779 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
784 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
787 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
789 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
794 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
797 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
798 incoming, 0, (void *)cb);
799 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
804 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
807 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
808 incoming, 0, (void *)cb);
809 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
814 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
817 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
818 incoming, 0, (void *)cb);
819 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
824 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
826 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
828 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
833 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
834 void (*ondelete)(struct osmtpd_ctx *, void *))
836 oncreatecb_session = oncreate;
837 ondeletecb_session = ondelete;
841 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
842 void (*ondelete)(struct osmtpd_ctx *, void *))
844 oncreatecb_message = oncreate;
845 ondeletecb_message = ondelete;
849 osmtpd_need(int lneeds)
855 osmtpd_register_need(int incoming)
857 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
859 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
861 if (needs & OSMTPD_NEED_GREETING)
862 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
864 if (needs & OSMTPD_NEED_IDENTITY)
865 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
867 if (needs & OSMTPD_NEED_CIPHERS)
868 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
870 if (needs & OSMTPD_NEED_MSGID) {
871 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
873 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
875 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
878 if (needs & OSMTPD_NEED_MAILFROM) {
879 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
881 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
883 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
886 if (needs & OSMTPD_NEED_RCPTTO) {
887 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
889 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
891 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
894 if (needs & OSMTPD_NEED_EVPID) {
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
897 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
899 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
903 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
912 struct event_base *evbase;
914 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
915 struct osmtpd_callback *ridentity = NULL;
917 evbase = event_init();
919 if ((io_stdin = io_new()) == NULL ||
920 (io_stdout = io_new()) == NULL)
921 osmtpd_err(1, "io_new");
922 io_set_nonblocking(STDIN_FILENO);
923 io_set_fd(io_stdin, STDIN_FILENO);
924 io_set_callback(io_stdin, osmtpd_newline, NULL);
925 io_set_read(io_stdin);
926 io_set_nonblocking(STDOUT_FILENO);
927 io_set_fd(io_stdout, STDOUT_FILENO);
928 io_set_callback(io_stdout, osmtpd_outevt, NULL);
929 io_set_write(io_stdout);
931 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
932 if (osmtpd_callbacks[i].doregister) {
933 osmtpd_register_need(osmtpd_callbacks[i].incoming);
934 if (oncreatecb_message != NULL) {
935 osmtpd_register(OSMTPD_TYPE_REPORT,
936 OSMTPD_PHASE_TX_BEGIN,
937 osmtpd_callbacks[i].incoming, 0, NULL);
938 osmtpd_register(OSMTPD_TYPE_REPORT,
939 OSMTPD_PHASE_TX_ROLLBACK,
940 osmtpd_callbacks[i].incoming, 0, NULL);
941 osmtpd_register(OSMTPD_TYPE_REPORT,
942 OSMTPD_PHASE_TX_COMMIT,
943 osmtpd_callbacks[i].incoming, 0, NULL);
945 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
946 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
947 hidenity = &(osmtpd_callbacks[i]);
948 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
949 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
950 eidentity = &(osmtpd_callbacks[i]);
951 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
952 osmtpd_callbacks[i].phase ==
953 OSMTPD_PHASE_LINK_IDENTIFY &&
954 osmtpd_callbacks[i].incoming == 1)
955 ridentity = &(osmtpd_callbacks[i]);
958 if (ridentity != NULL && ridentity->storereport) {
959 if (hidenity != NULL && hidenity->doregister)
960 hidenity->storereport = 1;
961 if (eidentity != NULL && eidentity->doregister)
962 eidentity->storereport = 1;
964 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
965 if (osmtpd_callbacks[i].doregister) {
966 if (osmtpd_callbacks[i].cb != NULL)
968 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
969 osmtpd_typetostr(osmtpd_callbacks[i].type),
970 osmtpd_callbacks[i].incoming ? "in" : "out",
971 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
976 osmtpd_errx(1, "No events registered");
977 io_printf(io_stdout, "register|ready\n");
983 event_base_free(evbase);
987 osmtpd_err(int eval, const char *fmt, ...)
992 vfprintf(stderr, fmt, ap);
994 fprintf(stderr, ": %s\n", strerror(errno));
999 osmtpd_errx(int eval, const char *fmt, ...)
1004 vfprintf(stderr, fmt, ap);
1006 fprintf(stderr, "\n");
1011 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1013 static char *linedup = NULL;
1014 static size_t dupsize = 0;
1015 struct osmtpd_session *ctx, search;
1016 enum osmtpd_type type;
1017 enum osmtpd_phase phase;
1018 int version_major, version_minor, incoming;
1021 const char *errstr = NULL;
1026 if (ev == IO_DISCONNECTED) {
1030 if (ev != IO_DATAIN)
1032 while ((line = io_getline(io, &linelen)) != NULL) {
1033 if (dupsize < linelen) {
1034 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1035 osmtpd_err(1, NULL);
1036 dupsize = linelen + 1;
1038 strlcpy(linedup, line, dupsize);
1039 if ((end = strchr(line, '|')) == NULL)
1040 osmtpd_errx(1, "Invalid line received: missing "
1041 "version: %s", linedup);
1043 if (strcmp(line, "filter") == 0)
1044 type = OSMTPD_TYPE_FILTER;
1045 else if (strcmp(line, "report") == 0)
1046 type = OSMTPD_TYPE_REPORT;
1047 else if (strcmp(line, "config") == 0) {
1049 if (strcmp(line, "ready") == 0) {
1050 if (conf_cb != NULL)
1051 conf_cb(NULL, NULL);
1054 if ((end = strchr(line, '|')) == NULL)
1055 osmtpd_errx(1, "Invalid line received: missing "
1056 "key: %s", linedup);
1058 if (conf_cb != NULL)
1060 if (strcmp(line, "smtp-session-timeout") == 0) {
1061 session_timeout = strtonum(end, 0, INT_MAX,
1064 osmtpd_errx(1, "Invalid line received: "
1065 "invalid smtp-sesion-timeout: %s",
1071 osmtpd_errx(1, "Invalid line received: unknown message "
1072 "type: %s", linedup);
1074 version_major = strtoul(line, &end, 10);
1075 if (line == end || end[0] != '.')
1076 osmtpd_errx(1, "Invalid protocol received: %s",
1079 version_minor = strtoul(line, &end, 10);
1081 osmtpd_errx(1, "Invalid line received: missing time: "
1083 if (line == end || end[0] != '|')
1084 osmtpd_errx(1, "Invalid protocol received: %s",
1086 if (version_major != 0)
1087 osmtpd_errx(1, "Unsupported protocol received: %s",
1090 if ((end = strchr(line, '.')) == NULL)
1091 osmtpd_errx(1, "Invalid line received: invalid "
1092 "timestamp: %s", linedup);
1094 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1096 osmtpd_errx(1, "Invalid line received: invalid "
1097 "timestamp: %s", linedup);
1099 if ((end = strchr(line, '|')) == NULL)
1100 osmtpd_errx(1, "Invalid line received: missing "
1101 "direction: %s", linedup);
1103 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1105 osmtpd_errx(1, "Invalid line received: invalid "
1106 "timestamp: %s", linedup);
1107 tm.tv_nsec *= 10 * (9 - (end - line));
1109 if ((end = strchr(line, '|')) == NULL)
1110 osmtpd_errx(1, "Invalid line receieved: missing "
1111 "phase: %s", linedup);
1113 if (strcmp(line, "smtp-in") == 0)
1115 else if (strcmp(line, "smtp-out") == 0)
1118 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1121 if ((end = strchr(line, '|')) == NULL)
1122 osmtpd_errx(1, "Invalid line received: missing reqid: "
1125 phase = osmtpd_strtophase(line, linedup);
1128 search.ctx.reqid = strtoull(line, &end, 16);
1129 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1130 (end[0] != '|' && end[0] != '\0'))
1131 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1134 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1136 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1137 osmtpd_err(1, NULL);
1138 ctx->ctx.reqid = search.ctx.reqid;
1139 ctx->ctx.rdns = NULL;
1140 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1141 ctx->ctx.identity = NULL;
1142 ctx->ctx.greeting.identity = NULL;
1143 ctx->ctx.ciphers = NULL;
1145 ctx->ctx.mailfrom = NULL;
1146 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1147 if (ctx->ctx.rcptto == NULL)
1148 osmtpd_err(1, "malloc");
1149 ctx->ctx.rcptto[0] = NULL;
1150 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1151 ctx->ctx.src.ss_family = AF_UNSPEC;
1152 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1153 ctx->ctx.dst.ss_family = AF_UNSPEC;
1154 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1156 ctx->ctx.local_session = NULL;
1157 ctx->ctx.local_message = NULL;
1158 if (oncreatecb_session != NULL)
1159 ctx->ctx.local_session =
1160 oncreatecb_session(&ctx->ctx);
1162 ctx->ctx.type = type;
1163 ctx->ctx.phase = phase;
1164 ctx->ctx.version_major = version_major;
1165 ctx->ctx.version_minor = version_minor;
1166 ctx->ctx.incoming = incoming;
1167 ctx->ctx.tm.tv_sec = tm.tv_sec;
1168 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1171 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1172 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1173 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1174 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1177 if (i == NITEMS(osmtpd_callbacks)) {
1178 osmtpd_errx(1, "Invalid line received: received "
1179 "unregistered line: %s", linedup);
1181 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1182 ctx->ctx.token = strtoull(line, &end, 16);
1183 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1185 osmtpd_errx(1, "Invalid line received: invalid "
1186 "token: %s", linedup);
1189 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1190 &(ctx->ctx), line, linedup);
1195 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1200 case IO_DISCONNECTED:
1203 osmtpd_errx(1, "Unexpectd event");
1208 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1209 __unused char *params, __unused char *linedup)
1211 void (*f)(struct osmtpd_ctx *);
1218 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1219 __unused char *linedup)
1221 void (*f)(struct osmtpd_ctx *, const char *);
1228 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1231 struct sockaddr_storage ss;
1234 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1237 if ((address = strchr(params, '|')) == NULL)
1238 osmtpd_errx(1, "Invalid line received: missing address: %s",
1240 address++[0] = '\0';
1242 osmtpd_addrtoss(address, &ss, 0, linedup);
1245 f(ctx, hostname, &ss);
1249 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1250 char *identity, __unused char *linedup)
1252 void (*f)(struct osmtpd_ctx *, const char *);
1254 if (cb->storereport) {
1255 free(ctx->identity);
1256 if ((ctx->identity = strdup(identity)) == NULL)
1257 osmtpd_err(1, "strdup");
1265 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1266 char *params, char *linedup)
1269 enum osmtpd_status fcrdns;
1270 struct sockaddr_storage src, dst;
1271 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1272 struct sockaddr_storage *, struct sockaddr_storage *);
1274 if ((end = strchr(params, '|')) == NULL)
1275 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1280 if ((end = strchr(params, '|')) == NULL)
1281 osmtpd_errx(1, "Invalid line received: missing src: %s",
1284 if (strcmp(params, "pass") == 0)
1285 fcrdns = OSMTPD_STATUS_OK;
1286 else if (strcmp(params, "fail") == 0)
1287 fcrdns = OSMTPD_STATUS_PERMFAIL;
1288 else if (strcmp(params, "error") == 0)
1289 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1291 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1294 if ((end = strchr(params, '|')) == NULL)
1295 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1298 osmtpd_addrtoss(params, &src, 1, linedup);
1300 osmtpd_addrtoss(params, &dst, 1, linedup);
1301 if (cb->storereport) {
1302 if ((ctx->rdns = strdup(rdns)) == NULL)
1303 osmtpd_err(1, "strdup");
1304 ctx->fcrdns = fcrdns;
1305 memcpy(&(ctx->src), &src, sizeof(ctx->src));
1306 memcpy(&(ctx->dst), &dst, sizeof(ctx->dst));
1308 if ((f = cb->cb) != NULL)
1309 f(ctx, rdns, fcrdns, &src, &dst);
1313 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1314 __unused char *param, __unused char *linedup)
1316 void (*f)(struct osmtpd_ctx *);
1318 struct osmtpd_session *session, search;
1320 if ((f = cb->cb) != NULL)
1323 search.ctx.reqid = ctx->reqid;
1324 session = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1325 if (session != NULL) {
1326 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1327 if (ondeletecb_session != NULL)
1328 ondeletecb_session(ctx, session->ctx.local_session);
1329 free(session->ctx.rdns);
1330 free(session->ctx.identity);
1331 free(session->ctx.greeting.identity);
1332 free(session->ctx.ciphers);
1333 free(session->ctx.mailfrom);
1334 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1335 free(session->ctx.rcptto[i]);
1336 free(session->ctx.rcptto);
1342 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1343 char *identity, __unused char *linedup)
1345 void (*f)(struct osmtpd_ctx *, const char *);
1347 if (cb->storereport) {
1348 free(ctx->greeting.identity);
1349 if ((ctx->greeting.identity = strdup(identity)) == NULL)
1350 osmtpd_err(1, NULL);
1353 if ((f = cb->cb) != NULL)
1358 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1359 char *identity, __unused char *linedup)
1361 void (*f)(struct osmtpd_ctx *, const char *);
1363 if (cb->storereport) {
1364 free(ctx->identity);
1365 if ((ctx->identity = strdup(identity)) == NULL)
1366 osmtpd_err(1, NULL);
1369 if ((f = cb->cb) != NULL)
1374 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1375 char *ciphers, __unused char *linedup)
1377 void (*f)(struct osmtpd_ctx *, const char *);
1379 if (cb->storereport) {
1380 if ((ctx->ciphers = strdup(ciphers)) == NULL)
1381 osmtpd_err(1, NULL);
1384 if ((f = cb->cb) != NULL)
1389 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1390 char *msgid, char *linedup)
1392 unsigned long imsgid;
1394 void (*f)(struct osmtpd_ctx *, uint32_t);
1397 imsgid = strtoul(msgid, &endptr, 16);
1398 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1399 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1401 ctx->msgid = imsgid;
1402 /* Check if we're in range */
1403 if ((unsigned long) ctx->msgid != imsgid)
1404 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1407 if (!cb->storereport)
1410 if (oncreatecb_message != NULL)
1411 ctx->local_message = oncreatecb_message(ctx);
1413 if ((f = cb->cb) != NULL)
1418 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1419 char *params, char *linedup)
1421 char *end, *mailfrom;
1422 enum osmtpd_status status;
1423 unsigned long imsgid;
1425 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1426 enum osmtpd_status);
1429 imsgid = strtoul(params, &end, 16);
1430 if ((imsgid == ULONG_MAX && errno != 0))
1431 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1434 osmtpd_errx(1, "Invalid line received: missing address: %s",
1437 if ((unsigned long) msgid != imsgid)
1438 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1442 if ((end = strchr(params, '|')) == NULL)
1443 osmtpd_errx(1, "Invalid line received: missing status: %s",
1446 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1448 status = osmtpd_strtostatus(end, linedup);
1451 status = osmtpd_strtostatus(params, linedup);
1453 if (cb->storereport) {
1454 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1455 osmtpd_err(1, NULL);
1458 if ((f = cb->cb) != NULL)
1459 f(ctx, msgid, mailfrom, status);
1463 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1464 char *params, char *linedup)
1467 enum osmtpd_status status;
1468 unsigned long imsgid;
1471 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1472 enum osmtpd_status);
1475 imsgid = strtoul(params, &end, 16);
1476 if ((imsgid == ULONG_MAX && errno != 0))
1477 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1480 osmtpd_errx(1, "Invalid line received: missing address: %s",
1483 if ((unsigned long) msgid != imsgid)
1484 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1488 if ((end = strchr(params, '|')) == NULL)
1489 osmtpd_errx(1, "Invalid line received: missing status: %s",
1493 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1495 status = osmtpd_strtostatus(end, linedup);
1498 status = osmtpd_strtostatus(params, linedup);
1501 if (cb->storereport) {
1502 for (i = 0; ctx->rcptto[i] != NULL; i++)
1504 ctx->rcptto = reallocarray(ctx->rcptto, i + 2,
1505 sizeof(*(ctx->rcptto)));
1506 if (ctx->rcptto == NULL)
1507 osmtpd_err(1, NULL);
1509 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1510 osmtpd_err(1, NULL);
1511 ctx->rcptto[i + 1] = NULL;
1514 if ((f = cb->cb) != NULL)
1515 f(ctx, msgid, rcptto, status);
1519 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1520 char *params, char *linedup)
1522 unsigned long imsgid;
1526 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1529 imsgid = strtoul(params, &end, 16);
1530 if ((imsgid == ULONG_MAX && errno != 0))
1531 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1534 osmtpd_errx(1, "Invalid line received: missing address: %s",
1537 if ((unsigned long) msgid != imsgid)
1538 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1542 evpid = strtoull(params, &end, 16);
1543 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1545 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1547 if (cb->storereport)
1550 if ((f = cb->cb) != NULL)
1551 f(ctx, msgid, evpid);
1555 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1556 char *params, char *linedup)
1559 unsigned long imsgid;
1561 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1564 imsgid = strtoul(params, &end, 16);
1565 if ((imsgid == ULONG_MAX && errno != 0))
1566 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1569 osmtpd_errx(1, "Invalid line received: missing address: %s",
1572 if ((unsigned long) msgid != imsgid)
1573 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1577 if ((f = cb->cb) != NULL)
1578 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1582 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1583 char *params, char *linedup)
1586 const char *errstr = NULL;
1587 unsigned long imsgid;
1590 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1593 imsgid = strtoul(params, &end, 16);
1594 if ((imsgid == ULONG_MAX && errno != 0))
1595 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1598 osmtpd_errx(1, "Invalid line received: missing address: %s",
1601 if ((unsigned long) msgid != imsgid)
1602 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1606 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1608 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1611 if ((f = cb->cb) != NULL)
1612 f(ctx, msgid, msgsz);
1614 if (ondeletecb_message != NULL) {
1615 ondeletecb_message(ctx, ctx->local_message);
1616 ctx->local_message = NULL;
1619 free(ctx->mailfrom);
1620 ctx->mailfrom = NULL;
1622 for (i = 0; ctx->rcptto[i] != NULL; i++)
1623 free(ctx->rcptto[i]);
1624 ctx->rcptto[0] = NULL;
1630 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1631 char *params, char *linedup)
1634 unsigned long imsgid;
1637 void (*f)(struct osmtpd_ctx *, uint32_t);
1640 imsgid = strtoul(params, &end, 16);
1641 if ((imsgid == ULONG_MAX && errno != 0))
1642 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1645 osmtpd_errx(1, "Invalid line received: missing address: %s",
1648 if ((unsigned long) msgid != imsgid)
1649 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1652 if ((f = cb->cb) != NULL)
1655 if (ondeletecb_message != NULL) {
1656 ondeletecb_message(ctx, ctx->local_message);
1657 ctx->local_message = NULL;
1660 free(ctx->mailfrom);
1661 ctx->mailfrom = NULL;
1663 for (i = 0; ctx->rcptto[i] != NULL; i++)
1664 free(ctx->rcptto[i]);
1665 ctx->rcptto[0] = NULL;
1671 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1673 if (ctx->version_major == 0 && ctx->version_minor < 5)
1674 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1675 "proceed\n", ctx->token, ctx->reqid);
1677 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1678 "proceed\n", ctx->reqid, ctx->token);
1682 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1686 if (code < 200 || code > 599)
1687 osmtpd_errx(1, "Invalid reject code");
1689 if (ctx->version_major == 0 && ctx->version_minor < 5)
1690 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1691 "reject|%d ", ctx->token, ctx->reqid, code);
1693 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1694 "reject|%d ", ctx->reqid, ctx->token, code);
1695 va_start(ap, reason);
1696 io_vprintf(io_stdout, reason, ap);
1698 io_printf(io_stdout, "\n");
1702 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1703 int subject, int detail, const char *reason, ...)
1707 if (code < 200 || code > 599)
1708 osmtpd_errx(1, "Invalid reject code");
1709 if (class < 2 || class > 5)
1710 osmtpd_errx(1, "Invalid enhanced status class");
1711 if (subject < 0 || subject > 999)
1712 osmtpd_errx(1, "Invalid enhanced status subject");
1713 if (detail < 0 || detail > 999)
1714 osmtpd_errx(1, "Invalid enhanced status detail");
1716 if (ctx->version_major == 0 && ctx->version_minor < 5)
1717 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1718 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1721 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1722 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1724 va_start(ap, reason);
1725 io_vprintf(io_stdout, reason, ap);
1727 io_printf(io_stdout, "\n");
1731 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1735 if (ctx->version_major == 0 && ctx->version_minor < 5)
1736 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1737 "disconnect|421 ", ctx->token, ctx->reqid);
1739 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1740 "disconnect|421 ", ctx->reqid, ctx->token);
1741 va_start(ap, reason);
1742 io_vprintf(io_stdout, reason, ap);
1744 io_printf(io_stdout, "\n");
1748 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1749 int detail, const char *reason, ...)
1753 if (class <= 2 || class >= 5)
1754 osmtpd_errx(1, "Invalid enhanced status class");
1755 if (subject < 0 || subject > 999)
1756 osmtpd_errx(1, "Invalid enhanced status subject");
1757 if (detail < 0 || detail > 999)
1758 osmtpd_errx(1, "Invalid enhanced status detail");
1759 if (ctx->version_major == 0 && ctx->version_minor < 5)
1760 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1761 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1764 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1765 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1767 va_start(ap, reason);
1768 io_vprintf(io_stdout, reason, ap);
1770 io_printf(io_stdout, "\n");
1774 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1778 if (ctx->version_major == 0 && ctx->version_minor < 5)
1779 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1780 "rewrite|", ctx->token, ctx->reqid);
1782 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1783 "rewrite|", ctx->reqid, ctx->token);
1784 va_start(ap, value);
1785 io_vprintf(io_stdout, value, ap);
1787 io_printf(io_stdout, "\n");
1791 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1795 if (ctx->version_major == 0 && ctx->version_minor < 5)
1796 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1797 ctx->token, ctx->reqid);
1799 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1800 ctx->reqid, ctx->token);
1802 io_vprintf(io_stdout, line, ap);
1804 io_printf(io_stdout, "\n");
1808 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1809 int storereport, void *cb)
1814 osmtpd_errx(1, "Can't register when proc is running");
1816 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1817 if (type == osmtpd_callbacks[i].type &&
1818 phase == osmtpd_callbacks[i].phase &&
1819 incoming == osmtpd_callbacks[i].incoming) {
1820 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
1821 osmtpd_errx(1, "Event already registered");
1823 osmtpd_callbacks[i].cb = cb;
1824 osmtpd_callbacks[i].doregister = 1;
1826 osmtpd_callbacks[i].storereport = 1;
1831 osmtpd_errx(1, "Trying to register unknown event");
1834 static enum osmtpd_phase
1835 osmtpd_strtophase(const char *phase, const char *linedup)
1837 if (strcmp(phase, "connect") == 0)
1838 return OSMTPD_PHASE_CONNECT;
1839 if (strcmp(phase, "helo") == 0)
1840 return OSMTPD_PHASE_HELO;
1841 if (strcmp(phase, "ehlo") == 0)
1842 return OSMTPD_PHASE_EHLO;
1843 if (strcmp(phase, "starttls") == 0)
1844 return OSMTPD_PHASE_STARTTLS;
1845 if (strcmp(phase, "auth") == 0)
1846 return OSMTPD_PHASE_AUTH;
1847 if (strcmp(phase, "mail-from") == 0)
1848 return OSMTPD_PHASE_MAIL_FROM;
1849 if (strcmp(phase, "rcpt-to") == 0)
1850 return OSMTPD_PHASE_RCPT_TO;
1851 if (strcmp(phase, "data") == 0)
1852 return OSMTPD_PHASE_DATA;
1853 if (strcmp(phase, "data-line") == 0)
1854 return OSMTPD_PHASE_DATA_LINE;
1855 if (strcmp(phase, "rset") == 0)
1856 return OSMTPD_PHASE_RSET;
1857 if (strcmp(phase, "quit") == 0)
1858 return OSMTPD_PHASE_QUIT;
1859 if (strcmp(phase, "noop") == 0)
1860 return OSMTPD_PHASE_NOOP;
1861 if (strcmp(phase, "help") == 0)
1862 return OSMTPD_PHASE_HELP;
1863 if (strcmp(phase, "wiz") == 0)
1864 return OSMTPD_PHASE_WIZ;
1865 if (strcmp(phase, "commit") == 0)
1866 return OSMTPD_PHASE_COMMIT;
1867 if (strcmp(phase, "link-connect") == 0)
1868 return OSMTPD_PHASE_LINK_CONNECT;
1869 if (strcmp(phase, "link-disconnect") == 0)
1870 return OSMTPD_PHASE_LINK_DISCONNECT;
1871 if (strcmp(phase, "link-greeting") == 0)
1872 return OSMTPD_PHASE_LINK_GREETING;
1873 if (strcmp(phase, "link-identify") == 0)
1874 return OSMTPD_PHASE_LINK_IDENTIFY;
1875 if (strcmp(phase, "link-tls") == 0)
1876 return OSMTPD_PHASE_LINK_TLS;
1877 if (strcmp(phase, "tx-begin") == 0)
1878 return OSMTPD_PHASE_TX_BEGIN;
1879 if (strcmp(phase, "tx-mail") == 0)
1880 return OSMTPD_PHASE_TX_MAIL;
1881 if (strcmp(phase, "tx-rcpt") == 0)
1882 return OSMTPD_PHASE_TX_RCPT;
1883 if (strcmp(phase, "tx-envelope") == 0)
1884 return OSMTPD_PHASE_TX_ENVELOPE;
1885 if (strcmp(phase, "tx-data") == 0)
1886 return OSMTPD_PHASE_TX_DATA;
1887 if (strcmp(phase, "tx-commit") == 0)
1888 return OSMTPD_PHASE_TX_COMMIT;
1889 if (strcmp(phase, "tx-rollback") == 0)
1890 return OSMTPD_PHASE_TX_ROLLBACK;
1891 if (strcmp(phase, "protocol-client") == 0)
1892 return OSMTPD_PHASE_PROTOCOL_CLIENT;
1893 if (strcmp(phase, "protocol-server") == 0)
1894 return OSMTPD_PHASE_PROTOCOL_SERVER;
1895 if (strcmp(phase, "filter-response") == 0)
1896 return OSMTPD_PHASE_FILTER_RESPONSE;
1897 if (strcmp(phase, "timeout") == 0)
1898 return OSMTPD_PHASE_TIMEOUT;
1899 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
1903 osmtpd_typetostr(enum osmtpd_type type)
1906 case OSMTPD_TYPE_FILTER:
1908 case OSMTPD_TYPE_REPORT:
1911 osmtpd_errx(1, "In valid type: %d\n", type);
1915 osmtpd_phasetostr(enum osmtpd_phase phase)
1918 case OSMTPD_PHASE_CONNECT:
1920 case OSMTPD_PHASE_HELO:
1922 case OSMTPD_PHASE_EHLO:
1924 case OSMTPD_PHASE_STARTTLS:
1926 case OSMTPD_PHASE_AUTH:
1928 case OSMTPD_PHASE_MAIL_FROM:
1930 case OSMTPD_PHASE_RCPT_TO:
1932 case OSMTPD_PHASE_DATA:
1934 case OSMTPD_PHASE_DATA_LINE:
1936 case OSMTPD_PHASE_RSET:
1938 case OSMTPD_PHASE_QUIT:
1940 case OSMTPD_PHASE_NOOP:
1942 case OSMTPD_PHASE_HELP:
1944 case OSMTPD_PHASE_WIZ:
1946 case OSMTPD_PHASE_COMMIT:
1948 case OSMTPD_PHASE_LINK_CONNECT:
1949 return "link-connect";
1950 case OSMTPD_PHASE_LINK_DISCONNECT:
1951 return "link-disconnect";
1952 case OSMTPD_PHASE_LINK_GREETING:
1953 return "link-greeting";
1954 case OSMTPD_PHASE_LINK_IDENTIFY:
1955 return "link-identify";
1956 case OSMTPD_PHASE_LINK_TLS:
1958 case OSMTPD_PHASE_TX_BEGIN:
1960 case OSMTPD_PHASE_TX_MAIL:
1962 case OSMTPD_PHASE_TX_RCPT:
1964 case OSMTPD_PHASE_TX_ENVELOPE:
1965 return "tx-envelope";
1966 case OSMTPD_PHASE_TX_DATA:
1968 case OSMTPD_PHASE_TX_COMMIT:
1970 case OSMTPD_PHASE_TX_ROLLBACK:
1971 return "tx-rollback";
1972 case OSMTPD_PHASE_PROTOCOL_CLIENT:
1973 return "protocol-client";
1974 case OSMTPD_PHASE_PROTOCOL_SERVER:
1975 return "protocol-server";
1976 case OSMTPD_PHASE_FILTER_RESPONSE:
1977 return "filter-response";
1978 case OSMTPD_PHASE_TIMEOUT:
1981 osmtpd_errx(1, "In valid phase: %d\n", phase);
1984 static enum osmtpd_status
1985 osmtpd_strtostatus(const char *status, char *linedup)
1987 if (strcmp(status, "ok") == 0)
1988 return OSMTPD_STATUS_OK;
1989 else if (strcmp(status, "tempfail") == 0)
1990 return OSMTPD_STATUS_TEMPFAIL;
1991 else if (strcmp(status, "permfail") == 0)
1992 return OSMTPD_STATUS_PERMFAIL;
1993 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
1997 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2001 const char *errstr = NULL;
2002 struct sockaddr_in *sin;
2003 struct sockaddr_in6 *sin6;
2004 struct sockaddr_un *sun;
2007 if (addr[0] == '[') {
2008 sin6 = (struct sockaddr_in6 *)ss;
2009 sin6->sin6_family = AF_INET6;
2010 sin6->sin6_port = 0;
2012 if ((port = strrchr(addr, ':')) == NULL)
2013 osmtpd_errx(1, "Invalid line received: invalid "
2014 "address (%s): %s", addr, linedup);
2015 if (port[-1] != ']')
2016 osmtpd_errx(1, "Invalid line received: invalid "
2017 "address (%s): %s", addr, linedup);
2019 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2022 osmtpd_errx(1, "Invalid line received: invalid "
2023 "address (%s): %s", addr, linedup);
2027 if (addr[n - 1] != ']')
2028 osmtpd_errx(1, "Invalid line received: invalid "
2029 "address (%s): %s", addr, linedup);
2032 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2040 osmtpd_errx(1, "Invalid line received: invalid address "
2041 "(%s): %s", addr, linedup);
2047 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2050 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2051 sun = (struct sockaddr_un *)ss;
2052 sun->sun_family = AF_UNIX;
2053 if (strlcpy(sun->sun_path, addr,
2054 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2055 osmtpd_errx(1, "Invalid line received: address too "
2056 "long (%s): %s", addr, linedup);
2059 sin = (struct sockaddr_in *)ss;
2060 sin->sin_family = AF_INET;
2063 if ((port = strrchr(addr, ':')) == NULL)
2064 osmtpd_errx(1, "Invalid line received: invalid "
2065 "address (%s): %s", addr, linedup);
2067 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2070 osmtpd_errx(1, "Invalid line received: invalid "
2071 "address (%s): %s", addr, linedup);
2074 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2080 osmtpd_errx(1, "Invalid line received: invalid address "
2081 "(%s): %s", addr, linedup);
2085 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2092 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2094 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2097 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);