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 struct osmtpd_callback {
45 enum osmtpd_type type;
46 enum osmtpd_phase phase;
47 int incoming;
48 void (*osmtpd_cb)(struct osmtpd_callback *, struct osmtpd_ctx *, char *,
49 char *);
50 void *cb;
51 int doregister;
52 int storereport;
53 };
55 struct osmtpd_session {
56 struct osmtpd_ctx ctx;
57 RB_ENTRY(osmtpd_session) entry;
58 };
60 static void osmtpd_register(enum osmtpd_type, enum osmtpd_phase, int, int,
61 void *);
62 static const char *osmtpd_typetostr(enum osmtpd_type);
63 static const char *osmtpd_phasetostr(enum osmtpd_phase);
64 static enum osmtpd_phase osmtpd_strtophase(const char *, const char *);
65 static void osmtpd_newline(struct io *, int, void *);
66 static void osmtpd_outevt(struct io *, int, void *);
67 static void osmtpd_noargs(struct osmtpd_callback *, struct osmtpd_ctx *,
68 char *, char *);
69 static void osmtpd_onearg(struct osmtpd_callback *, struct osmtpd_ctx *,
70 char *, char *);
71 static void osmtpd_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
72 char *, char *);
73 static void osmtpd_identify(struct osmtpd_callback *, struct osmtpd_ctx *,
74 char *, char *);
75 static void osmtpd_link_connect(struct osmtpd_callback *, struct osmtpd_ctx *,
76 char *, char *);
77 static void osmtpd_link_disconnect(struct osmtpd_callback *,
78 struct osmtpd_ctx *, char *, char *);
79 static void osmtpd_link_greeting(struct osmtpd_callback *, struct osmtpd_ctx *,
80 char *, char *);
81 static void osmtpd_link_identify(struct osmtpd_callback *, struct osmtpd_ctx *,
82 char *, char *);
83 static void osmtpd_link_tls(struct osmtpd_callback *, struct osmtpd_ctx *,
84 char *, char *);
85 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
86 char *, char *);
87 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
88 char *, char *);
89 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
90 char *, char *);
91 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
92 char *, char *);
93 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
94 char *, char *);
95 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
96 char *, char *);
97 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
98 char *, char *);
99 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
100 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
101 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
102 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
103 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
104 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
105 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
106 static void (*conf_cb)(const char *, const char *);
108 static struct osmtpd_callback osmtpd_callbacks[] = {
110 OSMTPD_TYPE_FILTER,
111 OSMTPD_PHASE_CONNECT,
112 1,
113 osmtpd_connect,
114 NULL,
115 0,
117 },
119 OSMTPD_TYPE_FILTER,
120 OSMTPD_PHASE_HELO,
121 1,
122 osmtpd_identify,
123 NULL,
124 0,
126 },
128 OSMTPD_TYPE_FILTER,
129 OSMTPD_PHASE_EHLO,
130 1,
131 osmtpd_identify,
132 NULL,
133 0,
135 },
137 OSMTPD_TYPE_FILTER,
138 OSMTPD_PHASE_STARTTLS,
139 1,
140 osmtpd_noargs,
141 NULL,
142 0,
144 },
146 OSMTPD_TYPE_FILTER,
147 OSMTPD_PHASE_AUTH,
148 1,
149 osmtpd_onearg,
150 NULL,
151 0,
153 },
155 OSMTPD_TYPE_FILTER,
156 OSMTPD_PHASE_MAIL_FROM,
157 1,
158 osmtpd_onearg,
159 NULL,
160 0,
162 },
164 OSMTPD_TYPE_FILTER,
165 OSMTPD_PHASE_RCPT_TO,
166 1,
167 osmtpd_onearg,
168 NULL,
169 0,
171 },
173 OSMTPD_TYPE_FILTER,
174 OSMTPD_PHASE_DATA,
175 1,
176 osmtpd_noargs,
177 NULL,
178 0,
180 },
182 OSMTPD_TYPE_FILTER,
183 OSMTPD_PHASE_DATA_LINE,
184 1,
185 osmtpd_onearg,
186 NULL,
187 0,
189 },
191 OSMTPD_TYPE_FILTER,
192 OSMTPD_PHASE_RSET,
193 1,
194 osmtpd_noargs,
195 NULL,
196 0,
198 },
200 OSMTPD_TYPE_FILTER,
201 OSMTPD_PHASE_QUIT,
202 1,
203 osmtpd_noargs,
204 NULL,
205 0,
207 },
209 OSMTPD_TYPE_FILTER,
210 OSMTPD_PHASE_NOOP,
211 1,
212 osmtpd_noargs,
213 NULL,
214 0,
216 },
218 OSMTPD_TYPE_FILTER,
219 OSMTPD_PHASE_HELP,
220 1,
221 osmtpd_noargs,
222 NULL,
223 0,
225 },
227 OSMTPD_TYPE_FILTER,
228 OSMTPD_PHASE_WIZ,
229 1,
230 osmtpd_noargs,
231 NULL,
232 0,
234 },
236 OSMTPD_TYPE_FILTER,
237 OSMTPD_PHASE_COMMIT,
238 1,
239 osmtpd_noargs,
240 NULL,
241 0,
243 },
245 OSMTPD_TYPE_REPORT,
246 OSMTPD_PHASE_LINK_CONNECT,
247 1,
248 osmtpd_link_connect,
249 NULL,
250 0,
252 },
254 OSMTPD_TYPE_REPORT,
255 OSMTPD_PHASE_LINK_DISCONNECT,
256 1,
257 osmtpd_link_disconnect,
258 NULL,
259 0,
261 },
263 OSMTPD_TYPE_REPORT,
264 OSMTPD_PHASE_LINK_GREETING,
265 1,
266 osmtpd_link_greeting,
267 NULL,
268 0,
270 },
272 OSMTPD_TYPE_REPORT,
273 OSMTPD_PHASE_LINK_IDENTIFY,
274 1,
275 osmtpd_link_identify,
276 NULL,
277 0,
279 },
281 OSMTPD_TYPE_REPORT,
282 OSMTPD_PHASE_LINK_TLS,
283 1,
284 osmtpd_link_tls,
285 NULL,
286 0,
288 },
290 OSMTPD_TYPE_REPORT,
291 OSMTPD_PHASE_TX_BEGIN,
292 1,
293 osmtpd_tx_begin,
294 NULL,
295 0,
297 },
299 OSMTPD_TYPE_REPORT,
300 OSMTPD_PHASE_TX_MAIL,
301 1,
302 osmtpd_tx_mail,
303 NULL,
304 0,
306 },
308 OSMTPD_TYPE_REPORT,
309 OSMTPD_PHASE_TX_RCPT,
310 1,
311 osmtpd_tx_rcpt,
312 NULL,
313 0,
315 },
317 OSMTPD_TYPE_REPORT,
318 OSMTPD_PHASE_TX_ENVELOPE,
319 1,
320 osmtpd_tx_envelope,
321 NULL,
322 0,
324 },
326 OSMTPD_TYPE_REPORT,
327 OSMTPD_PHASE_TX_DATA,
328 1,
329 osmtpd_tx_data,
330 NULL,
331 0,
333 },
335 OSMTPD_TYPE_REPORT,
336 OSMTPD_PHASE_TX_COMMIT,
337 1,
338 osmtpd_tx_commit,
339 NULL,
340 0,
342 },
344 OSMTPD_TYPE_REPORT,
345 OSMTPD_PHASE_TX_ROLLBACK,
346 1,
347 osmtpd_tx_rollback,
348 NULL,
349 0,
351 },
353 OSMTPD_TYPE_REPORT,
354 OSMTPD_PHASE_PROTOCOL_CLIENT,
355 1,
356 osmtpd_onearg,
357 NULL,
358 0,
360 },
362 OSMTPD_TYPE_REPORT,
363 OSMTPD_PHASE_PROTOCOL_SERVER,
364 1,
365 osmtpd_onearg,
366 NULL,
367 0,
369 },
371 OSMTPD_TYPE_REPORT,
372 OSMTPD_PHASE_FILTER_RESPONSE,
373 1,
374 osmtpd_onearg,
375 NULL,
376 0,
378 },
380 OSMTPD_TYPE_REPORT,
381 OSMTPD_PHASE_TIMEOUT,
382 1,
383 osmtpd_noargs,
384 NULL,
385 0,
387 },
389 OSMTPD_TYPE_REPORT,
390 OSMTPD_PHASE_LINK_CONNECT,
391 0,
392 osmtpd_link_connect,
393 NULL,
394 0,
396 },
398 OSMTPD_TYPE_REPORT,
399 OSMTPD_PHASE_LINK_DISCONNECT,
400 0,
401 osmtpd_link_disconnect,
402 NULL,
403 0,
405 },
407 OSMTPD_TYPE_REPORT,
408 OSMTPD_PHASE_LINK_GREETING,
409 0,
410 osmtpd_link_greeting,
411 NULL,
412 0,
414 },
416 OSMTPD_TYPE_REPORT,
417 OSMTPD_PHASE_LINK_IDENTIFY,
418 0,
419 osmtpd_link_identify,
420 NULL,
421 0,
423 },
425 OSMTPD_TYPE_REPORT,
426 OSMTPD_PHASE_LINK_TLS,
427 0,
428 osmtpd_link_tls,
429 NULL,
430 0,
432 },
434 OSMTPD_TYPE_REPORT,
435 OSMTPD_PHASE_TX_BEGIN,
436 0,
437 osmtpd_tx_begin,
438 NULL,
439 0,
441 },
443 OSMTPD_TYPE_REPORT,
444 OSMTPD_PHASE_TX_MAIL,
445 0,
446 osmtpd_tx_mail,
447 NULL,
448 0,
450 },
452 OSMTPD_TYPE_REPORT,
453 OSMTPD_PHASE_TX_RCPT,
454 0,
455 osmtpd_tx_rcpt,
456 NULL,
457 0,
459 },
461 OSMTPD_TYPE_REPORT,
462 OSMTPD_PHASE_TX_ENVELOPE,
463 0,
464 osmtpd_tx_envelope,
465 NULL,
466 0,
468 },
470 OSMTPD_TYPE_REPORT,
471 OSMTPD_PHASE_TX_DATA,
472 0,
473 osmtpd_tx_data,
474 NULL,
475 0,
477 },
479 OSMTPD_TYPE_REPORT,
480 OSMTPD_PHASE_TX_COMMIT,
481 0,
482 osmtpd_tx_commit,
483 NULL,
484 0,
486 },
488 OSMTPD_TYPE_REPORT,
489 OSMTPD_PHASE_TX_ROLLBACK,
490 0,
491 osmtpd_tx_rollback,
492 NULL,
493 0,
495 },
497 OSMTPD_TYPE_REPORT,
498 OSMTPD_PHASE_PROTOCOL_CLIENT,
499 0,
500 osmtpd_onearg,
501 NULL,
502 0,
504 },
506 OSMTPD_TYPE_REPORT,
507 OSMTPD_PHASE_PROTOCOL_SERVER,
508 0,
509 osmtpd_onearg,
510 NULL,
511 0,
513 },
515 OSMTPD_TYPE_REPORT,
516 OSMTPD_PHASE_FILTER_RESPONSE,
517 0,
518 osmtpd_onearg,
519 NULL,
520 0,
522 },
524 OSMTPD_TYPE_REPORT,
525 OSMTPD_PHASE_TIMEOUT,
526 0,
527 osmtpd_noargs,
528 NULL,
529 0,
532 };
534 static struct io *io_stdout;
535 static int needs;
536 static int ready = 0;
537 /* Default from smtpd */
538 static int session_timeout = 300;
540 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
541 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
543 void
544 osmtpd_register_conf(void (*cb)(const char *, const char *))
546 conf_cb = cb;
549 void
550 osmtpd_register_filter_connect(void (*cb)(struct osmtpd_ctx *, const char *,
551 struct sockaddr_storage *))
553 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
554 (void *)cb);
555 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
556 NULL);
559 void
560 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
562 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
563 (void *)cb);
564 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
565 NULL);
568 void
569 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
571 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
572 (void *)cb);
573 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
574 NULL);
577 void
578 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
580 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 1, 0,
581 (void *)cb);
582 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
583 NULL);
586 void
587 osmtpd_register_filter_auth(void (*cb)(struct osmtpd_ctx *, const char *))
589 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 1, 0,
590 (void *)cb);
591 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
592 NULL);
595 void
596 osmtpd_register_filter_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
598 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 1, 0,
599 (void *)cb);
600 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
601 NULL);
604 void
605 osmtpd_register_filter_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
607 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 1, 0,
608 (void *)cb);
609 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
610 NULL);
613 void
614 osmtpd_register_filter_data(void (*cb)(struct osmtpd_ctx *))
616 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 1, 0,
617 (void *)cb);
618 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
619 NULL);
622 void
623 osmtpd_register_filter_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
625 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 1, 0,
626 (void *)cb);
627 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
628 NULL);
631 void
632 osmtpd_register_filter_rset(void (*cb)(struct osmtpd_ctx *))
634 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 1, 0,
635 (void *)cb);
636 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
637 NULL);
640 void
641 osmtpd_register_filter_quit(void (*cb)(struct osmtpd_ctx *))
643 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 1, 0,
644 (void *)cb);
645 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
646 NULL);
649 void
650 osmtpd_register_filter_noop(void (*cb)(struct osmtpd_ctx *))
652 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 1, 0,
653 (void *)cb);
654 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
655 NULL);
658 void
659 osmtpd_register_filter_help(void (*cb)(struct osmtpd_ctx *))
661 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 1, 0,
662 (void *)cb);
663 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
664 NULL);
667 void
668 osmtpd_register_filter_wiz(void (*cb)(struct osmtpd_ctx *))
670 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 1, 0,
671 (void *)cb);
672 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
673 NULL);
676 void
677 osmtpd_register_filter_commit(void (*cb)(struct osmtpd_ctx *))
679 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
680 (void *)cb);
681 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
682 NULL);
685 void
686 osmtpd_register_report_connect(int incoming, void (*cb)(struct osmtpd_ctx *,
687 const char *, enum osmtpd_status, struct sockaddr_storage *,
688 struct sockaddr_storage *))
690 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
691 0, (void *)cb);
692 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
693 incoming, 0, NULL);
696 void
697 osmtpd_register_report_disconnect(int incoming, void (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
700 incoming, 0, (void *)cb);
703 void
704 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
705 const char *))
707 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
708 incoming, 0, (void *)cb);
709 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
710 incoming, 0, NULL);
713 void
714 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
715 const char *))
717 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, incoming, 0,
718 (void *)cb);
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
720 incoming, 0, NULL);
723 void
724 osmtpd_register_report_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
725 uint32_t))
727 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
728 (void *)cb);
729 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
730 incoming, 0, NULL);
733 void
734 osmtpd_register_report_mail(int incoming, void (*cb)(struct osmtpd_ctx *,
735 uint32_t, const char *, enum osmtpd_status))
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, incoming, 0,
738 (void *)cb);
739 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
740 incoming, 0, NULL);
743 void
744 osmtpd_register_report_rcpt(int incoming, void (*cb)(struct osmtpd_ctx *,
745 uint32_t, const char *, enum osmtpd_status))
747 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, incoming, 0,
748 (void *)cb);
749 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
750 incoming, 0, NULL);
753 void
754 osmtpd_register_report_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
755 uint32_t, uint64_t))
757 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, incoming,
758 0, (void *)cb);
759 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
760 incoming, 0, NULL);
763 void
764 osmtpd_register_report_data(int incoming, void (*cb)(struct osmtpd_ctx *,
765 uint32_t, enum osmtpd_status))
767 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
768 (void *)cb);
769 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
770 incoming, 0, NULL);
773 void
774 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
775 uint32_t, size_t))
777 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
778 (void *)cb);
779 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
780 incoming, 0, NULL);
783 void
784 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
785 uint32_t))
787 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
788 0, (void *)cb);
789 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
790 incoming, 0, NULL);
793 void
794 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
795 const char *))
797 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
798 incoming, 0, (void *)cb);
799 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
800 incoming, 0, NULL);
803 void
804 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
805 const char *))
807 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
808 incoming, 0, (void *)cb);
809 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
810 incoming, 0, NULL);
813 void
814 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
815 const char *))
817 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
818 incoming, 0, (void *)cb);
819 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
820 incoming, 0, NULL);
823 void
824 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
826 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
827 (void *)cb);
828 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
829 incoming, 0, NULL);
832 void
833 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
834 void (*ondelete)(struct osmtpd_ctx *, void *))
836 oncreatecb_session = oncreate;
837 ondeletecb_session = ondelete;
840 void
841 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
842 void (*ondelete)(struct osmtpd_ctx *, void *))
844 oncreatecb_message = oncreate;
845 ondeletecb_message = ondelete;
848 void
849 osmtpd_need(int lneeds)
851 needs |= lneeds;
854 static void
855 osmtpd_register_need(int incoming)
857 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
858 OSMTPD_NEED_FCRDNS))
859 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
860 incoming, 1, NULL);
861 if (needs & OSMTPD_NEED_GREETING)
862 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
863 incoming, 1, NULL);
864 if (needs & OSMTPD_NEED_IDENTITY)
865 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
866 incoming, 1, NULL);
867 if (needs & OSMTPD_NEED_CIPHERS)
868 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
869 incoming, 1, NULL);
870 if (needs & OSMTPD_NEED_MSGID) {
871 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
872 incoming, 1, NULL);
873 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
874 incoming, 0, NULL);
875 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
876 incoming, 0, NULL);
878 if (needs & OSMTPD_NEED_MAILFROM) {
879 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
880 incoming, 1, NULL);
881 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
882 incoming, 0, NULL);
883 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
884 incoming, 0, NULL);
886 if (needs & OSMTPD_NEED_RCPTTO) {
887 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
888 incoming, 1, NULL);
889 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
890 incoming, 0, NULL);
891 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
892 incoming, 0, NULL);
894 if (needs & OSMTPD_NEED_EVPID) {
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
896 incoming, 1, NULL);
897 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
898 incoming, 0, NULL);
899 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
900 incoming, 0, NULL);
903 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
904 incoming, 0, NULL);
907 void
908 osmtpd_run(void)
910 size_t i = 0;
911 int registered = 0;
912 struct event_base *evbase;
913 struct io *io_stdin;
914 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
915 struct osmtpd_callback *ridentity = NULL;
917 evbase = event_init();
919 if ((io_stdin = io_new()) == NULL ||
920 (io_stdout = io_new()) == NULL)
921 osmtpd_err(1, "io_new");
922 io_set_nonblocking(STDIN_FILENO);
923 io_set_fd(io_stdin, STDIN_FILENO);
924 io_set_callback(io_stdin, osmtpd_newline, NULL);
925 io_set_read(io_stdin);
926 io_set_nonblocking(STDOUT_FILENO);
927 io_set_fd(io_stdout, STDOUT_FILENO);
928 io_set_callback(io_stdout, osmtpd_outevt, NULL);
929 io_set_write(io_stdout);
931 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
932 if (osmtpd_callbacks[i].doregister) {
933 osmtpd_register_need(osmtpd_callbacks[i].incoming);
934 if (oncreatecb_message != NULL) {
935 osmtpd_register(OSMTPD_TYPE_REPORT,
936 OSMTPD_PHASE_TX_BEGIN,
937 osmtpd_callbacks[i].incoming, 0, NULL);
938 osmtpd_register(OSMTPD_TYPE_REPORT,
939 OSMTPD_PHASE_TX_ROLLBACK,
940 osmtpd_callbacks[i].incoming, 0, NULL);
941 osmtpd_register(OSMTPD_TYPE_REPORT,
942 OSMTPD_PHASE_TX_COMMIT,
943 osmtpd_callbacks[i].incoming, 0, NULL);
945 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
946 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
947 hidenity = &(osmtpd_callbacks[i]);
948 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
949 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
950 eidentity = &(osmtpd_callbacks[i]);
951 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
952 osmtpd_callbacks[i].phase ==
953 OSMTPD_PHASE_LINK_IDENTIFY &&
954 osmtpd_callbacks[i].incoming == 1)
955 ridentity = &(osmtpd_callbacks[i]);
958 if (ridentity != NULL && ridentity->storereport) {
959 if (hidenity != NULL && hidenity->doregister)
960 hidenity->storereport = 1;
961 if (eidentity != NULL && eidentity->doregister)
962 eidentity->storereport = 1;
964 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
965 if (osmtpd_callbacks[i].doregister) {
966 if (osmtpd_callbacks[i].cb != NULL)
967 registered = 1;
968 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
969 osmtpd_typetostr(osmtpd_callbacks[i].type),
970 osmtpd_callbacks[i].incoming ? "in" : "out",
971 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
975 if (!registered)
976 osmtpd_errx(1, "No events registered");
977 io_printf(io_stdout, "register|ready\n");
978 ready = 1;
980 event_dispatch();
981 io_free(io_stdin);
982 io_free(io_stdout);
983 event_base_free(evbase);
986 __dead void
987 osmtpd_err(int eval, const char *fmt, ...)
989 va_list ap;
991 va_start(ap, fmt);
992 vfprintf(stderr, fmt, ap);
993 va_end(ap);
994 fprintf(stderr, ": %s\n", strerror(errno));
995 exit(eval);
998 __dead void
999 osmtpd_errx(int eval, const char *fmt, ...)
1001 va_list ap;
1003 va_start(ap, fmt);
1004 vfprintf(stderr, fmt, ap);
1005 va_end(ap);
1006 fprintf(stderr, "\n");
1007 exit(eval);
1010 static void
1011 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1013 static char *linedup = NULL;
1014 static size_t dupsize = 0;
1015 struct osmtpd_session *ctx, search;
1016 enum osmtpd_type type;
1017 enum osmtpd_phase phase;
1018 int version_major, version_minor, incoming;
1019 struct timespec tm;
1020 char *line = NULL;
1021 const char *errstr = NULL;
1022 size_t linelen;
1023 char *end;
1024 size_t i;
1026 if (ev == IO_DISCONNECTED) {
1027 event_loopexit(0);
1028 return;
1030 if (ev != IO_DATAIN)
1031 return;
1032 while ((line = io_getline(io, &linelen)) != NULL) {
1033 if (dupsize < linelen) {
1034 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1035 osmtpd_err(1, NULL);
1036 dupsize = linelen + 1;
1038 strlcpy(linedup, line, dupsize);
1039 if ((end = strchr(line, '|')) == NULL)
1040 osmtpd_errx(1, "Invalid line received: missing "
1041 "version: %s", linedup);
1042 end++[0] = '\0';
1043 if (strcmp(line, "filter") == 0)
1044 type = OSMTPD_TYPE_FILTER;
1045 else if (strcmp(line, "report") == 0)
1046 type = OSMTPD_TYPE_REPORT;
1047 else if (strcmp(line, "config") == 0) {
1048 line = end;
1049 if (strcmp(line, "ready") == 0) {
1050 if (conf_cb != NULL)
1051 conf_cb(NULL, NULL);
1052 continue;
1054 if ((end = strchr(line, '|')) == NULL)
1055 osmtpd_errx(1, "Invalid line received: missing "
1056 "key: %s", linedup);
1057 end++[0] = '\0';
1058 if (conf_cb != NULL)
1059 conf_cb(line, end);
1060 if (strcmp(line, "smtp-session-timeout") == 0) {
1061 session_timeout = strtonum(end, 0, INT_MAX,
1062 &errstr);
1063 if (errstr != NULL)
1064 osmtpd_errx(1, "Invalid line received: "
1065 "invalid smtp-sesion-timeout: %s",
1066 linedup);
1068 continue;
1070 else
1071 osmtpd_errx(1, "Invalid line received: unknown message "
1072 "type: %s", linedup);
1073 line = end;
1074 version_major = strtoul(line, &end, 10);
1075 if (line == end || end[0] != '.')
1076 osmtpd_errx(1, "Invalid protocol received: %s",
1077 linedup);
1078 line = end + 1;
1079 version_minor = strtoul(line, &end, 10);
1080 if (end[0] == '\0')
1081 osmtpd_errx(1, "Invalid line received: missing time: "
1082 "%s", linedup);
1083 if (line == end || end[0] != '|')
1084 osmtpd_errx(1, "Invalid protocol received: %s",
1085 linedup);
1086 if (version_major != 0)
1087 osmtpd_errx(1, "Unsupported protocol received: %s",
1088 linedup);
1089 line = end + 1;
1090 if ((end = strchr(line, '.')) == NULL)
1091 osmtpd_errx(1, "Invalid line received: invalid "
1092 "timestamp: %s", linedup);
1093 end++[0] = '\0';
1094 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1095 if (errstr != NULL)
1096 osmtpd_errx(1, "Invalid line received: invalid "
1097 "timestamp: %s", linedup);
1098 line = end;
1099 if ((end = strchr(line, '|')) == NULL)
1100 osmtpd_errx(1, "Invalid line received: missing "
1101 "direction: %s", linedup);
1102 end++[0] = '\0';
1103 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1104 if (errstr != NULL)
1105 osmtpd_errx(1, "Invalid line received: invalid "
1106 "timestamp: %s", linedup);
1107 tm.tv_nsec *= 10 * (9 - (end - line));
1108 line = end;
1109 if ((end = strchr(line, '|')) == NULL)
1110 osmtpd_errx(1, "Invalid line receieved: missing "
1111 "phase: %s", linedup);
1112 end++[0] = '\0';
1113 if (strcmp(line, "smtp-in") == 0)
1114 incoming = 1;
1115 else if (strcmp(line, "smtp-out") == 0)
1116 incoming = 0;
1117 else
1118 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1119 linedup);
1120 line = end;
1121 if ((end = strchr(line, '|')) == NULL)
1122 osmtpd_errx(1, "Invalid line received: missing reqid: "
1123 "%s", linedup);
1124 end++[0] = '\0';
1125 phase = osmtpd_strtophase(line, linedup);
1126 line = end;
1127 errno = 0;
1128 search.ctx.reqid = strtoull(line, &end, 16);
1129 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1130 (end[0] != '|' && end[0] != '\0'))
1131 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1132 "%s", linedup);
1133 line = end + 1;
1134 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1135 if (ctx == NULL) {
1136 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1137 osmtpd_err(1, NULL);
1138 ctx->ctx.reqid = search.ctx.reqid;
1139 ctx->ctx.rdns = NULL;
1140 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1141 ctx->ctx.identity = NULL;
1142 ctx->ctx.greeting.identity = NULL;
1143 ctx->ctx.ciphers = NULL;
1144 ctx->ctx.msgid = 0;
1145 ctx->ctx.mailfrom = NULL;
1146 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1147 if (ctx->ctx.rcptto == NULL)
1148 osmtpd_err(1, "malloc");
1149 ctx->ctx.rcptto[0] = NULL;
1150 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1151 ctx->ctx.src.ss_family = AF_UNSPEC;
1152 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1153 ctx->ctx.dst.ss_family = AF_UNSPEC;
1154 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1155 ctx->ctx.evpid = 0;
1156 ctx->ctx.local_session = NULL;
1157 ctx->ctx.local_message = NULL;
1158 if (oncreatecb_session != NULL)
1159 ctx->ctx.local_session =
1160 oncreatecb_session(&ctx->ctx);
1162 ctx->ctx.type = type;
1163 ctx->ctx.phase = phase;
1164 ctx->ctx.version_major = version_major;
1165 ctx->ctx.version_minor = version_minor;
1166 ctx->ctx.incoming = incoming;
1167 ctx->ctx.tm.tv_sec = tm.tv_sec;
1168 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1169 ctx->ctx.token = 0;
1171 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1172 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1173 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1174 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1175 break;
1177 if (i == NITEMS(osmtpd_callbacks)) {
1178 osmtpd_errx(1, "Invalid line received: received "
1179 "unregistered line: %s", linedup);
1181 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1182 ctx->ctx.token = strtoull(line, &end, 16);
1183 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1184 end[0] != '|')
1185 osmtpd_errx(1, "Invalid line received: invalid "
1186 "token: %s", linedup);
1187 line = end + 1;
1189 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1190 &(ctx->ctx), line, linedup);
1194 static void
1195 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1197 switch (evt) {
1198 case IO_LOWAT:
1199 return;
1200 case IO_DISCONNECTED:
1201 exit(0);
1202 default:
1203 osmtpd_errx(1, "Unexpectd event");
1207 static void
1208 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1209 __unused char *params, __unused char *linedup)
1211 void (*f)(struct osmtpd_ctx *);
1213 f = cb->cb;
1214 f(ctx);
1217 static void
1218 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1219 __unused char *linedup)
1221 void (*f)(struct osmtpd_ctx *, const char *);
1223 f = cb->cb;
1224 f(ctx, line);
1227 static void
1228 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1229 char *linedup)
1231 struct sockaddr_storage ss;
1232 char *hostname;
1233 char *address;
1234 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1236 hostname = params;
1237 if ((address = strchr(params, '|')) == NULL)
1238 osmtpd_errx(1, "Invalid line received: missing address: %s",
1239 linedup);
1240 address++[0] = '\0';
1242 osmtpd_addrtoss(address, &ss, 0, linedup);
1244 f = cb->cb;
1245 f(ctx, hostname, &ss);
1248 static void
1249 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1250 char *identity, __unused char *linedup)
1252 void (*f)(struct osmtpd_ctx *, const char *);
1254 if (cb->storereport) {
1255 free(ctx->identity);
1256 if ((ctx->identity = strdup(identity)) == NULL)
1257 osmtpd_err(1, "strdup");
1260 f = cb->cb;
1261 f(ctx, identity);
1264 static void
1265 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1266 char *params, char *linedup)
1268 char *end, *rdns;
1269 enum osmtpd_status fcrdns;
1270 struct sockaddr_storage src, dst;
1271 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1272 struct sockaddr_storage *, struct sockaddr_storage *);
1274 if ((end = strchr(params, '|')) == NULL)
1275 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1276 linedup);
1277 end++[0] = '\0';
1278 rdns = params;
1279 params = end;
1280 if ((end = strchr(params, '|')) == NULL)
1281 osmtpd_errx(1, "Invalid line received: missing src: %s",
1282 linedup);
1283 end++[0] = '\0';
1284 if (strcmp(params, "pass") == 0)
1285 fcrdns = OSMTPD_STATUS_OK;
1286 else if (strcmp(params, "fail") == 0)
1287 fcrdns = OSMTPD_STATUS_PERMFAIL;
1288 else if (strcmp(params, "error") == 0)
1289 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1290 else
1291 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1292 linedup);
1293 params = end;
1294 if ((end = strchr(params, '|')) == NULL)
1295 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1296 linedup);
1297 end++[0] = '\0';
1298 osmtpd_addrtoss(params, &src, 1, linedup);
1299 params = end;
1300 osmtpd_addrtoss(params, &dst, 1, linedup);
1301 if (cb->storereport) {
1302 if ((ctx->rdns = strdup(rdns)) == NULL)
1303 osmtpd_err(1, "strdup");
1304 ctx->fcrdns = fcrdns;
1305 memcpy(&(ctx->src), &src, sizeof(ctx->src));
1306 memcpy(&(ctx->dst), &dst, sizeof(ctx->dst));
1308 if ((f = cb->cb) != NULL)
1309 f(ctx, rdns, fcrdns, &src, &dst);
1312 static void
1313 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1314 __unused char *param, __unused char *linedup)
1316 void (*f)(struct osmtpd_ctx *);
1317 size_t i;
1318 struct osmtpd_session *session, search;
1320 if ((f = cb->cb) != NULL)
1321 f(ctx);
1323 search.ctx.reqid = ctx->reqid;
1324 session = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1325 if (session != NULL) {
1326 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1327 if (ondeletecb_session != NULL)
1328 ondeletecb_session(ctx, session->ctx.local_session);
1329 free(session->ctx.rdns);
1330 free(session->ctx.identity);
1331 free(session->ctx.greeting.identity);
1332 free(session->ctx.ciphers);
1333 free(session->ctx.mailfrom);
1334 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1335 free(session->ctx.rcptto[i]);
1336 free(session->ctx.rcptto);
1337 free(session);
1341 static void
1342 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1343 char *identity, __unused char *linedup)
1345 void (*f)(struct osmtpd_ctx *, const char *);
1347 if (cb->storereport) {
1348 free(ctx->greeting.identity);
1349 if ((ctx->greeting.identity = strdup(identity)) == NULL)
1350 osmtpd_err(1, NULL);
1353 if ((f = cb->cb) != NULL)
1354 f(ctx, identity);
1357 static void
1358 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1359 char *identity, __unused char *linedup)
1361 void (*f)(struct osmtpd_ctx *, const char *);
1363 if (cb->storereport) {
1364 free(ctx->identity);
1365 if ((ctx->identity = strdup(identity)) == NULL)
1366 osmtpd_err(1, NULL);
1369 if ((f = cb->cb) != NULL)
1370 f(ctx, identity);
1373 static void
1374 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1375 char *ciphers, __unused char *linedup)
1377 void (*f)(struct osmtpd_ctx *, const char *);
1379 if (cb->storereport) {
1380 if ((ctx->ciphers = strdup(ciphers)) == NULL)
1381 osmtpd_err(1, NULL);
1384 if ((f = cb->cb) != NULL)
1385 f(ctx, ciphers);
1388 static void
1389 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1390 char *msgid, char *linedup)
1392 unsigned long imsgid;
1393 char *endptr;
1394 void (*f)(struct osmtpd_ctx *, uint32_t);
1396 errno = 0;
1397 imsgid = strtoul(msgid, &endptr, 16);
1398 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1399 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1400 linedup);
1401 ctx->msgid = imsgid;
1402 /* Check if we're in range */
1403 if ((unsigned long) ctx->msgid != imsgid)
1404 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1405 linedup);
1407 if (!cb->storereport)
1408 ctx->msgid = 0;
1410 if (oncreatecb_message != NULL)
1411 ctx->local_message = oncreatecb_message(ctx);
1413 if ((f = cb->cb) != NULL)
1414 f(ctx, imsgid);
1417 static void
1418 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1419 char *params, char *linedup)
1421 char *end, *mailfrom;
1422 enum osmtpd_status status;
1423 unsigned long imsgid;
1424 uint32_t msgid;
1425 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1426 enum osmtpd_status);
1428 errno = 0;
1429 imsgid = strtoul(params, &end, 16);
1430 if ((imsgid == ULONG_MAX && errno != 0))
1431 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1432 linedup);
1433 if (end[0] != '|')
1434 osmtpd_errx(1, "Invalid line received: missing address: %s",
1435 linedup);
1436 msgid = imsgid;
1437 if ((unsigned long) msgid != imsgid)
1438 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1439 linedup);
1440 params = end + 1;
1442 if ((end = strchr(params, '|')) == NULL)
1443 osmtpd_errx(1, "Invalid line received: missing status: %s",
1444 linedup);
1445 end++[0] = '\0';
1446 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1447 mailfrom = params;
1448 status = osmtpd_strtostatus(end, linedup);
1449 } else {
1450 mailfrom = end;
1451 status = osmtpd_strtostatus(params, linedup);
1453 if (cb->storereport) {
1454 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1455 osmtpd_err(1, NULL);
1458 if ((f = cb->cb) != NULL)
1459 f(ctx, msgid, mailfrom, status);
1462 static void
1463 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1464 char *params, char *linedup)
1466 char *end, *rcptto;
1467 enum osmtpd_status status;
1468 unsigned long imsgid;
1469 uint32_t msgid;
1470 size_t i;
1471 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1472 enum osmtpd_status);
1474 errno = 0;
1475 imsgid = strtoul(params, &end, 16);
1476 if ((imsgid == ULONG_MAX && errno != 0))
1477 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1478 linedup);
1479 if (end[0] != '|')
1480 osmtpd_errx(1, "Invalid line received: missing address: %s",
1481 linedup);
1482 msgid = imsgid;
1483 if ((unsigned long) msgid != imsgid)
1484 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1485 linedup);
1486 params = end + 1;
1488 if ((end = strchr(params, '|')) == NULL)
1489 osmtpd_errx(1, "Invalid line received: missing status: %s",
1490 linedup);
1491 end++[0] = '\0';
1493 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1494 rcptto = params;
1495 status = osmtpd_strtostatus(end, linedup);
1496 } else {
1497 rcptto = end;
1498 status = osmtpd_strtostatus(params, linedup);
1501 if (cb->storereport) {
1502 for (i = 0; ctx->rcptto[i] != NULL; i++)
1504 ctx->rcptto = reallocarray(ctx->rcptto, i + 2,
1505 sizeof(*(ctx->rcptto)));
1506 if (ctx->rcptto == NULL)
1507 osmtpd_err(1, NULL);
1509 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1510 osmtpd_err(1, NULL);
1511 ctx->rcptto[i + 1] = NULL;
1514 if ((f = cb->cb) != NULL)
1515 f(ctx, msgid, rcptto, status);
1518 static void
1519 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1520 char *params, char *linedup)
1522 unsigned long imsgid;
1523 uint32_t msgid;
1524 uint64_t evpid;
1525 char *end;
1526 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1528 errno = 0;
1529 imsgid = strtoul(params, &end, 16);
1530 if ((imsgid == ULONG_MAX && errno != 0))
1531 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1532 linedup);
1533 if (end[0] != '|')
1534 osmtpd_errx(1, "Invalid line received: missing address: %s",
1535 linedup);
1536 msgid = imsgid;
1537 if ((unsigned long) msgid != imsgid)
1538 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1539 linedup);
1540 params = end + 1;
1542 evpid = strtoull(params, &end, 16);
1543 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1544 end[0] != '\0')
1545 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1546 linedup);
1547 if (cb->storereport)
1548 ctx->evpid = evpid;
1550 if ((f = cb->cb) != NULL)
1551 f(ctx, msgid, evpid);
1554 static void
1555 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1556 char *params, char *linedup)
1558 char *end;
1559 unsigned long imsgid;
1560 uint32_t msgid;
1561 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1563 errno = 0;
1564 imsgid = strtoul(params, &end, 16);
1565 if ((imsgid == ULONG_MAX && errno != 0))
1566 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1567 linedup);
1568 if (end[0] != '|')
1569 osmtpd_errx(1, "Invalid line received: missing address: %s",
1570 linedup);
1571 msgid = imsgid;
1572 if ((unsigned long) msgid != imsgid)
1573 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1574 linedup);
1575 params = end + 1;
1577 if ((f = cb->cb) != NULL)
1578 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1581 static void
1582 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1583 char *params, char *linedup)
1585 char *end;
1586 const char *errstr = NULL;
1587 unsigned long imsgid;
1588 uint32_t msgid;
1589 size_t i, msgsz;
1590 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1592 errno = 0;
1593 imsgid = strtoul(params, &end, 16);
1594 if ((imsgid == ULONG_MAX && errno != 0))
1595 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1596 linedup);
1597 if (end[0] != '|')
1598 osmtpd_errx(1, "Invalid line received: missing address: %s",
1599 linedup);
1600 msgid = imsgid;
1601 if ((unsigned long) msgid != imsgid)
1602 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1603 linedup);
1604 params = end + 1;
1606 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1607 if (errstr != NULL)
1608 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1609 linedup);
1611 if ((f = cb->cb) != NULL)
1612 f(ctx, msgid, msgsz);
1614 if (ondeletecb_message != NULL) {
1615 ondeletecb_message(ctx, ctx->local_message);
1616 ctx->local_message = NULL;
1619 free(ctx->mailfrom);
1620 ctx->mailfrom = NULL;
1622 for (i = 0; ctx->rcptto[i] != NULL; i++)
1623 free(ctx->rcptto[i]);
1624 ctx->rcptto[0] = NULL;
1625 ctx->evpid = 0;
1626 ctx->msgid = 0;
1629 static void
1630 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1631 char *params, char *linedup)
1633 char *end;
1634 unsigned long imsgid;
1635 uint32_t msgid;
1636 size_t i;
1637 void (*f)(struct osmtpd_ctx *, uint32_t);
1639 errno = 0;
1640 imsgid = strtoul(params, &end, 16);
1641 if ((imsgid == ULONG_MAX && errno != 0))
1642 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1643 linedup);
1644 if (end[0] != '\0')
1645 osmtpd_errx(1, "Invalid line received: missing address: %s",
1646 linedup);
1647 msgid = imsgid;
1648 if ((unsigned long) msgid != imsgid)
1649 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1650 linedup);
1652 if ((f = cb->cb) != NULL)
1653 f(ctx, msgid);
1655 if (ondeletecb_message != NULL) {
1656 ondeletecb_message(ctx, ctx->local_message);
1657 ctx->local_message = NULL;
1660 free(ctx->mailfrom);
1661 ctx->mailfrom = NULL;
1663 for (i = 0; ctx->rcptto[i] != NULL; i++)
1664 free(ctx->rcptto[i]);
1665 ctx->rcptto[0] = NULL;
1666 ctx->evpid = 0;
1667 ctx->msgid = 0;
1670 void
1671 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1673 if (ctx->version_major == 0 && ctx->version_minor < 5)
1674 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1675 "proceed\n", ctx->token, ctx->reqid);
1676 else
1677 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1678 "proceed\n", ctx->reqid, ctx->token);
1681 void
1682 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1684 va_list ap;
1686 if (code < 200 || code > 599)
1687 osmtpd_errx(1, "Invalid reject code");
1689 if (ctx->version_major == 0 && ctx->version_minor < 5)
1690 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1691 "reject|%d ", ctx->token, ctx->reqid, code);
1692 else
1693 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1694 "reject|%d ", ctx->reqid, ctx->token, code);
1695 va_start(ap, reason);
1696 io_vprintf(io_stdout, reason, ap);
1697 va_end(ap);
1698 io_printf(io_stdout, "\n");
1701 void
1702 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1703 int subject, int detail, const char *reason, ...)
1705 va_list ap;
1707 if (code < 200 || code > 599)
1708 osmtpd_errx(1, "Invalid reject code");
1709 if (class < 2 || class > 5)
1710 osmtpd_errx(1, "Invalid enhanced status class");
1711 if (subject < 0 || subject > 999)
1712 osmtpd_errx(1, "Invalid enhanced status subject");
1713 if (detail < 0 || detail > 999)
1714 osmtpd_errx(1, "Invalid enhanced status detail");
1716 if (ctx->version_major == 0 && ctx->version_minor < 5)
1717 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1718 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1719 subject, detail);
1720 else
1721 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1722 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1723 subject, detail);
1724 va_start(ap, reason);
1725 io_vprintf(io_stdout, reason, ap);
1726 va_end(ap);
1727 io_printf(io_stdout, "\n");
1730 void
1731 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1733 va_list ap;
1735 if (ctx->version_major == 0 && ctx->version_minor < 5)
1736 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1737 "disconnect|421 ", ctx->token, ctx->reqid);
1738 else
1739 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1740 "disconnect|421 ", ctx->reqid, ctx->token);
1741 va_start(ap, reason);
1742 io_vprintf(io_stdout, reason, ap);
1743 va_end(ap);
1744 io_printf(io_stdout, "\n");
1747 void
1748 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1749 int detail, const char *reason, ...)
1751 va_list ap;
1753 if (class <= 2 || class >= 5)
1754 osmtpd_errx(1, "Invalid enhanced status class");
1755 if (subject < 0 || subject > 999)
1756 osmtpd_errx(1, "Invalid enhanced status subject");
1757 if (detail < 0 || detail > 999)
1758 osmtpd_errx(1, "Invalid enhanced status detail");
1759 if (ctx->version_major == 0 && ctx->version_minor < 5)
1760 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1761 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1762 subject, detail);
1763 else
1764 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1765 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1766 subject, detail);
1767 va_start(ap, reason);
1768 io_vprintf(io_stdout, reason, ap);
1769 va_end(ap);
1770 io_printf(io_stdout, "\n");
1773 void
1774 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1776 va_list ap;
1778 if (ctx->version_major == 0 && ctx->version_minor < 5)
1779 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1780 "rewrite|", ctx->token, ctx->reqid);
1781 else
1782 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1783 "rewrite|", ctx->reqid, ctx->token);
1784 va_start(ap, value);
1785 io_vprintf(io_stdout, value, ap);
1786 va_end(ap);
1787 io_printf(io_stdout, "\n");
1790 void
1791 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1793 va_list ap;
1795 if (ctx->version_major == 0 && ctx->version_minor < 5)
1796 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1797 ctx->token, ctx->reqid);
1798 else
1799 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1800 ctx->reqid, ctx->token);
1801 va_start(ap, line);
1802 io_vprintf(io_stdout, line, ap);
1803 va_end(ap);
1804 io_printf(io_stdout, "\n");
1807 static void
1808 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1809 int storereport, void *cb)
1811 size_t i;
1813 if (ready)
1814 osmtpd_errx(1, "Can't register when proc is running");
1816 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1817 if (type == osmtpd_callbacks[i].type &&
1818 phase == osmtpd_callbacks[i].phase &&
1819 incoming == osmtpd_callbacks[i].incoming) {
1820 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
1821 osmtpd_errx(1, "Event already registered");
1822 if (cb != NULL)
1823 osmtpd_callbacks[i].cb = cb;
1824 osmtpd_callbacks[i].doregister = 1;
1825 if (storereport)
1826 osmtpd_callbacks[i].storereport = 1;
1827 return;
1830 /* NOT REACHED */
1831 osmtpd_errx(1, "Trying to register unknown event");
1834 static enum osmtpd_phase
1835 osmtpd_strtophase(const char *phase, const char *linedup)
1837 if (strcmp(phase, "connect") == 0)
1838 return OSMTPD_PHASE_CONNECT;
1839 if (strcmp(phase, "helo") == 0)
1840 return OSMTPD_PHASE_HELO;
1841 if (strcmp(phase, "ehlo") == 0)
1842 return OSMTPD_PHASE_EHLO;
1843 if (strcmp(phase, "starttls") == 0)
1844 return OSMTPD_PHASE_STARTTLS;
1845 if (strcmp(phase, "auth") == 0)
1846 return OSMTPD_PHASE_AUTH;
1847 if (strcmp(phase, "mail-from") == 0)
1848 return OSMTPD_PHASE_MAIL_FROM;
1849 if (strcmp(phase, "rcpt-to") == 0)
1850 return OSMTPD_PHASE_RCPT_TO;
1851 if (strcmp(phase, "data") == 0)
1852 return OSMTPD_PHASE_DATA;
1853 if (strcmp(phase, "data-line") == 0)
1854 return OSMTPD_PHASE_DATA_LINE;
1855 if (strcmp(phase, "rset") == 0)
1856 return OSMTPD_PHASE_RSET;
1857 if (strcmp(phase, "quit") == 0)
1858 return OSMTPD_PHASE_QUIT;
1859 if (strcmp(phase, "noop") == 0)
1860 return OSMTPD_PHASE_NOOP;
1861 if (strcmp(phase, "help") == 0)
1862 return OSMTPD_PHASE_HELP;
1863 if (strcmp(phase, "wiz") == 0)
1864 return OSMTPD_PHASE_WIZ;
1865 if (strcmp(phase, "commit") == 0)
1866 return OSMTPD_PHASE_COMMIT;
1867 if (strcmp(phase, "link-connect") == 0)
1868 return OSMTPD_PHASE_LINK_CONNECT;
1869 if (strcmp(phase, "link-disconnect") == 0)
1870 return OSMTPD_PHASE_LINK_DISCONNECT;
1871 if (strcmp(phase, "link-greeting") == 0)
1872 return OSMTPD_PHASE_LINK_GREETING;
1873 if (strcmp(phase, "link-identify") == 0)
1874 return OSMTPD_PHASE_LINK_IDENTIFY;
1875 if (strcmp(phase, "link-tls") == 0)
1876 return OSMTPD_PHASE_LINK_TLS;
1877 if (strcmp(phase, "tx-begin") == 0)
1878 return OSMTPD_PHASE_TX_BEGIN;
1879 if (strcmp(phase, "tx-mail") == 0)
1880 return OSMTPD_PHASE_TX_MAIL;
1881 if (strcmp(phase, "tx-rcpt") == 0)
1882 return OSMTPD_PHASE_TX_RCPT;
1883 if (strcmp(phase, "tx-envelope") == 0)
1884 return OSMTPD_PHASE_TX_ENVELOPE;
1885 if (strcmp(phase, "tx-data") == 0)
1886 return OSMTPD_PHASE_TX_DATA;
1887 if (strcmp(phase, "tx-commit") == 0)
1888 return OSMTPD_PHASE_TX_COMMIT;
1889 if (strcmp(phase, "tx-rollback") == 0)
1890 return OSMTPD_PHASE_TX_ROLLBACK;
1891 if (strcmp(phase, "protocol-client") == 0)
1892 return OSMTPD_PHASE_PROTOCOL_CLIENT;
1893 if (strcmp(phase, "protocol-server") == 0)
1894 return OSMTPD_PHASE_PROTOCOL_SERVER;
1895 if (strcmp(phase, "filter-response") == 0)
1896 return OSMTPD_PHASE_FILTER_RESPONSE;
1897 if (strcmp(phase, "timeout") == 0)
1898 return OSMTPD_PHASE_TIMEOUT;
1899 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
1902 static const char *
1903 osmtpd_typetostr(enum osmtpd_type type)
1905 switch (type) {
1906 case OSMTPD_TYPE_FILTER:
1907 return "filter";
1908 case OSMTPD_TYPE_REPORT:
1909 return "report";
1911 osmtpd_errx(1, "In valid type: %d\n", type);
1914 static const char *
1915 osmtpd_phasetostr(enum osmtpd_phase phase)
1917 switch (phase) {
1918 case OSMTPD_PHASE_CONNECT:
1919 return "connect";
1920 case OSMTPD_PHASE_HELO:
1921 return "helo";
1922 case OSMTPD_PHASE_EHLO:
1923 return "ehlo";
1924 case OSMTPD_PHASE_STARTTLS:
1925 return "starttls";
1926 case OSMTPD_PHASE_AUTH:
1927 return "auth";
1928 case OSMTPD_PHASE_MAIL_FROM:
1929 return "mail-from";
1930 case OSMTPD_PHASE_RCPT_TO:
1931 return "rcpt-to";
1932 case OSMTPD_PHASE_DATA:
1933 return "data";
1934 case OSMTPD_PHASE_DATA_LINE:
1935 return "data-line";
1936 case OSMTPD_PHASE_RSET:
1937 return "rset";
1938 case OSMTPD_PHASE_QUIT:
1939 return "quit";
1940 case OSMTPD_PHASE_NOOP:
1941 return "noop";
1942 case OSMTPD_PHASE_HELP:
1943 return "help";
1944 case OSMTPD_PHASE_WIZ:
1945 return "wiz";
1946 case OSMTPD_PHASE_COMMIT:
1947 return "commit";
1948 case OSMTPD_PHASE_LINK_CONNECT:
1949 return "link-connect";
1950 case OSMTPD_PHASE_LINK_DISCONNECT:
1951 return "link-disconnect";
1952 case OSMTPD_PHASE_LINK_GREETING:
1953 return "link-greeting";
1954 case OSMTPD_PHASE_LINK_IDENTIFY:
1955 return "link-identify";
1956 case OSMTPD_PHASE_LINK_TLS:
1957 return "link-tls";
1958 case OSMTPD_PHASE_TX_BEGIN:
1959 return "tx-begin";
1960 case OSMTPD_PHASE_TX_MAIL:
1961 return "tx-mail";
1962 case OSMTPD_PHASE_TX_RCPT:
1963 return "tx-rcpt";
1964 case OSMTPD_PHASE_TX_ENVELOPE:
1965 return "tx-envelope";
1966 case OSMTPD_PHASE_TX_DATA:
1967 return "tx-data";
1968 case OSMTPD_PHASE_TX_COMMIT:
1969 return "tx-commit";
1970 case OSMTPD_PHASE_TX_ROLLBACK:
1971 return "tx-rollback";
1972 case OSMTPD_PHASE_PROTOCOL_CLIENT:
1973 return "protocol-client";
1974 case OSMTPD_PHASE_PROTOCOL_SERVER:
1975 return "protocol-server";
1976 case OSMTPD_PHASE_FILTER_RESPONSE:
1977 return "filter-response";
1978 case OSMTPD_PHASE_TIMEOUT:
1979 return "timeout";
1981 osmtpd_errx(1, "In valid phase: %d\n", phase);
1984 static enum osmtpd_status
1985 osmtpd_strtostatus(const char *status, char *linedup)
1987 if (strcmp(status, "ok") == 0)
1988 return OSMTPD_STATUS_OK;
1989 else if (strcmp(status, "tempfail") == 0)
1990 return OSMTPD_STATUS_TEMPFAIL;
1991 else if (strcmp(status, "permfail") == 0)
1992 return OSMTPD_STATUS_PERMFAIL;
1993 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
1996 static void
1997 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
1998 char *linedup)
2000 char *port = NULL;
2001 const char *errstr = NULL;
2002 struct sockaddr_in *sin;
2003 struct sockaddr_in6 *sin6;
2004 struct sockaddr_un *sun;
2005 size_t n;
2007 if (addr[0] == '[') {
2008 sin6 = (struct sockaddr_in6 *)ss;
2009 sin6->sin6_family = AF_INET6;
2010 sin6->sin6_port = 0;
2011 if (hasport) {
2012 if ((port = strrchr(addr, ':')) == NULL)
2013 osmtpd_errx(1, "Invalid line received: invalid "
2014 "address (%s): %s", addr, linedup);
2015 if (port[-1] != ']')
2016 osmtpd_errx(1, "Invalid line received: invalid "
2017 "address (%s): %s", addr, linedup);
2018 port++;
2019 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2020 &errstr));
2021 if (errstr != NULL)
2022 osmtpd_errx(1, "Invalid line received: invalid "
2023 "address (%s): %s", addr, linedup);
2024 port[-2] = '\0';
2025 } else {
2026 n = strlen(addr);
2027 if (addr[n - 1] != ']')
2028 osmtpd_errx(1, "Invalid line received: invalid "
2029 "address (%s): %s", addr, linedup);
2030 addr[n - 1] = '\0';
2032 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2033 case 1:
2034 break;
2035 case 0:
2036 if (hasport)
2037 port[-2] = ']';
2038 else
2039 addr[n - 1] = ']';
2040 osmtpd_errx(1, "Invalid line received: invalid address "
2041 "(%s): %s", addr, linedup);
2042 default:
2043 if (hasport)
2044 port[-2] = ']';
2045 else
2046 addr[n - 1] = ']';
2047 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2048 linedup);
2050 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2051 sun = (struct sockaddr_un *)ss;
2052 sun->sun_family = AF_UNIX;
2053 if (strlcpy(sun->sun_path, addr,
2054 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2055 osmtpd_errx(1, "Invalid line received: address too "
2056 "long (%s): %s", addr, linedup);
2058 } else {
2059 sin = (struct sockaddr_in *)ss;
2060 sin->sin_family = AF_INET;
2061 sin->sin_port = 0;
2062 if (hasport) {
2063 if ((port = strrchr(addr, ':')) == NULL)
2064 osmtpd_errx(1, "Invalid line received: invalid "
2065 "address (%s): %s", addr, linedup);
2066 port++;
2067 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2068 &errstr));
2069 if (errstr != NULL)
2070 osmtpd_errx(1, "Invalid line received: invalid "
2071 "address (%s): %s", addr, linedup);
2072 port[-1] = '\0';
2074 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2075 case 1:
2076 break;
2077 case 0:
2078 if (hasport)
2079 port[-1] = ':';
2080 osmtpd_errx(1, "Invalid line received: invalid address "
2081 "(%s): %s", addr, linedup);
2082 default:
2083 if (hasport)
2084 port[-1] = ':';
2085 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2086 linedup);
2091 static int
2092 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2094 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2097 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);