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_link_auth(struct osmtpd_callback *, struct osmtpd_ctx *,
86 char *, char *);
87 static void osmtpd_tx_begin(struct osmtpd_callback *, struct osmtpd_ctx *,
88 char *, char *);
89 static void osmtpd_tx_mail(struct osmtpd_callback *, struct osmtpd_ctx *,
90 char *, char *);
91 static void osmtpd_tx_rcpt(struct osmtpd_callback *, struct osmtpd_ctx *,
92 char *, char *);
93 static void osmtpd_tx_envelope(struct osmtpd_callback *, struct osmtpd_ctx *,
94 char *, char *);
95 static void osmtpd_tx_data(struct osmtpd_callback *, struct osmtpd_ctx *,
96 char *, char *);
97 static void osmtpd_tx_commit(struct osmtpd_callback *, struct osmtpd_ctx *,
98 char *, char *);
99 static void osmtpd_tx_rollback(struct osmtpd_callback *, struct osmtpd_ctx *,
100 char *, char *);
101 static void osmtpd_addrtoss(char *, struct sockaddr_storage *, int, char *);
102 static enum osmtpd_status osmtpd_strtostatus(const char *, char *);
103 static int osmtpd_session_cmp(struct osmtpd_session *, struct osmtpd_session *);
104 static void *(*oncreatecb_session)(struct osmtpd_ctx *) = NULL;
105 static void (*ondeletecb_session)(struct osmtpd_ctx *, void *) = NULL;
106 static void *(*oncreatecb_message)(struct osmtpd_ctx *) = NULL;
107 static void (*ondeletecb_message)(struct osmtpd_ctx *, void *) = NULL;
108 static void (*conf_cb)(const char *, const char *);
110 static struct osmtpd_callback osmtpd_callbacks[] = {
112 OSMTPD_TYPE_FILTER,
113 OSMTPD_PHASE_CONNECT,
114 1,
115 osmtpd_connect,
116 NULL,
117 0,
119 },
121 OSMTPD_TYPE_FILTER,
122 OSMTPD_PHASE_HELO,
123 1,
124 osmtpd_identify,
125 NULL,
126 0,
128 },
130 OSMTPD_TYPE_FILTER,
131 OSMTPD_PHASE_EHLO,
132 1,
133 osmtpd_identify,
134 NULL,
135 0,
137 },
139 OSMTPD_TYPE_FILTER,
140 OSMTPD_PHASE_STARTTLS,
141 1,
142 osmtpd_noargs,
143 NULL,
144 0,
146 },
148 OSMTPD_TYPE_FILTER,
149 OSMTPD_PHASE_AUTH,
150 1,
151 osmtpd_onearg,
152 NULL,
153 0,
155 },
157 OSMTPD_TYPE_FILTER,
158 OSMTPD_PHASE_MAIL_FROM,
159 1,
160 osmtpd_onearg,
161 NULL,
162 0,
164 },
166 OSMTPD_TYPE_FILTER,
167 OSMTPD_PHASE_RCPT_TO,
168 1,
169 osmtpd_onearg,
170 NULL,
171 0,
173 },
175 OSMTPD_TYPE_FILTER,
176 OSMTPD_PHASE_DATA,
177 1,
178 osmtpd_noargs,
179 NULL,
180 0,
182 },
184 OSMTPD_TYPE_FILTER,
185 OSMTPD_PHASE_DATA_LINE,
186 1,
187 osmtpd_onearg,
188 NULL,
189 0,
191 },
193 OSMTPD_TYPE_FILTER,
194 OSMTPD_PHASE_RSET,
195 1,
196 osmtpd_noargs,
197 NULL,
198 0,
200 },
202 OSMTPD_TYPE_FILTER,
203 OSMTPD_PHASE_QUIT,
204 1,
205 osmtpd_noargs,
206 NULL,
207 0,
209 },
211 OSMTPD_TYPE_FILTER,
212 OSMTPD_PHASE_NOOP,
213 1,
214 osmtpd_noargs,
215 NULL,
216 0,
218 },
220 OSMTPD_TYPE_FILTER,
221 OSMTPD_PHASE_HELP,
222 1,
223 osmtpd_noargs,
224 NULL,
225 0,
227 },
229 OSMTPD_TYPE_FILTER,
230 OSMTPD_PHASE_WIZ,
231 1,
232 osmtpd_noargs,
233 NULL,
234 0,
236 },
238 OSMTPD_TYPE_FILTER,
239 OSMTPD_PHASE_COMMIT,
240 1,
241 osmtpd_noargs,
242 NULL,
243 0,
245 },
247 OSMTPD_TYPE_REPORT,
248 OSMTPD_PHASE_LINK_CONNECT,
249 1,
250 osmtpd_link_connect,
251 NULL,
252 0,
254 },
256 OSMTPD_TYPE_REPORT,
257 OSMTPD_PHASE_LINK_DISCONNECT,
258 1,
259 osmtpd_link_disconnect,
260 NULL,
261 0,
263 },
265 OSMTPD_TYPE_REPORT,
266 OSMTPD_PHASE_LINK_GREETING,
267 1,
268 osmtpd_link_greeting,
269 NULL,
270 0,
272 },
274 OSMTPD_TYPE_REPORT,
275 OSMTPD_PHASE_LINK_IDENTIFY,
276 1,
277 osmtpd_link_identify,
278 NULL,
279 0,
281 },
283 OSMTPD_TYPE_REPORT,
284 OSMTPD_PHASE_LINK_TLS,
285 1,
286 osmtpd_link_tls,
287 NULL,
288 0,
290 },
292 OSMTPD_TYPE_REPORT,
293 OSMTPD_PHASE_LINK_AUTH,
294 1,
295 osmtpd_link_auth,
296 NULL,
297 0,
299 },
301 OSMTPD_TYPE_REPORT,
302 OSMTPD_PHASE_TX_BEGIN,
303 1,
304 osmtpd_tx_begin,
305 NULL,
306 0,
308 },
310 OSMTPD_TYPE_REPORT,
311 OSMTPD_PHASE_TX_MAIL,
312 1,
313 osmtpd_tx_mail,
314 NULL,
315 0,
317 },
319 OSMTPD_TYPE_REPORT,
320 OSMTPD_PHASE_TX_RCPT,
321 1,
322 osmtpd_tx_rcpt,
323 NULL,
324 0,
326 },
328 OSMTPD_TYPE_REPORT,
329 OSMTPD_PHASE_TX_ENVELOPE,
330 1,
331 osmtpd_tx_envelope,
332 NULL,
333 0,
335 },
337 OSMTPD_TYPE_REPORT,
338 OSMTPD_PHASE_TX_DATA,
339 1,
340 osmtpd_tx_data,
341 NULL,
342 0,
344 },
346 OSMTPD_TYPE_REPORT,
347 OSMTPD_PHASE_TX_COMMIT,
348 1,
349 osmtpd_tx_commit,
350 NULL,
351 0,
353 },
355 OSMTPD_TYPE_REPORT,
356 OSMTPD_PHASE_TX_ROLLBACK,
357 1,
358 osmtpd_tx_rollback,
359 NULL,
360 0,
362 },
364 OSMTPD_TYPE_REPORT,
365 OSMTPD_PHASE_PROTOCOL_CLIENT,
366 1,
367 osmtpd_onearg,
368 NULL,
369 0,
371 },
373 OSMTPD_TYPE_REPORT,
374 OSMTPD_PHASE_PROTOCOL_SERVER,
375 1,
376 osmtpd_onearg,
377 NULL,
378 0,
380 },
382 OSMTPD_TYPE_REPORT,
383 OSMTPD_PHASE_FILTER_RESPONSE,
384 1,
385 osmtpd_onearg,
386 NULL,
387 0,
389 },
391 OSMTPD_TYPE_REPORT,
392 OSMTPD_PHASE_TIMEOUT,
393 1,
394 osmtpd_noargs,
395 NULL,
396 0,
398 },
400 OSMTPD_TYPE_REPORT,
401 OSMTPD_PHASE_LINK_CONNECT,
402 0,
403 osmtpd_link_connect,
404 NULL,
405 0,
407 },
409 OSMTPD_TYPE_REPORT,
410 OSMTPD_PHASE_LINK_DISCONNECT,
411 0,
412 osmtpd_link_disconnect,
413 NULL,
414 0,
416 },
418 OSMTPD_TYPE_REPORT,
419 OSMTPD_PHASE_LINK_GREETING,
420 0,
421 osmtpd_link_greeting,
422 NULL,
423 0,
425 },
427 OSMTPD_TYPE_REPORT,
428 OSMTPD_PHASE_LINK_IDENTIFY,
429 0,
430 osmtpd_link_identify,
431 NULL,
432 0,
434 },
436 OSMTPD_TYPE_REPORT,
437 OSMTPD_PHASE_LINK_TLS,
438 0,
439 osmtpd_link_tls,
440 NULL,
441 0,
443 },
445 OSMTPD_TYPE_REPORT,
446 OSMTPD_PHASE_LINK_AUTH,
447 0,
448 osmtpd_link_auth,
449 NULL,
450 0,
452 },
454 OSMTPD_TYPE_REPORT,
455 OSMTPD_PHASE_TX_BEGIN,
456 0,
457 osmtpd_tx_begin,
458 NULL,
459 0,
461 },
463 OSMTPD_TYPE_REPORT,
464 OSMTPD_PHASE_TX_MAIL,
465 0,
466 osmtpd_tx_mail,
467 NULL,
468 0,
470 },
472 OSMTPD_TYPE_REPORT,
473 OSMTPD_PHASE_TX_RCPT,
474 0,
475 osmtpd_tx_rcpt,
476 NULL,
477 0,
479 },
481 OSMTPD_TYPE_REPORT,
482 OSMTPD_PHASE_TX_ENVELOPE,
483 0,
484 osmtpd_tx_envelope,
485 NULL,
486 0,
488 },
490 OSMTPD_TYPE_REPORT,
491 OSMTPD_PHASE_TX_DATA,
492 0,
493 osmtpd_tx_data,
494 NULL,
495 0,
497 },
499 OSMTPD_TYPE_REPORT,
500 OSMTPD_PHASE_TX_COMMIT,
501 0,
502 osmtpd_tx_commit,
503 NULL,
504 0,
506 },
508 OSMTPD_TYPE_REPORT,
509 OSMTPD_PHASE_TX_ROLLBACK,
510 0,
511 osmtpd_tx_rollback,
512 NULL,
513 0,
515 },
517 OSMTPD_TYPE_REPORT,
518 OSMTPD_PHASE_PROTOCOL_CLIENT,
519 0,
520 osmtpd_onearg,
521 NULL,
522 0,
524 },
526 OSMTPD_TYPE_REPORT,
527 OSMTPD_PHASE_PROTOCOL_SERVER,
528 0,
529 osmtpd_onearg,
530 NULL,
531 0,
533 },
535 OSMTPD_TYPE_REPORT,
536 OSMTPD_PHASE_FILTER_RESPONSE,
537 0,
538 osmtpd_onearg,
539 NULL,
540 0,
542 },
544 OSMTPD_TYPE_REPORT,
545 OSMTPD_PHASE_TIMEOUT,
546 0,
547 osmtpd_noargs,
548 NULL,
549 0,
552 };
554 static struct io *io_stdout;
555 static int needs;
556 static int ready = 0;
557 /* Default from smtpd */
558 static int session_timeout = 300;
560 RB_HEAD(osmtpd_sessions, osmtpd_session) osmtpd_sessions = RB_INITIALIZER(NULL);
561 RB_PROTOTYPE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);
563 void
564 osmtpd_register_conf(void (*cb)(const char *, const char *))
566 conf_cb = cb;
569 void
570 osmtpd_register_filter_connect(void (*cb)(struct osmtpd_ctx *, const char *,
571 struct sockaddr_storage *))
573 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_CONNECT, 1, 0,
574 (void *)cb);
575 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
576 NULL);
579 void
580 osmtpd_register_filter_helo(void (*cb)(struct osmtpd_ctx *, const char *))
582 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELO, 1, 0,
583 (void *)cb);
584 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
585 NULL);
588 void
589 osmtpd_register_filter_ehlo(void (*cb)(struct osmtpd_ctx *, const char *))
591 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_EHLO, 1, 0,
592 (void *)cb);
593 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
594 NULL);
597 void
598 osmtpd_register_filter_starttls(void (*cb)(struct osmtpd_ctx *))
600 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_STARTTLS, 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_auth(void (*cb)(struct osmtpd_ctx *, const char *))
609 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_AUTH, 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_mailfrom(void (*cb)(struct osmtpd_ctx *, const char *))
618 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_MAIL_FROM, 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_rcptto(void (*cb)(struct osmtpd_ctx *, const char *))
627 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RCPT_TO, 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_data(void (*cb)(struct osmtpd_ctx *))
636 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA, 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_dataline(void (*cb)(struct osmtpd_ctx *, const char *))
645 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_DATA_LINE, 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_rset(void (*cb)(struct osmtpd_ctx *))
654 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_RSET, 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_quit(void (*cb)(struct osmtpd_ctx *))
663 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_QUIT, 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_noop(void (*cb)(struct osmtpd_ctx *))
672 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_NOOP, 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_help(void (*cb)(struct osmtpd_ctx *))
681 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_HELP, 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_wiz(void (*cb)(struct osmtpd_ctx *))
690 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_WIZ, 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_commit(void (*cb)(struct osmtpd_ctx *))
699 osmtpd_register(OSMTPD_TYPE_FILTER, OSMTPD_PHASE_COMMIT, 1, 0,
700 (void *)cb);
701 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT, 1, 0,
702 NULL);
705 void
706 osmtpd_register_report_connect(int incoming, void (*cb)(struct osmtpd_ctx *,
707 const char *, enum osmtpd_status, struct sockaddr_storage *,
708 struct sockaddr_storage *))
710 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT, incoming,
711 0, (void *)cb);
712 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
713 incoming, 0, NULL);
716 void
717 osmtpd_register_report_disconnect(int incoming, void (*cb)(struct osmtpd_ctx *))
719 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
720 incoming, 0, (void *)cb);
723 void
724 osmtpd_register_report_identify(int incoming, void (*cb)(struct osmtpd_ctx *,
725 const char *))
727 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
728 incoming, 0, (void *)cb);
729 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
730 incoming, 0, NULL);
733 void
734 osmtpd_register_report_tls(int incoming, void (*cb)(struct osmtpd_ctx *,
735 const char *))
737 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS, 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_auth(int incoming, void (*cb)(struct osmtpd_ctx *,
745 const char *, enum osmtpd_auth_status))
747 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH, 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_begin(int incoming, void (*cb)(struct osmtpd_ctx *,
755 uint32_t))
757 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN, incoming, 0,
758 (void *)cb);
759 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
760 incoming, 0, NULL);
763 void
764 osmtpd_register_report_mail(int incoming, void (*cb)(struct osmtpd_ctx *,
765 uint32_t, const char *, enum osmtpd_status))
767 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL, 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_rcpt(int incoming, void (*cb)(struct osmtpd_ctx *,
775 uint32_t, const char *, enum osmtpd_status))
777 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT, 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_envelope(int incoming, void (*cb)(struct osmtpd_ctx *,
785 uint32_t, uint64_t))
787 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE, 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_data(int incoming, void (*cb)(struct osmtpd_ctx *,
795 uint32_t, enum osmtpd_status))
797 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_DATA, incoming, 0,
798 (void *)cb);
799 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
800 incoming, 0, NULL);
803 void
804 osmtpd_register_report_commit(int incoming, void (*cb)(struct osmtpd_ctx *,
805 uint32_t, size_t))
807 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT, incoming, 0,
808 (void *)cb);
809 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
810 incoming, 0, NULL);
813 void
814 osmtpd_register_report_rollback(int incoming, void (*cb)(struct osmtpd_ctx *,
815 uint32_t))
817 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK, incoming,
818 0, (void *)cb);
819 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
820 incoming, 0, NULL);
823 void
824 osmtpd_register_report_client(int incoming, void (*cb)(struct osmtpd_ctx *,
825 const char *))
827 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_CLIENT,
828 incoming, 0, (void *)cb);
829 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
830 incoming, 0, NULL);
833 void
834 osmtpd_register_report_server(int incoming, void (*cb)(struct osmtpd_ctx *,
835 const char *))
837 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_PROTOCOL_SERVER,
838 incoming, 0, (void *)cb);
839 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
840 incoming, 0, NULL);
843 void
844 osmtpd_register_report_response(int incoming, void (*cb)(struct osmtpd_ctx *,
845 const char *))
847 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_FILTER_RESPONSE,
848 incoming, 0, (void *)cb);
849 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
850 incoming, 0, NULL);
853 void
854 osmtpd_register_report_timeout(int incoming, void (*cb)(struct osmtpd_ctx *))
856 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TIMEOUT, incoming, 0,
857 (void *)cb);
858 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
859 incoming, 0, NULL);
862 void
863 osmtpd_local_session(void *(*oncreate)(struct osmtpd_ctx *),
864 void (*ondelete)(struct osmtpd_ctx *, void *))
866 oncreatecb_session = oncreate;
867 ondeletecb_session = ondelete;
870 void
871 osmtpd_local_message(void *(*oncreate)(struct osmtpd_ctx *),
872 void (*ondelete)(struct osmtpd_ctx *, void *))
874 oncreatecb_message = oncreate;
875 ondeletecb_message = ondelete;
878 void
879 osmtpd_need(int lneeds)
881 needs |= lneeds;
884 static void
885 osmtpd_register_need(int incoming)
887 if (needs & (OSMTPD_NEED_SRC | OSMTPD_NEED_DST | OSMTPD_NEED_RDNS |
888 OSMTPD_NEED_FCRDNS))
889 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_CONNECT,
890 incoming, 1, NULL);
891 if (needs & OSMTPD_NEED_GREETING)
892 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_GREETING,
893 incoming, 1, NULL);
894 if (needs & OSMTPD_NEED_IDENTITY)
895 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_IDENTIFY,
896 incoming, 1, NULL);
897 if (needs & OSMTPD_NEED_CIPHERS)
898 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_TLS,
899 incoming, 1, NULL);
900 if (needs & OSMTPD_NEED_USERNAME)
901 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_AUTH,
902 incoming, 1, NULL);
903 if (needs & OSMTPD_NEED_MSGID) {
904 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_BEGIN,
905 incoming, 1, NULL);
906 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
907 incoming, 0, NULL);
908 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
909 incoming, 0, NULL);
911 if (needs & OSMTPD_NEED_MAILFROM) {
912 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_MAIL,
913 incoming, 1, NULL);
914 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
915 incoming, 0, NULL);
916 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
917 incoming, 0, NULL);
919 if (needs & OSMTPD_NEED_RCPTTO) {
920 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_RCPT,
921 incoming, 1, NULL);
922 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
923 incoming, 0, NULL);
924 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
925 incoming, 0, NULL);
927 if (needs & OSMTPD_NEED_EVPID) {
928 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ENVELOPE,
929 incoming, 1, NULL);
930 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_ROLLBACK,
931 incoming, 0, NULL);
932 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_TX_COMMIT,
933 incoming, 0, NULL);
936 osmtpd_register(OSMTPD_TYPE_REPORT, OSMTPD_PHASE_LINK_DISCONNECT,
937 incoming, 0, NULL);
940 void
941 osmtpd_run(void)
943 size_t i = 0;
944 int registered = 0;
945 struct event_base *evbase;
946 struct io *io_stdin;
947 struct osmtpd_callback *hidenity = NULL, *eidentity = NULL;
948 struct osmtpd_callback *ridentity = NULL;
950 evbase = event_init();
952 if ((io_stdin = io_new()) == NULL ||
953 (io_stdout = io_new()) == NULL)
954 osmtpd_err(1, "io_new");
955 io_set_nonblocking(STDIN_FILENO);
956 io_set_fd(io_stdin, STDIN_FILENO);
957 io_set_callback(io_stdin, osmtpd_newline, NULL);
958 io_set_read(io_stdin);
959 io_set_nonblocking(STDOUT_FILENO);
960 io_set_fd(io_stdout, STDOUT_FILENO);
961 io_set_callback(io_stdout, osmtpd_outevt, NULL);
962 io_set_write(io_stdout);
964 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
965 if (osmtpd_callbacks[i].doregister) {
966 osmtpd_register_need(osmtpd_callbacks[i].incoming);
967 if (oncreatecb_message != NULL) {
968 osmtpd_register(OSMTPD_TYPE_REPORT,
969 OSMTPD_PHASE_TX_BEGIN,
970 osmtpd_callbacks[i].incoming, 0, NULL);
971 osmtpd_register(OSMTPD_TYPE_REPORT,
972 OSMTPD_PHASE_TX_ROLLBACK,
973 osmtpd_callbacks[i].incoming, 0, NULL);
974 osmtpd_register(OSMTPD_TYPE_REPORT,
975 OSMTPD_PHASE_TX_COMMIT,
976 osmtpd_callbacks[i].incoming, 0, NULL);
978 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
979 osmtpd_callbacks[i].phase == OSMTPD_PHASE_HELO)
980 hidenity = &(osmtpd_callbacks[i]);
981 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_FILTER &&
982 osmtpd_callbacks[i].phase == OSMTPD_PHASE_EHLO)
983 eidentity = &(osmtpd_callbacks[i]);
984 if (osmtpd_callbacks[i].type == OSMTPD_TYPE_REPORT &&
985 osmtpd_callbacks[i].phase ==
986 OSMTPD_PHASE_LINK_IDENTIFY &&
987 osmtpd_callbacks[i].incoming == 1)
988 ridentity = &(osmtpd_callbacks[i]);
991 if (ridentity != NULL && ridentity->storereport) {
992 if (hidenity != NULL && hidenity->doregister)
993 hidenity->storereport = 1;
994 if (eidentity != NULL && eidentity->doregister)
995 eidentity->storereport = 1;
997 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
998 if (osmtpd_callbacks[i].doregister) {
999 if (osmtpd_callbacks[i].cb != NULL)
1000 registered = 1;
1001 io_printf(io_stdout, "register|%s|smtp-%s|%s\n",
1002 osmtpd_typetostr(osmtpd_callbacks[i].type),
1003 osmtpd_callbacks[i].incoming ? "in" : "out",
1004 osmtpd_phasetostr(osmtpd_callbacks[i].phase));
1008 if (!registered)
1009 osmtpd_errx(1, "No events registered");
1010 io_printf(io_stdout, "register|ready\n");
1011 ready = 1;
1013 event_dispatch();
1014 io_free(io_stdin);
1015 io_free(io_stdout);
1016 event_base_free(evbase);
1019 __dead void
1020 osmtpd_err(int eval, const char *fmt, ...)
1022 va_list ap;
1024 va_start(ap, fmt);
1025 vfprintf(stderr, fmt, ap);
1026 va_end(ap);
1027 fprintf(stderr, ": %s\n", strerror(errno));
1028 exit(eval);
1031 __dead void
1032 osmtpd_errx(int eval, const char *fmt, ...)
1034 va_list ap;
1036 va_start(ap, fmt);
1037 vfprintf(stderr, fmt, ap);
1038 va_end(ap);
1039 fprintf(stderr, "\n");
1040 exit(eval);
1043 static void
1044 osmtpd_newline(struct io *io, int ev, __unused void *arg)
1046 static char *linedup = NULL;
1047 static size_t dupsize = 0;
1048 struct osmtpd_session *ctx, search;
1049 enum osmtpd_type type;
1050 enum osmtpd_phase phase;
1051 int version_major, version_minor, incoming;
1052 struct timespec tm;
1053 char *line = NULL;
1054 const char *errstr = NULL;
1055 size_t linelen;
1056 char *end;
1057 size_t i;
1059 if (ev == IO_DISCONNECTED) {
1060 event_loopexit(0);
1061 return;
1063 if (ev != IO_DATAIN)
1064 return;
1066 * Multiple calls to io_printf (through osmtpd_filter_dataline) can
1067 * cause a build-up of kevents, because of event_add/event_del loop.
1069 io_pause(io_stdout, IO_OUT);
1070 while ((line = io_getline(io, &linelen)) != NULL) {
1071 if (dupsize < linelen) {
1072 if ((linedup = realloc(linedup, linelen + 1)) == NULL)
1073 osmtpd_err(1, NULL);
1074 dupsize = linelen + 1;
1076 strlcpy(linedup, line, dupsize);
1077 if ((end = strchr(line, '|')) == NULL)
1078 osmtpd_errx(1, "Invalid line received: missing "
1079 "version: %s", linedup);
1080 end++[0] = '\0';
1081 if (strcmp(line, "filter") == 0)
1082 type = OSMTPD_TYPE_FILTER;
1083 else if (strcmp(line, "report") == 0)
1084 type = OSMTPD_TYPE_REPORT;
1085 else if (strcmp(line, "config") == 0) {
1086 line = end;
1087 if (strcmp(line, "ready") == 0) {
1088 if (conf_cb != NULL)
1089 conf_cb(NULL, NULL);
1090 continue;
1092 if ((end = strchr(line, '|')) == NULL)
1093 osmtpd_errx(1, "Invalid line received: missing "
1094 "key: %s", linedup);
1095 end++[0] = '\0';
1096 if (conf_cb != NULL)
1097 conf_cb(line, end);
1098 if (strcmp(line, "smtp-session-timeout") == 0) {
1099 session_timeout = strtonum(end, 0, INT_MAX,
1100 &errstr);
1101 if (errstr != NULL)
1102 osmtpd_errx(1, "Invalid line received: "
1103 "invalid smtp-sesion-timeout: %s",
1104 linedup);
1106 continue;
1108 else
1109 osmtpd_errx(1, "Invalid line received: unknown message "
1110 "type: %s", linedup);
1111 line = end;
1112 version_major = strtoul(line, &end, 10);
1113 if (line == end || end[0] != '.')
1114 osmtpd_errx(1, "Invalid protocol received: %s",
1115 linedup);
1116 line = end + 1;
1117 version_minor = strtoul(line, &end, 10);
1118 if (end[0] == '\0')
1119 osmtpd_errx(1, "Invalid line received: missing time: "
1120 "%s", linedup);
1121 if (line == end || end[0] != '|')
1122 osmtpd_errx(1, "Invalid protocol received: %s",
1123 linedup);
1124 if (version_major != 0)
1125 osmtpd_errx(1, "Unsupported protocol received: %s",
1126 linedup);
1127 line = end + 1;
1128 if ((end = strchr(line, '.')) == NULL)
1129 osmtpd_errx(1, "Invalid line received: invalid "
1130 "timestamp: %s", linedup);
1131 end++[0] = '\0';
1132 tm.tv_sec = (time_t) strtonum(line, 0, INT64_MAX, &errstr);
1133 if (errstr != NULL)
1134 osmtpd_errx(1, "Invalid line received: invalid "
1135 "timestamp: %s", linedup);
1136 line = end;
1137 if ((end = strchr(line, '|')) == NULL)
1138 osmtpd_errx(1, "Invalid line received: missing "
1139 "direction: %s", linedup);
1140 end++[0] = '\0';
1141 tm.tv_nsec = (long) strtonum(line, 0, LONG_MAX, &errstr);
1142 if (errstr != NULL)
1143 osmtpd_errx(1, "Invalid line received: invalid "
1144 "timestamp: %s", linedup);
1145 tm.tv_nsec *= 10 * (9 - (end - line));
1146 line = end;
1147 if ((end = strchr(line, '|')) == NULL)
1148 osmtpd_errx(1, "Invalid line received: missing "
1149 "phase: %s", linedup);
1150 end++[0] = '\0';
1151 if (strcmp(line, "smtp-in") == 0)
1152 incoming = 1;
1153 else if (strcmp(line, "smtp-out") == 0)
1154 incoming = 0;
1155 else
1156 osmtpd_errx(1, "Invalid line: invalid direction: %s",
1157 linedup);
1158 line = end;
1159 if ((end = strchr(line, '|')) == NULL)
1160 osmtpd_errx(1, "Invalid line received: missing reqid: "
1161 "%s", linedup);
1162 end++[0] = '\0';
1163 phase = osmtpd_strtophase(line, linedup);
1164 line = end;
1165 errno = 0;
1166 search.ctx.reqid = strtoull(line, &end, 16);
1167 if ((search.ctx.reqid == ULLONG_MAX && errno != 0) ||
1168 (end[0] != '|' && end[0] != '\0'))
1169 osmtpd_errx(1, "Invalid line received: invalid reqid: "
1170 "%s", linedup);
1171 line = end + 1;
1172 ctx = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1173 if (ctx == NULL) {
1174 if ((ctx = malloc(sizeof(*ctx))) == NULL)
1175 osmtpd_err(1, NULL);
1176 ctx->ctx.reqid = search.ctx.reqid;
1177 ctx->ctx.rdns = NULL;
1178 ctx->ctx.fcrdns = OSMTPD_STATUS_TEMPFAIL;
1179 ctx->ctx.identity = NULL;
1180 ctx->ctx.greeting.identity = NULL;
1181 ctx->ctx.ciphers = NULL;
1182 ctx->ctx.msgid = 0;
1183 ctx->ctx.username = NULL;
1184 ctx->ctx.mailfrom = NULL;
1185 ctx->ctx.rcptto = malloc(sizeof(*(ctx->ctx.rcptto)));
1186 if (ctx->ctx.rcptto == NULL)
1187 osmtpd_err(1, "malloc");
1188 ctx->ctx.rcptto[0] = NULL;
1189 memset(&(ctx->ctx.src), 0, sizeof(ctx->ctx.src));
1190 ctx->ctx.src.ss_family = AF_UNSPEC;
1191 memset(&(ctx->ctx.dst), 0, sizeof(ctx->ctx.dst));
1192 ctx->ctx.dst.ss_family = AF_UNSPEC;
1193 RB_INSERT(osmtpd_sessions, &osmtpd_sessions, ctx);
1194 ctx->ctx.evpid = 0;
1195 ctx->ctx.local_session = NULL;
1196 ctx->ctx.local_message = NULL;
1197 if (oncreatecb_session != NULL)
1198 ctx->ctx.local_session =
1199 oncreatecb_session(&ctx->ctx);
1201 ctx->ctx.type = type;
1202 ctx->ctx.phase = phase;
1203 ctx->ctx.version_major = version_major;
1204 ctx->ctx.version_minor = version_minor;
1205 ctx->ctx.incoming = incoming;
1206 ctx->ctx.tm.tv_sec = tm.tv_sec;
1207 ctx->ctx.tm.tv_nsec = tm.tv_nsec;
1208 ctx->ctx.token = 0;
1210 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1211 if (ctx->ctx.type == osmtpd_callbacks[i].type &&
1212 ctx->ctx.phase == osmtpd_callbacks[i].phase &&
1213 ctx->ctx.incoming == osmtpd_callbacks[i].incoming)
1214 break;
1216 if (i == NITEMS(osmtpd_callbacks)) {
1217 osmtpd_errx(1, "Invalid line received: received "
1218 "unregistered line: %s", linedup);
1220 if (ctx->ctx.type == OSMTPD_TYPE_FILTER) {
1221 ctx->ctx.token = strtoull(line, &end, 16);
1222 if ((ctx->ctx.token == ULLONG_MAX && errno != 0) ||
1223 end[0] != '|')
1224 osmtpd_errx(1, "Invalid line received: invalid "
1225 "token: %s", linedup);
1226 line = end + 1;
1228 osmtpd_callbacks[i].osmtpd_cb(&(osmtpd_callbacks[i]),
1229 &(ctx->ctx), line, linedup);
1231 io_resume(io_stdout, IO_OUT);
1234 static void
1235 osmtpd_outevt(__unused struct io *io, int evt, __unused void *arg)
1237 switch (evt) {
1238 case IO_LOWAT:
1239 return;
1240 case IO_DISCONNECTED:
1241 exit(0);
1242 default:
1243 osmtpd_errx(1, "Unexpectd event");
1247 static void
1248 osmtpd_noargs(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1249 __unused char *params, __unused char *linedup)
1251 void (*f)(struct osmtpd_ctx *);
1253 f = cb->cb;
1254 f(ctx);
1257 static void
1258 osmtpd_onearg(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *line,
1259 __unused char *linedup)
1261 void (*f)(struct osmtpd_ctx *, const char *);
1263 f = cb->cb;
1264 f(ctx, line);
1267 static void
1268 osmtpd_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx, char *params,
1269 char *linedup)
1271 struct sockaddr_storage ss;
1272 char *hostname;
1273 char *address;
1274 void (*f)(struct osmtpd_ctx *, const char *, struct sockaddr_storage *);
1276 hostname = params;
1277 if ((address = strchr(params, '|')) == NULL)
1278 osmtpd_errx(1, "Invalid line received: missing address: %s",
1279 linedup);
1280 address++[0] = '\0';
1282 osmtpd_addrtoss(address, &ss, 0, linedup);
1284 f = cb->cb;
1285 f(ctx, hostname, &ss);
1288 static void
1289 osmtpd_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1290 char *identity, __unused char *linedup)
1292 void (*f)(struct osmtpd_ctx *, const char *);
1294 if (cb->storereport) {
1295 free(ctx->identity);
1296 if ((ctx->identity = strdup(identity)) == NULL)
1297 osmtpd_err(1, "strdup");
1300 f = cb->cb;
1301 f(ctx, identity);
1304 static void
1305 osmtpd_link_connect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1306 char *params, char *linedup)
1308 char *end, *rdns;
1309 enum osmtpd_status fcrdns;
1310 struct sockaddr_storage src, dst;
1311 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_status,
1312 struct sockaddr_storage *, struct sockaddr_storage *);
1314 if ((end = strchr(params, '|')) == NULL)
1315 osmtpd_errx(1, "Invalid line received: missing fcrdns: %s",
1316 linedup);
1317 end++[0] = '\0';
1318 rdns = params;
1319 params = end;
1320 if ((end = strchr(params, '|')) == NULL)
1321 osmtpd_errx(1, "Invalid line received: missing src: %s",
1322 linedup);
1323 end++[0] = '\0';
1324 if (strcmp(params, "pass") == 0)
1325 fcrdns = OSMTPD_STATUS_OK;
1326 else if (strcmp(params, "fail") == 0)
1327 fcrdns = OSMTPD_STATUS_PERMFAIL;
1328 else if (strcmp(params, "error") == 0)
1329 fcrdns = OSMTPD_STATUS_TEMPFAIL;
1330 else
1331 osmtpd_errx(1, "Invalid line received: invalid fcrdns: %s",
1332 linedup);
1333 params = end;
1334 if ((end = strchr(params, '|')) == NULL)
1335 osmtpd_errx(1, "Invalid line received: missing dst: %s",
1336 linedup);
1337 end++[0] = '\0';
1338 osmtpd_addrtoss(params, &src, 1, linedup);
1339 params = end;
1340 osmtpd_addrtoss(params, &dst, 1, linedup);
1341 if (cb->storereport) {
1342 if ((ctx->rdns = strdup(rdns)) == NULL)
1343 osmtpd_err(1, "strdup");
1344 ctx->fcrdns = fcrdns;
1345 memcpy(&(ctx->src), &src, sizeof(ctx->src));
1346 memcpy(&(ctx->dst), &dst, sizeof(ctx->dst));
1348 if ((f = cb->cb) != NULL)
1349 f(ctx, rdns, fcrdns, &src, &dst);
1352 static void
1353 osmtpd_link_disconnect(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1354 __unused char *param, __unused char *linedup)
1356 void (*f)(struct osmtpd_ctx *);
1357 size_t i;
1358 struct osmtpd_session *session, search;
1360 if ((f = cb->cb) != NULL)
1361 f(ctx);
1363 search.ctx.reqid = ctx->reqid;
1364 session = RB_FIND(osmtpd_sessions, &osmtpd_sessions, &search);
1365 if (session != NULL) {
1366 RB_REMOVE(osmtpd_sessions, &osmtpd_sessions, session);
1367 if (ondeletecb_session != NULL)
1368 ondeletecb_session(ctx, session->ctx.local_session);
1369 free(session->ctx.rdns);
1370 free(session->ctx.identity);
1371 free(session->ctx.greeting.identity);
1372 free(session->ctx.ciphers);
1373 free(session->ctx.username);
1374 free(session->ctx.mailfrom);
1375 for (i = 0; session->ctx.rcptto[i] != NULL; i++)
1376 free(session->ctx.rcptto[i]);
1377 free(session->ctx.rcptto);
1378 free(session);
1382 static void
1383 osmtpd_link_greeting(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1384 char *identity, __unused char *linedup)
1386 void (*f)(struct osmtpd_ctx *, const char *);
1388 if (cb->storereport) {
1389 free(ctx->greeting.identity);
1390 if ((ctx->greeting.identity = strdup(identity)) == NULL)
1391 osmtpd_err(1, NULL);
1394 if ((f = cb->cb) != NULL)
1395 f(ctx, identity);
1398 static void
1399 osmtpd_link_identify(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1400 char *identity, __unused char *linedup)
1402 void (*f)(struct osmtpd_ctx *, const char *);
1404 if (cb->storereport) {
1405 free(ctx->identity);
1406 if ((ctx->identity = strdup(identity)) == NULL)
1407 osmtpd_err(1, NULL);
1410 if ((f = cb->cb) != NULL)
1411 f(ctx, identity);
1414 static void
1415 osmtpd_link_tls(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1416 char *ciphers, __unused char *linedup)
1418 void (*f)(struct osmtpd_ctx *, const char *);
1420 if (cb->storereport) {
1421 if ((ctx->ciphers = strdup(ciphers)) == NULL)
1422 osmtpd_err(1, NULL);
1425 if ((f = cb->cb) != NULL)
1426 f(ctx, ciphers);
1429 static void
1430 osmtpd_link_auth(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1431 char *username, char *linedup)
1433 void (*f)(struct osmtpd_ctx *, const char *, enum osmtpd_auth_status);
1434 char *status;
1435 enum osmtpd_auth_status s;
1437 if ((status = strrchr(username, '|')) == NULL)
1438 osmtpd_errx(1, "Invalid auth received: %s", linedup);
1439 status[0] = '\0';
1440 status++;
1441 if (strcmp(status, "pass") == 0)
1442 s = OSMTPD_AUTH_PASS;
1443 else if (strcmp(status, "fail") == 0)
1444 s = OSMTPD_AUTH_FAIL;
1445 else if (strcmp(status, "error") == 0)
1446 s = OSMTPD_AUTH_ERROR;
1447 else
1448 osmtpd_errx(1, "Invalid auth status received: %s", linedup);
1450 if (cb->storereport && s == OSMTPD_AUTH_PASS) {
1451 if ((ctx->username = strdup(username)) == NULL)
1452 osmtpd_err(1, NULL);
1455 if ((f = cb->cb) != NULL)
1456 f(ctx, username, s);
1459 static void
1460 osmtpd_tx_begin(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1461 char *msgid, char *linedup)
1463 unsigned long imsgid;
1464 char *endptr;
1465 void (*f)(struct osmtpd_ctx *, uint32_t);
1467 errno = 0;
1468 imsgid = strtoul(msgid, &endptr, 16);
1469 if ((imsgid == ULONG_MAX && errno != 0) || endptr[0] != '\0')
1470 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1471 linedup);
1472 ctx->msgid = imsgid;
1473 /* Check if we're in range */
1474 if ((unsigned long) ctx->msgid != imsgid)
1475 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1476 linedup);
1478 if (!cb->storereport)
1479 ctx->msgid = 0;
1481 if (oncreatecb_message != NULL)
1482 ctx->local_message = oncreatecb_message(ctx);
1484 if ((f = cb->cb) != NULL)
1485 f(ctx, imsgid);
1488 static void
1489 osmtpd_tx_mail(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1490 char *params, char *linedup)
1492 char *end, *mailfrom;
1493 enum osmtpd_status status;
1494 unsigned long imsgid;
1495 uint32_t msgid;
1496 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1497 enum osmtpd_status);
1499 errno = 0;
1500 imsgid = strtoul(params, &end, 16);
1501 if ((imsgid == ULONG_MAX && errno != 0))
1502 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1503 linedup);
1504 if (end[0] != '|')
1505 osmtpd_errx(1, "Invalid line received: missing address: %s",
1506 linedup);
1507 msgid = imsgid;
1508 if ((unsigned long) msgid != imsgid)
1509 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1510 linedup);
1511 params = end + 1;
1513 if ((end = strchr(params, '|')) == NULL)
1514 osmtpd_errx(1, "Invalid line received: missing status: %s",
1515 linedup);
1516 end++[0] = '\0';
1517 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1518 mailfrom = params;
1519 status = osmtpd_strtostatus(end, linedup);
1520 } else {
1521 mailfrom = end;
1522 status = osmtpd_strtostatus(params, linedup);
1524 if (cb->storereport) {
1525 if ((ctx->mailfrom = strdup(mailfrom)) == NULL)
1526 osmtpd_err(1, NULL);
1529 if ((f = cb->cb) != NULL)
1530 f(ctx, msgid, mailfrom, status);
1533 static void
1534 osmtpd_tx_rcpt(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1535 char *params, char *linedup)
1537 char *end, *rcptto;
1538 enum osmtpd_status status;
1539 unsigned long imsgid;
1540 uint32_t msgid;
1541 size_t i;
1542 void (*f)(struct osmtpd_ctx *, uint32_t, const char *,
1543 enum osmtpd_status);
1545 errno = 0;
1546 imsgid = strtoul(params, &end, 16);
1547 if ((imsgid == ULONG_MAX && errno != 0))
1548 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1549 linedup);
1550 if (end[0] != '|')
1551 osmtpd_errx(1, "Invalid line received: missing address: %s",
1552 linedup);
1553 msgid = imsgid;
1554 if ((unsigned long) msgid != imsgid)
1555 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1556 linedup);
1557 params = end + 1;
1559 if ((end = strchr(params, '|')) == NULL)
1560 osmtpd_errx(1, "Invalid line received: missing status: %s",
1561 linedup);
1562 end++[0] = '\0';
1564 if (ctx->version_major == 0 && ctx->version_minor < 6) {
1565 rcptto = params;
1566 status = osmtpd_strtostatus(end, linedup);
1567 } else {
1568 rcptto = end;
1569 status = osmtpd_strtostatus(params, linedup);
1572 if (cb->storereport) {
1573 for (i = 0; ctx->rcptto[i] != NULL; i++)
1575 ctx->rcptto = reallocarray(ctx->rcptto, i + 2,
1576 sizeof(*(ctx->rcptto)));
1577 if (ctx->rcptto == NULL)
1578 osmtpd_err(1, NULL);
1580 if ((ctx->rcptto[i] = strdup(rcptto)) == NULL)
1581 osmtpd_err(1, NULL);
1582 ctx->rcptto[i + 1] = NULL;
1585 if ((f = cb->cb) != NULL)
1586 f(ctx, msgid, rcptto, status);
1589 static void
1590 osmtpd_tx_envelope(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1591 char *params, char *linedup)
1593 unsigned long imsgid;
1594 uint32_t msgid;
1595 uint64_t evpid;
1596 char *end;
1597 void (*f)(struct osmtpd_ctx *, uint32_t, uint64_t);
1599 errno = 0;
1600 imsgid = strtoul(params, &end, 16);
1601 if ((imsgid == ULONG_MAX && errno != 0))
1602 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1603 linedup);
1604 if (end[0] != '|')
1605 osmtpd_errx(1, "Invalid line received: missing address: %s",
1606 linedup);
1607 msgid = imsgid;
1608 if ((unsigned long) msgid != imsgid)
1609 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1610 linedup);
1611 params = end + 1;
1613 evpid = strtoull(params, &end, 16);
1614 if ((ctx->evpid == ULLONG_MAX && errno != 0) ||
1615 end[0] != '\0')
1616 osmtpd_errx(1, "Invalid line received: invalid evpid: %s",
1617 linedup);
1618 if (cb->storereport)
1619 ctx->evpid = evpid;
1621 if ((f = cb->cb) != NULL)
1622 f(ctx, msgid, evpid);
1625 static void
1626 osmtpd_tx_data(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1627 char *params, char *linedup)
1629 char *end;
1630 unsigned long imsgid;
1631 uint32_t msgid;
1632 void (*f)(struct osmtpd_ctx *, uint32_t, enum osmtpd_status);
1634 errno = 0;
1635 imsgid = strtoul(params, &end, 16);
1636 if ((imsgid == ULONG_MAX && errno != 0))
1637 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1638 linedup);
1639 if (end[0] != '|')
1640 osmtpd_errx(1, "Invalid line received: missing address: %s",
1641 linedup);
1642 msgid = imsgid;
1643 if ((unsigned long) msgid != imsgid)
1644 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1645 linedup);
1646 params = end + 1;
1648 if ((f = cb->cb) != NULL)
1649 f(ctx, msgid, osmtpd_strtostatus(params, linedup));
1652 static void
1653 osmtpd_tx_commit(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1654 char *params, char *linedup)
1656 char *end;
1657 const char *errstr = NULL;
1658 unsigned long imsgid;
1659 uint32_t msgid;
1660 size_t i, msgsz;
1661 void (*f)(struct osmtpd_ctx *, uint32_t, size_t);
1663 errno = 0;
1664 imsgid = strtoul(params, &end, 16);
1665 if ((imsgid == ULONG_MAX && errno != 0))
1666 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1667 linedup);
1668 if (end[0] != '|')
1669 osmtpd_errx(1, "Invalid line received: missing address: %s",
1670 linedup);
1671 msgid = imsgid;
1672 if ((unsigned long) msgid != imsgid)
1673 osmtpd_errx(1, "Invalid line received: invalid msgid: %s",
1674 linedup);
1675 params = end + 1;
1677 msgsz = strtonum(params, 0, UINT32_MAX, &errstr);
1678 if (errstr != NULL)
1679 osmtpd_errx(1, "Invalid line received: invalid msg size: %s",
1680 linedup);
1682 if ((f = cb->cb) != NULL)
1683 f(ctx, msgid, msgsz);
1685 if (ondeletecb_message != NULL) {
1686 ondeletecb_message(ctx, ctx->local_message);
1687 ctx->local_message = NULL;
1690 free(ctx->mailfrom);
1691 ctx->mailfrom = NULL;
1693 for (i = 0; ctx->rcptto[i] != NULL; i++)
1694 free(ctx->rcptto[i]);
1695 ctx->rcptto[0] = NULL;
1696 ctx->evpid = 0;
1697 ctx->msgid = 0;
1700 static void
1701 osmtpd_tx_rollback(struct osmtpd_callback *cb, struct osmtpd_ctx *ctx,
1702 char *params, char *linedup)
1704 char *end;
1705 unsigned long imsgid;
1706 uint32_t msgid;
1707 size_t i;
1708 void (*f)(struct osmtpd_ctx *, uint32_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] != '\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);
1723 if ((f = cb->cb) != NULL)
1724 f(ctx, msgid);
1726 if (ondeletecb_message != NULL) {
1727 ondeletecb_message(ctx, ctx->local_message);
1728 ctx->local_message = NULL;
1731 free(ctx->mailfrom);
1732 ctx->mailfrom = NULL;
1734 for (i = 0; ctx->rcptto[i] != NULL; i++)
1735 free(ctx->rcptto[i]);
1736 ctx->rcptto[0] = NULL;
1737 ctx->evpid = 0;
1738 ctx->msgid = 0;
1741 void
1742 osmtpd_filter_proceed(struct osmtpd_ctx *ctx)
1744 if (ctx->version_major == 0 && ctx->version_minor < 5)
1745 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1746 "proceed\n", ctx->token, ctx->reqid);
1747 else
1748 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1749 "proceed\n", ctx->reqid, ctx->token);
1752 void
1753 osmtpd_filter_reject(struct osmtpd_ctx *ctx, int code, const char *reason, ...)
1755 va_list ap;
1757 if (code < 200 || code > 599)
1758 osmtpd_errx(1, "Invalid reject code");
1760 if (ctx->version_major == 0 && ctx->version_minor < 5)
1761 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1762 "reject|%d ", ctx->token, ctx->reqid, code);
1763 else
1764 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1765 "reject|%d ", ctx->reqid, ctx->token, code);
1766 va_start(ap, reason);
1767 io_vprintf(io_stdout, reason, ap);
1768 va_end(ap);
1769 io_printf(io_stdout, "\n");
1772 void
1773 osmtpd_filter_reject_enh(struct osmtpd_ctx *ctx, int code, int class,
1774 int subject, int detail, const char *reason, ...)
1776 va_list ap;
1778 if (code < 200 || code > 599)
1779 osmtpd_errx(1, "Invalid reject code");
1780 if (class < 2 || class > 5)
1781 osmtpd_errx(1, "Invalid enhanced status class");
1782 if (subject < 0 || subject > 999)
1783 osmtpd_errx(1, "Invalid enhanced status subject");
1784 if (detail < 0 || detail > 999)
1785 osmtpd_errx(1, "Invalid enhanced status detail");
1787 if (ctx->version_major == 0 && ctx->version_minor < 5)
1788 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1789 "reject|%d %d.%d.%d ", ctx->token, ctx->reqid, code, class,
1790 subject, detail);
1791 else
1792 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1793 "reject|%d %d.%d.%d ", ctx->reqid, ctx->token, code, class,
1794 subject, detail);
1795 va_start(ap, reason);
1796 io_vprintf(io_stdout, reason, ap);
1797 va_end(ap);
1798 io_printf(io_stdout, "\n");
1801 void
1802 osmtpd_filter_disconnect(struct osmtpd_ctx *ctx, const char *reason, ...)
1804 va_list ap;
1806 if (ctx->version_major == 0 && ctx->version_minor < 5)
1807 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1808 "disconnect|421 ", ctx->token, ctx->reqid);
1809 else
1810 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1811 "disconnect|421 ", ctx->reqid, ctx->token);
1812 va_start(ap, reason);
1813 io_vprintf(io_stdout, reason, ap);
1814 va_end(ap);
1815 io_printf(io_stdout, "\n");
1818 void
1819 osmtpd_filter_disconnect_enh(struct osmtpd_ctx *ctx, int class, int subject,
1820 int detail, const char *reason, ...)
1822 va_list ap;
1824 if (class <= 2 || class >= 5)
1825 osmtpd_errx(1, "Invalid enhanced status class");
1826 if (subject < 0 || subject > 999)
1827 osmtpd_errx(1, "Invalid enhanced status subject");
1828 if (detail < 0 || detail > 999)
1829 osmtpd_errx(1, "Invalid enhanced status detail");
1830 if (ctx->version_major == 0 && ctx->version_minor < 5)
1831 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1832 "disconnect|421 %d.%d.%d ", ctx->token, ctx->reqid, class,
1833 subject, detail);
1834 else
1835 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1836 "disconnect|421 %d.%d.%d ", ctx->reqid, ctx->token, class,
1837 subject, detail);
1838 va_start(ap, reason);
1839 io_vprintf(io_stdout, reason, ap);
1840 va_end(ap);
1841 io_printf(io_stdout, "\n");
1844 void
1845 osmtpd_filter_rewrite(struct osmtpd_ctx *ctx, const char *value, ...)
1847 va_list ap;
1849 if (ctx->version_major == 0 && ctx->version_minor < 5)
1850 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1851 "rewrite|", ctx->token, ctx->reqid);
1852 else
1853 io_printf(io_stdout, "filter-result|%016"PRIx64"|%016"PRIx64"|"
1854 "rewrite|", ctx->reqid, ctx->token);
1855 va_start(ap, value);
1856 io_vprintf(io_stdout, value, ap);
1857 va_end(ap);
1858 io_printf(io_stdout, "\n");
1861 void
1862 osmtpd_filter_dataline(struct osmtpd_ctx *ctx, const char *line, ...)
1864 va_list ap;
1866 if (ctx->version_major == 0 && ctx->version_minor < 5)
1867 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1868 ctx->token, ctx->reqid);
1869 else
1870 io_printf(io_stdout, "filter-dataline|%016"PRIx64"|%016"PRIx64"|",
1871 ctx->reqid, ctx->token);
1872 va_start(ap, line);
1873 io_vprintf(io_stdout, line, ap);
1874 va_end(ap);
1875 io_printf(io_stdout, "\n");
1878 static void
1879 osmtpd_register(enum osmtpd_type type, enum osmtpd_phase phase, int incoming,
1880 int storereport, void *cb)
1882 size_t i;
1884 if (ready)
1885 osmtpd_errx(1, "Can't register when proc is running");
1887 for (i = 0; i < NITEMS(osmtpd_callbacks); i++) {
1888 if (type == osmtpd_callbacks[i].type &&
1889 phase == osmtpd_callbacks[i].phase &&
1890 incoming == osmtpd_callbacks[i].incoming) {
1891 if (osmtpd_callbacks[i].cb != NULL && cb != NULL)
1892 osmtpd_errx(1, "Event already registered");
1893 if (cb != NULL)
1894 osmtpd_callbacks[i].cb = cb;
1895 osmtpd_callbacks[i].doregister = 1;
1896 if (storereport)
1897 osmtpd_callbacks[i].storereport = 1;
1898 return;
1901 /* NOT REACHED */
1902 osmtpd_errx(1, "Trying to register unknown event");
1905 static enum osmtpd_phase
1906 osmtpd_strtophase(const char *phase, const char *linedup)
1908 if (strcmp(phase, "connect") == 0)
1909 return OSMTPD_PHASE_CONNECT;
1910 if (strcmp(phase, "helo") == 0)
1911 return OSMTPD_PHASE_HELO;
1912 if (strcmp(phase, "ehlo") == 0)
1913 return OSMTPD_PHASE_EHLO;
1914 if (strcmp(phase, "starttls") == 0)
1915 return OSMTPD_PHASE_STARTTLS;
1916 if (strcmp(phase, "auth") == 0)
1917 return OSMTPD_PHASE_AUTH;
1918 if (strcmp(phase, "mail-from") == 0)
1919 return OSMTPD_PHASE_MAIL_FROM;
1920 if (strcmp(phase, "rcpt-to") == 0)
1921 return OSMTPD_PHASE_RCPT_TO;
1922 if (strcmp(phase, "data") == 0)
1923 return OSMTPD_PHASE_DATA;
1924 if (strcmp(phase, "data-line") == 0)
1925 return OSMTPD_PHASE_DATA_LINE;
1926 if (strcmp(phase, "rset") == 0)
1927 return OSMTPD_PHASE_RSET;
1928 if (strcmp(phase, "quit") == 0)
1929 return OSMTPD_PHASE_QUIT;
1930 if (strcmp(phase, "noop") == 0)
1931 return OSMTPD_PHASE_NOOP;
1932 if (strcmp(phase, "help") == 0)
1933 return OSMTPD_PHASE_HELP;
1934 if (strcmp(phase, "wiz") == 0)
1935 return OSMTPD_PHASE_WIZ;
1936 if (strcmp(phase, "commit") == 0)
1937 return OSMTPD_PHASE_COMMIT;
1938 if (strcmp(phase, "link-connect") == 0)
1939 return OSMTPD_PHASE_LINK_CONNECT;
1940 if (strcmp(phase, "link-disconnect") == 0)
1941 return OSMTPD_PHASE_LINK_DISCONNECT;
1942 if (strcmp(phase, "link-greeting") == 0)
1943 return OSMTPD_PHASE_LINK_GREETING;
1944 if (strcmp(phase, "link-identify") == 0)
1945 return OSMTPD_PHASE_LINK_IDENTIFY;
1946 if (strcmp(phase, "link-tls") == 0)
1947 return OSMTPD_PHASE_LINK_TLS;
1948 if (strcmp(phase, "link-auth") == 0)
1949 return OSMTPD_PHASE_LINK_AUTH;
1950 if (strcmp(phase, "tx-begin") == 0)
1951 return OSMTPD_PHASE_TX_BEGIN;
1952 if (strcmp(phase, "tx-mail") == 0)
1953 return OSMTPD_PHASE_TX_MAIL;
1954 if (strcmp(phase, "tx-rcpt") == 0)
1955 return OSMTPD_PHASE_TX_RCPT;
1956 if (strcmp(phase, "tx-envelope") == 0)
1957 return OSMTPD_PHASE_TX_ENVELOPE;
1958 if (strcmp(phase, "tx-data") == 0)
1959 return OSMTPD_PHASE_TX_DATA;
1960 if (strcmp(phase, "tx-commit") == 0)
1961 return OSMTPD_PHASE_TX_COMMIT;
1962 if (strcmp(phase, "tx-rollback") == 0)
1963 return OSMTPD_PHASE_TX_ROLLBACK;
1964 if (strcmp(phase, "protocol-client") == 0)
1965 return OSMTPD_PHASE_PROTOCOL_CLIENT;
1966 if (strcmp(phase, "protocol-server") == 0)
1967 return OSMTPD_PHASE_PROTOCOL_SERVER;
1968 if (strcmp(phase, "filter-response") == 0)
1969 return OSMTPD_PHASE_FILTER_RESPONSE;
1970 if (strcmp(phase, "timeout") == 0)
1971 return OSMTPD_PHASE_TIMEOUT;
1972 osmtpd_errx(1, "Invalid line received: invalid phase: %s", linedup);
1975 static const char *
1976 osmtpd_typetostr(enum osmtpd_type type)
1978 switch (type) {
1979 case OSMTPD_TYPE_FILTER:
1980 return "filter";
1981 case OSMTPD_TYPE_REPORT:
1982 return "report";
1984 osmtpd_errx(1, "In valid type: %d\n", type);
1987 static const char *
1988 osmtpd_phasetostr(enum osmtpd_phase phase)
1990 switch (phase) {
1991 case OSMTPD_PHASE_CONNECT:
1992 return "connect";
1993 case OSMTPD_PHASE_HELO:
1994 return "helo";
1995 case OSMTPD_PHASE_EHLO:
1996 return "ehlo";
1997 case OSMTPD_PHASE_STARTTLS:
1998 return "starttls";
1999 case OSMTPD_PHASE_AUTH:
2000 return "auth";
2001 case OSMTPD_PHASE_MAIL_FROM:
2002 return "mail-from";
2003 case OSMTPD_PHASE_RCPT_TO:
2004 return "rcpt-to";
2005 case OSMTPD_PHASE_DATA:
2006 return "data";
2007 case OSMTPD_PHASE_DATA_LINE:
2008 return "data-line";
2009 case OSMTPD_PHASE_RSET:
2010 return "rset";
2011 case OSMTPD_PHASE_QUIT:
2012 return "quit";
2013 case OSMTPD_PHASE_NOOP:
2014 return "noop";
2015 case OSMTPD_PHASE_HELP:
2016 return "help";
2017 case OSMTPD_PHASE_WIZ:
2018 return "wiz";
2019 case OSMTPD_PHASE_COMMIT:
2020 return "commit";
2021 case OSMTPD_PHASE_LINK_CONNECT:
2022 return "link-connect";
2023 case OSMTPD_PHASE_LINK_DISCONNECT:
2024 return "link-disconnect";
2025 case OSMTPD_PHASE_LINK_GREETING:
2026 return "link-greeting";
2027 case OSMTPD_PHASE_LINK_IDENTIFY:
2028 return "link-identify";
2029 case OSMTPD_PHASE_LINK_TLS:
2030 return "link-tls";
2031 case OSMTPD_PHASE_LINK_AUTH:
2032 return "link-auth";
2033 case OSMTPD_PHASE_TX_BEGIN:
2034 return "tx-begin";
2035 case OSMTPD_PHASE_TX_MAIL:
2036 return "tx-mail";
2037 case OSMTPD_PHASE_TX_RCPT:
2038 return "tx-rcpt";
2039 case OSMTPD_PHASE_TX_ENVELOPE:
2040 return "tx-envelope";
2041 case OSMTPD_PHASE_TX_DATA:
2042 return "tx-data";
2043 case OSMTPD_PHASE_TX_COMMIT:
2044 return "tx-commit";
2045 case OSMTPD_PHASE_TX_ROLLBACK:
2046 return "tx-rollback";
2047 case OSMTPD_PHASE_PROTOCOL_CLIENT:
2048 return "protocol-client";
2049 case OSMTPD_PHASE_PROTOCOL_SERVER:
2050 return "protocol-server";
2051 case OSMTPD_PHASE_FILTER_RESPONSE:
2052 return "filter-response";
2053 case OSMTPD_PHASE_TIMEOUT:
2054 return "timeout";
2056 osmtpd_errx(1, "In valid phase: %d\n", phase);
2059 static enum osmtpd_status
2060 osmtpd_strtostatus(const char *status, char *linedup)
2062 if (strcmp(status, "ok") == 0)
2063 return OSMTPD_STATUS_OK;
2064 else if (strcmp(status, "tempfail") == 0)
2065 return OSMTPD_STATUS_TEMPFAIL;
2066 else if (strcmp(status, "permfail") == 0)
2067 return OSMTPD_STATUS_PERMFAIL;
2068 osmtpd_errx(1, "Invalid line received: invalid status: %s\n", linedup);
2071 static void
2072 osmtpd_addrtoss(char *addr, struct sockaddr_storage *ss, int hasport,
2073 char *linedup)
2075 char *port = NULL;
2076 const char *errstr = NULL;
2077 struct sockaddr_in *sin;
2078 struct sockaddr_in6 *sin6;
2079 struct sockaddr_un *sun;
2080 size_t n;
2082 if (addr[0] == '[') {
2083 sin6 = (struct sockaddr_in6 *)ss;
2084 sin6->sin6_family = AF_INET6;
2085 sin6->sin6_port = 0;
2086 if (hasport) {
2087 if ((port = strrchr(addr, ':')) == NULL)
2088 osmtpd_errx(1, "Invalid line received: invalid "
2089 "address (%s): %s", addr, linedup);
2090 if (port[-1] != ']')
2091 osmtpd_errx(1, "Invalid line received: invalid "
2092 "address (%s): %s", addr, linedup);
2093 port++;
2094 sin6->sin6_port = htons(strtonum(port, 0, UINT16_MAX,
2095 &errstr));
2096 if (errstr != NULL)
2097 osmtpd_errx(1, "Invalid line received: invalid "
2098 "address (%s): %s", addr, linedup);
2099 port[-2] = '\0';
2100 } else {
2101 n = strlen(addr);
2102 if (addr[n - 1] != ']')
2103 osmtpd_errx(1, "Invalid line received: invalid "
2104 "address (%s): %s", addr, linedup);
2105 addr[n - 1] = '\0';
2107 switch (inet_pton(AF_INET6, addr + 1, &(sin6->sin6_addr))) {
2108 case 1:
2109 break;
2110 case 0:
2111 if (hasport)
2112 port[-2] = ']';
2113 else
2114 addr[n - 1] = ']';
2115 osmtpd_errx(1, "Invalid line received: invalid address "
2116 "(%s): %s", addr, linedup);
2117 default:
2118 if (hasport)
2119 port[-2] = ']';
2120 else
2121 addr[n - 1] = ']';
2122 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2123 linedup);
2125 } else if (strncasecmp(addr, "unix:", 5) == 0) {
2126 sun = (struct sockaddr_un *)ss;
2127 sun->sun_family = AF_UNIX;
2128 if (strlcpy(sun->sun_path, addr,
2129 sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) {
2130 osmtpd_errx(1, "Invalid line received: address too "
2131 "long (%s): %s", addr, linedup);
2133 } else {
2134 sin = (struct sockaddr_in *)ss;
2135 sin->sin_family = AF_INET;
2136 sin->sin_port = 0;
2137 if (hasport) {
2138 if ((port = strrchr(addr, ':')) == NULL)
2139 osmtpd_errx(1, "Invalid line received: invalid "
2140 "address (%s): %s", addr, linedup);
2141 port++;
2142 sin->sin_port = htons(strtonum(port, 0, UINT16_MAX,
2143 &errstr));
2144 if (errstr != NULL)
2145 osmtpd_errx(1, "Invalid line received: invalid "
2146 "address (%s): %s", addr, linedup);
2147 port[-1] = '\0';
2149 switch (inet_pton(AF_INET, addr, &(sin->sin_addr))) {
2150 case 1:
2151 break;
2152 case 0:
2153 if (hasport)
2154 port[-1] = ':';
2155 osmtpd_errx(1, "Invalid line received: invalid address "
2156 "(%s): %s", addr, linedup);
2157 default:
2158 if (hasport)
2159 port[-1] = ':';
2160 osmtpd_err(1, "Can't parse address (%s): %s", addr,
2161 linedup);
2166 static int
2167 osmtpd_session_cmp(struct osmtpd_session *a, struct osmtpd_session *b)
2169 return a->ctx.reqid < b->ctx.reqid ? -1 : a->ctx.reqid > b->ctx.reqid;
2172 RB_GENERATE_STATIC(osmtpd_sessions, osmtpd_session, entry, osmtpd_session_cmp);