1 a248a3c1 2019-03-27 martijn #include <sys/time.h>
2 a248a3c1 2019-03-27 martijn #include <sys/socket.h>
4 a248a3c1 2019-03-27 martijn #include <arpa/inet.h>
5 a248a3c1 2019-03-27 martijn #include <err.h>
6 a248a3c1 2019-03-27 martijn #include <errno.h>
7 a248a3c1 2019-03-27 martijn #include <inttypes.h>
8 a248a3c1 2019-03-27 martijn #include <stdio.h>
9 a248a3c1 2019-03-27 martijn #include <stdlib.h>
10 a248a3c1 2019-03-27 martijn #include <string.h>
12 a248a3c1 2019-03-27 martijn #include "smtp_proc.h"
14 a248a3c1 2019-03-27 martijn #define NITEMS(x) (sizeof(x) / sizeof(*x))
16 a248a3c1 2019-03-27 martijn typedef int (*smtp_cb)(char *, int, time_t, char *, char *, uint64_t, uint64_t,
19 a248a3c1 2019-03-27 martijn struct smtp_callback;
21 a248a3c1 2019-03-27 martijn static int smtp_register(char *, char *, char *, smtp_cb);
22 a248a3c1 2019-03-27 martijn static void smtp_connect(struct smtp_callback *, int, time_t, uint64_t,
23 a248a3c1 2019-03-27 martijn uint64_t, char *);
24 a248a3c1 2019-03-27 martijn static void smtp_data(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
26 a248a3c1 2019-03-27 martijn static void smtp_data_line(struct smtp_callback *, int, time_t, uint64_t,
27 a248a3c1 2019-03-27 martijn uint64_t, char *);
28 a248a3c1 2019-03-27 martijn static void smtp_rset(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
30 a248a3c1 2019-03-27 martijn static void smtp_quit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
32 a248a3c1 2019-03-27 martijn static void smtp_noop(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
34 a248a3c1 2019-03-27 martijn static void smtp_help(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
36 a248a3c1 2019-03-27 martijn static void smtp_wiz(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
38 a248a3c1 2019-03-27 martijn static void smtp_commit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
40 a248a3c1 2019-03-27 martijn static void smtp_handle(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
43 a248a3c1 2019-03-27 martijn struct smtp_callback {
44 a248a3c1 2019-03-27 martijn char *type;
45 a248a3c1 2019-03-27 martijn char *phase;
46 a248a3c1 2019-03-27 martijn char *direction;
47 a248a3c1 2019-03-27 martijn void (*smtp_parse)(struct smtp_callback *, int, time_t, uint64_t,
48 a248a3c1 2019-03-27 martijn uint64_t, char *);
49 a248a3c1 2019-03-27 martijn smtp_cb cb;
50 a248a3c1 2019-03-27 martijn } smtp_callbacks[] = {
51 a248a3c1 2019-03-27 martijn {"filter", "connect", "smtp-in", smtp_connect, NULL},
52 a248a3c1 2019-03-27 martijn {"filter", "data", "smtp-in", smtp_data, NULL},
53 a248a3c1 2019-03-27 martijn {"filter", "data-line", "smtp-in", smtp_data_line, NULL},
54 a248a3c1 2019-03-27 martijn {"filter", "rset", "smtp-in", smtp_rset, NULL},
55 a248a3c1 2019-03-27 martijn {"filter", "quit", "smtp-in", smtp_quit, NULL},
56 a248a3c1 2019-03-27 martijn {"filter", "noop", "smtp-in", smtp_noop, NULL},
57 a248a3c1 2019-03-27 martijn {"filter", "help", "smtp-in", smtp_help, NULL},
58 a248a3c1 2019-03-27 martijn {"filter", "wiz", "smtp-in", smtp_wiz, NULL},
59 a248a3c1 2019-03-27 martijn {"filter", "commit", "smtp-in", smtp_commit, NULL}
62 a248a3c1 2019-03-27 martijn static int ready = 0;
65 a248a3c1 2019-03-27 martijn smtp_register_filter_connect(enum filter_decision (*cb)(char *, int, time_t,
66 a248a3c1 2019-03-27 martijn char *, char *, uint64_t, uint64_t, struct smtp_filter_connect *))
68 a248a3c1 2019-03-27 martijn return smtp_register("filter", "connect", "smtp-in", (smtp_cb) cb);
72 a248a3c1 2019-03-27 martijn smtp_run(void)
74 a248a3c1 2019-03-27 martijn char *line = NULL;
75 a248a3c1 2019-03-27 martijn size_t linesize = 0;
76 a248a3c1 2019-03-27 martijn ssize_t linelen;
77 a248a3c1 2019-03-27 martijn char *start, *end, *type, *direction, *phase, *params;
78 a248a3c1 2019-03-27 martijn int version;
79 a248a3c1 2019-03-27 martijn time_t tm;
80 a248a3c1 2019-03-27 martijn uint64_t reqid, token;
83 a248a3c1 2019-03-27 martijn printf("register|ready\n");
84 a248a3c1 2019-03-27 martijn ready = 1;
86 a248a3c1 2019-03-27 martijn while ((linelen = getline(&line, &linesize, stdin)) != -1) {
87 a248a3c1 2019-03-27 martijn if (line[linelen - 1] != '\n')
88 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing newline");
89 a248a3c1 2019-03-27 martijn line[linelen - 1] = '\0';
90 a248a3c1 2019-03-27 martijn type = line;
91 a248a3c1 2019-03-27 martijn if ((start = strchr(type, '|')) == NULL)
92 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing version");
93 a248a3c1 2019-03-27 martijn start++[0] = '\0';
94 a248a3c1 2019-03-27 martijn if ((end = strchr(start, '|')) == NULL)
95 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing time");
96 a248a3c1 2019-03-27 martijn end++[0] = '\0';
97 a248a3c1 2019-03-27 martijn if (strcmp(start, "1") != 0)
98 a248a3c1 2019-03-27 martijn errx(1, "Unsupported protocol received: %s", start);
99 a248a3c1 2019-03-27 martijn version = 1;
100 a248a3c1 2019-03-27 martijn start = end;
101 a248a3c1 2019-03-27 martijn if ((direction = strchr(start, '|')) == NULL)
102 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing direction");
103 a248a3c1 2019-03-27 martijn direction++[0] = '\0';
104 a248a3c1 2019-03-27 martijn tm = (time_t) strtoull(start, &end, 10);
105 a248a3c1 2019-03-27 martijn if (start[0] == '\0' || end[0] != '\0')
106 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: invalid timestamp");
107 a248a3c1 2019-03-27 martijn if ((phase = strchr(direction, '|')) == NULL)
108 a248a3c1 2019-03-27 martijn errx(1, "Invalid line receieved: missing phase");
109 a248a3c1 2019-03-27 martijn phase++[0] = '\0';
110 a248a3c1 2019-03-27 martijn if ((start = strchr(phase, '|')) == NULL)
111 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing reqid");
112 a248a3c1 2019-03-27 martijn start++[0] = '\0';
113 a248a3c1 2019-03-27 martijn reqid = strtoull(start, &end, 16);
114 a248a3c1 2019-03-27 martijn if (start[0] == '|' || end[0] != '|')
115 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: invalid reqid");
116 a248a3c1 2019-03-27 martijn end++[0] = '\0';
117 a248a3c1 2019-03-27 martijn start = end;
118 a248a3c1 2019-03-27 martijn token = strtoull(start, &end, 16);
119 a248a3c1 2019-03-27 martijn if (start[0] == '|' || end[0] != '|')
120 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: invalid token");
121 a248a3c1 2019-03-27 martijn params = end + 1;
123 a248a3c1 2019-03-27 martijn for (i = 0; i < NITEMS(smtp_callbacks); i++) {
124 a248a3c1 2019-03-27 martijn if (strcmp(type, smtp_callbacks[i].type) == 0 &&
125 a248a3c1 2019-03-27 martijn strcmp(phase, smtp_callbacks[i].phase) == 0 &&
126 a248a3c1 2019-03-27 martijn strcmp(direction, smtp_callbacks[i].direction) == 0)
129 a248a3c1 2019-03-27 martijn if (i == NITEMS(smtp_callbacks)) {
130 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: received unregistered "
131 a248a3c1 2019-03-27 martijn "%s: %s", type, phase);
133 a248a3c1 2019-03-27 martijn smtp_callbacks[i].smtp_parse(&(smtp_callbacks[i]), version, tm,
134 a248a3c1 2019-03-27 martijn reqid, token, params);
138 a248a3c1 2019-03-27 martijn static void
139 a248a3c1 2019-03-27 martijn smtp_connect(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
140 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
142 a248a3c1 2019-03-27 martijn struct smtp_filter_connect sfconnect;
143 a248a3c1 2019-03-27 martijn char *address;
144 a248a3c1 2019-03-27 martijn int ret;
146 a248a3c1 2019-03-27 martijn sfconnect.hostname = params;
147 a248a3c1 2019-03-27 martijn if ((address = strchr(params, '|')) == NULL)
148 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: missing address");
149 a248a3c1 2019-03-27 martijn address++[0] = '\0';
151 a248a3c1 2019-03-27 martijn sfconnect.af = AF_INET;
152 a248a3c1 2019-03-27 martijn if (strncasecmp(address, "ipv6:", 5) == 0) {
153 a248a3c1 2019-03-27 martijn sfconnect.af = AF_INET6;
154 a248a3c1 2019-03-27 martijn address += 5;
157 a248a3c1 2019-03-27 martijn ret = inet_pton(sfconnect.af, address, sfconnect.af == AF_INET ?
158 a248a3c1 2019-03-27 martijn (void *)&(sfconnect.addr) : (void *)&(sfconnect.addr6));
159 a248a3c1 2019-03-27 martijn if (ret == 0)
160 a248a3c1 2019-03-27 martijn errx(1, "Invalid line received: Couldn't parse address");
161 a248a3c1 2019-03-27 martijn if (ret == -1)
162 a248a3c1 2019-03-27 martijn err(1, "Couldn't convert address");
164 a248a3c1 2019-03-27 martijn smtp_handle(cb, version, tm, reqid, token, (void *)(&sfconnect));
167 a248a3c1 2019-03-27 martijn static void
168 a248a3c1 2019-03-27 martijn smtp_data(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
169 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
173 a248a3c1 2019-03-27 martijn static void
174 a248a3c1 2019-03-27 martijn smtp_data_line(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
175 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
179 a248a3c1 2019-03-27 martijn static void
180 a248a3c1 2019-03-27 martijn smtp_rset(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
181 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
185 a248a3c1 2019-03-27 martijn static void
186 a248a3c1 2019-03-27 martijn smtp_quit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
187 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
191 a248a3c1 2019-03-27 martijn static void
192 a248a3c1 2019-03-27 martijn smtp_noop(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
193 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
197 a248a3c1 2019-03-27 martijn static void
198 a248a3c1 2019-03-27 martijn smtp_help(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
199 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
203 a248a3c1 2019-03-27 martijn static void
204 a248a3c1 2019-03-27 martijn smtp_wiz(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
205 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
209 a248a3c1 2019-03-27 martijn static void
210 a248a3c1 2019-03-27 martijn smtp_commit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
211 a248a3c1 2019-03-27 martijn uint64_t token, char *params)
215 a248a3c1 2019-03-27 martijn static void
216 a248a3c1 2019-03-27 martijn smtp_handle(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
217 a248a3c1 2019-03-27 martijn uint64_t token, void *params)
219 a248a3c1 2019-03-27 martijn int ret;
221 a248a3c1 2019-03-27 martijn switch (cb->cb(cb->type, version, tm, cb->direction, cb->phase, reqid,
222 a248a3c1 2019-03-27 martijn token, params)) {
223 a248a3c1 2019-03-27 martijn case FILTER_PROCEED:
224 a248a3c1 2019-03-27 martijn printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n",
225 a248a3c1 2019-03-27 martijn token, reqid);
227 a248a3c1 2019-03-27 martijn case FILTER_REJECT:
228 a248a3c1 2019-03-27 martijn printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%s\n",
229 a248a3c1 2019-03-27 martijn token, reqid, "451 Proper message later");
231 a248a3c1 2019-03-27 martijn case FILTER_DISCONNECT:
232 a248a3c1 2019-03-27 martijn printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|"
233 a248a3c1 2019-03-27 martijn "%s\n", token, reqid, "421 Proper message later");
235 a248a3c1 2019-03-27 martijn case FILTER_REWRITE:
236 a248a3c1 2019-03-27 martijn errx(1, "Not sure what is intended here yet");
240 a248a3c1 2019-03-27 martijn static int
241 a248a3c1 2019-03-27 martijn smtp_register(char *type, char *phase, char *direction, smtp_cb cb)
245 a248a3c1 2019-03-27 martijn if (ready) {
246 a248a3c1 2019-03-27 martijn errx(1, "Can't register when proc is running");
248 a248a3c1 2019-03-27 martijn for (i = 0; i < NITEMS(smtp_callbacks); i++) {
249 a248a3c1 2019-03-27 martijn if (strcmp(type, smtp_callbacks[i].type) == 0 &&
250 a248a3c1 2019-03-27 martijn strcmp(phase, smtp_callbacks[i].phase) == 0 &&
251 a248a3c1 2019-03-27 martijn strcmp(direction, smtp_callbacks[i].direction) == 0) {
252 a248a3c1 2019-03-27 martijn if (smtp_callbacks[i].cb != NULL) {
253 a248a3c1 2019-03-27 martijn errno = EALREADY;
254 a248a3c1 2019-03-27 martijn return -1;
256 a248a3c1 2019-03-27 martijn smtp_callbacks[i].cb = cb;
257 a248a3c1 2019-03-27 martijn printf("register|%s|%s|%s\n", type, direction, phase);
258 a248a3c1 2019-03-27 martijn return 0;
261 a248a3c1 2019-03-27 martijn errno = EINVAL;
262 a248a3c1 2019-03-27 martijn return -1;
266 a248a3c1 2019-03-27 martijn //filter|1|1553668146|smtp-in|connect|478cc771bf86f378|5161a9ce4540b4d1|<unknown>|100.64.7.2