Blob


1 /*
2 * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
3 *
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.
7 *
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.
15 */
16 #include <sys/time.h>
17 #include <sys/tree.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
24 #include <err.h>
25 #include <errno.h>
26 #include <event.h>
27 #include <fcntl.h>
28 #include <inttypes.h>
29 #include <limits.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <syslog.h>
35 #include <unistd.h>
37 #include "opensmtpd.h"
38 #include "ioev.h"
40 #define NITEMS(x) (sizeof(x) / sizeof(*x))
42 struct osmtpd_callback {
43 enum osmtpd_type type;
44 enum osmtpd_phase phase;
45 int incoming;
46 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_ctx *, char *,
47 char *);
48 void *cb;
49 int doregister;
50 int storereport;
51 };
53 struct osmtpd_session {
54 struct osmtpd_ctx ctx;
55 RB_ENTRY(osmtpd_session) entry;
56 };
58 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
59 void *);
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 *,
66 char *, char *);
67 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_ctx *,
68 char *, char *);
69 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
70 char *, char *);
71 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
72 char *, char *);
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 *,
76 char *, char *);
77 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_ctx *,
78 char *, char *);
79 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
80 char *, char *);
81 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
82 char *, char *);
83 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
84 char *, char *);
85 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
86 char *, char *);
87 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
88 char *, char *);
89 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
90 char *, char *);
91 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
92 char *, char *);
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[] = {
102 OSMTPD_TYPE_FILTER,
103 OSMTPD_PHASE_CONNECT,
104 1,
105 osmtpd_connect,
106 NULL,
107 0,
109 },
111 OSMTPD_TYPE_FILTER,
112 OSMTPD_PHASE_HELO,
113 1,
114 osmtpd_onearg,
115 NULL,
116 0,
118 },
120 OSMTPD_TYPE_FILTER,
121 OSMTPD_PHASE_EHLO,
122 1,
123 osmtpd_onearg,
124 NULL,
125 0,
127 },
129 OSMTPD_TYPE_FILTER,
130 OSMTPD_PHASE_STARTTLS,
131 1,
132 osmtpd_noargs,
133 NULL,
134 0,
136 },
138 OSMTPD_TYPE_FILTER,
139 OSMTPD_PHASE_AUTH,
140 1,
141 osmtpd_onearg,
142 NULL,
143 0,
145 },
147 OSMTPD_TYPE_FILTER,
148 OSMTPD_PHASE_MAIL_FROM,
149 1,
150 osmtpd_onearg,
151 NULL,
152 0,
154 },
156 OSMTPD_TYPE_FILTER,
157 OSMTPD_PHASE_RCPT_TO,
158 1,
159 osmtpd_onearg,
160 NULL,
161 0,
163 },
165 OSMTPD_TYPE_FILTER,
166 OSMTPD_PHASE_DATA,
167 1,
168 osmtpd_noargs,
169 NULL,
170 0,
172 },
174 OSMTPD_TYPE_FILTER,
175 OSMTPD_PHASE_DATA_LINE,
176 1,
177 osmtpd_onearg,
178 NULL,
179 0,
181 },
183 OSMTPD_TYPE_FILTER,
184 OSMTPD_PHASE_RSET,
185 1,
186 osmtpd_noargs,
187 NULL,
188 0,
190 },
192 OSMTPD_TYPE_FILTER,
193 OSMTPD_PHASE_QUIT,
194 1,
195 osmtpd_noargs,
196 NULL,
197 0,
199 },
201 OSMTPD_TYPE_FILTER,
202 OSMTPD_PHASE_NOOP,
203 1,
204 osmtpd_noargs,
205 NULL,
206 0,
208 },
210 OSMTPD_TYPE_FILTER,
211 OSMTPD_PHASE_HELP,
212 1,
213 osmtpd_noargs,
214 NULL,
215 0,
217 },
219 OSMTPD_TYPE_FILTER,
220 OSMTPD_PHASE_WIZ,
221 1,
222 osmtpd_noargs,
223 NULL,
224 0,
226 },
228 OSMTPD_TYPE_FILTER,
229 OSMTPD_PHASE_COMMIT,
230 1,
231 osmtpd_noargs,
232 NULL,
233 0,
235 },
237 OSMTPD_TYPE_REPORT,
238 OSMTPD_PHASE_LINK_CONNECT,
239 1,
240 osmtpd_link_connect,
241 NULL,
242 0,
244 },
246 OSMTPD_TYPE_REPORT,
247 OSMTPD_PHASE_LINK_DISCONNECT,
248 1,
249 osmtpd_link_disconnect,
250 NULL,
251 0,
253 },
255 OSMTPD_TYPE_REPORT,
256 OSMTPD_PHASE_LINK_IDENTIFY,
257 1,
258 osmtpd_link_identify,
259 NULL,
260 0,
262 },
264 OSMTPD_TYPE_REPORT,
265 OSMTPD_PHASE_LINK_TLS,
266 1,
267 osmtpd_link_tls,
268 NULL,
269 0,
271 },
273 OSMTPD_TYPE_REPORT,
274 OSMTPD_PHASE_TX_BEGIN,
275 1,
276 osmtpd_tx_begin,
277 NULL,
278 0,
280 },
282 OSMTPD_TYPE_REPORT,
283 OSMTPD_PHASE_TX_MAIL,
284 1,
285 osmtpd_tx_mail,
286 NULL,
287 0,
289 },
291 OSMTPD_TYPE_REPORT,
292 OSMTPD_PHASE_TX_RCPT,
293 1,
294 osmtpd_tx_rcpt,
295 NULL,
296 0,
298 },
300 OSMTPD_TYPE_REPORT,
301 OSMTPD_PHASE_TX_ENVELOPE,
302 1,
303 osmtpd_tx_envelope,
304 NULL,
305 0,
307 },
309 OSMTPD_TYPE_REPORT,
310 OSMTPD_PHASE_TX_DATA,
311 1,
312 osmtpd_tx_data,
313 NULL,
314 0,
316 },
318 OSMTPD_TYPE_REPORT,
319 OSMTPD_PHASE_TX_COMMIT,
320 1,
321 osmtpd_tx_commit,
322 NULL,
323 0,
325 },
327 OSMTPD_TYPE_REPORT,
328 OSMTPD_PHASE_TX_ROLLBACK,
329 1,
330 osmtpd_tx_rollback,
331 NULL,
332 0,
334 },
336 OSMTPD_TYPE_REPORT,
337 OSMTPD_PHASE_PROTOCOL_CLIENT,
338 1,
339 osmtpd_onearg,
340 NULL,
341 0,
343 },
345 OSMTPD_TYPE_REPORT,
346 OSMTPD_PHASE_PROTOCOL_SERVER,
347 1,
348 osmtpd_onearg,
349 NULL,
350 0,
352 },
354 OSMTPD_TYPE_REPORT,
355 OSMTPD_PHASE_FILTER_RESPONSE,
356 1,
357 osmtpd_onearg,
358 NULL,
359 0,
361 },
363 OSMTPD_TYPE_REPORT,
364 OSMTPD_PHASE_TIMEOUT,
365 1,
366 osmtpd_noargs,
367 NULL,
368 0,
370 },
372 OSMTPD_TYPE_REPORT,
373 OSMTPD_PHASE_LINK_CONNECT,
374 0,
375 osmtpd_link_connect,
376 NULL,
377 0,
379 },
381 OSMTPD_TYPE_REPORT,
382 OSMTPD_PHASE_LINK_DISCONNECT,
383 0,
384 osmtpd_link_disconnect,
385 NULL,
386 0,
388 },
390 OSMTPD_TYPE_REPORT,
391 OSMTPD_PHASE_LINK_IDENTIFY,
392 0,
393 osmtpd_link_identify,
394 NULL,
395 0,
397 },
399 OSMTPD_TYPE_REPORT,
400 OSMTPD_PHASE_LINK_TLS,
401 0,
402 osmtpd_link_tls,
403 NULL,
404 0,
406 },
408 OSMTPD_TYPE_REPORT,
409 OSMTPD_PHASE_TX_BEGIN,
410 0,
411 osmtpd_tx_begin,
412 NULL,
413 0,
415 },
417 OSMTPD_TYPE_REPORT,
418 OSMTPD_PHASE_TX_MAIL,
419 0,
420 osmtpd_tx_mail,
421 NULL,
422 0,
424 },
426 OSMTPD_TYPE_REPORT,
427 OSMTPD_PHASE_TX_RCPT,
428 0,
429 osmtpd_tx_rcpt,
430 NULL,
431 0,
433 },
435 OSMTPD_TYPE_REPORT,
436 OSMTPD_PHASE_TX_ENVELOPE,
437 0,
438 osmtpd_tx_envelope,
439 NULL,
440 0,
442 },
444 OSMTPD_TYPE_REPORT,
445 OSMTPD_PHASE_TX_DATA,
446 0,
447 osmtpd_tx_data,
448 NULL,
449 0,
451 },
453 OSMTPD_TYPE_REPORT,
454 OSMTPD_PHASE_TX_COMMIT,
455 0,
456 osmtpd_tx_commit,
457 NULL,
458 0,
460 },
462 OSMTPD_TYPE_REPORT,
463 OSMTPD_PHASE_TX_ROLLBACK,
464 0,
465 osmtpd_tx_rollback,
466 NULL,
467 0,
469 },
471 OSMTPD_TYPE_REPORT,
472 OSMTPD_PHASE_PROTOCOL_CLIENT,
473 0,
474 osmtpd_onearg,
475 NULL,
476 0,
478 },
480 OSMTPD_TYPE_REPORT,
481 OSMTPD_PHASE_PROTOCOL_SERVER,
482 0,
483 osmtpd_onearg,
484 NULL,
485 0,
487 },
489 OSMTPD_TYPE_REPORT,
490 OSMTPD_PHASE_FILTER_RESPONSE,
491 0,
492 osmtpd_onearg,
493 NULL,
494 0,
496 },
498 OSMTPD_TYPE_REPORT,
499 OSMTPD_PHASE_TIMEOUT,
500 0,
501 osmtpd_noargs,
502 NULL,
503 0,
506 };
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);
516 void
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,
521 (void *)cb);
522 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
523 NULL);
526 void
527 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
529 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
530 (void *)cb);
531 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
532 NULL);
535 void
536 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
538 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
539 (void *)cb);
540 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
541 NULL);
544 void
545 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
547 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
548 (void *)cb);
549 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
550 NULL);
553 void
554 osmtpd_register_filter_auth(void (*cb)(struct osmtpd_ctx *, const char *))
556 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
557 (void *)cb);
558 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
559 NULL);
562 void
563 osmtpd_register_filter_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
565 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
566 (void *)cb);
567 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
568 NULL);
571 void
572 osmtpd_register_filter_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
574 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
575 (void *)cb);
576 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
577 NULL);
580 void
581 osmtpd_register_filter_data(void (*cb)(struct osmtpd_ctx *))
583 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
584 (void *)cb);
585 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
586 NULL);
589 void
590 osmtpd_register_filter_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
592 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
593 (void *)cb);
594 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
595 NULL);
598 void
599 osmtpd_register_filter_rset(void (*cb)(struct osmtpd_ctx *))
601 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
602 (void *)cb);
603 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
604 NULL);
607 void
608 osmtpd_register_filter_quit(void (*cb)(struct osmtpd_ctx *))
610 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
611 (void *)cb);
612 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
613 NULL);
616 void
617 osmtpd_register_filter_noop(void (*cb)(struct osmtpd_ctx *))
619 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
620 (void *)cb);
621 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
622 NULL);
625 void
626 osmtpd_register_filter_help(void (*cb)(struct osmtpd_ctx *))
628 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
629 (void *)cb);
630 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
631 NULL);
634 void
635 osmtpd_register_filter_wiz(void (*cb)(struct osmtpd_ctx *))
637 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
638 (void *)cb);
639 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
640 NULL);
643 void
644 osmtpd_register_filter_commit(void (*cb)(struct osmtpd_ctx *))
646 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
647 (void *)cb);
648 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
649 NULL);
652 void
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,
658 0, (void *)cb);
659 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
660 incoming, 0, NULL);
663 void
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);
670 void
671 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
672 const char *))
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,
677 incoming, 0, NULL);
680 void
681 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
682 const char *))
684 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
685 (void *)cb);
686 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
687 incoming, 0, NULL);
690 void
691 osmtpd_register_report_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
692 uint32_t))
694 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
695 (void *)cb);
696 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
697 incoming, 0, NULL);
700 void
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,
705 (void *)cb);
706 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
707 incoming, 0, NULL);
710 void
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,
715 (void *)cb);
716 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
717 incoming, 0, NULL);
720 void
721 osmtpd_register_report_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
722 uint32_t, uint64_t))
724 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
725 0, (void *)cb);
726 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
727 incoming, 0, NULL);
730 void
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,
735 (void *)cb);
736 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
737 incoming, 0, NULL);
740 void
741 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
742 uint32_t, size_t))
744 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
745 (void *)cb);
746 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
747 incoming, 0, NULL);
750 void
751 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
752 uint32_t))
754 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
755 0, (void *)cb);
756 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
757 incoming, 0, NULL);
760 void
761 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
762 const char *))
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,
767 incoming, 0, NULL);
770 void
771 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
772 const char *))
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,
777 incoming, 0, NULL);
780 void
781 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
782 const char *))
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,
787 incoming, 0, NULL);
790 void
791 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
793 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
794 (void *)cb);
795 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
796 incoming, 0, NULL);
799 void
800 osmtpd_localdata(void *(*oncreate)(struct osmtpd_ctx *),
801 void (*ondelete)(struct osmtpd_ctx *, void *))
803 oncreatecb = oncreate;
804 ondeletecb = ondelete;
807 void
808 osmtpd_need(int incoming, int needs)
810 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
811 OSMTPD_NEED_FRDNS))
812 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_LINK_CONNECT,
813 incoming, 1, NULL);
814 if (needs & OSMTPD_NEED_IDENTITY)
815 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
816 incoming, 1, NULL);
817 if (needs & OSMTPD_NEED_CIPHERS)
818 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
819 incoming, 1, NULL);
820 if (needs & OSMTPD_NEED_MSGID) {
821 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
822 incoming, 1, NULL);
823 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
824 incoming, 0, NULL);
825 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
826 incoming, 0, NULL);
828 if (needs & OSMTPD_NEED_MAILFROM) {
829 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
830 incoming, 1, NULL);
831 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
832 incoming, 0, NULL);
833 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
834 incoming, 0, NULL);
836 if (needs & OSMTPD_NEED_RCPTTO) {
837 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
838 incoming, 1, NULL);
839 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
840 incoming, 0, NULL);
841 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
842 incoming, 0, NULL);
844 if (needs & OSMTPD_NEED_EVPID) {
845 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
846 incoming, 1, NULL);
847 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
848 incoming, 0, NULL);
849 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
850 incoming, 0, NULL);
853 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
854 incoming, 0, NULL);
857 void
858 osmtpd_run(void)
860 size_t i = 0;
861 int registered = 0;
862 /* Doesn't leak, since it needs to exists until the application ends. */
863 struct io *io_stdin;
865 event_init();
867 if ((io_stdin = io_new()) == NULL ||
868 (io_stdout = io_new()) == NULL)
869 err(1, "io_new");
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)
882 registered = 1;
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));
890 if (!registered)
891 errx(1, "No events registered");
892 io_printf(io_stdout, "register|ready\n");
893 ready = 1;
895 event_dispatch();
898 static void
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;
907 struct timespec tm;
908 char *line = NULL;
909 const char *errstr = NULL;
910 size_t linelen;
911 char *end;
912 size_t i;
914 if (ev == IO_DISCONNECTED)
915 exit(0);
916 if (ev != IO_DATAIN)
917 return;
918 while ((line = io_getline(io, &linelen)) > 0) {
919 if (dupsize < linelen) {
920 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
921 err(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);
927 end++[0] = '\0';
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) {
933 line = end;
934 if (strcmp(line, "ready") == 0)
935 continue;
936 if ((end = strchr(line, '|')) == NULL)
937 errx(1, "Invalid line received: missing key: %s", linedup);
938 end++[0] = '\0';
939 if (strcmp(line, "smtp-session-timeout") == 0) {
940 session_timeout = strtonum(end, 0, INT_MAX,
941 &errstr);
942 if (errstr != NULL)
943 errx(1, "Invalid line received: "
944 "invalid smtp-sesion-timeout: %s",
945 linedup);
947 continue;
949 else
950 errx(1, "Invalid line received: unknown message type: %s", linedup);
951 line = end;
952 if ((end = strchr(line, '|')) == NULL)
953 errx(1, "Invalid line received: missing time: %s", linedup);
954 end++[0] = '\0';
955 if (strcmp(line, "0.1") != 0)
956 errx(1, "Unsupported protocol received: %s", linedup);
957 version_major = 0;
958 version_minor = 1;
959 line = end;
960 if ((end = strchr(line, '.')) == NULL)
961 errx(1, "Invalid line received: invalid timestamp: %s", linedup);
962 end++[0] = '\0';
963 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
964 if (errstr != NULL)
965 errx(1, "Invalid line received: invalid timestamp: %s", linedup);
966 line = end;
967 if ((end = strchr(line, '|')) == NULL)
968 errx(1, "Invalid line received: missing direction: %s", linedup);
969 end++[0] = '\0';
970 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
971 if (errstr != NULL)
972 errx(1, "Invalid line received: invalid timestamp: %s",
973 linedup);
974 tm.tv_nsec *= 10 * (9 - (end - line));
975 line = end;
976 if ((end = strchr(line, '|')) == NULL)
977 errx(1, "Invalid line receieved: missing phase: %s",
978 linedup);
979 end++[0] = '\0';
980 if (strcmp(line, "smtp-in") == 0)
981 incoming = 1;
982 else if (strcmp(line, "smtp-out") == 0)
983 incoming = 0;
984 else
985 errx(1, "Invalid line: invalid direction: %s", linedup);
986 line = end;
987 if ((end = strchr(line, '|')) == NULL)
988 errx(1, "Invalid line received: missing reqid: %s",
989 linedup);
990 end++[0] = '\0';
991 phase = osmtpd_strtophase(line, linedup);
992 line = end;
993 errno = 0;
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",
998 linedup);
999 line = end + 1;
1000 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1001 if (ctx == NULL) {
1002 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1003 err(1, 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;
1009 ctx->ctx.msgid = 0;
1010 ctx->ctx.mailfrom = NULL;
1011 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1012 if (ctx->ctx.rcptto == NULL)
1013 err(1, "malloc");
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);
1020 ctx->ctx.evpid = 0;
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;
1032 ctx->ctx.token = 0;
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)
1038 break;
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) ||
1047 end[0] != '|')
1048 errx(1, "Invalid line received: invalid token: %s", linedup);
1049 line = end + 1;
1051 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1052 &(ctx->ctx), line, linedup);
1056 static void
1057 osmtpd_outevt(struct io *io, int evt, void *arg)
1059 switch (evt) {
1060 case IO_LOWAT:
1061 return;
1062 case IO_DISCONNECTED:
1063 exit(0);
1064 default:
1065 errx(1, "Unexpectd event");
1069 static void
1070 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1071 char *linedup)
1073 void (*f)(struct osmtpd_ctx *);
1075 f = cb->cb;
1076 f(ctx);
1079 static void
1080 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1081 char *linedup)
1083 void (*f)(struct osmtpd_ctx *, const char *);
1085 f = cb->cb;
1086 f(ctx, line);
1089 static void
1090 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1091 char *linedup)
1093 struct sockaddr_storage ss;
1094 char *hostname;
1095 char *address;
1096 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1098 hostname = params;
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);
1105 f = cb->cb;
1106 f(ctx, hostname, &ss);
1109 static void
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);
1120 end++[0] = '\0';
1121 rdns = params;
1122 params = end;
1123 if ((end = strchr(params, '|')) == NULL)
1124 errx(1, "Invalid line received: missing src: %s", linedup);
1125 end++[0] = '\0';
1126 fcrdns = params;
1127 params = end;
1128 if ((end = strchr(params, '|')) == NULL)
1129 errx(1, "Invalid line received: missing dst: %s", linedup);
1130 end++[0] = '\0';
1131 osmtpd_addrtoss(params, &src, 1, linedup);
1132 params = end;
1133 osmtpd_addrtoss(params, &dst, 1, linedup);
1134 if (cb->storereport) {
1135 if ((ctx->rdns = strdup(params)) == NULL)
1136 err(1, NULL);
1137 if ((ctx->fcrdns = strdup(params)) == NULL)
1138 err(1, 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);
1146 static void
1147 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1148 char *param, char *linedup)
1150 void (*f)(struct osmtpd_ctx *);
1151 size_t i;
1152 struct osmtpd_session *session, search;
1154 if ((f = cb->cb) != NULL)
1155 f(ctx);
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);
1171 free(session);
1175 static void
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)
1183 err(1, NULL);
1186 if ((f = cb->cb) != NULL)
1187 f(ctx, identity);
1190 static void
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)
1198 err(1, NULL);
1201 if ((f = cb->cb) != NULL)
1202 f(ctx, ciphers);
1205 static void
1206 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1207 char *msgid, char *linedup)
1209 unsigned long imsgid;
1210 char *endptr;
1211 void (*f)(struct osmtpd_ctx *, uint32_t);
1213 errno = 0;
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)
1223 ctx->msgid = 0;
1225 if ((f = cb->cb) != NULL)
1226 f(ctx, imsgid);
1229 static void
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;
1235 uint32_t msgid;
1236 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1237 enum osmtpd_status);
1239 errno = 0;
1240 imsgid = strtoul(params, &end, 16);
1241 if ((imsgid == ULONG_MAX && errno != 0))
1242 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1243 if (end[0] != '|')
1244 errx(1, "Invalid line received: missing address: %s", linedup);
1245 msgid = imsgid;
1246 if ((unsigned long) msgid != imsgid)
1247 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1248 params = end + 1;
1250 if ((end = strchr(params, '|')) == NULL)
1251 errx(1, "Invalid line received: missing status: %s", linedup);
1252 end++[0] = '\0';
1253 mailfrom = params;
1254 if (cb->storereport) {
1255 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1256 err(1, NULL);
1258 params = end;
1260 if ((f = cb->cb) != NULL)
1261 f(ctx, msgid, mailfrom, osmtpd_strtostatus(params, linedup));
1264 static void
1265 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1266 char *params, char *linedup)
1268 char *end, *rcptto;
1269 unsigned long imsgid;
1270 uint32_t msgid;
1271 size_t i;
1272 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1273 enum osmtpd_status);
1275 errno = 0;
1276 imsgid = strtoul(params, &end, 16);
1277 if ((imsgid == ULONG_MAX && errno != 0))
1278 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1279 if (end[0] != '|')
1280 errx(1, "Invalid line received: missing address: %s", linedup);
1281 msgid = imsgid;
1282 if ((unsigned long) msgid != imsgid)
1283 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1284 params = end + 1;
1286 if ((end = strchr(params, '|')) == NULL)
1287 errx(1, "Invalid line received: missing status: %s", linedup);
1288 end++[0] = '\0';
1290 rcptto = params;
1291 params = end;
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)
1299 err(1, NULL);
1301 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1302 err(1, NULL);
1303 ctx->rcptto[i + 1] = NULL;
1306 if ((f = cb->cb) != NULL)
1307 f(ctx, msgid, rcptto,
1308 osmtpd_strtostatus(params, linedup));
1311 static void
1312 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1313 char *params, char *linedup)
1315 unsigned long imsgid;
1316 uint32_t msgid;
1317 uint64_t evpid;
1318 char *end;
1319 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1321 errno = 0;
1322 imsgid = strtoul(params, &end, 16);
1323 if ((imsgid == ULONG_MAX && errno != 0))
1324 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1325 if (end[0] != '|')
1326 errx(1, "Invalid line received: missing address: %s", linedup);
1327 msgid = imsgid;
1328 if ((unsigned long) msgid != imsgid)
1329 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1330 params = end + 1;
1332 evpid = strtoull(params, &end, 16);
1333 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1334 end[0] != '\0')
1335 errx(1, "Invalid line received: invalid evpid: %s", linedup);
1336 if (cb->storereport)
1337 ctx->evpid = evpid;
1339 if ((f = cb->cb) != NULL)
1340 f(ctx, msgid, evpid);
1343 static void
1344 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1345 char *params, char *linedup)
1347 char *end;
1348 unsigned long imsgid;
1349 uint32_t msgid;
1350 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1352 errno = 0;
1353 imsgid = strtoul(params, &end, 16);
1354 if ((imsgid == ULONG_MAX && errno != 0))
1355 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1356 if (end[0] != '|')
1357 errx(1, "Invalid line received: missing address: %s", linedup);
1358 msgid = imsgid;
1359 if ((unsigned long) msgid != imsgid)
1360 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1361 params = end + 1;
1363 if ((f = cb->cb) != NULL)
1364 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1367 static void
1368 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1369 char *params, char *linedup)
1371 char *end;
1372 const char *errstr;
1373 unsigned long imsgid;
1374 uint32_t msgid;
1375 size_t i, msgsz;
1376 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1378 errno = 0;
1379 imsgid = strtoul(params, &end, 16);
1380 if ((imsgid == ULONG_MAX && errno != 0))
1381 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1382 if (end[0] != '|')
1383 errx(1, "Invalid line received: missing address: %s", linedup);
1384 msgid = imsgid;
1385 if ((unsigned long) msgid != imsgid)
1386 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1387 params = end + 1;
1389 msgsz = strtonum(params, 0, SIZE_MAX, &errstr);
1390 if (errstr != NULL)
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;
1399 ctx->evpid = 0;
1400 ctx->msgid = 0;
1402 if ((f = cb->cb) != NULL)
1403 f(ctx, msgid, msgsz);
1406 static void
1407 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1408 char *params, char *linedup)
1410 char *end;
1411 unsigned long imsgid;
1412 uint32_t msgid;
1413 size_t i;
1414 void (*f)(struct osmtpd_ctx *, uint32_t);
1416 errno = 0;
1417 imsgid = strtoul(params, &end, 16);
1418 if ((imsgid == ULONG_MAX && errno != 0))
1419 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1420 if (end[0] != '\0')
1421 errx(1, "Invalid line received: missing address: %s", linedup);
1422 msgid = imsgid;
1423 if ((unsigned long) msgid != imsgid)
1424 errx(1, "Invalid line received: invalid msgid: %s", linedup);
1426 if ((f = cb->cb) != NULL)
1427 f(ctx, msgid);
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;
1435 ctx->evpid = 0;
1436 ctx->msgid = 0;
1439 void
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);
1446 void
1447 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1449 va_list ap;
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);
1458 va_end(ap);
1459 io_printf(io_stdout, "\n");
1462 void
1463 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1465 va_list ap;
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);
1471 va_end(ap);
1472 io_printf(io_stdout, "\n");
1475 void
1476 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1478 va_list ap;
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);
1484 va_end(ap);
1485 io_printf(io_stdout, "\n");
1488 void
1489 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1491 va_list ap;
1493 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1494 ctx->token, ctx->reqid);
1495 va_start(ap, line);
1496 io_vprintf(io_stdout, line, ap);
1497 va_end(ap);
1498 io_printf(io_stdout, "\n");
1501 static void
1502 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1503 int storereport, void *cb)
1505 size_t i;
1507 if (ready)
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;
1518 if (storereport)
1519 osmtpd_callbacks[i].storereport = 1;
1520 return;
1523 /* NOT REACHED */
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);
1593 static const char *
1594 osmtpd_typetostr(enum osmtpd_type type)
1596 switch (type) {
1597 case OSMTPD_TYPE_FILTER:
1598 return "filter";
1599 case OSMTPD_TYPE_REPORT:
1600 return "report";
1602 errx(1, "In valid type: %d\n", type);
1605 static const char *
1606 osmtpd_phasetostr(enum osmtpd_phase phase)
1608 switch (phase) {
1609 case OSMTPD_PHASE_CONNECT:
1610 return "connect";
1611 case OSMTPD_PHASE_HELO:
1612 return "helo";
1613 case OSMTPD_PHASE_EHLO:
1614 return "ehlo";
1615 case OSMTPD_PHASE_STARTTLS:
1616 return "starttls";
1617 case OSMTPD_PHASE_AUTH:
1618 return "auth";
1619 case OSMTPD_PHASE_MAIL_FROM:
1620 return "mail-from";
1621 case OSMTPD_PHASE_RCPT_TO:
1622 return "rcpt-to";
1623 case OSMTPD_PHASE_DATA:
1624 return "data";
1625 case OSMTPD_PHASE_DATA_LINE:
1626 return "data-line";
1627 case OSMTPD_PHASE_RSET:
1628 return "rset";
1629 case OSMTPD_PHASE_QUIT:
1630 return "quit";
1631 case OSMTPD_PHASE_NOOP:
1632 return "noop";
1633 case OSMTPD_PHASE_HELP:
1634 return "help";
1635 case OSMTPD_PHASE_WIZ:
1636 return "wiz";
1637 case OSMTPD_PHASE_COMMIT:
1638 return "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:
1646 return "link-tls";
1647 case OSMTPD_PHASE_TX_BEGIN:
1648 return "tx-begin";
1649 case OSMTPD_PHASE_TX_MAIL:
1650 return "tx-mail";
1651 case OSMTPD_PHASE_TX_RCPT:
1652 return "tx-rcpt";
1653 case OSMTPD_PHASE_TX_ENVELOPE:
1654 return "tx-envelope";
1655 case OSMTPD_PHASE_TX_DATA:
1656 return "tx-data";
1657 case OSMTPD_PHASE_TX_COMMIT:
1658 return "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:
1668 return "timeout";
1670 errx(1, "In valid phase: %d\n", phase);
1673 static enum
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);
1685 static void
1686 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
1687 char *linedup)
1689 char *port;
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;
1700 if (hasport) {
1701 if ((port = strrchr(addr, ':')) == NULL)
1702 errx(1, "Invalid line received: invalid "
1703 "address (%s): %s", addr, linedup);
1704 port++;
1705 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
1706 &errstr));
1707 if (errstr != NULL)
1708 errx(1, "Invalid line received: invalid "
1709 "address (%s): %s", addr, linedup);
1710 port[-1] = '\0';
1712 switch (inet_pton(AF_INET6, addr + 5, &(sin6->sin6_addr))) {
1713 case 1:
1714 break;
1715 case 0:
1716 port[-1] = ':';
1717 errx(1, "Invalid line received: invalid address "
1718 "(%s): %s", addr, linedup);
1719 default:
1720 port[-1] = ':';
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);
1732 } else {
1733 sin = (struct sockaddr_in *)ss;
1734 sin->sin_len = sizeof(*sin);
1735 sin->sin_family = AF_INET;
1736 sin->sin_port = 0;
1737 if (hasport) {
1738 if ((port = strrchr(addr, ':')) == NULL)
1739 errx(1, "Invalid line received: invalid "
1740 "address (%s): %s", addr, linedup);
1741 port++;
1742 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
1743 &errstr));
1744 if (errstr != NULL)
1745 errx(1, "Invalid line received: invalid "
1746 "address (%s): %s", addr, linedup);
1747 port[-1] = '\0';
1749 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
1750 case 1:
1751 break;
1752 case 0:
1753 port[-1] = ':';
1754 errx(1, "Invalid line received: invalid address "
1755 "(%s): %s", addr, linedup);
1756 default:
1757 port[-1] = ':';
1758 err(1, "Can't parse address (%s): %s", addr, linedup);
1763 static int
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);