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.
18 #include <sys/socket.h>
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
37 #include "opensmtpd.h"
40 #define NITEMS(x) (sizeof(x) / sizeof(*x))
42 struct osmtpd_callback {
43 enum osmtpd_type type;
44 enum osmtpd_phase phase;
46 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_ctx *, char *,
53 struct osmtpd_session {
54 struct osmtpd_ctx ctx;
55 RB_ENTRY(osmtpd_session) entry;
58 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
60 static const char *osmtpd_typetostr(enum osmtpd_type);
61 static const char *osmtpd_phasetostr(enum osmtpd_phase);
62 static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
63 static void osmtpd_newline(struct io *, int, void *);
64 static void osmtpd_outevt(struct io *, int, void *);
65 static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_ctx *,
67 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_ctx *,
69 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
71 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
73 static void osmtpd_link_disconnect(struct osmtpd_callback *,
74 struct osmtpd_ctx *, char *, char *);
75 static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_ctx *,
77 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_ctx *,
79 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
81 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
83 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
85 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
87 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
89 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
91 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
93 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
94 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
95 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
96 static void *(*oncreatecb)(struct osmtpd_ctx *) = NULL;
97 static void (*ondeletecb)(struct osmtpd_ctx *, void *) = NULL;
100 static struct osmtpd_callback osmtpd_callbacks[] = {
103 OSMTPD_PHASE_CONNECT,
130 OSMTPD_PHASE_STARTTLS,
148 OSMTPD_PHASE_MAIL_FROM,
157 OSMTPD_PHASE_RCPT_TO,
175 OSMTPD_PHASE_DATA_LINE,
238 OSMTPD_PHASE_LINK_CONNECT,
247 OSMTPD_PHASE_LINK_DISCONNECT,
249 osmtpd_link_disconnect,
256 OSMTPD_PHASE_LINK_IDENTIFY,
258 osmtpd_link_identify,
265 OSMTPD_PHASE_LINK_TLS,
274 OSMTPD_PHASE_TX_BEGIN,
283 OSMTPD_PHASE_TX_MAIL,
292 OSMTPD_PHASE_TX_RCPT,
301 OSMTPD_PHASE_TX_ENVELOPE,
310 OSMTPD_PHASE_TX_DATA,
319 OSMTPD_PHASE_TX_COMMIT,
328 OSMTPD_PHASE_TX_ROLLBACK,
337 OSMTPD_PHASE_PROTOCOL_CLIENT,
346 OSMTPD_PHASE_PROTOCOL_SERVER,
355 OSMTPD_PHASE_FILTER_RESPONSE,
364 OSMTPD_PHASE_TIMEOUT,
373 OSMTPD_PHASE_LINK_CONNECT,
382 OSMTPD_PHASE_LINK_DISCONNECT,
384 osmtpd_link_disconnect,
391 OSMTPD_PHASE_LINK_IDENTIFY,
393 osmtpd_link_identify,
400 OSMTPD_PHASE_LINK_TLS,
409 OSMTPD_PHASE_TX_BEGIN,
418 OSMTPD_PHASE_TX_MAIL,
427 OSMTPD_PHASE_TX_RCPT,
436 OSMTPD_PHASE_TX_ENVELOPE,
445 OSMTPD_PHASE_TX_DATA,
454 OSMTPD_PHASE_TX_COMMIT,
463 OSMTPD_PHASE_TX_ROLLBACK,
472 OSMTPD_PHASE_PROTOCOL_CLIENT,
481 OSMTPD_PHASE_PROTOCOL_SERVER,
490 OSMTPD_PHASE_FILTER_RESPONSE,
499 OSMTPD_PHASE_TIMEOUT,
508 static struct io *io_stdout;
509 static int ready = 0;
510 /* Default from smtpd */
511 static int session_timeout = 300;
513 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
514 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
517 osmtpd_register_filter_connect(void (*cb)(struct osmtpd_ctx *, const char *,
518 struct sockaddr_storage *))
520 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
522 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
527 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
529 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
531 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
536 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
538 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
540 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
545 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
547 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
549 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
554 osmtpd_register_filter_auth(void (*cb)(struct osmtpd_ctx *, const char *))
556 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
558 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
563 osmtpd_register_filter_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
565 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
567 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
572 osmtpd_register_filter_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
574 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
576 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
581 osmtpd_register_filter_data(void (*cb)(struct osmtpd_ctx *))
583 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
585 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
590 osmtpd_register_filter_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
592 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
594 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
599 osmtpd_register_filter_rset(void (*cb)(struct osmtpd_ctx *))
601 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
603 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
608 osmtpd_register_filter_quit(void (*cb)(struct osmtpd_ctx *))
610 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
612 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
617 osmtpd_register_filter_noop(void (*cb)(struct osmtpd_ctx *))
619 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
621 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
626 osmtpd_register_filter_help(void (*cb)(struct osmtpd_ctx *))
628 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
630 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
635 osmtpd_register_filter_wiz(void (*cb)(struct osmtpd_ctx *))
637 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
639 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
644 osmtpd_register_filter_commit(void (*cb)(struct osmtpd_ctx *))
646 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
648 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
653 osmtpd_register_report_connect(int incoming, void (*cb)(struct osmtpd_ctx *,
654 const char *, const char *, struct sockaddr_storage *,
655 struct sockaddr_storage *))
657 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_LINK_CONNECT, incoming,
659 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
664 osmtpd_register_report_disconnect(int incoming, void (*cb)(struct osmtpd_ctx *))
666 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
667 incoming, 0, (void *)cb);
671 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
674 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
675 incoming, 0, (void *)cb);
676 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
681 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
684 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
686 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
691 osmtpd_register_report_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
694 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
696 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
701 osmtpd_register_report_mail(int incoming, void (*cb)(struct osmtpd_ctx *,
702 uint32_t, const char *, enum osmtpd_status))
704 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
706 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
711 osmtpd_register_report_rcpt(int incoming, void (*cb)(struct osmtpd_ctx *,
712 uint32_t, const char *, enum osmtpd_status))
714 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
716 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
721 osmtpd_register_report_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
724 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
726 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
731 osmtpd_register_report_data(int incoming, void (*cb)(struct osmtpd_ctx *,
732 uint32_t, enum osmtpd_status))
734 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
736 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
741 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
744 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
746 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
751 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
754 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
756 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
761 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
764 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
765 incoming, 0, (void *)cb);
766 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
771 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
774 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
775 incoming, 0, (void *)cb);
776 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
781 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
784 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
785 incoming, 0, (void *)cb);
786 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
791 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
793 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
795 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
800 osmtpd_localdata(void *(*oncreate)(struct osmtpd_ctx *),
801 void (*ondelete)(struct osmtpd_ctx *, void *))
803 oncreatecb = oncreate;
804 ondeletecb = ondelete;
808 osmtpd_need(int incoming, int needs)
810 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
812 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_LINK_CONNECT,
814 if (needs & OSMTPD_NEED_IDENTITY)
815 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
817 if (needs & OSMTPD_NEED_CIPHERS)
818 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
820 if (needs & OSMTPD_NEED_MSGID) {
821 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
823 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
825 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
828 if (needs & OSMTPD_NEED_MAILFROM) {
829 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
831 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
833 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
836 if (needs & OSMTPD_NEED_RCPTTO) {
837 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
839 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
841 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
844 if (needs & OSMTPD_NEED_EVPID) {
845 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
847 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
849 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
853 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
862 /* Doesn't leak, since it needs to exists until the application ends. */
867 if ((io_stdin = io_new()) == NULL ||
868 (io_stdout = io_new()) == NULL)
870 io_set_nonblocking(STDIN_FILENO);
871 io_set_fd(io_stdin, STDIN_FILENO);
872 io_set_callback(io_stdin, osmtpd_newline, NULL);
873 io_set_read(io_stdin);
874 io_set_nonblocking(STDOUT_FILENO);
875 io_set_fd(io_stdout, STDOUT_FILENO);
876 io_set_callback(io_stdout, osmtpd_outevt, NULL);
877 io_set_write(io_stdout);
879 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
880 if (osmtpd_callbacks[i].doregister) {
881 if (osmtpd_callbacks[i].cb != NULL)
883 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
884 osmtpd_typetostr(osmtpd_callbacks[i].type),
885 osmtpd_callbacks[i].incoming ? "in" : "out",
886 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
891 errx(1, "No events registered");
892 io_printf(io_stdout, "register|ready\n");
899 osmtpd_newline(struct io *io, int ev, void *arg)
901 static char *linedup = NULL;
902 static size_t dupsize = 0;
903 struct osmtpd_session *ctx, search;
904 enum osmtpd_type type;
905 enum osmtpd_phase phase;
906 int version_major, version_minor, incoming;
909 const char *errstr = NULL;
914 if (ev == IO_DISCONNECTED)
918 while ((line = io_getline(io, &linelen)) > 0) {
919 if (dupsize < linelen) {
920 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
922 dupsize = linelen + 1;
924 strlcpy(linedup, line, dupsize);
925 if ((end = strchr(line, '|')) == NULL)
926 errx(1, "Invalid line received: missing version: %s", linedup);
928 if (strcmp(line, "filter") == 0)
929 type = OSMTPD_TYPE_FILTER;
930 else if (strcmp(line, "report") == 0)
931 type = OSMTPD_TYPE_REPORT;
932 else if (strcmp(line, "config") == 0) {
934 if (strcmp(line, "ready") == 0)
936 if ((end = strchr(line, '|')) == NULL)
937 errx(1, "Invalid line received: missing key: %s", linedup);
939 if (strcmp(line, "smtp-session-timeout") == 0) {
940 session_timeout = strtonum(end, 0, INT_MAX,
943 errx(1, "Invalid line received: "
944 "invalid smtp-sesion-timeout: %s",
950 errx(1, "Invalid line received: unknown message type: %s", linedup);
952 if ((end = strchr(line, '|')) == NULL)
953 errx(1, "Invalid line received: missing time: %s", linedup);
955 if (strcmp(line, "0.1") != 0)
956 errx(1, "Unsupported protocol received: %s", linedup);
960 if ((end = strchr(line, '.')) == NULL)
961 errx(1, "Invalid line received: invalid timestamp: %s", linedup);
963 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
965 errx(1, "Invalid line received: invalid timestamp: %s", linedup);
967 if ((end = strchr(line, '|')) == NULL)
968 errx(1, "Invalid line received: missing direction: %s", linedup);
970 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
972 errx(1, "Invalid line received: invalid timestamp: %s",
974 tm.tv_nsec *= 10 * (9 - (end - line));
976 if ((end = strchr(line, '|')) == NULL)
977 errx(1, "Invalid line receieved: missing phase: %s",
980 if (strcmp(line, "smtp-in") == 0)
982 else if (strcmp(line, "smtp-out") == 0)
985 errx(1, "Invalid line: invalid direction: %s", linedup);
987 if ((end = strchr(line, '|')) == NULL)
988 errx(1, "Invalid line received: missing reqid: %s",
991 phase = osmtpd_strtophase(line, linedup);
994 search.ctx.reqid = strtoull(line, &end, 16);
995 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
996 (end[0] != '|' && end[0] != '\0'))
997 errx(1, "Invalid line received: invalid reqid: %s",
1000 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1002 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1004 ctx->ctx.reqid = search.ctx.reqid;
1005 ctx->ctx.rdns = NULL;
1006 ctx->ctx.fcrdns = NULL;
1007 ctx->ctx.identity = NULL;
1008 ctx->ctx.ciphers = NULL;
1010 ctx->ctx.mailfrom = NULL;
1011 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1012 if (ctx->ctx.rcptto == NULL)
1014 ctx->ctx.rcptto[0] = NULL;
1015 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1016 ctx->ctx.src.ss_family = AF_UNSPEC;
1017 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1018 ctx->ctx.dst.ss_family = AF_UNSPEC;
1019 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1021 ctx->ctx.local = NULL;
1022 if (oncreatecb != NULL)
1023 ctx->ctx.local = oncreatecb(&ctx->ctx);
1025 ctx->ctx.type = type;
1026 ctx->ctx.phase = phase;
1027 ctx->ctx.version_major = version_major;
1028 ctx->ctx.version_minor = version_minor;
1029 ctx->ctx.incoming = incoming;
1030 ctx->ctx.tm.tv_sec = tm.tv_sec;
1031 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1034 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1035 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1036 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1037 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1040 if (i == NITEMS(osmtpd_callbacks)) {
1041 errx(1, "Invalid line received: received unregistered "
1042 "line: %s", linedup);
1044 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1045 ctx->ctx.token = strtoull(line, &end, 16);
1046 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1048 errx(1, "Invalid line received: invalid token: %s", linedup);
1051 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1052 &(ctx->ctx), line, linedup);
1057 osmtpd_outevt(struct io *io, int evt, void *arg)
1062 case IO_DISCONNECTED:
1065 errx(1, "Unexpectd event");
1070 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1073 void (*f)(struct osmtpd_ctx *);
1080 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1083 void (*f)(struct osmtpd_ctx *, const char *);
1090 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1093 struct sockaddr_storage ss;
1096 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1099 if ((address = strchr(params, '|')) == NULL)
1100 errx(1, "Invalid line received: missing address: %s", linedup);
1101 address++[0] = '\0';
1103 osmtpd_addrtoss(address, &ss, 0, linedup);
1106 f(ctx, hostname, &ss);
1110 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1111 char *params, char *linedup)
1113 char *end, *rdns, *fcrdns;
1114 struct sockaddr_storage src, dst;
1115 void (*f)(struct osmtpd_ctx *, const char *, const char *,
1116 struct sockaddr_storage *, struct sockaddr_storage *);
1118 if ((end = strchr(params, '|')) == NULL)
1119 errx(1, "Invalid line received: missing fcrdns: %s", linedup);
1123 if ((end = strchr(params, '|')) == NULL)
1124 errx(1, "Invalid line received: missing src: %s", linedup);
1128 if ((end = strchr(params, '|')) == NULL)
1129 errx(1, "Invalid line received: missing dst: %s", linedup);
1131 osmtpd_addrtoss(params, &src, 1, linedup);
1133 osmtpd_addrtoss(params, &dst, 1, linedup);
1134 if (cb->storereport) {
1135 if ((ctx->rdns = strdup(params)) == NULL)
1137 if ((ctx->fcrdns = strdup(params)) == NULL)
1139 memcpy(&(ctx->src), &src, sizeof(ctx->src));
1140 memcpy(&(ctx->dst), &dst, sizeof(ctx->dst));
1142 if ((f = cb->cb) != NULL)
1143 f(ctx, rdns, fcrdns, &src, &dst);
1147 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1148 char *param, char *linedup)
1150 void (*f)(struct osmtpd_ctx *);
1152 struct osmtpd_session *session, search;
1154 if ((f = cb->cb) != NULL)
1157 search.ctx.reqid = ctx->reqid;
1158 session = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1159 if (session != NULL) {
1160 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1161 if (ondeletecb != NULL)
1162 ondeletecb(ctx, session->ctx.local);
1163 free(session->ctx.rdns);
1164 free(session->ctx.fcrdns);
1165 free(session->ctx.identity);
1166 free(session->ctx.ciphers);
1167 free(session->ctx.mailfrom);
1168 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1169 free(session->ctx.rcptto[i]);
1170 free(session->ctx.rcptto);
1176 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1177 char *identity, char *linedup)
1179 void (*f)(struct osmtpd_ctx *, const char *);
1181 if (cb->storereport) {
1182 if ((ctx->identity = strdup(identity)) == NULL)
1186 if ((f = cb->cb) != NULL)
1191 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1192 char *ciphers, char *linedup)
1194 void (*f)(struct osmtpd_ctx *, const char *);
1196 if (cb->storereport) {
1197 if ((ctx->ciphers = strdup(ciphers)) == NULL)
1201 if ((f = cb->cb) != NULL)
1206 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1207 char *msgid, char *linedup)
1209 unsigned long imsgid;
1211 void (*f)(struct osmtpd_ctx *, uint32_t);
1214 imsgid = strtoul(msgid, &endptr, 16);
1215 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1216 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1217 ctx->msgid = imsgid;
1218 /* Check if we're in range */
1219 if ((unsigned long) ctx->msgid != imsgid)
1220 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1222 if (!cb->storereport)
1225 if ((f = cb->cb) != NULL)
1230 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1231 char *params, char *linedup)
1233 char *end, *mailfrom;
1234 unsigned long imsgid;
1236 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1237 enum osmtpd_status);
1240 imsgid = strtoul(params, &end, 16);
1241 if ((imsgid == ULONG_MAX && errno != 0))
1242 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1244 errx(1, "Invalid line received: missing address: %s", linedup);
1246 if ((unsigned long) msgid != imsgid)
1247 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1250 if ((end = strchr(params, '|')) == NULL)
1251 errx(1, "Invalid line received: missing status: %s", linedup);
1254 if (cb->storereport) {
1255 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1260 if ((f = cb->cb) != NULL)
1261 f(ctx, msgid, mailfrom, osmtpd_strtostatus(params, linedup));
1265 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1266 char *params, char *linedup)
1269 unsigned long imsgid;
1272 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1273 enum osmtpd_status);
1276 imsgid = strtoul(params, &end, 16);
1277 if ((imsgid == ULONG_MAX && errno != 0))
1278 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1280 errx(1, "Invalid line received: missing address: %s", linedup);
1282 if ((unsigned long) msgid != imsgid)
1283 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1286 if ((end = strchr(params, '|')) == NULL)
1287 errx(1, "Invalid line received: missing status: %s", linedup);
1293 if (cb->storereport) {
1294 for (i = 0; ctx->rcptto[i] != NULL; i++)
1296 ctx->rcptto = reallocarray(ctx->rcptto, i + 2,
1297 sizeof(*(ctx->rcptto)));
1298 if (ctx->rcptto == NULL)
1301 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1303 ctx->rcptto[i + 1] = NULL;
1306 if ((f = cb->cb) != NULL)
1307 f(ctx, msgid, rcptto,
1308 osmtpd_strtostatus(params, linedup));
1312 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1313 char *params, char *linedup)
1315 unsigned long imsgid;
1319 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1322 imsgid = strtoul(params, &end, 16);
1323 if ((imsgid == ULONG_MAX && errno != 0))
1324 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1326 errx(1, "Invalid line received: missing address: %s", linedup);
1328 if ((unsigned long) msgid != imsgid)
1329 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1332 evpid = strtoull(params, &end, 16);
1333 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1335 errx(1, "Invalid line received: invalid evpid: %s", linedup);
1336 if (cb->storereport)
1339 if ((f = cb->cb) != NULL)
1340 f(ctx, msgid, evpid);
1344 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1345 char *params, char *linedup)
1348 unsigned long imsgid;
1350 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1353 imsgid = strtoul(params, &end, 16);
1354 if ((imsgid == ULONG_MAX && errno != 0))
1355 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1357 errx(1, "Invalid line received: missing address: %s", linedup);
1359 if ((unsigned long) msgid != imsgid)
1360 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1363 if ((f = cb->cb) != NULL)
1364 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1368 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1369 char *params, char *linedup)
1373 unsigned long imsgid;
1376 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1379 imsgid = strtoul(params, &end, 16);
1380 if ((imsgid == ULONG_MAX && errno != 0))
1381 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1383 errx(1, "Invalid line received: missing address: %s", linedup);
1385 if ((unsigned long) msgid != imsgid)
1386 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1389 msgsz = strtonum(params, 0, SIZE_MAX, &errstr);
1391 errx(1, "Invalid line received: invalid msg size: %s", linedup);
1393 free(ctx->mailfrom);
1394 ctx->mailfrom = NULL;
1396 for (i = 0; ctx->rcptto[i] != NULL; i++)
1397 free(ctx->rcptto[i]);
1398 ctx->rcptto[0] = NULL;
1402 if ((f = cb->cb) != NULL)
1403 f(ctx, msgid, msgsz);
1407 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1408 char *params, char *linedup)
1411 unsigned long imsgid;
1414 void (*f)(struct osmtpd_ctx *, uint32_t);
1417 imsgid = strtoul(params, &end, 16);
1418 if ((imsgid == ULONG_MAX && errno != 0))
1419 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1421 errx(1, "Invalid line received: missing address: %s", linedup);
1423 if ((unsigned long) msgid != imsgid)
1424 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1426 if ((f = cb->cb) != NULL)
1429 free(ctx->mailfrom);
1430 ctx->mailfrom = NULL;
1432 for (i = 0; ctx->rcptto[i] != NULL; i++)
1433 free(ctx->rcptto[i]);
1434 ctx->rcptto[0] = NULL;
1440 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1442 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1443 "proceed\n", ctx->token, ctx->reqid);
1447 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1451 if (code < 200 || code > 599)
1452 errx(1, "Invalid reject code");
1454 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|reject|"
1455 "%d ", ctx->token, ctx->reqid, code);
1456 va_start(ap, reason);
1457 io_vprintf(io_stdout, reason, ap);
1459 io_printf(io_stdout, "\n");
1463 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1467 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1468 "disconnect|421 ", ctx->token, ctx->reqid);
1469 va_start(ap, reason);
1470 io_vprintf(io_stdout, reason, ap);
1472 io_printf(io_stdout, "\n");
1476 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1480 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1481 "rewrite|", ctx->token, ctx->reqid);
1482 va_start(ap, value);
1483 io_vprintf(io_stdout, value, ap);
1485 io_printf(io_stdout, "\n");
1489 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1493 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1494 ctx->token, ctx->reqid);
1496 io_vprintf(io_stdout, line, ap);
1498 io_printf(io_stdout, "\n");
1502 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1503 int storereport, void *cb)
1508 errx(1, "Can't register when proc is running");
1510 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1511 if (type == osmtpd_callbacks[i].type &&
1512 phase == osmtpd_callbacks[i].phase &&
1513 incoming == osmtpd_callbacks[i].incoming) {
1514 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
1515 errx(1, "Event already registered");
1516 osmtpd_callbacks[i].cb = cb;
1517 osmtpd_callbacks[i].doregister = 1;
1519 osmtpd_callbacks[i].storereport = 1;
1524 errx(1, "Trying to register unknown event");
1527 static enum osmtpd_phase
1528 osmtpd_strtophase(const char *phase, const char *linedup)
1530 if (strcmp(phase, "connect") == 0)
1531 return OSMTPD_PHASE_CONNECT;
1532 if (strcmp(phase, "helo") == 0)
1533 return OSMTPD_PHASE_HELO;
1534 if (strcmp(phase, "ehlo") == 0)
1535 return OSMTPD_PHASE_EHLO;
1536 if (strcmp(phase, "starttls") == 0)
1537 return OSMTPD_PHASE_STARTTLS;
1538 if (strcmp(phase, "auth") == 0)
1539 return OSMTPD_PHASE_AUTH;
1540 if (strcmp(phase, "mail-from") == 0)
1541 return OSMTPD_PHASE_MAIL_FROM;
1542 if (strcmp(phase, "rcpt-to") == 0)
1543 return OSMTPD_PHASE_RCPT_TO;
1544 if (strcmp(phase, "data") == 0)
1545 return OSMTPD_PHASE_DATA;
1546 if (strcmp(phase, "data-line") == 0)
1547 return OSMTPD_PHASE_DATA_LINE;
1548 if (strcmp(phase, "rset") == 0)
1549 return OSMTPD_PHASE_RSET;
1550 if (strcmp(phase, "quit") == 0)
1551 return OSMTPD_PHASE_QUIT;
1552 if (strcmp(phase, "noop") == 0)
1553 return OSMTPD_PHASE_NOOP;
1554 if (strcmp(phase, "help") == 0)
1555 return OSMTPD_PHASE_HELP;
1556 if (strcmp(phase, "wiz") == 0)
1557 return OSMTPD_PHASE_WIZ;
1558 if (strcmp(phase, "commit") == 0)
1559 return OSMTPD_PHASE_COMMIT;
1560 if (strcmp(phase, "link-connect") == 0)
1561 return OSMTPD_PHASE_LINK_CONNECT;
1562 if (strcmp(phase, "link-disconnect") == 0)
1563 return OSMTPD_PHASE_LINK_DISCONNECT;
1564 if (strcmp(phase, "link-identify") == 0)
1565 return OSMTPD_PHASE_LINK_IDENTIFY;
1566 if (strcmp(phase, "link-tls") == 0)
1567 return OSMTPD_PHASE_LINK_TLS;
1568 if (strcmp(phase, "tx-begin") == 0)
1569 return OSMTPD_PHASE_TX_BEGIN;
1570 if (strcmp(phase, "tx-mail") == 0)
1571 return OSMTPD_PHASE_TX_MAIL;
1572 if (strcmp(phase, "tx-rcpt") == 0)
1573 return OSMTPD_PHASE_TX_RCPT;
1574 if (strcmp(phase, "tx-envelope") == 0)
1575 return OSMTPD_PHASE_TX_ENVELOPE;
1576 if (strcmp(phase, "tx-data") == 0)
1577 return OSMTPD_PHASE_TX_DATA;
1578 if (strcmp(phase, "tx-commit") == 0)
1579 return OSMTPD_PHASE_TX_COMMIT;
1580 if (strcmp(phase, "tx-rollback") == 0)
1581 return OSMTPD_PHASE_TX_ROLLBACK;
1582 if (strcmp(phase, "protocol-client") == 0)
1583 return OSMTPD_PHASE_PROTOCOL_CLIENT;
1584 if (strcmp(phase, "protocol-server") == 0)
1585 return OSMTPD_PHASE_PROTOCOL_SERVER;
1586 if (strcmp(phase, "filter-response") == 0)
1587 return OSMTPD_PHASE_FILTER_RESPONSE;
1588 if (strcmp(phase, "timeout") == 0)
1589 return OSMTPD_PHASE_TIMEOUT;
1590 errx(1, "Invalid line received: invalid phase: %s", linedup);
1594 osmtpd_typetostr(enum osmtpd_type type)
1597 case OSMTPD_TYPE_FILTER:
1599 case OSMTPD_TYPE_REPORT:
1602 errx(1, "In valid type: %d\n", type);
1606 osmtpd_phasetostr(enum osmtpd_phase phase)
1609 case OSMTPD_PHASE_CONNECT:
1611 case OSMTPD_PHASE_HELO:
1613 case OSMTPD_PHASE_EHLO:
1615 case OSMTPD_PHASE_STARTTLS:
1617 case OSMTPD_PHASE_AUTH:
1619 case OSMTPD_PHASE_MAIL_FROM:
1621 case OSMTPD_PHASE_RCPT_TO:
1623 case OSMTPD_PHASE_DATA:
1625 case OSMTPD_PHASE_DATA_LINE:
1627 case OSMTPD_PHASE_RSET:
1629 case OSMTPD_PHASE_QUIT:
1631 case OSMTPD_PHASE_NOOP:
1633 case OSMTPD_PHASE_HELP:
1635 case OSMTPD_PHASE_WIZ:
1637 case OSMTPD_PHASE_COMMIT:
1639 case OSMTPD_PHASE_LINK_CONNECT:
1640 return "link-connect";
1641 case OSMTPD_PHASE_LINK_DISCONNECT:
1642 return "link-disconnect";
1643 case OSMTPD_PHASE_LINK_IDENTIFY:
1644 return "link-identify";
1645 case OSMTPD_PHASE_LINK_TLS:
1647 case OSMTPD_PHASE_TX_BEGIN:
1649 case OSMTPD_PHASE_TX_MAIL:
1651 case OSMTPD_PHASE_TX_RCPT:
1653 case OSMTPD_PHASE_TX_ENVELOPE:
1654 return "tx-envelope";
1655 case OSMTPD_PHASE_TX_DATA:
1657 case OSMTPD_PHASE_TX_COMMIT:
1659 case OSMTPD_PHASE_TX_ROLLBACK:
1660 return "tx-rollback";
1661 case OSMTPD_PHASE_PROTOCOL_CLIENT:
1662 return "protocol-client";
1663 case OSMTPD_PHASE_PROTOCOL_SERVER:
1664 return "protocol-server";
1665 case OSMTPD_PHASE_FILTER_RESPONSE:
1666 return "filter-response";
1667 case OSMTPD_PHASE_TIMEOUT:
1670 errx(1, "In valid phase: %d\n", phase);
1674 osmtpd_status osmtpd_strtostatus(const char *status, char *linedup)
1676 if (strcmp(status, "ok") == 0)
1677 return OSMTPD_STATUS_OK;
1678 else if (strcmp(status, "tempfail") == 0)
1679 return OSMTPD_STATUS_TEMPFAIL;
1680 else if (strcmp(status, "permfail") == 0)
1681 return OSMTPD_STATUS_PERMFAIL;
1682 errx(1, "Invalid line received: invalid status: %s\n", linedup);
1686 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
1690 const char *errstr = NULL;
1691 struct sockaddr_in *sin;
1692 struct sockaddr_in6 *sin6;
1693 struct sockaddr_un *sun;
1695 if (strncasecmp(addr, "ipv6:", 5) == 0) {
1696 sin6 = (struct sockaddr_in6 *)ss;
1697 sin6->sin6_len = sizeof(*sin6);
1698 sin6->sin6_family = AF_INET6;
1699 sin6->sin6_port = 0;
1701 if ((port = strrchr(addr, ':')) == NULL)
1702 errx(1, "Invalid line received: invalid "
1703 "address (%s): %s", addr, linedup);
1705 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
1708 errx(1, "Invalid line received: invalid "
1709 "address (%s): %s", addr, linedup);
1712 switch (inet_pton(AF_INET6, addr + 5, &(sin6->sin6_addr))) {
1717 errx(1, "Invalid line received: invalid address "
1718 "(%s): %s", addr, linedup);
1721 err(1, "Can't parse address (%s): %s", addr, linedup);
1723 } else if (strncasecmp(addr, "unix:", 5) == 0) {
1724 sun = (struct sockaddr_un *)ss;
1725 sun->sun_len = sizeof(*sun);
1726 sun->sun_family = AF_UNIX;
1727 if (strlcpy(sun->sun_path, addr,
1728 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
1729 errx(1, "Invalid line received: address too long (%s): "
1730 "%s", addr, linedup);
1733 sin = (struct sockaddr_in *)ss;
1734 sin->sin_len = sizeof(*sin);
1735 sin->sin_family = AF_INET;
1738 if ((port = strrchr(addr, ':')) == NULL)
1739 errx(1, "Invalid line received: invalid "
1740 "address (%s): %s", addr, linedup);
1742 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
1745 errx(1, "Invalid line received: invalid "
1746 "address (%s): %s", addr, linedup);
1749 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
1754 errx(1, "Invalid line received: invalid address "
1755 "(%s): %s", addr, linedup);
1758 err(1, "Can't parse address (%s): %s", addr, linedup);
1764 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
1766 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
1769 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);