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 #define _GNU_SOURCE 1
18 #include <sys/time.h>
19 #include <sys/tree.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
26 #include <errno.h>
27 #include <event.h>
28 #include <fcntl.h>
29 #include <inttypes.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <unistd.h>
38 #include "openbsd-compat.h"
39 #include "opensmtpd.h"
40 #include "ioev.h"
42 #define NITEMS(x) (sizeof(x) / sizeof(*x))
44 enum osmtpd_session_status {
45 SESSION_OK = 0,
46 SESSION_ERROR,
47 SESSION_DISCONNECTED
48 };
50 struct osmtpd_session {
51 struct osmtpd_ctx ctx; /* Must remain first element */
52 enum osmtpd_session_status status;
53 RB_ENTRY(osmtpd_session) entry;
54 };
56 struct osmtpd_callback {
57 enum osmtpd_type type;
58 enum osmtpd_phase phase;
59 int incoming;
60 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_session *,
61 char *, char *);
62 void *cb;
63 int doregister;
64 int storereport;
65 };
67 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
68 void *);
69 static const char *osmtpd_typetostr(enum osmtpd_type);
70 static const char *osmtpd_phasetostr(enum osmtpd_phase);
71 static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
72 static void osmtpd_newline(struct io *, int, void *);
73 static void osmtpd_outevt(struct io *, int, void *);
74 static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_session *,
75 char *, char *);
76 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_session *,
77 char *, char *);
78 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_session *,
79 char *, char *);
80 static void osmtpd_identify(struct osmtpd_callback *, struct osmtpd_session *,
81 char *, char *);
82 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_session *,
83 char *, char *);
84 static void osmtpd_link_disconnect(struct osmtpd_callback *,
85 struct osmtpd_session *, char *, char *);
86 static void osmtpd_link_greeting(struct osmtpd_callback *, struct osmtpd_session *,
87 char *, char *);
88 static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_session *,
89 char *, char *);
90 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_session *,
91 char *, char *);
92 static void osmtpd_link_auth(struct osmtpd_callback *, struct osmtpd_session *,
93 char *, char *);
94 static void osmtpd_tx_reset(struct osmtpd_callback *, struct osmtpd_session *,
95 char *, char *);
96 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_session *,
97 char *, char *);
98 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_session *,
99 char *, char *);
100 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_session *,
101 char *, char *);
102 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_session *,
103 char *, char *);
104 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_session *,
105 char *, char *);
106 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_session *,
107 char *, char *);
108 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_session *,
109 char *, char *);
110 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
111 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
112 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
113 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
114 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
115 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
116 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
117 static void (*conf_cb)(const char *, const char *);
119 static struct osmtpd_callback osmtpd_callbacks[] = {
121 OSMTPD_TYPE_FILTER,
122 OSMTPD_PHASE_CONNECT,
123 1,
124 osmtpd_connect,
125 NULL,
126 0,
128 },
130 OSMTPD_TYPE_FILTER,
131 OSMTPD_PHASE_HELO,
132 1,
133 osmtpd_identify,
134 NULL,
135 0,
137 },
139 OSMTPD_TYPE_FILTER,
140 OSMTPD_PHASE_EHLO,
141 1,
142 osmtpd_identify,
143 NULL,
144 0,
146 },
148 OSMTPD_TYPE_FILTER,
149 OSMTPD_PHASE_STARTTLS,
150 1,
151 osmtpd_noargs,
152 NULL,
153 0,
155 },
157 OSMTPD_TYPE_FILTER,
158 OSMTPD_PHASE_AUTH,
159 1,
160 osmtpd_onearg,
161 NULL,
162 0,
164 },
166 OSMTPD_TYPE_FILTER,
167 OSMTPD_PHASE_MAIL_FROM,
168 1,
169 osmtpd_onearg,
170 NULL,
171 0,
173 },
175 OSMTPD_TYPE_FILTER,
176 OSMTPD_PHASE_RCPT_TO,
177 1,
178 osmtpd_onearg,
179 NULL,
180 0,
182 },
184 OSMTPD_TYPE_FILTER,
185 OSMTPD_PHASE_DATA,
186 1,
187 osmtpd_noargs,
188 NULL,
189 0,
191 },
193 OSMTPD_TYPE_FILTER,
194 OSMTPD_PHASE_DATA_LINE,
195 1,
196 osmtpd_onearg,
197 NULL,
198 0,
200 },
202 OSMTPD_TYPE_FILTER,
203 OSMTPD_PHASE_RSET,
204 1,
205 osmtpd_noargs,
206 NULL,
207 0,
209 },
211 OSMTPD_TYPE_FILTER,
212 OSMTPD_PHASE_QUIT,
213 1,
214 osmtpd_noargs,
215 NULL,
216 0,
218 },
220 OSMTPD_TYPE_FILTER,
221 OSMTPD_PHASE_NOOP,
222 1,
223 osmtpd_noargs,
224 NULL,
225 0,
227 },
229 OSMTPD_TYPE_FILTER,
230 OSMTPD_PHASE_HELP,
231 1,
232 osmtpd_noargs,
233 NULL,
234 0,
236 },
238 OSMTPD_TYPE_FILTER,
239 OSMTPD_PHASE_WIZ,
240 1,
241 osmtpd_noargs,
242 NULL,
243 0,
245 },
247 OSMTPD_TYPE_FILTER,
248 OSMTPD_PHASE_COMMIT,
249 1,
250 osmtpd_noargs,
251 NULL,
252 0,
254 },
256 OSMTPD_TYPE_REPORT,
257 OSMTPD_PHASE_LINK_CONNECT,
258 1,
259 osmtpd_link_connect,
260 NULL,
261 0,
263 },
265 OSMTPD_TYPE_REPORT,
266 OSMTPD_PHASE_LINK_DISCONNECT,
267 1,
268 osmtpd_link_disconnect,
269 NULL,
270 0,
272 },
274 OSMTPD_TYPE_REPORT,
275 OSMTPD_PHASE_LINK_GREETING,
276 1,
277 osmtpd_link_greeting,
278 NULL,
279 0,
281 },
283 OSMTPD_TYPE_REPORT,
284 OSMTPD_PHASE_LINK_IDENTIFY,
285 1,
286 osmtpd_link_identify,
287 NULL,
288 0,
290 },
292 OSMTPD_TYPE_REPORT,
293 OSMTPD_PHASE_LINK_TLS,
294 1,
295 osmtpd_link_tls,
296 NULL,
297 0,
299 },
301 OSMTPD_TYPE_REPORT,
302 OSMTPD_PHASE_LINK_AUTH,
303 1,
304 osmtpd_link_auth,
305 NULL,
306 0,
308 },
310 OSMTPD_TYPE_REPORT,
311 OSMTPD_PHASE_TX_RESET,
312 1,
313 osmtpd_tx_reset,
314 NULL,
315 0,
317 },
319 OSMTPD_TYPE_REPORT,
320 OSMTPD_PHASE_TX_BEGIN,
321 1,
322 osmtpd_tx_begin,
323 NULL,
324 0,
326 },
328 OSMTPD_TYPE_REPORT,
329 OSMTPD_PHASE_TX_MAIL,
330 1,
331 osmtpd_tx_mail,
332 NULL,
333 0,
335 },
337 OSMTPD_TYPE_REPORT,
338 OSMTPD_PHASE_TX_RCPT,
339 1,
340 osmtpd_tx_rcpt,
341 NULL,
342 0,
344 },
346 OSMTPD_TYPE_REPORT,
347 OSMTPD_PHASE_TX_ENVELOPE,
348 1,
349 osmtpd_tx_envelope,
350 NULL,
351 0,
353 },
355 OSMTPD_TYPE_REPORT,
356 OSMTPD_PHASE_TX_DATA,
357 1,
358 osmtpd_tx_data,
359 NULL,
360 0,
362 },
364 OSMTPD_TYPE_REPORT,
365 OSMTPD_PHASE_TX_COMMIT,
366 1,
367 osmtpd_tx_commit,
368 NULL,
369 0,
371 },
373 OSMTPD_TYPE_REPORT,
374 OSMTPD_PHASE_TX_ROLLBACK,
375 1,
376 osmtpd_tx_rollback,
377 NULL,
378 0,
380 },
382 OSMTPD_TYPE_REPORT,
383 OSMTPD_PHASE_PROTOCOL_CLIENT,
384 1,
385 osmtpd_onearg,
386 NULL,
387 0,
389 },
391 OSMTPD_TYPE_REPORT,
392 OSMTPD_PHASE_PROTOCOL_SERVER,
393 1,
394 osmtpd_onearg,
395 NULL,
396 0,
398 },
400 OSMTPD_TYPE_REPORT,
401 OSMTPD_PHASE_FILTER_RESPONSE,
402 1,
403 osmtpd_onearg,
404 NULL,
405 0,
407 },
409 OSMTPD_TYPE_REPORT,
410 OSMTPD_PHASE_TIMEOUT,
411 1,
412 osmtpd_noargs,
413 NULL,
414 0,
416 },
418 OSMTPD_TYPE_REPORT,
419 OSMTPD_PHASE_LINK_CONNECT,
420 0,
421 osmtpd_link_connect,
422 NULL,
423 0,
425 },
427 OSMTPD_TYPE_REPORT,
428 OSMTPD_PHASE_LINK_DISCONNECT,
429 0,
430 osmtpd_link_disconnect,
431 NULL,
432 0,
434 },
436 OSMTPD_TYPE_REPORT,
437 OSMTPD_PHASE_LINK_GREETING,
438 0,
439 osmtpd_link_greeting,
440 NULL,
441 0,
443 },
445 OSMTPD_TYPE_REPORT,
446 OSMTPD_PHASE_LINK_IDENTIFY,
447 0,
448 osmtpd_link_identify,
449 NULL,
450 0,
452 },
454 OSMTPD_TYPE_REPORT,
455 OSMTPD_PHASE_LINK_TLS,
456 0,
457 osmtpd_link_tls,
458 NULL,
459 0,
461 },
463 OSMTPD_TYPE_REPORT,
464 OSMTPD_PHASE_LINK_AUTH,
465 0,
466 osmtpd_link_auth,
467 NULL,
468 0,
470 },
472 OSMTPD_TYPE_REPORT,
473 OSMTPD_PHASE_TX_RESET,
474 0,
475 osmtpd_tx_reset,
476 NULL,
477 0,
479 },
481 OSMTPD_TYPE_REPORT,
482 OSMTPD_PHASE_TX_BEGIN,
483 0,
484 osmtpd_tx_begin,
485 NULL,
486 0,
488 },
490 OSMTPD_TYPE_REPORT,
491 OSMTPD_PHASE_TX_MAIL,
492 0,
493 osmtpd_tx_mail,
494 NULL,
495 0,
497 },
499 OSMTPD_TYPE_REPORT,
500 OSMTPD_PHASE_TX_RCPT,
501 0,
502 osmtpd_tx_rcpt,
503 NULL,
504 0,
506 },
508 OSMTPD_TYPE_REPORT,
509 OSMTPD_PHASE_TX_ENVELOPE,
510 0,
511 osmtpd_tx_envelope,
512 NULL,
513 0,
515 },
517 OSMTPD_TYPE_REPORT,
518 OSMTPD_PHASE_TX_DATA,
519 0,
520 osmtpd_tx_data,
521 NULL,
522 0,
524 },
526 OSMTPD_TYPE_REPORT,
527 OSMTPD_PHASE_TX_COMMIT,
528 0,
529 osmtpd_tx_commit,
530 NULL,
531 0,
533 },
535 OSMTPD_TYPE_REPORT,
536 OSMTPD_PHASE_TX_ROLLBACK,
537 0,
538 osmtpd_tx_rollback,
539 NULL,
540 0,
542 },
544 OSMTPD_TYPE_REPORT,
545 OSMTPD_PHASE_PROTOCOL_CLIENT,
546 0,
547 osmtpd_onearg,
548 NULL,
549 0,
551 },
553 OSMTPD_TYPE_REPORT,
554 OSMTPD_PHASE_PROTOCOL_SERVER,
555 0,
556 osmtpd_onearg,
557 NULL,
558 0,
560 },
562 OSMTPD_TYPE_REPORT,
563 OSMTPD_PHASE_FILTER_RESPONSE,
564 0,
565 osmtpd_onearg,
566 NULL,
567 0,
569 },
571 OSMTPD_TYPE_REPORT,
572 OSMTPD_PHASE_TIMEOUT,
573 0,
574 osmtpd_noargs,
575 NULL,
576 0,
579 };
581 static struct io *io_stdout;
582 static int needs;
583 static int ready = 0;
584 /* Default from smtpd */
585 static int session_timeout = 300;
587 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
588 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
590 void
591 osmtpd_register_conf(void (*cb)(const char *, const char *))
593 conf_cb = cb;
596 void
597 osmtpd_register_filter_connect(int (*cb)(struct osmtpd_ctx *, const char *,
598 struct sockaddr_storage *))
600 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
601 (void *)cb);
602 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
603 NULL);
606 void
607 osmtpd_register_filter_helo(int (*cb)(struct osmtpd_ctx *, const char *))
609 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
610 (void *)cb);
611 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
612 NULL);
615 void
616 osmtpd_register_filter_ehlo(int (*cb)(struct osmtpd_ctx *, const char *))
618 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
619 (void *)cb);
620 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
621 NULL);
624 void
625 osmtpd_register_filter_starttls(int (*cb)(struct osmtpd_ctx *))
627 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
628 (void *)cb);
629 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
630 NULL);
633 void
634 osmtpd_register_filter_auth(int (*cb)(struct osmtpd_ctx *, const char *))
636 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
637 (void *)cb);
638 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
639 NULL);
642 void
643 osmtpd_register_filter_mailfrom(int (*cb)(struct osmtpd_ctx *, const char *))
645 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
646 (void *)cb);
647 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
648 NULL);
651 void
652 osmtpd_register_filter_rcptto(int (*cb)(struct osmtpd_ctx *, const char *))
654 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
655 (void *)cb);
656 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
657 NULL);
660 void
661 osmtpd_register_filter_data(int (*cb)(struct osmtpd_ctx *))
663 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
664 (void *)cb);
665 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
666 NULL);
669 void
670 osmtpd_register_filter_dataline(int (*cb)(struct osmtpd_ctx *, const char *))
672 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
673 (void *)cb);
674 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
675 NULL);
678 void
679 osmtpd_register_filter_rset(int (*cb)(struct osmtpd_ctx *))
681 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
682 (void *)cb);
683 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
684 NULL);
687 void
688 osmtpd_register_filter_quit(int (*cb)(struct osmtpd_ctx *))
690 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
691 (void *)cb);
692 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
693 NULL);
696 void
697 osmtpd_register_filter_noop(int (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
700 (void *)cb);
701 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
702 NULL);
705 void
706 osmtpd_register_filter_help(int (*cb)(struct osmtpd_ctx *))
708 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
709 (void *)cb);
710 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
711 NULL);
714 void
715 osmtpd_register_filter_wiz(int (*cb)(struct osmtpd_ctx *))
717 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
718 (void *)cb);
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
720 NULL);
723 void
724 osmtpd_register_filter_commit(int (*cb)(struct osmtpd_ctx *))
726 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
727 (void *)cb);
728 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
729 NULL);
732 void
733 osmtpd_register_report_connect(int incoming, int (*cb)(struct osmtpd_ctx *,
734 const char *, enum osmtpd_status, struct sockaddr_storage *,
735 struct sockaddr_storage *))
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
738 0, (void *)cb);
739 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
740 incoming, 0, NULL);
743 void
744 osmtpd_register_report_disconnect(int incoming, int (*cb)(struct osmtpd_ctx *))
746 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
747 incoming, 0, (void *)cb);
750 void
751 osmtpd_register_report_identify(int incoming, int (*cb)(struct osmtpd_ctx *,
752 const char *))
754 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
755 incoming, 0, (void *)cb);
756 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
757 incoming, 0, NULL);
760 void
761 osmtpd_register_report_tls(int incoming, int (*cb)(struct osmtpd_ctx *,
762 const char *))
764 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
765 (void *)cb);
766 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
767 incoming, 0, NULL);
770 void
771 osmtpd_register_report_auth(int incoming, int (*cb)(struct osmtpd_ctx *,
772 const char *, enum osmtpd_auth_status))
774 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, incoming, 0,
775 (void *)cb);
776 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
777 incoming, 0, NULL);
780 void
781 osmtpd_register_report_reset(int incoming, int (*cb)(struct osmtpd_ctx *,
782 uint32_t))
784 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET, incoming, 0,
785 (void *)cb);
786 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
787 incoming, 0, NULL);
790 void
791 osmtpd_register_report_begin(int incoming, int (*cb)(struct osmtpd_ctx *,
792 uint32_t))
794 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
795 (void *)cb);
796 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
797 incoming, 0, NULL);
800 void
801 osmtpd_register_report_mail(int incoming, int (*cb)(struct osmtpd_ctx *,
802 uint32_t, const char *, enum osmtpd_status))
804 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
805 (void *)cb);
806 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
807 incoming, 0, NULL);
810 void
811 osmtpd_register_report_rcpt(int incoming, int (*cb)(struct osmtpd_ctx *,
812 uint32_t, const char *, enum osmtpd_status))
814 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
815 (void *)cb);
816 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
817 incoming, 0, NULL);
820 void
821 osmtpd_register_report_envelope(int incoming, int (*cb)(struct osmtpd_ctx *,
822 uint32_t, uint64_t))
824 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
825 0, (void *)cb);
826 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
827 incoming, 0, NULL);
830 void
831 osmtpd_register_report_data(int incoming, int (*cb)(struct osmtpd_ctx *,
832 uint32_t, enum osmtpd_status))
834 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
835 (void *)cb);
836 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
837 incoming, 0, NULL);
840 void
841 osmtpd_register_report_commit(int incoming, int (*cb)(struct osmtpd_ctx *,
842 uint32_t, size_t))
844 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
845 (void *)cb);
846 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
847 incoming, 0, NULL);
850 void
851 osmtpd_register_report_rollback(int incoming, int (*cb)(struct osmtpd_ctx *,
852 uint32_t))
854 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
855 0, (void *)cb);
856 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
857 incoming, 0, NULL);
860 void
861 osmtpd_register_report_client(int incoming, int (*cb)(struct osmtpd_ctx *,
862 const char *))
864 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
865 incoming, 0, (void *)cb);
866 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
867 incoming, 0, NULL);
870 void
871 osmtpd_register_report_server(int incoming, int (*cb)(struct osmtpd_ctx *,
872 const char *))
874 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
875 incoming, 0, (void *)cb);
876 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
877 incoming, 0, NULL);
880 void
881 osmtpd_register_report_response(int incoming, int (*cb)(struct osmtpd_ctx *,
882 const char *))
884 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
885 incoming, 0, (void *)cb);
886 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
887 incoming, 0, NULL);
890 void
891 osmtpd_register_report_timeout(int incoming, int (*cb)(struct osmtpd_ctx *))
893 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
894 (void *)cb);
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
896 incoming, 0, NULL);
899 void
900 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
901 void (*ondelete)(struct osmtpd_ctx *, void *))
903 oncreatecb_session = oncreate;
904 ondeletecb_session = ondelete;
907 void
908 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
909 void (*ondelete)(struct osmtpd_ctx *, void *))
911 oncreatecb_message = oncreate;
912 ondeletecb_message = ondelete;
915 void
916 osmtpd_need(int lneeds)
918 needs |= lneeds;
921 static void
922 osmtpd_register_need(int incoming)
924 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
925 OSMTPD_NEED_FCRDNS))
926 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
927 incoming, 1, NULL);
928 if (needs & OSMTPD_NEED_GREETING)
929 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
930 incoming, 1, NULL);
931 if (needs & OSMTPD_NEED_IDENTITY)
932 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
933 incoming, 1, NULL);
934 if (needs & OSMTPD_NEED_CIPHERS)
935 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
936 incoming, 1, NULL);
937 if (needs & OSMTPD_NEED_USERNAME)
938 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
939 incoming, 1, NULL);
940 if (needs & OSMTPD_NEED_MSGID) {
941 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
942 incoming, 1, NULL);
943 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
944 incoming, 0, NULL);
946 if (needs & OSMTPD_NEED_MAILFROM) {
947 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
948 incoming, 1, NULL);
949 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
950 incoming, 0, NULL);
952 if (needs & OSMTPD_NEED_RCPTTO) {
953 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
954 incoming, 1, NULL);
955 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
956 incoming, 0, NULL);
958 if (needs & OSMTPD_NEED_EVPID) {
959 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
960 incoming, 1, NULL);
961 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RESET,
962 incoming, 0, NULL);
965 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
966 incoming, 0, NULL);
969 void
970 osmtpd_run(void)
972 size_t i = 0;
973 int registered = 0;
974 struct event_base *evbase;
975 struct io *io_stdin;
976 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
977 struct osmtpd_callback *ridentity = NULL;
979 evbase = event_init();
981 if ((io_stdin = io_new()) == NULL ||
982 (io_stdout = io_new()) == NULL)
983 osmtpd_err(1, "io_new");
984 io_set_nonblocking(STDIN_FILENO);
985 io_set_fd(io_stdin, STDIN_FILENO);
986 io_set_callback(io_stdin, osmtpd_newline, NULL);
987 io_set_read(io_stdin);
988 io_set_nonblocking(STDOUT_FILENO);
989 io_set_fd(io_stdout, STDOUT_FILENO);
990 io_set_callback(io_stdout, osmtpd_outevt, NULL);
991 io_set_write(io_stdout);
993 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
994 if (osmtpd_callbacks[i].doregister) {
995 osmtpd_register_need(osmtpd_callbacks[i].incoming);
996 if (oncreatecb_message != NULL) {
997 osmtpd_register(OSMTPD_TYPE_REPORT,
998 OSMTPD_PHASE_TX_BEGIN,
999 osmtpd_callbacks[i].incoming, 0, NULL);
1000 osmtpd_register(OSMTPD_TYPE_REPORT,
1001 OSMTPD_PHASE_TX_RESET,
1002 osmtpd_callbacks[i].incoming, 0, NULL);
1004 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1005 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
1006 hidenity = &(osmtpd_callbacks[i]);
1007 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
1008 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
1009 eidentity = &(osmtpd_callbacks[i]);
1010 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
1011 osmtpd_callbacks[i].phase ==
1012 OSMTPD_PHASE_LINK_IDENTIFY &&
1013 osmtpd_callbacks[i].incoming == 1)
1014 ridentity = &(osmtpd_callbacks[i]);
1017 if (ridentity != NULL && ridentity->storereport) {
1018 if (hidenity != NULL && hidenity->doregister)
1019 hidenity->storereport = 1;
1020 if (eidentity != NULL && eidentity->doregister)
1021 eidentity->storereport = 1;
1023 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1024 if (osmtpd_callbacks[i].doregister) {
1025 if (osmtpd_callbacks[i].cb != NULL)
1026 registered = 1;
1027 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1028 osmtpd_typetostr(osmtpd_callbacks[i].type),
1029 osmtpd_callbacks[i].incoming ? "in" : "out",
1030 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1034 if (!registered)
1035 osmtpd_errx(1, "No events registered");
1036 io_printf(io_stdout, "register|ready\n");
1037 ready = 1;
1039 event_dispatch();
1040 io_free(io_stdin);
1041 io_free(io_stdout);
1042 event_base_free(evbase);
1045 void
1046 osmtpd_warn(struct osmtpd_ctx *ctx, const char *fmt, ...)
1048 va_list ap;
1050 if (ctx)
1051 fprintf(stderr, "%016"PRIx64, ctx->reqid);
1052 va_start(ap, fmt);
1053 vfprintf(stderr, fmt, ap);
1054 va_end(ap);
1055 fprintf(stderr, ": %s\n", strerror(errno));
1058 void
1059 osmtpd_warnx(struct osmtpd_ctx *ctx, const char *fmt, ...)
1061 va_list ap;
1063 if (ctx)
1064 fprintf(stderr, "%016"PRIx64, ctx->reqid);
1065 va_start(ap, fmt);
1066 vfprintf(stderr, fmt, ap);
1067 va_end(ap);
1068 fprintf(stderr, "\n");
1071 __dead void
1072 osmtpd_err(int eval, const char *fmt, ...)
1074 va_list ap;
1076 va_start(ap, fmt);
1077 vfprintf(stderr, fmt, ap);
1078 va_end(ap);
1079 fprintf(stderr, ": %s\n", strerror(errno));
1080 exit(eval);
1083 __dead void
1084 osmtpd_errx(int eval, const char *fmt, ...)
1086 va_list ap;
1088 va_start(ap, fmt);
1089 vfprintf(stderr, fmt, ap);
1090 va_end(ap);
1091 fprintf(stderr, "\n");
1092 exit(eval);
1095 static void
1096 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1098 static char *linedup = NULL;
1099 static size_t dupsize = 0;
1100 struct osmtpd_session *ctx, search;
1101 enum osmtpd_type type;
1102 enum osmtpd_phase phase;
1103 int version_major, version_minor, incoming;
1104 struct timespec tm;
1105 char *line = NULL;
1106 const char *errstr = NULL;
1107 size_t linelen;
1108 char *end;
1109 size_t i;
1111 if (ev == IO_DISCONNECTED) {
1112 event_loopexit(0);
1113 return;
1115 if (ev != IO_DATAIN)
1116 return;
1118 * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1119 * cause a build-up of kevents, because of event_add/event_del loop.
1121 io_pause(io_stdout, IO_OUT);
1122 while ((line = io_getline(io, &linelen)) != NULL) {
1123 if (dupsize < linelen) {
1124 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1125 osmtpd_err(1, NULL);
1126 dupsize = linelen + 1;
1128 strlcpy(linedup, line, dupsize);
1129 if ((end = strchr(line, '|')) == NULL)
1130 osmtpd_errx(1, "Invalid line received: missing "
1131 "version: %s", linedup);
1132 end++[0] = '\0';
1133 if (strcmp(line, "filter") == 0)
1134 type = OSMTPD_TYPE_FILTER;
1135 else if (strcmp(line, "report") == 0)
1136 type = OSMTPD_TYPE_REPORT;
1137 else if (strcmp(line, "config") == 0) {
1138 line = end;
1139 if (strcmp(line, "ready") == 0) {
1140 if (conf_cb != NULL)
1141 conf_cb(NULL, NULL);
1142 continue;
1144 if ((end = strchr(line, '|')) == NULL)
1145 osmtpd_errx(1, "Invalid line received: missing "
1146 "key: %s", linedup);
1147 end++[0] = '\0';
1148 if (conf_cb != NULL)
1149 conf_cb(line, end);
1150 if (strcmp(line, "smtp-session-timeout") == 0) {
1151 session_timeout = strtonum(end, 0, INT_MAX,
1152 &errstr);
1153 if (errstr != NULL)
1154 osmtpd_errx(1, "Invalid line received: "
1155 "invalid smtp-sesion-timeout: %s",
1156 linedup);
1158 continue;
1160 else
1161 osmtpd_errx(1, "Invalid line received: unknown message "
1162 "type: %s", linedup);
1163 line = end;
1164 version_major = strtoul(line, &end, 10);
1165 if (line == end || end[0] != '.')
1166 osmtpd_errx(1, "Invalid protocol received: %s",
1167 linedup);
1168 line = end + 1;
1169 version_minor = strtoul(line, &end, 10);
1170 if (end[0] == '\0')
1171 osmtpd_errx(1, "Invalid line received: missing time: "
1172 "%s", linedup);
1173 if (line == end || end[0] != '|')
1174 osmtpd_errx(1, "Invalid protocol received: %s",
1175 linedup);
1176 if (version_major != 0)
1177 osmtpd_errx(1, "Unsupported protocol received: %s",
1178 linedup);
1179 line = end + 1;
1180 if ((end = strchr(line, '.')) == NULL)
1181 osmtpd_errx(1, "Invalid line received: invalid "
1182 "timestamp: %s", linedup);
1183 end++[0] = '\0';
1184 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1185 if (errstr != NULL)
1186 osmtpd_errx(1, "Invalid line received: invalid "
1187 "timestamp: %s", linedup);
1188 line = end;
1189 if ((end = strchr(line, '|')) == NULL)
1190 osmtpd_errx(1, "Invalid line received: missing "
1191 "direction: %s", linedup);
1192 end++[0] = '\0';
1193 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1194 if (errstr != NULL)
1195 osmtpd_errx(1, "Invalid line received: invalid "
1196 "timestamp: %s", linedup);
1197 tm.tv_nsec *= 10 * (9 - (end - line));
1198 line = end;
1199 if ((end = strchr(line, '|')) == NULL)
1200 osmtpd_errx(1, "Invalid line received: missing "
1201 "phase: %s", linedup);
1202 end++[0] = '\0';
1203 if (strcmp(line, "smtp-in") == 0)
1204 incoming = 1;
1205 else if (strcmp(line, "smtp-out") == 0)
1206 incoming = 0;
1207 else
1208 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1209 linedup);
1210 line = end;
1211 if ((end = strchr(line, '|')) == NULL)
1212 osmtpd_errx(1, "Invalid line received: missing reqid: "
1213 "%s", linedup);
1214 end++[0] = '\0';
1215 phase = osmtpd_strtophase(line, linedup);
1216 line = end;
1217 errno = 0;
1218 search.ctx.reqid = strtoull(line, &end, 16);
1219 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1220 (end[0] != '|' && end[0] != '\0'))
1221 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1222 "%s", linedup);
1223 line = end + 1;
1224 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1225 if (ctx == NULL) {
1226 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1227 osmtpd_err(1, NULL);
1228 ctx->status = SESSION_OK;
1229 ctx->ctx.reqid = search.ctx.reqid;
1230 ctx->ctx.rdns = NULL;
1231 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1232 ctx->ctx.identity = NULL;
1233 ctx->ctx.greeting.identity = NULL;
1234 ctx->ctx.ciphers = NULL;
1235 ctx->ctx.msgid = 0;
1236 ctx->ctx.username = NULL;
1237 ctx->ctx.mailfrom = NULL;
1238 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1239 if (ctx->ctx.rcptto == NULL)
1240 osmtpd_err(1, "malloc");
1241 ctx->ctx.rcptto[0] = NULL;
1242 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1243 ctx->ctx.src.ss_family = AF_UNSPEC;
1244 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1245 ctx->ctx.dst.ss_family = AF_UNSPEC;
1246 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1247 ctx->ctx.evpid = 0;
1248 ctx->ctx.local_session = NULL;
1249 ctx->ctx.local_message = NULL;
1250 if (oncreatecb_session != NULL)
1251 if ((ctx->ctx.local_session =
1252 oncreatecb_session(&ctx->ctx)) == NULL)
1253 ctx->status = SESSION_ERROR;
1255 ctx->ctx.type = type;
1256 ctx->ctx.phase = phase;
1257 ctx->ctx.version_major = version_major;
1258 ctx->ctx.version_minor = version_minor;
1259 ctx->ctx.incoming = incoming;
1260 ctx->ctx.tm.tv_sec = tm.tv_sec;
1261 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1262 ctx->ctx.token = 0;
1264 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1265 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1266 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1267 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1268 break;
1270 if (i == NITEMS(osmtpd_callbacks)) {
1271 osmtpd_errx(1, "Invalid line received: received "
1272 "unregistered line: %s", linedup);
1274 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1275 ctx->ctx.token = strtoull(line, &end, 16);
1276 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1277 end[0] != '|')
1278 osmtpd_errx(1, "Invalid line received: invalid "
1279 "token: %s", linedup);
1280 line = end + 1;
1281 if (ctx->status == SESSION_ERROR)
1282 osmtpd_filter_disconnect(&ctx->ctx,
1283 "internal server error");
1285 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1286 ctx, line, linedup);
1288 io_resume(io_stdout, IO_OUT);
1291 static void
1292 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1294 switch (evt) {
1295 case IO_LOWAT:
1296 return;
1297 case IO_DISCONNECTED:
1298 exit(0);
1299 default:
1300 osmtpd_errx(1, "Unexpectd event");
1304 static void
1305 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_session *session,
1306 __unused char *params, __unused char *linedup)
1308 int (*f)(struct osmtpd_ctx *);
1310 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1311 if (f(&session->ctx))
1312 session->status = SESSION_ERROR;
1315 static void
1316 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_session *session,
1317 char *line, __unused char *linedup)
1319 int (*f)(struct osmtpd_ctx *, const char *);
1321 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1322 if (f(&session->ctx, line))
1323 session->status = SESSION_ERROR;
1326 static void
1327 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1328 char *params, char *linedup)
1330 struct sockaddr_storage ss;
1331 char *hostname;
1332 char *address;
1333 int (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1335 hostname = params;
1336 if ((address = strchr(params, '|')) == NULL)
1337 osmtpd_errx(1, "Invalid line received: missing address: %s",
1338 linedup);
1339 address++[0] = '\0';
1341 osmtpd_addrtoss(address, &ss, 0, linedup);
1343 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1344 if (f(&session->ctx, hostname, &ss))
1345 session->status = SESSION_ERROR;
1348 static void
1349 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1350 char *identity, __unused char *linedup)
1352 int (*f)(struct osmtpd_ctx *, const char *);
1354 if (cb->storereport) {
1355 free(session->ctx.identity);
1356 if ((session->ctx.identity = strdup(identity)) == NULL)
1357 osmtpd_err(1, "strdup");
1360 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1361 if (f(&session->ctx, identity))
1362 session->status = SESSION_ERROR;
1365 static void
1366 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_session *session,
1367 char *params, char *linedup)
1369 char *end, *rdns;
1370 enum osmtpd_status fcrdns;
1371 struct sockaddr_storage src, dst;
1372 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1373 struct sockaddr_storage *, struct sockaddr_storage *);
1375 if ((end = strchr(params, '|')) == NULL)
1376 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1377 linedup);
1378 end++[0] = '\0';
1379 rdns = params;
1380 params = end;
1381 if ((end = strchr(params, '|')) == NULL)
1382 osmtpd_errx(1, "Invalid line received: missing src: %s",
1383 linedup);
1384 end++[0] = '\0';
1385 if (strcmp(params, "pass") == 0)
1386 fcrdns = OSMTPD_STATUS_OK;
1387 else if (strcmp(params, "fail") == 0)
1388 fcrdns = OSMTPD_STATUS_PERMFAIL;
1389 else if (strcmp(params, "error") == 0)
1390 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1391 else
1392 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1393 linedup);
1394 params = end;
1395 if ((end = strchr(params, '|')) == NULL)
1396 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1397 linedup);
1398 end++[0] = '\0';
1399 osmtpd_addrtoss(params, &src, 1, linedup);
1400 params = end;
1401 osmtpd_addrtoss(params, &dst, 1, linedup);
1402 if (cb->storereport) {
1403 if ((session->ctx.rdns = strdup(rdns)) == NULL)
1404 osmtpd_err(1, "strdup");
1405 session->ctx.fcrdns = fcrdns;
1406 memcpy(&session->ctx.src, &src, sizeof(session->ctx.src));
1407 memcpy(&session->ctx.dst, &dst, sizeof(session->ctx.dst));
1409 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1410 if (f(&session->ctx, rdns, fcrdns, &src, &dst))
1411 session->status = SESSION_ERROR;
1414 static void
1415 osmtpd_link_disconnect(struct osmtpd_callback *cb,
1416 struct osmtpd_session *session, __unused char *param,
1417 __unused char *linedup)
1419 int (*f)(struct osmtpd_ctx *);
1420 size_t i;
1422 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1423 if (f(&session->ctx))
1424 session->status = SESSION_ERROR;
1426 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1427 if (ondeletecb_session != NULL && session->ctx.local_session != NULL)
1428 ondeletecb_session(&session->ctx, session->ctx.local_session);
1429 free(session->ctx.rdns);
1430 free(session->ctx.identity);
1431 free(session->ctx.greeting.identity);
1432 free(session->ctx.ciphers);
1433 free(session->ctx.username);
1434 free(session->ctx.mailfrom);
1435 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1436 free(session->ctx.rcptto[i]);
1437 free(session->ctx.rcptto);
1438 free(session);
1441 static void
1442 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_session *session,
1443 char *identity, __unused char *linedup)
1445 int (*f)(struct osmtpd_ctx *, const char *);
1447 if (cb->storereport) {
1448 free(session->ctx.greeting.identity);
1449 if ((session->ctx.greeting.identity = strdup(identity)) == NULL)
1450 osmtpd_err(1, NULL);
1453 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1454 if (f(&session->ctx, identity))
1455 session->status = SESSION_ERROR;
1458 static void
1459 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_session *session,
1460 char *identity, __unused char *linedup)
1462 int (*f)(struct osmtpd_ctx *, const char *);
1464 if (cb->storereport) {
1465 free(session->ctx.identity);
1466 if ((session->ctx.identity = strdup(identity)) == NULL)
1467 osmtpd_err(1, NULL);
1470 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1471 if (f(&session->ctx, identity))
1472 session->status = SESSION_ERROR;
1475 static void
1476 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_session *session,
1477 char *ciphers, __unused char *linedup)
1479 int (*f)(struct osmtpd_ctx *, const char *);
1481 if (cb->storereport) {
1482 if ((session->ctx.ciphers = strdup(ciphers)) == NULL)
1483 osmtpd_err(1, NULL);
1486 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1487 if (f(&session->ctx, ciphers))
1488 session->status = SESSION_ERROR;
1491 static void
1492 osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_session *session,
1493 char *username, char *linedup)
1495 int (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1496 char *status;
1497 enum osmtpd_auth_status s;
1499 if ((status = strrchr(username, '|')) == NULL)
1500 osmtpd_errx(1, "Invalid auth received: %s", linedup);
1501 status[0] = '\0';
1502 status++;
1503 if (strcmp(status, "pass") == 0)
1504 s = OSMTPD_AUTH_PASS;
1505 else if (strcmp(status, "fail") == 0)
1506 s = OSMTPD_AUTH_FAIL;
1507 else if (strcmp(status, "error") == 0)
1508 s = OSMTPD_AUTH_ERROR;
1509 else
1510 osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1512 if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1513 if ((session->ctx.username = strdup(username)) == NULL)
1514 osmtpd_err(1, NULL);
1517 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1518 if (f(&session->ctx, username, s))
1519 session->status = SESSION_ERROR;
1522 static void
1523 osmtpd_tx_reset(struct osmtpd_callback *cb, struct osmtpd_session *session,
1524 char *params, char *linedup)
1526 char *end;
1527 unsigned long imsgid;
1528 uint32_t msgid;
1529 size_t i;
1530 int (*f)(struct osmtpd_ctx *, uint32_t);
1532 errno = 0;
1533 imsgid = strtoul(params, &end, 16);
1534 if ((imsgid == ULONG_MAX && errno != 0))
1535 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1536 linedup);
1537 if (end[0] != '\0')
1538 osmtpd_errx(1, "Invalid line received: missing address: %s",
1539 linedup);
1540 msgid = imsgid;
1541 if ((unsigned long) msgid != imsgid)
1542 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1543 linedup);
1545 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1546 if (f(&session->ctx, msgid))
1547 session->status = SESSION_ERROR;
1549 if (ondeletecb_message != NULL && session->ctx.local_message != NULL) {
1550 ondeletecb_message(&session->ctx, session->ctx.local_message);
1551 session->ctx.local_message = NULL;
1554 free(session->ctx.mailfrom);
1555 session->ctx.mailfrom = NULL;
1557 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1558 free(session->ctx.rcptto[i]);
1559 session->ctx.rcptto[0] = NULL;
1560 session->ctx.evpid = 0;
1561 session->ctx.msgid = 0;
1564 static void
1565 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_session *session,
1566 char *msgid, char *linedup)
1568 unsigned long imsgid;
1569 char *endptr;
1570 int (*f)(struct osmtpd_ctx *, uint32_t);
1572 errno = 0;
1573 imsgid = strtoul(msgid, &endptr, 16);
1574 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1575 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1576 linedup);
1577 session->ctx.msgid = imsgid;
1578 /* Check if we're in range */
1579 if ((unsigned long) session->ctx.msgid != imsgid)
1580 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1581 linedup);
1583 if (!cb->storereport)
1584 session->ctx.msgid = 0;
1586 if (oncreatecb_message != NULL) {
1587 session->ctx.local_message = oncreatecb_message(&session->ctx);
1588 if (session->ctx.local_message == NULL)
1589 session->status = SESSION_ERROR;
1592 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1593 if (f(&session->ctx, imsgid))
1594 session->status = SESSION_ERROR;
1597 static void
1598 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_session *session,
1599 char *params, char *linedup)
1601 char *end, *mailfrom;
1602 enum osmtpd_status status;
1603 unsigned long imsgid;
1604 uint32_t msgid;
1605 int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1606 enum osmtpd_status);
1608 errno = 0;
1609 imsgid = strtoul(params, &end, 16);
1610 if ((imsgid == ULONG_MAX && errno != 0))
1611 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1612 linedup);
1613 if (end[0] != '|')
1614 osmtpd_errx(1, "Invalid line received: missing address: %s",
1615 linedup);
1616 msgid = imsgid;
1617 if ((unsigned long) msgid != imsgid)
1618 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1619 linedup);
1620 params = end + 1;
1622 if ((end = strchr(params, '|')) == NULL)
1623 osmtpd_errx(1, "Invalid line received: missing status: %s",
1624 linedup);
1625 end++[0] = '\0';
1626 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1627 mailfrom = params;
1628 status = osmtpd_strtostatus(end, linedup);
1629 } else {
1630 mailfrom = end;
1631 status = osmtpd_strtostatus(params, linedup);
1633 if (cb->storereport) {
1634 if ((session->ctx.mailfrom = strdup(mailfrom)) == NULL)
1635 osmtpd_err(1, NULL);
1638 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1639 if (f(&session->ctx, msgid, mailfrom, status))
1640 session->status = SESSION_ERROR;
1643 static void
1644 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_session *session,
1645 char *params, char *linedup)
1647 char *end, *rcptto;
1648 enum osmtpd_status status;
1649 unsigned long imsgid;
1650 uint32_t msgid;
1651 size_t i;
1652 int (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1653 enum osmtpd_status);
1655 errno = 0;
1656 imsgid = strtoul(params, &end, 16);
1657 if ((imsgid == ULONG_MAX && errno != 0))
1658 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1659 linedup);
1660 if (end[0] != '|')
1661 osmtpd_errx(1, "Invalid line received: missing address: %s",
1662 linedup);
1663 msgid = imsgid;
1664 if ((unsigned long) msgid != imsgid)
1665 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1666 linedup);
1667 params = end + 1;
1669 if ((end = strchr(params, '|')) == NULL)
1670 osmtpd_errx(1, "Invalid line received: missing status: %s",
1671 linedup);
1672 end++[0] = '\0';
1674 if (session->ctx.version_major == 0 && session->ctx.version_minor < 6) {
1675 rcptto = params;
1676 status = osmtpd_strtostatus(end, linedup);
1677 } else {
1678 rcptto = end;
1679 status = osmtpd_strtostatus(params, linedup);
1682 if (cb->storereport) {
1683 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1685 session->ctx.rcptto = reallocarray(session->ctx.rcptto, i + 2,
1686 sizeof(*session->ctx.rcptto));
1687 if (session->ctx.rcptto == NULL)
1688 osmtpd_err(1, NULL);
1690 if ((session->ctx.rcptto[i] = strdup(rcptto)) == NULL)
1691 osmtpd_err(1, NULL);
1692 session->ctx.rcptto[i + 1] = NULL;
1695 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1696 if (f(&session->ctx, msgid, rcptto, status))
1697 session->status = SESSION_ERROR;
1700 static void
1701 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_session *session,
1702 char *params, char *linedup)
1704 unsigned long imsgid;
1705 uint32_t msgid;
1706 uint64_t evpid;
1707 char *end;
1708 int (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1710 errno = 0;
1711 imsgid = strtoul(params, &end, 16);
1712 if ((imsgid == ULONG_MAX && errno != 0))
1713 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1714 linedup);
1715 if (end[0] != '|')
1716 osmtpd_errx(1, "Invalid line received: missing address: %s",
1717 linedup);
1718 msgid = imsgid;
1719 if ((unsigned long) msgid != imsgid)
1720 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1721 linedup);
1722 params = end + 1;
1724 evpid = strtoull(params, &end, 16);
1725 if ((session->ctx.evpid == ULLONG_MAX && errno != 0) || end[0] != '\0')
1726 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1727 linedup);
1728 if (cb->storereport)
1729 session->ctx.evpid = evpid;
1731 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1732 if (f(&session->ctx, msgid, evpid))
1733 session->status = SESSION_ERROR;
1736 static void
1737 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_session *session,
1738 char *params, char *linedup)
1740 char *end;
1741 unsigned long imsgid;
1742 uint32_t msgid;
1743 int (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1745 errno = 0;
1746 imsgid = strtoul(params, &end, 16);
1747 if ((imsgid == ULONG_MAX && errno != 0))
1748 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1749 linedup);
1750 if (end[0] != '|')
1751 osmtpd_errx(1, "Invalid line received: missing address: %s",
1752 linedup);
1753 msgid = imsgid;
1754 if ((unsigned long) msgid != imsgid)
1755 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1756 linedup);
1757 params = end + 1;
1759 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1760 if (f(&session->ctx, msgid, osmtpd_strtostatus(params, linedup)))
1761 session->status = SESSION_ERROR;
1764 static void
1765 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_session *session,
1766 char *params, char *linedup)
1768 char *end;
1769 const char *errstr = NULL;
1770 unsigned long imsgid;
1771 uint32_t msgid;
1772 size_t msgsz;
1773 int (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1775 errno = 0;
1776 imsgid = strtoul(params, &end, 16);
1777 if ((imsgid == ULONG_MAX && errno != 0))
1778 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1779 linedup);
1780 if (end[0] != '|')
1781 osmtpd_errx(1, "Invalid line received: missing address: %s",
1782 linedup);
1783 msgid = imsgid;
1784 if ((unsigned long) msgid != imsgid)
1785 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1786 linedup);
1787 params = end + 1;
1789 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1790 if (errstr != NULL)
1791 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1792 linedup);
1794 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1795 if (f(&session->ctx, msgid, msgsz))
1796 session->status = SESSION_ERROR;
1799 static void
1800 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_session *session,
1801 char *params, char *linedup)
1803 char *end;
1804 unsigned long imsgid;
1805 uint32_t msgid;
1806 int (*f)(struct osmtpd_ctx *, uint32_t);
1808 errno = 0;
1809 imsgid = strtoul(params, &end, 16);
1810 if ((imsgid == ULONG_MAX && errno != 0))
1811 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1812 linedup);
1813 if (end[0] != '\0')
1814 osmtpd_errx(1, "Invalid line received: missing address: %s",
1815 linedup);
1816 msgid = imsgid;
1817 if ((unsigned long) msgid != imsgid)
1818 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1819 linedup);
1821 if ((f = cb->cb) != NULL && session->status == SESSION_OK)
1822 if (f(&session->ctx, msgid))
1823 session->status = SESSION_ERROR;
1826 void
1827 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1829 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1831 if (session->status == SESSION_DISCONNECTED)
1832 return;
1834 if (ctx->version_major == 0 && ctx->version_minor < 5)
1835 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1836 "proceed\n", ctx->token, ctx->reqid);
1837 else
1838 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1839 "proceed\n", ctx->reqid, ctx->token);
1842 void
1843 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1845 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1846 va_list ap;
1848 if (session->status == SESSION_DISCONNECTED)
1849 return;
1851 if (code < 200 || code > 599)
1852 osmtpd_errx(1, "Invalid reject code");
1854 if (ctx->version_major == 0 && ctx->version_minor < 5)
1855 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1856 "reject|%d ", ctx->token, ctx->reqid, code);
1857 else
1858 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1859 "reject|%d ", ctx->reqid, ctx->token, code);
1860 va_start(ap, reason);
1861 io_vprintf(io_stdout, reason, ap);
1862 va_end(ap);
1863 io_printf(io_stdout, "\n");
1866 void
1867 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1868 int subject, int detail, const char *reason, ...)
1870 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1871 va_list ap;
1873 if (session->status == SESSION_DISCONNECTED)
1874 return;
1876 if (code < 200 || code > 599)
1877 osmtpd_errx(1, "Invalid reject code");
1878 if (class < 2 || class > 5)
1879 osmtpd_errx(1, "Invalid enhanced status class");
1880 if (subject < 0 || subject > 999)
1881 osmtpd_errx(1, "Invalid enhanced status subject");
1882 if (detail < 0 || detail > 999)
1883 osmtpd_errx(1, "Invalid enhanced status detail");
1885 if (ctx->version_major == 0 && ctx->version_minor < 5)
1886 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1887 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1888 subject, detail);
1889 else
1890 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1891 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1892 subject, detail);
1893 va_start(ap, reason);
1894 io_vprintf(io_stdout, reason, ap);
1895 va_end(ap);
1896 io_printf(io_stdout, "\n");
1899 void
1900 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1902 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1903 va_list ap;
1905 if (session->status == SESSION_DISCONNECTED)
1906 return;
1908 if (ctx->version_major == 0 && ctx->version_minor < 5)
1909 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1910 "disconnect|421 ", ctx->token, ctx->reqid);
1911 else
1912 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1913 "disconnect|421 ", ctx->reqid, ctx->token);
1914 va_start(ap, reason);
1915 io_vprintf(io_stdout, reason, ap);
1916 va_end(ap);
1917 io_printf(io_stdout, "\n");
1918 session->status = SESSION_DISCONNECTED;
1921 void
1922 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1923 int detail, const char *reason, ...)
1925 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1926 va_list ap;
1928 if (session->status == SESSION_DISCONNECTED)
1929 return;
1931 if (class <= 2 || class >= 5)
1932 osmtpd_errx(1, "Invalid enhanced status class");
1933 if (subject < 0 || subject > 999)
1934 osmtpd_errx(1, "Invalid enhanced status subject");
1935 if (detail < 0 || detail > 999)
1936 osmtpd_errx(1, "Invalid enhanced status detail");
1937 if (ctx->version_major == 0 && ctx->version_minor < 5)
1938 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1939 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1940 subject, detail);
1941 else
1942 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1943 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1944 subject, detail);
1945 va_start(ap, reason);
1946 io_vprintf(io_stdout, reason, ap);
1947 va_end(ap);
1948 io_printf(io_stdout, "\n");
1949 session->status = SESSION_DISCONNECTED;
1952 void
1953 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1955 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1956 va_list ap;
1958 if (session->status == SESSION_DISCONNECTED)
1959 return;
1961 if (ctx->version_major == 0 && ctx->version_minor < 5)
1962 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1963 "rewrite|", ctx->token, ctx->reqid);
1964 else
1965 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1966 "rewrite|", ctx->reqid, ctx->token);
1967 va_start(ap, value);
1968 io_vprintf(io_stdout, value, ap);
1969 va_end(ap);
1970 io_printf(io_stdout, "\n");
1973 void
1974 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1976 struct osmtpd_session *session = (struct osmtpd_session *)ctx;
1977 va_list ap;
1979 if (session->status == SESSION_DISCONNECTED)
1980 return;
1982 if (ctx->version_major == 0 && ctx->version_minor < 5)
1983 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1984 ctx->token, ctx->reqid);
1985 else
1986 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1987 ctx->reqid, ctx->token);
1988 va_start(ap, line);
1989 io_vprintf(io_stdout, line, ap);
1990 va_end(ap);
1991 io_printf(io_stdout, "\n");
1994 static void
1995 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1996 int storereport, void *cb)
1998 size_t i;
2000 if (ready)
2001 osmtpd_errx(1, "Can't register when proc is running");
2003 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
2004 if (type == osmtpd_callbacks[i].type &&
2005 phase == osmtpd_callbacks[i].phase &&
2006 incoming == osmtpd_callbacks[i].incoming) {
2007 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
2008 osmtpd_errx(1, "Event already registered");
2009 if (cb != NULL)
2010 osmtpd_callbacks[i].cb = cb;
2011 osmtpd_callbacks[i].doregister = 1;
2012 if (storereport)
2013 osmtpd_callbacks[i].storereport = 1;
2014 return;
2017 /* NOT REACHED */
2018 osmtpd_errx(1, "Trying to register unknown event");
2021 static enum osmtpd_phase
2022 osmtpd_strtophase(const char *phase, const char *linedup)
2024 if (strcmp(phase, "connect") == 0)
2025 return OSMTPD_PHASE_CONNECT;
2026 if (strcmp(phase, "helo") == 0)
2027 return OSMTPD_PHASE_HELO;
2028 if (strcmp(phase, "ehlo") == 0)
2029 return OSMTPD_PHASE_EHLO;
2030 if (strcmp(phase, "starttls") == 0)
2031 return OSMTPD_PHASE_STARTTLS;
2032 if (strcmp(phase, "auth") == 0)
2033 return OSMTPD_PHASE_AUTH;
2034 if (strcmp(phase, "mail-from") == 0)
2035 return OSMTPD_PHASE_MAIL_FROM;
2036 if (strcmp(phase, "rcpt-to") == 0)
2037 return OSMTPD_PHASE_RCPT_TO;
2038 if (strcmp(phase, "data") == 0)
2039 return OSMTPD_PHASE_DATA;
2040 if (strcmp(phase, "data-line") == 0)
2041 return OSMTPD_PHASE_DATA_LINE;
2042 if (strcmp(phase, "rset") == 0)
2043 return OSMTPD_PHASE_RSET;
2044 if (strcmp(phase, "quit") == 0)
2045 return OSMTPD_PHASE_QUIT;
2046 if (strcmp(phase, "noop") == 0)
2047 return OSMTPD_PHASE_NOOP;
2048 if (strcmp(phase, "help") == 0)
2049 return OSMTPD_PHASE_HELP;
2050 if (strcmp(phase, "wiz") == 0)
2051 return OSMTPD_PHASE_WIZ;
2052 if (strcmp(phase, "commit") == 0)
2053 return OSMTPD_PHASE_COMMIT;
2054 if (strcmp(phase, "link-connect") == 0)
2055 return OSMTPD_PHASE_LINK_CONNECT;
2056 if (strcmp(phase, "link-disconnect") == 0)
2057 return OSMTPD_PHASE_LINK_DISCONNECT;
2058 if (strcmp(phase, "link-greeting") == 0)
2059 return OSMTPD_PHASE_LINK_GREETING;
2060 if (strcmp(phase, "link-identify") == 0)
2061 return OSMTPD_PHASE_LINK_IDENTIFY;
2062 if (strcmp(phase, "link-tls") == 0)
2063 return OSMTPD_PHASE_LINK_TLS;
2064 if (strcmp(phase, "link-auth") == 0)
2065 return OSMTPD_PHASE_LINK_AUTH;
2066 if (strcmp(phase, "tx-reset") == 0)
2067 return OSMTPD_PHASE_TX_RESET;
2068 if (strcmp(phase, "tx-begin") == 0)
2069 return OSMTPD_PHASE_TX_BEGIN;
2070 if (strcmp(phase, "tx-mail") == 0)
2071 return OSMTPD_PHASE_TX_MAIL;
2072 if (strcmp(phase, "tx-rcpt") == 0)
2073 return OSMTPD_PHASE_TX_RCPT;
2074 if (strcmp(phase, "tx-envelope") == 0)
2075 return OSMTPD_PHASE_TX_ENVELOPE;
2076 if (strcmp(phase, "tx-data") == 0)
2077 return OSMTPD_PHASE_TX_DATA;
2078 if (strcmp(phase, "tx-commit") == 0)
2079 return OSMTPD_PHASE_TX_COMMIT;
2080 if (strcmp(phase, "tx-rollback") == 0)
2081 return OSMTPD_PHASE_TX_ROLLBACK;
2082 if (strcmp(phase, "protocol-client") == 0)
2083 return OSMTPD_PHASE_PROTOCOL_CLIENT;
2084 if (strcmp(phase, "protocol-server") == 0)
2085 return OSMTPD_PHASE_PROTOCOL_SERVER;
2086 if (strcmp(phase, "filter-response") == 0)
2087 return OSMTPD_PHASE_FILTER_RESPONSE;
2088 if (strcmp(phase, "timeout") == 0)
2089 return OSMTPD_PHASE_TIMEOUT;
2090 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
2093 static const char *
2094 osmtpd_typetostr(enum osmtpd_type type)
2096 switch (type) {
2097 case OSMTPD_TYPE_FILTER:
2098 return "filter";
2099 case OSMTPD_TYPE_REPORT:
2100 return "report";
2102 osmtpd_errx(1, "In valid type: %d\n", type);
2105 static const char *
2106 osmtpd_phasetostr(enum osmtpd_phase phase)
2108 switch (phase) {
2109 case OSMTPD_PHASE_CONNECT:
2110 return "connect";
2111 case OSMTPD_PHASE_HELO:
2112 return "helo";
2113 case OSMTPD_PHASE_EHLO:
2114 return "ehlo";
2115 case OSMTPD_PHASE_STARTTLS:
2116 return "starttls";
2117 case OSMTPD_PHASE_AUTH:
2118 return "auth";
2119 case OSMTPD_PHASE_MAIL_FROM:
2120 return "mail-from";
2121 case OSMTPD_PHASE_RCPT_TO:
2122 return "rcpt-to";
2123 case OSMTPD_PHASE_DATA:
2124 return "data";
2125 case OSMTPD_PHASE_DATA_LINE:
2126 return "data-line";
2127 case OSMTPD_PHASE_RSET:
2128 return "rset";
2129 case OSMTPD_PHASE_QUIT:
2130 return "quit";
2131 case OSMTPD_PHASE_NOOP:
2132 return "noop";
2133 case OSMTPD_PHASE_HELP:
2134 return "help";
2135 case OSMTPD_PHASE_WIZ:
2136 return "wiz";
2137 case OSMTPD_PHASE_COMMIT:
2138 return "commit";
2139 case OSMTPD_PHASE_LINK_CONNECT:
2140 return "link-connect";
2141 case OSMTPD_PHASE_LINK_DISCONNECT:
2142 return "link-disconnect";
2143 case OSMTPD_PHASE_LINK_GREETING:
2144 return "link-greeting";
2145 case OSMTPD_PHASE_LINK_IDENTIFY:
2146 return "link-identify";
2147 case OSMTPD_PHASE_LINK_TLS:
2148 return "link-tls";
2149 case OSMTPD_PHASE_LINK_AUTH:
2150 return "link-auth";
2151 case OSMTPD_PHASE_TX_RESET:
2152 return "tx-reset";
2153 case OSMTPD_PHASE_TX_BEGIN:
2154 return "tx-begin";
2155 case OSMTPD_PHASE_TX_MAIL:
2156 return "tx-mail";
2157 case OSMTPD_PHASE_TX_RCPT:
2158 return "tx-rcpt";
2159 case OSMTPD_PHASE_TX_ENVELOPE:
2160 return "tx-envelope";
2161 case OSMTPD_PHASE_TX_DATA:
2162 return "tx-data";
2163 case OSMTPD_PHASE_TX_COMMIT:
2164 return "tx-commit";
2165 case OSMTPD_PHASE_TX_ROLLBACK:
2166 return "tx-rollback";
2167 case OSMTPD_PHASE_PROTOCOL_CLIENT:
2168 return "protocol-client";
2169 case OSMTPD_PHASE_PROTOCOL_SERVER:
2170 return "protocol-server";
2171 case OSMTPD_PHASE_FILTER_RESPONSE:
2172 return "filter-response";
2173 case OSMTPD_PHASE_TIMEOUT:
2174 return "timeout";
2176 osmtpd_errx(1, "In valid phase: %d\n", phase);
2179 static enum osmtpd_status
2180 osmtpd_strtostatus(const char *status, char *linedup)
2182 if (strcmp(status, "ok") == 0)
2183 return OSMTPD_STATUS_OK;
2184 else if (strcmp(status, "tempfail") == 0)
2185 return OSMTPD_STATUS_TEMPFAIL;
2186 else if (strcmp(status, "permfail") == 0)
2187 return OSMTPD_STATUS_PERMFAIL;
2188 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2191 static void
2192 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2193 char *linedup)
2195 char *port = NULL;
2196 const char *errstr = NULL;
2197 struct sockaddr_in *sin;
2198 struct sockaddr_in6 *sin6;
2199 struct sockaddr_un *sun;
2200 size_t n;
2202 if (addr[0] == '[') {
2203 sin6 = (struct sockaddr_in6 *)ss;
2204 sin6->sin6_family = AF_INET6;
2205 sin6->sin6_port = 0;
2206 if (hasport) {
2207 if ((port = strrchr(addr, ':')) == NULL)
2208 osmtpd_errx(1, "Invalid line received: invalid "
2209 "address (%s): %s", addr, linedup);
2210 if (port[-1] != ']')
2211 osmtpd_errx(1, "Invalid line received: invalid "
2212 "address (%s): %s", addr, linedup);
2213 port++;
2214 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2215 &errstr));
2216 if (errstr != NULL)
2217 osmtpd_errx(1, "Invalid line received: invalid "
2218 "address (%s): %s", addr, linedup);
2219 port[-2] = '\0';
2220 } else {
2221 n = strlen(addr);
2222 if (addr[n - 1] != ']')
2223 osmtpd_errx(1, "Invalid line received: invalid "
2224 "address (%s): %s", addr, linedup);
2225 addr[n - 1] = '\0';
2227 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2228 case 1:
2229 break;
2230 case 0:
2231 if (hasport)
2232 port[-2] = ']';
2233 else
2234 addr[n - 1] = ']';
2235 osmtpd_errx(1, "Invalid line received: invalid address "
2236 "(%s): %s", addr, linedup);
2237 default:
2238 if (hasport)
2239 port[-2] = ']';
2240 else
2241 addr[n - 1] = ']';
2242 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2243 linedup);
2245 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2246 sun = (struct sockaddr_un *)ss;
2247 sun->sun_family = AF_UNIX;
2248 if (strlcpy(sun->sun_path, addr,
2249 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2250 osmtpd_errx(1, "Invalid line received: address too "
2251 "long (%s): %s", addr, linedup);
2253 } else {
2254 sin = (struct sockaddr_in *)ss;
2255 sin->sin_family = AF_INET;
2256 sin->sin_port = 0;
2257 if (hasport) {
2258 if ((port = strrchr(addr, ':')) == NULL)
2259 osmtpd_errx(1, "Invalid line received: invalid "
2260 "address (%s): %s", addr, linedup);
2261 port++;
2262 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2263 &errstr));
2264 if (errstr != NULL)
2265 osmtpd_errx(1, "Invalid line received: invalid "
2266 "address (%s): %s", addr, linedup);
2267 port[-1] = '\0';
2269 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2270 case 1:
2271 break;
2272 case 0:
2273 if (hasport)
2274 port[-1] = ':';
2275 osmtpd_errx(1, "Invalid line received: invalid address "
2276 "(%s): %s", addr, linedup);
2277 default:
2278 if (hasport)
2279 port[-1] = ':';
2280 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2281 linedup);
2286 static int
2287 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2289 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2292 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);