1 | /* |
---|
2 | * Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers. |
---|
3 | * All rights reserved. |
---|
4 | * |
---|
5 | * By using this file, you agree to the terms and conditions set |
---|
6 | * forth in the LICENSE file which can be found at the top level of |
---|
7 | * the sendmail distribution. |
---|
8 | * |
---|
9 | */ |
---|
10 | |
---|
11 | #include <sendmail.h> |
---|
12 | |
---|
13 | SM_RCSID("@(#)$Id: milter.c,v 1.1.1.1 2003-04-08 15:09:16 zacheiss Exp $") |
---|
14 | |
---|
15 | #if MILTER |
---|
16 | # include <libmilter/mfapi.h> |
---|
17 | # include <libmilter/mfdef.h> |
---|
18 | |
---|
19 | # include <errno.h> |
---|
20 | # include <sys/time.h> |
---|
21 | |
---|
22 | # if NETINET || NETINET6 |
---|
23 | # include <arpa/inet.h> |
---|
24 | # endif /* NETINET || NETINET6 */ |
---|
25 | |
---|
26 | # include <sm/fdset.h> |
---|
27 | |
---|
28 | static void milter_connect_timeout __P((void)); |
---|
29 | static void milter_error __P((struct milter *, ENVELOPE *)); |
---|
30 | static int milter_open __P((struct milter *, bool, ENVELOPE *)); |
---|
31 | static void milter_parse_timeouts __P((char *, struct milter *)); |
---|
32 | |
---|
33 | static char *MilterConnectMacros[MAXFILTERMACROS + 1]; |
---|
34 | static char *MilterHeloMacros[MAXFILTERMACROS + 1]; |
---|
35 | static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; |
---|
36 | static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; |
---|
37 | |
---|
38 | # define MILTER_CHECK_DONE_MSG() \ |
---|
39 | if (*state == SMFIR_REPLYCODE || \ |
---|
40 | *state == SMFIR_REJECT || \ |
---|
41 | *state == SMFIR_DISCARD || \ |
---|
42 | *state == SMFIR_TEMPFAIL) \ |
---|
43 | { \ |
---|
44 | /* Abort the filters to let them know we are done with msg */ \ |
---|
45 | milter_abort(e); \ |
---|
46 | } |
---|
47 | |
---|
48 | # if _FFR_QUARANTINE |
---|
49 | # define MILTER_CHECK_ERROR(initial, action) \ |
---|
50 | if (!initial && tTd(71, 100)) \ |
---|
51 | { \ |
---|
52 | if (e->e_quarmsg == NULL) \ |
---|
53 | { \ |
---|
54 | e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ |
---|
55 | "filter failure"); \ |
---|
56 | macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ |
---|
57 | e->e_quarmsg); \ |
---|
58 | } \ |
---|
59 | } \ |
---|
60 | else if (tTd(71, 101)) \ |
---|
61 | { \ |
---|
62 | if (e->e_quarmsg == NULL) \ |
---|
63 | { \ |
---|
64 | e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ |
---|
65 | "filter failure"); \ |
---|
66 | macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ |
---|
67 | e->e_quarmsg); \ |
---|
68 | } \ |
---|
69 | } \ |
---|
70 | else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ |
---|
71 | *state = SMFIR_TEMPFAIL; \ |
---|
72 | else if (bitnset(SMF_REJECT, m->mf_flags)) \ |
---|
73 | *state = SMFIR_REJECT; \ |
---|
74 | else \ |
---|
75 | action; |
---|
76 | # else /* _FFR_QUARANTINE */ |
---|
77 | # define MILTER_CHECK_ERROR(initial, action) \ |
---|
78 | if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ |
---|
79 | *state = SMFIR_TEMPFAIL; \ |
---|
80 | else if (bitnset(SMF_REJECT, m->mf_flags)) \ |
---|
81 | *state = SMFIR_REJECT; \ |
---|
82 | else \ |
---|
83 | action; |
---|
84 | # endif /* _FFR_QUARANTINE */ |
---|
85 | |
---|
86 | # define MILTER_CHECK_REPLYCODE(default) \ |
---|
87 | if (response == NULL || \ |
---|
88 | strlen(response) + 1 != (size_t) rlen || \ |
---|
89 | rlen < 3 || \ |
---|
90 | (response[0] != '4' && response[0] != '5') || \ |
---|
91 | !isascii(response[1]) || !isdigit(response[1]) || \ |
---|
92 | !isascii(response[2]) || !isdigit(response[2])) \ |
---|
93 | { \ |
---|
94 | if (response != NULL) \ |
---|
95 | sm_free(response); /* XXX */ \ |
---|
96 | response = newstr(default); \ |
---|
97 | } \ |
---|
98 | else \ |
---|
99 | { \ |
---|
100 | char *ptr = response; \ |
---|
101 | \ |
---|
102 | /* Check for unprotected %'s in the string */ \ |
---|
103 | while (*ptr != '\0') \ |
---|
104 | { \ |
---|
105 | if (*ptr == '%' && *++ptr != '%') \ |
---|
106 | { \ |
---|
107 | sm_free(response); /* XXX */ \ |
---|
108 | response = newstr(default); \ |
---|
109 | break; \ |
---|
110 | } \ |
---|
111 | ptr++; \ |
---|
112 | } \ |
---|
113 | } |
---|
114 | |
---|
115 | # define MILTER_DF_ERROR(msg) \ |
---|
116 | { \ |
---|
117 | int save_errno = errno; \ |
---|
118 | \ |
---|
119 | if (tTd(64, 5)) \ |
---|
120 | { \ |
---|
121 | sm_dprintf(msg, dfname, sm_errstring(save_errno)); \ |
---|
122 | sm_dprintf("\n"); \ |
---|
123 | } \ |
---|
124 | if (MilterLogLevel > 0) \ |
---|
125 | sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \ |
---|
126 | if (SuperSafe == SAFE_REALLY) \ |
---|
127 | { \ |
---|
128 | if (e->e_dfp != NULL) \ |
---|
129 | { \ |
---|
130 | (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \ |
---|
131 | e->e_dfp = NULL; \ |
---|
132 | } \ |
---|
133 | e->e_flags &= ~EF_HAS_DF; \ |
---|
134 | } \ |
---|
135 | errno = save_errno; \ |
---|
136 | } |
---|
137 | |
---|
138 | /* |
---|
139 | ** MILTER_TIMEOUT -- make sure socket is ready in time |
---|
140 | ** |
---|
141 | ** Parameters: |
---|
142 | ** routine -- routine name for debug/logging |
---|
143 | ** secs -- number of seconds in timeout |
---|
144 | ** write -- waiting to read or write? |
---|
145 | ** started -- whether this is part of a previous sequence |
---|
146 | ** |
---|
147 | ** Assumes 'm' is a milter structure for the current socket. |
---|
148 | */ |
---|
149 | |
---|
150 | # define MILTER_TIMEOUT(routine, secs, write, started) \ |
---|
151 | { \ |
---|
152 | int ret; \ |
---|
153 | int save_errno; \ |
---|
154 | fd_set fds; \ |
---|
155 | struct timeval tv; \ |
---|
156 | \ |
---|
157 | if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \ |
---|
158 | { \ |
---|
159 | if (tTd(64, 5)) \ |
---|
160 | sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ |
---|
161 | (routine), m->mf_name, m->mf_sock, \ |
---|
162 | SM_FD_SETSIZE); \ |
---|
163 | if (MilterLogLevel > 0) \ |
---|
164 | sm_syslog(LOG_ERR, e->e_id, \ |
---|
165 | "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \ |
---|
166 | m->mf_name, (routine), m->mf_sock, \ |
---|
167 | SM_FD_SETSIZE); \ |
---|
168 | milter_error(m, e); \ |
---|
169 | return NULL; \ |
---|
170 | } \ |
---|
171 | \ |
---|
172 | do \ |
---|
173 | { \ |
---|
174 | FD_ZERO(&fds); \ |
---|
175 | SM_FD_SET(m->mf_sock, &fds); \ |
---|
176 | tv.tv_sec = (secs); \ |
---|
177 | tv.tv_usec = 0; \ |
---|
178 | ret = select(m->mf_sock + 1, \ |
---|
179 | (write) ? NULL : &fds, \ |
---|
180 | (write) ? &fds : NULL, \ |
---|
181 | NULL, &tv); \ |
---|
182 | } while (ret < 0 && errno == EINTR); \ |
---|
183 | \ |
---|
184 | switch (ret) \ |
---|
185 | { \ |
---|
186 | case 0: \ |
---|
187 | if (tTd(64, 5)) \ |
---|
188 | sm_dprintf("milter_%s(%s): timeout\n", (routine), \ |
---|
189 | m->mf_name); \ |
---|
190 | if (MilterLogLevel > 0) \ |
---|
191 | sm_syslog(LOG_ERR, e->e_id, \ |
---|
192 | "Milter (%s): %s %s %s %s", \ |
---|
193 | m->mf_name, "timeout", \ |
---|
194 | started ? "during" : "before", \ |
---|
195 | "data", (routine)); \ |
---|
196 | milter_error(m, e); \ |
---|
197 | return NULL; \ |
---|
198 | \ |
---|
199 | case -1: \ |
---|
200 | save_errno = errno; \ |
---|
201 | if (tTd(64, 5)) \ |
---|
202 | sm_dprintf("milter_%s(%s): select: %s\n", (routine), \ |
---|
203 | m->mf_name, sm_errstring(save_errno)); \ |
---|
204 | if (MilterLogLevel > 0) \ |
---|
205 | { \ |
---|
206 | sm_syslog(LOG_ERR, e->e_id, \ |
---|
207 | "Milter (%s): select(%s): %s", \ |
---|
208 | m->mf_name, (routine), \ |
---|
209 | sm_errstring(save_errno)); \ |
---|
210 | } \ |
---|
211 | milter_error(m, e); \ |
---|
212 | return NULL; \ |
---|
213 | \ |
---|
214 | default: \ |
---|
215 | if (SM_FD_ISSET(m->mf_sock, &fds)) \ |
---|
216 | break; \ |
---|
217 | if (tTd(64, 5)) \ |
---|
218 | sm_dprintf("milter_%s(%s): socket not ready\n", \ |
---|
219 | (routine), m->mf_name); \ |
---|
220 | if (MilterLogLevel > 0) \ |
---|
221 | { \ |
---|
222 | sm_syslog(LOG_ERR, e->e_id, \ |
---|
223 | "Milter (%s): socket(%s) not ready", \ |
---|
224 | m->mf_name, (routine)); \ |
---|
225 | } \ |
---|
226 | milter_error(m, e); \ |
---|
227 | return NULL; \ |
---|
228 | } \ |
---|
229 | } |
---|
230 | |
---|
231 | /* |
---|
232 | ** Low level functions |
---|
233 | */ |
---|
234 | |
---|
235 | /* |
---|
236 | ** MILTER_READ -- read from a remote milter filter |
---|
237 | ** |
---|
238 | ** Parameters: |
---|
239 | ** m -- milter to read from. |
---|
240 | ** cmd -- return param for command read. |
---|
241 | ** rlen -- return length of response string. |
---|
242 | ** to -- timeout in seconds. |
---|
243 | ** e -- current envelope. |
---|
244 | ** |
---|
245 | ** Returns: |
---|
246 | ** response string (may be NULL) |
---|
247 | */ |
---|
248 | |
---|
249 | static char * |
---|
250 | milter_sysread(m, buf, sz, to, e) |
---|
251 | struct milter *m; |
---|
252 | char *buf; |
---|
253 | ssize_t sz; |
---|
254 | time_t to; |
---|
255 | ENVELOPE *e; |
---|
256 | { |
---|
257 | time_t readstart = 0; |
---|
258 | ssize_t len, curl; |
---|
259 | bool started = false; |
---|
260 | |
---|
261 | curl = 0; |
---|
262 | |
---|
263 | if (to > 0) |
---|
264 | readstart = curtime(); |
---|
265 | |
---|
266 | for (;;) |
---|
267 | { |
---|
268 | if (to > 0) |
---|
269 | { |
---|
270 | time_t now; |
---|
271 | |
---|
272 | now = curtime(); |
---|
273 | if (now - readstart >= to) |
---|
274 | { |
---|
275 | if (tTd(64, 5)) |
---|
276 | sm_dprintf("milter_read (%s): %s %s %s", |
---|
277 | m->mf_name, "timeout", |
---|
278 | started ? "during" : "before", |
---|
279 | "data read"); |
---|
280 | if (MilterLogLevel > 0) |
---|
281 | sm_syslog(LOG_ERR, e->e_id, |
---|
282 | "Milter (%s): %s %s %s", |
---|
283 | m->mf_name, "timeout", |
---|
284 | started ? "during" : "before", |
---|
285 | "data read"); |
---|
286 | milter_error(m, e); |
---|
287 | return NULL; |
---|
288 | } |
---|
289 | to -= now - readstart; |
---|
290 | readstart = now; |
---|
291 | MILTER_TIMEOUT("read", to, false, started); |
---|
292 | } |
---|
293 | |
---|
294 | len = read(m->mf_sock, buf + curl, sz - curl); |
---|
295 | |
---|
296 | if (len < 0) |
---|
297 | { |
---|
298 | int save_errno = errno; |
---|
299 | |
---|
300 | if (tTd(64, 5)) |
---|
301 | sm_dprintf("milter_read(%s): read returned %ld: %s\n", |
---|
302 | m->mf_name, (long) len, |
---|
303 | sm_errstring(save_errno)); |
---|
304 | if (MilterLogLevel > 0) |
---|
305 | sm_syslog(LOG_ERR, e->e_id, |
---|
306 | "Milter (%s): read returned %ld: %s", |
---|
307 | m->mf_name, (long) len, |
---|
308 | sm_errstring(save_errno)); |
---|
309 | milter_error(m, e); |
---|
310 | return NULL; |
---|
311 | } |
---|
312 | |
---|
313 | started = true; |
---|
314 | curl += len; |
---|
315 | if (len == 0 || curl >= sz) |
---|
316 | break; |
---|
317 | |
---|
318 | } |
---|
319 | |
---|
320 | if (curl != sz) |
---|
321 | { |
---|
322 | if (tTd(64, 5)) |
---|
323 | sm_dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n", |
---|
324 | m->mf_name, (long) curl, (long) sz); |
---|
325 | if (MilterLogLevel > 0) |
---|
326 | sm_syslog(LOG_ERR, e->e_id, |
---|
327 | "milter_read(%s): cmd read returned %ld, expecting %ld", |
---|
328 | m->mf_name, (long) curl, (long) sz); |
---|
329 | milter_error(m, e); |
---|
330 | return NULL; |
---|
331 | } |
---|
332 | return buf; |
---|
333 | } |
---|
334 | |
---|
335 | static char * |
---|
336 | milter_read(m, cmd, rlen, to, e) |
---|
337 | struct milter *m; |
---|
338 | char *cmd; |
---|
339 | ssize_t *rlen; |
---|
340 | time_t to; |
---|
341 | ENVELOPE *e; |
---|
342 | { |
---|
343 | time_t readstart = 0; |
---|
344 | ssize_t expl; |
---|
345 | mi_int32 i; |
---|
346 | char *buf; |
---|
347 | char data[MILTER_LEN_BYTES + 1]; |
---|
348 | |
---|
349 | *rlen = 0; |
---|
350 | *cmd = '\0'; |
---|
351 | |
---|
352 | if (to > 0) |
---|
353 | readstart = curtime(); |
---|
354 | |
---|
355 | if (milter_sysread(m, data, sizeof data, to, e) == NULL) |
---|
356 | return NULL; |
---|
357 | |
---|
358 | /* reset timeout */ |
---|
359 | if (to > 0) |
---|
360 | { |
---|
361 | time_t now; |
---|
362 | |
---|
363 | now = curtime(); |
---|
364 | if (now - readstart >= to) |
---|
365 | { |
---|
366 | if (tTd(64, 5)) |
---|
367 | sm_dprintf("milter_read(%s): timeout before data read\n", |
---|
368 | m->mf_name); |
---|
369 | if (MilterLogLevel > 0) |
---|
370 | sm_syslog(LOG_ERR, e->e_id, |
---|
371 | "Milter read(%s): timeout before data read", |
---|
372 | m->mf_name); |
---|
373 | milter_error(m, e); |
---|
374 | return NULL; |
---|
375 | } |
---|
376 | to -= now - readstart; |
---|
377 | } |
---|
378 | |
---|
379 | *cmd = data[MILTER_LEN_BYTES]; |
---|
380 | data[MILTER_LEN_BYTES] = '\0'; |
---|
381 | (void) memcpy(&i, data, MILTER_LEN_BYTES); |
---|
382 | expl = ntohl(i) - 1; |
---|
383 | |
---|
384 | if (tTd(64, 25)) |
---|
385 | sm_dprintf("milter_read(%s): expecting %ld bytes\n", |
---|
386 | m->mf_name, (long) expl); |
---|
387 | |
---|
388 | if (expl < 0) |
---|
389 | { |
---|
390 | if (tTd(64, 5)) |
---|
391 | sm_dprintf("milter_read(%s): read size %ld out of range\n", |
---|
392 | m->mf_name, (long) expl); |
---|
393 | if (MilterLogLevel > 0) |
---|
394 | sm_syslog(LOG_ERR, e->e_id, |
---|
395 | "milter_read(%s): read size %ld out of range", |
---|
396 | m->mf_name, (long) expl); |
---|
397 | milter_error(m, e); |
---|
398 | return NULL; |
---|
399 | } |
---|
400 | |
---|
401 | if (expl == 0) |
---|
402 | return NULL; |
---|
403 | |
---|
404 | buf = (char *) xalloc(expl); |
---|
405 | |
---|
406 | if (milter_sysread(m, buf, expl, to, e) == NULL) |
---|
407 | { |
---|
408 | sm_free(buf); /* XXX */ |
---|
409 | return NULL; |
---|
410 | } |
---|
411 | |
---|
412 | if (tTd(64, 50)) |
---|
413 | sm_dprintf("milter_read(%s): Returning %*s\n", |
---|
414 | m->mf_name, (int) expl, buf); |
---|
415 | *rlen = expl; |
---|
416 | return buf; |
---|
417 | } |
---|
418 | /* |
---|
419 | ** MILTER_WRITE -- write to a remote milter filter |
---|
420 | ** |
---|
421 | ** Parameters: |
---|
422 | ** m -- milter to read from. |
---|
423 | ** cmd -- command to send. |
---|
424 | ** buf -- optional command data. |
---|
425 | ** len -- length of buf. |
---|
426 | ** to -- timeout in seconds. |
---|
427 | ** e -- current envelope. |
---|
428 | ** |
---|
429 | ** Returns: |
---|
430 | ** buf if successful, NULL otherwise |
---|
431 | ** Not actually used anywhere but function prototype |
---|
432 | ** must match milter_read() |
---|
433 | */ |
---|
434 | |
---|
435 | static char * |
---|
436 | milter_write(m, cmd, buf, len, to, e) |
---|
437 | struct milter *m; |
---|
438 | char cmd; |
---|
439 | char *buf; |
---|
440 | ssize_t len; |
---|
441 | time_t to; |
---|
442 | ENVELOPE *e; |
---|
443 | { |
---|
444 | time_t writestart = (time_t) 0; |
---|
445 | ssize_t sl, i; |
---|
446 | mi_int32 nl; |
---|
447 | char data[MILTER_LEN_BYTES + 1]; |
---|
448 | bool started = false; |
---|
449 | |
---|
450 | if (len < 0 || len > MILTER_CHUNK_SIZE) |
---|
451 | { |
---|
452 | if (tTd(64, 5)) |
---|
453 | sm_dprintf("milter_write(%s): length %ld out of range\n", |
---|
454 | m->mf_name, (long) len); |
---|
455 | if (MilterLogLevel > 0) |
---|
456 | sm_syslog(LOG_ERR, e->e_id, |
---|
457 | "milter_write(%s): length %ld out of range", |
---|
458 | m->mf_name, (long) len); |
---|
459 | milter_error(m, e); |
---|
460 | return NULL; |
---|
461 | } |
---|
462 | |
---|
463 | if (tTd(64, 20)) |
---|
464 | sm_dprintf("milter_write(%s): cmd %c, len %ld\n", |
---|
465 | m->mf_name, cmd, (long) len); |
---|
466 | |
---|
467 | nl = htonl(len + 1); /* add 1 for the cmd char */ |
---|
468 | (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES); |
---|
469 | data[MILTER_LEN_BYTES] = cmd; |
---|
470 | sl = MILTER_LEN_BYTES + 1; |
---|
471 | |
---|
472 | if (to > 0) |
---|
473 | { |
---|
474 | writestart = curtime(); |
---|
475 | MILTER_TIMEOUT("write", to, true, started); |
---|
476 | } |
---|
477 | |
---|
478 | /* use writev() instead to send the whole stuff at once? */ |
---|
479 | i = write(m->mf_sock, (void *) data, sl); |
---|
480 | if (i != sl) |
---|
481 | { |
---|
482 | int save_errno = errno; |
---|
483 | |
---|
484 | if (tTd(64, 5)) |
---|
485 | sm_dprintf("milter_write (%s): write(%c) returned %ld, expected %ld: %s\n", |
---|
486 | m->mf_name, cmd, (long) i, (long) sl, |
---|
487 | sm_errstring(save_errno)); |
---|
488 | if (MilterLogLevel > 0) |
---|
489 | sm_syslog(LOG_ERR, e->e_id, |
---|
490 | "Milter (%s): write(%c) returned %ld, expected %ld: %s", |
---|
491 | m->mf_name, cmd, (long) i, (long) sl, |
---|
492 | sm_errstring(save_errno)); |
---|
493 | milter_error(m, e); |
---|
494 | return buf; |
---|
495 | } |
---|
496 | |
---|
497 | if (len <= 0 || buf == NULL) |
---|
498 | return buf; |
---|
499 | |
---|
500 | if (tTd(64, 50)) |
---|
501 | sm_dprintf("milter_write(%s): Sending %*s\n", |
---|
502 | m->mf_name, (int) len, buf); |
---|
503 | started = true; |
---|
504 | |
---|
505 | if (to > 0) |
---|
506 | { |
---|
507 | time_t now; |
---|
508 | |
---|
509 | now = curtime(); |
---|
510 | if (now - writestart >= to) |
---|
511 | { |
---|
512 | if (tTd(64, 5)) |
---|
513 | sm_dprintf("milter_write(%s): timeout before data write\n", |
---|
514 | m->mf_name); |
---|
515 | if (MilterLogLevel > 0) |
---|
516 | sm_syslog(LOG_ERR, e->e_id, |
---|
517 | "Milter (%s): timeout before data write", |
---|
518 | m->mf_name); |
---|
519 | milter_error(m, e); |
---|
520 | return NULL; |
---|
521 | } |
---|
522 | else |
---|
523 | { |
---|
524 | to -= now - writestart; |
---|
525 | MILTER_TIMEOUT("write", to, true, started); |
---|
526 | } |
---|
527 | } |
---|
528 | |
---|
529 | i = write(m->mf_sock, (void *) buf, len); |
---|
530 | if (i != len) |
---|
531 | { |
---|
532 | int save_errno = errno; |
---|
533 | |
---|
534 | if (tTd(64, 5)) |
---|
535 | sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n", |
---|
536 | m->mf_name, cmd, (long) i, (long) sl, |
---|
537 | sm_errstring(save_errno)); |
---|
538 | if (MilterLogLevel > 0) |
---|
539 | sm_syslog(LOG_ERR, e->e_id, |
---|
540 | "Milter (%s): write(%c) returned %ld, expected %ld: %s", |
---|
541 | m->mf_name, cmd, (long) i, (long) len, |
---|
542 | sm_errstring(save_errno)); |
---|
543 | milter_error(m, e); |
---|
544 | return NULL; |
---|
545 | } |
---|
546 | return buf; |
---|
547 | } |
---|
548 | |
---|
549 | /* |
---|
550 | ** Utility functions |
---|
551 | */ |
---|
552 | |
---|
553 | /* |
---|
554 | ** MILTER_OPEN -- connect to remote milter filter |
---|
555 | ** |
---|
556 | ** Parameters: |
---|
557 | ** m -- milter to connect to. |
---|
558 | ** parseonly -- parse but don't connect. |
---|
559 | ** e -- current envelope. |
---|
560 | ** |
---|
561 | ** Returns: |
---|
562 | ** connected socket if successful && !parseonly, |
---|
563 | ** 0 upon parse success if parseonly, |
---|
564 | ** -1 otherwise. |
---|
565 | */ |
---|
566 | |
---|
567 | static jmp_buf MilterConnectTimeout; |
---|
568 | |
---|
569 | static int |
---|
570 | milter_open(m, parseonly, e) |
---|
571 | struct milter *m; |
---|
572 | bool parseonly; |
---|
573 | ENVELOPE *e; |
---|
574 | { |
---|
575 | int sock = 0; |
---|
576 | SOCKADDR_LEN_T addrlen = 0; |
---|
577 | int addrno = 0; |
---|
578 | int save_errno; |
---|
579 | char *p; |
---|
580 | char *colon; |
---|
581 | char *at; |
---|
582 | struct hostent *hp = NULL; |
---|
583 | SOCKADDR addr; |
---|
584 | |
---|
585 | if (m->mf_conn == NULL || m->mf_conn[0] == '\0') |
---|
586 | { |
---|
587 | if (tTd(64, 5)) |
---|
588 | sm_dprintf("X%s: empty or missing socket information\n", |
---|
589 | m->mf_name); |
---|
590 | if (parseonly) |
---|
591 | syserr("X%s: empty or missing socket information", |
---|
592 | m->mf_name); |
---|
593 | else if (MilterLogLevel > 0) |
---|
594 | sm_syslog(LOG_ERR, e->e_id, |
---|
595 | "Milter (%s): empty or missing socket information", |
---|
596 | m->mf_name); |
---|
597 | milter_error(m, e); |
---|
598 | return -1; |
---|
599 | } |
---|
600 | |
---|
601 | /* protocol:filename or protocol:port@host */ |
---|
602 | memset(&addr, '\0', sizeof addr); |
---|
603 | p = m->mf_conn; |
---|
604 | colon = strchr(p, ':'); |
---|
605 | if (colon != NULL) |
---|
606 | { |
---|
607 | *colon = '\0'; |
---|
608 | |
---|
609 | if (*p == '\0') |
---|
610 | { |
---|
611 | # if NETUNIX |
---|
612 | /* default to AF_UNIX */ |
---|
613 | addr.sa.sa_family = AF_UNIX; |
---|
614 | # else /* NETUNIX */ |
---|
615 | # if NETINET |
---|
616 | /* default to AF_INET */ |
---|
617 | addr.sa.sa_family = AF_INET; |
---|
618 | # else /* NETINET */ |
---|
619 | # if NETINET6 |
---|
620 | /* default to AF_INET6 */ |
---|
621 | addr.sa.sa_family = AF_INET6; |
---|
622 | # else /* NETINET6 */ |
---|
623 | /* no protocols available */ |
---|
624 | if (MilterLogLevel > 0) |
---|
625 | sm_syslog(LOG_ERR, e->e_id, |
---|
626 | "Milter (%s): no valid socket protocols available", |
---|
627 | m->mf_name); |
---|
628 | milter_error(m, e); |
---|
629 | return -1; |
---|
630 | # endif /* NETINET6 */ |
---|
631 | # endif /* NETINET */ |
---|
632 | # endif /* NETUNIX */ |
---|
633 | } |
---|
634 | # if NETUNIX |
---|
635 | else if (sm_strcasecmp(p, "unix") == 0 || |
---|
636 | sm_strcasecmp(p, "local") == 0) |
---|
637 | addr.sa.sa_family = AF_UNIX; |
---|
638 | # endif /* NETUNIX */ |
---|
639 | # if NETINET |
---|
640 | else if (sm_strcasecmp(p, "inet") == 0) |
---|
641 | addr.sa.sa_family = AF_INET; |
---|
642 | # endif /* NETINET */ |
---|
643 | # if NETINET6 |
---|
644 | else if (sm_strcasecmp(p, "inet6") == 0) |
---|
645 | addr.sa.sa_family = AF_INET6; |
---|
646 | # endif /* NETINET6 */ |
---|
647 | else |
---|
648 | { |
---|
649 | # ifdef EPROTONOSUPPORT |
---|
650 | errno = EPROTONOSUPPORT; |
---|
651 | # else /* EPROTONOSUPPORT */ |
---|
652 | errno = EINVAL; |
---|
653 | # endif /* EPROTONOSUPPORT */ |
---|
654 | if (tTd(64, 5)) |
---|
655 | sm_dprintf("X%s: unknown socket type %s\n", |
---|
656 | m->mf_name, p); |
---|
657 | if (parseonly) |
---|
658 | syserr("X%s: unknown socket type %s", |
---|
659 | m->mf_name, p); |
---|
660 | else if (MilterLogLevel > 0) |
---|
661 | sm_syslog(LOG_ERR, e->e_id, |
---|
662 | "Milter (%s): unknown socket type %s", |
---|
663 | m->mf_name, p); |
---|
664 | milter_error(m, e); |
---|
665 | return -1; |
---|
666 | } |
---|
667 | *colon++ = ':'; |
---|
668 | } |
---|
669 | else |
---|
670 | { |
---|
671 | /* default to AF_UNIX */ |
---|
672 | addr.sa.sa_family = AF_UNIX; |
---|
673 | colon = p; |
---|
674 | } |
---|
675 | |
---|
676 | # if NETUNIX |
---|
677 | if (addr.sa.sa_family == AF_UNIX) |
---|
678 | { |
---|
679 | long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; |
---|
680 | |
---|
681 | at = colon; |
---|
682 | if (strlen(colon) >= sizeof addr.sunix.sun_path) |
---|
683 | { |
---|
684 | if (tTd(64, 5)) |
---|
685 | sm_dprintf("X%s: local socket name %s too long\n", |
---|
686 | m->mf_name, colon); |
---|
687 | errno = EINVAL; |
---|
688 | if (parseonly) |
---|
689 | syserr("X%s: local socket name %s too long", |
---|
690 | m->mf_name, colon); |
---|
691 | else if (MilterLogLevel > 0) |
---|
692 | sm_syslog(LOG_ERR, e->e_id, |
---|
693 | "Milter (%s): local socket name %s too long", |
---|
694 | m->mf_name, colon); |
---|
695 | milter_error(m, e); |
---|
696 | return -1; |
---|
697 | } |
---|
698 | errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, |
---|
699 | S_IRUSR|S_IWUSR, NULL); |
---|
700 | |
---|
701 | /* if just parsing .cf file, socket doesn't need to exist */ |
---|
702 | if (parseonly && errno == ENOENT) |
---|
703 | { |
---|
704 | if (OpMode == MD_DAEMON || |
---|
705 | OpMode == MD_FGDAEMON) |
---|
706 | (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, |
---|
707 | "WARNING: X%s: local socket name %s missing\n", |
---|
708 | m->mf_name, colon); |
---|
709 | } |
---|
710 | else if (errno != 0) |
---|
711 | { |
---|
712 | /* if not safe, don't create */ |
---|
713 | save_errno = errno; |
---|
714 | if (tTd(64, 5)) |
---|
715 | sm_dprintf("X%s: local socket name %s unsafe\n", |
---|
716 | m->mf_name, colon); |
---|
717 | errno = save_errno; |
---|
718 | if (parseonly) |
---|
719 | { |
---|
720 | if (OpMode == MD_DAEMON || |
---|
721 | OpMode == MD_FGDAEMON || |
---|
722 | OpMode == MD_SMTP) |
---|
723 | syserr("X%s: local socket name %s unsafe", |
---|
724 | m->mf_name, colon); |
---|
725 | } |
---|
726 | else if (MilterLogLevel > 0) |
---|
727 | sm_syslog(LOG_ERR, e->e_id, |
---|
728 | "Milter (%s): local socket name %s unsafe", |
---|
729 | m->mf_name, colon); |
---|
730 | milter_error(m, e); |
---|
731 | return -1; |
---|
732 | } |
---|
733 | |
---|
734 | (void) sm_strlcpy(addr.sunix.sun_path, colon, |
---|
735 | sizeof addr.sunix.sun_path); |
---|
736 | addrlen = sizeof (struct sockaddr_un); |
---|
737 | } |
---|
738 | else |
---|
739 | # endif /* NETUNIX */ |
---|
740 | # if NETINET || NETINET6 |
---|
741 | if (false |
---|
742 | # if NETINET |
---|
743 | || addr.sa.sa_family == AF_INET |
---|
744 | # endif /* NETINET */ |
---|
745 | # if NETINET6 |
---|
746 | || addr.sa.sa_family == AF_INET6 |
---|
747 | # endif /* NETINET6 */ |
---|
748 | ) |
---|
749 | { |
---|
750 | unsigned short port; |
---|
751 | |
---|
752 | /* Parse port@host */ |
---|
753 | at = strchr(colon, '@'); |
---|
754 | if (at == NULL) |
---|
755 | { |
---|
756 | if (tTd(64, 5)) |
---|
757 | sm_dprintf("X%s: bad address %s (expected port@host)\n", |
---|
758 | m->mf_name, colon); |
---|
759 | if (parseonly) |
---|
760 | syserr("X%s: bad address %s (expected port@host)", |
---|
761 | m->mf_name, colon); |
---|
762 | else if (MilterLogLevel > 0) |
---|
763 | sm_syslog(LOG_ERR, e->e_id, |
---|
764 | "Milter (%s): bad address %s (expected port@host)", |
---|
765 | m->mf_name, colon); |
---|
766 | milter_error(m, e); |
---|
767 | return -1; |
---|
768 | } |
---|
769 | *at = '\0'; |
---|
770 | if (isascii(*colon) && isdigit(*colon)) |
---|
771 | port = htons((unsigned short) atoi(colon)); |
---|
772 | else |
---|
773 | { |
---|
774 | # ifdef NO_GETSERVBYNAME |
---|
775 | if (tTd(64, 5)) |
---|
776 | sm_dprintf("X%s: invalid port number %s\n", |
---|
777 | m->mf_name, colon); |
---|
778 | if (parseonly) |
---|
779 | syserr("X%s: invalid port number %s", |
---|
780 | m->mf_name, colon); |
---|
781 | else if (MilterLogLevel > 0) |
---|
782 | sm_syslog(LOG_ERR, e->e_id, |
---|
783 | "Milter (%s): invalid port number %s", |
---|
784 | m->mf_name, colon); |
---|
785 | milter_error(m, e); |
---|
786 | return -1; |
---|
787 | # else /* NO_GETSERVBYNAME */ |
---|
788 | register struct servent *sp; |
---|
789 | |
---|
790 | sp = getservbyname(colon, "tcp"); |
---|
791 | if (sp == NULL) |
---|
792 | { |
---|
793 | save_errno = errno; |
---|
794 | if (tTd(64, 5)) |
---|
795 | sm_dprintf("X%s: unknown port name %s\n", |
---|
796 | m->mf_name, colon); |
---|
797 | errno = save_errno; |
---|
798 | if (parseonly) |
---|
799 | syserr("X%s: unknown port name %s", |
---|
800 | m->mf_name, colon); |
---|
801 | else if (MilterLogLevel > 0) |
---|
802 | sm_syslog(LOG_ERR, e->e_id, |
---|
803 | "Milter (%s): unknown port name %s", |
---|
804 | m->mf_name, colon); |
---|
805 | milter_error(m, e); |
---|
806 | return -1; |
---|
807 | } |
---|
808 | port = sp->s_port; |
---|
809 | # endif /* NO_GETSERVBYNAME */ |
---|
810 | } |
---|
811 | *at++ = '@'; |
---|
812 | if (*at == '[') |
---|
813 | { |
---|
814 | char *end; |
---|
815 | |
---|
816 | end = strchr(at, ']'); |
---|
817 | if (end != NULL) |
---|
818 | { |
---|
819 | bool found = false; |
---|
820 | # if NETINET |
---|
821 | unsigned long hid = INADDR_NONE; |
---|
822 | # endif /* NETINET */ |
---|
823 | # if NETINET6 |
---|
824 | struct sockaddr_in6 hid6; |
---|
825 | # endif /* NETINET6 */ |
---|
826 | |
---|
827 | *end = '\0'; |
---|
828 | # if NETINET |
---|
829 | if (addr.sa.sa_family == AF_INET && |
---|
830 | (hid = inet_addr(&at[1])) != INADDR_NONE) |
---|
831 | { |
---|
832 | addr.sin.sin_addr.s_addr = hid; |
---|
833 | addr.sin.sin_port = port; |
---|
834 | found = true; |
---|
835 | } |
---|
836 | # endif /* NETINET */ |
---|
837 | # if NETINET6 |
---|
838 | (void) memset(&hid6, '\0', sizeof hid6); |
---|
839 | if (addr.sa.sa_family == AF_INET6 && |
---|
840 | anynet_pton(AF_INET6, &at[1], |
---|
841 | &hid6.sin6_addr) == 1) |
---|
842 | { |
---|
843 | addr.sin6.sin6_addr = hid6.sin6_addr; |
---|
844 | addr.sin6.sin6_port = port; |
---|
845 | found = true; |
---|
846 | } |
---|
847 | # endif /* NETINET6 */ |
---|
848 | *end = ']'; |
---|
849 | if (!found) |
---|
850 | { |
---|
851 | if (tTd(64, 5)) |
---|
852 | sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", |
---|
853 | m->mf_name, at); |
---|
854 | if (parseonly) |
---|
855 | syserr("X%s: Invalid numeric domain spec \"%s\"", |
---|
856 | m->mf_name, at); |
---|
857 | else if (MilterLogLevel > 0) |
---|
858 | sm_syslog(LOG_ERR, e->e_id, |
---|
859 | "Milter (%s): Invalid numeric domain spec \"%s\"", |
---|
860 | m->mf_name, at); |
---|
861 | milter_error(m, e); |
---|
862 | return -1; |
---|
863 | } |
---|
864 | } |
---|
865 | else |
---|
866 | { |
---|
867 | if (tTd(64, 5)) |
---|
868 | sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", |
---|
869 | m->mf_name, at); |
---|
870 | if (parseonly) |
---|
871 | syserr("X%s: Invalid numeric domain spec \"%s\"", |
---|
872 | m->mf_name, at); |
---|
873 | else if (MilterLogLevel > 0) |
---|
874 | sm_syslog(LOG_ERR, e->e_id, |
---|
875 | "Milter (%s): Invalid numeric domain spec \"%s\"", |
---|
876 | m->mf_name, at); |
---|
877 | milter_error(m, e); |
---|
878 | return -1; |
---|
879 | } |
---|
880 | } |
---|
881 | else |
---|
882 | { |
---|
883 | hp = sm_gethostbyname(at, addr.sa.sa_family); |
---|
884 | if (hp == NULL) |
---|
885 | { |
---|
886 | save_errno = errno; |
---|
887 | if (tTd(64, 5)) |
---|
888 | sm_dprintf("X%s: Unknown host name %s\n", |
---|
889 | m->mf_name, at); |
---|
890 | errno = save_errno; |
---|
891 | if (parseonly) |
---|
892 | syserr("X%s: Unknown host name %s", |
---|
893 | m->mf_name, at); |
---|
894 | else if (MilterLogLevel > 0) |
---|
895 | sm_syslog(LOG_ERR, e->e_id, |
---|
896 | "Milter (%s): Unknown host name %s", |
---|
897 | m->mf_name, at); |
---|
898 | milter_error(m, e); |
---|
899 | return -1; |
---|
900 | } |
---|
901 | addr.sa.sa_family = hp->h_addrtype; |
---|
902 | switch (hp->h_addrtype) |
---|
903 | { |
---|
904 | # if NETINET |
---|
905 | case AF_INET: |
---|
906 | memmove(&addr.sin.sin_addr, |
---|
907 | hp->h_addr, INADDRSZ); |
---|
908 | addr.sin.sin_port = port; |
---|
909 | addrlen = sizeof (struct sockaddr_in); |
---|
910 | addrno = 1; |
---|
911 | break; |
---|
912 | # endif /* NETINET */ |
---|
913 | |
---|
914 | # if NETINET6 |
---|
915 | case AF_INET6: |
---|
916 | memmove(&addr.sin6.sin6_addr, |
---|
917 | hp->h_addr, IN6ADDRSZ); |
---|
918 | addr.sin6.sin6_port = port; |
---|
919 | addrlen = sizeof (struct sockaddr_in6); |
---|
920 | addrno = 1; |
---|
921 | break; |
---|
922 | # endif /* NETINET6 */ |
---|
923 | |
---|
924 | default: |
---|
925 | if (tTd(64, 5)) |
---|
926 | sm_dprintf("X%s: Unknown protocol for %s (%d)\n", |
---|
927 | m->mf_name, at, |
---|
928 | hp->h_addrtype); |
---|
929 | if (parseonly) |
---|
930 | syserr("X%s: Unknown protocol for %s (%d)", |
---|
931 | m->mf_name, at, hp->h_addrtype); |
---|
932 | else if (MilterLogLevel > 0) |
---|
933 | sm_syslog(LOG_ERR, e->e_id, |
---|
934 | "Milter (%s): Unknown protocol for %s (%d)", |
---|
935 | m->mf_name, at, |
---|
936 | hp->h_addrtype); |
---|
937 | milter_error(m, e); |
---|
938 | # if NETINET6 |
---|
939 | freehostent(hp); |
---|
940 | # endif /* NETINET6 */ |
---|
941 | return -1; |
---|
942 | } |
---|
943 | } |
---|
944 | } |
---|
945 | else |
---|
946 | # endif /* NETINET || NETINET6 */ |
---|
947 | { |
---|
948 | if (tTd(64, 5)) |
---|
949 | sm_dprintf("X%s: unknown socket protocol\n", |
---|
950 | m->mf_name); |
---|
951 | if (parseonly) |
---|
952 | syserr("X%s: unknown socket protocol", m->mf_name); |
---|
953 | else if (MilterLogLevel > 0) |
---|
954 | sm_syslog(LOG_ERR, e->e_id, |
---|
955 | "Milter (%s): unknown socket protocol", |
---|
956 | m->mf_name); |
---|
957 | milter_error(m, e); |
---|
958 | return -1; |
---|
959 | } |
---|
960 | |
---|
961 | /* just parsing through? */ |
---|
962 | if (parseonly) |
---|
963 | { |
---|
964 | m->mf_state = SMFS_READY; |
---|
965 | # if NETINET6 |
---|
966 | if (hp != NULL) |
---|
967 | freehostent(hp); |
---|
968 | # endif /* NETINET6 */ |
---|
969 | return 0; |
---|
970 | } |
---|
971 | |
---|
972 | /* sanity check */ |
---|
973 | if (m->mf_state != SMFS_READY && |
---|
974 | m->mf_state != SMFS_CLOSED) |
---|
975 | { |
---|
976 | /* shouldn't happen */ |
---|
977 | if (tTd(64, 1)) |
---|
978 | sm_dprintf("Milter (%s): Trying to open filter in state %c\n", |
---|
979 | m->mf_name, (char) m->mf_state); |
---|
980 | milter_error(m, e); |
---|
981 | # if NETINET6 |
---|
982 | if (hp != NULL) |
---|
983 | freehostent(hp); |
---|
984 | # endif /* NETINET6 */ |
---|
985 | return -1; |
---|
986 | } |
---|
987 | |
---|
988 | /* nope, actually connecting */ |
---|
989 | for (;;) |
---|
990 | { |
---|
991 | sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); |
---|
992 | if (sock < 0) |
---|
993 | { |
---|
994 | save_errno = errno; |
---|
995 | if (tTd(64, 5)) |
---|
996 | sm_dprintf("Milter (%s): error creating socket: %s\n", |
---|
997 | m->mf_name, |
---|
998 | sm_errstring(save_errno)); |
---|
999 | if (MilterLogLevel > 0) |
---|
1000 | sm_syslog(LOG_ERR, e->e_id, |
---|
1001 | "Milter (%s): error creating socket: %s", |
---|
1002 | m->mf_name, sm_errstring(save_errno)); |
---|
1003 | milter_error(m, e); |
---|
1004 | # if NETINET6 |
---|
1005 | if (hp != NULL) |
---|
1006 | freehostent(hp); |
---|
1007 | # endif /* NETINET6 */ |
---|
1008 | return -1; |
---|
1009 | } |
---|
1010 | |
---|
1011 | if (setjmp(MilterConnectTimeout) == 0) |
---|
1012 | { |
---|
1013 | SM_EVENT *ev = NULL; |
---|
1014 | int i; |
---|
1015 | |
---|
1016 | if (m->mf_timeout[SMFTO_CONNECT] > 0) |
---|
1017 | ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT], |
---|
1018 | milter_connect_timeout, 0); |
---|
1019 | |
---|
1020 | i = connect(sock, (struct sockaddr *) &addr, addrlen); |
---|
1021 | save_errno = errno; |
---|
1022 | if (ev != NULL) |
---|
1023 | sm_clrevent(ev); |
---|
1024 | errno = save_errno; |
---|
1025 | if (i >= 0) |
---|
1026 | break; |
---|
1027 | } |
---|
1028 | |
---|
1029 | /* couldn't connect.... try next address */ |
---|
1030 | save_errno = errno; |
---|
1031 | p = CurHostName; |
---|
1032 | CurHostName = at; |
---|
1033 | if (tTd(64, 5)) |
---|
1034 | sm_dprintf("milter_open (%s): open %s failed: %s\n", |
---|
1035 | m->mf_name, at, sm_errstring(save_errno)); |
---|
1036 | if (MilterLogLevel > 13) |
---|
1037 | sm_syslog(LOG_INFO, e->e_id, |
---|
1038 | "Milter (%s): open %s failed: %s", |
---|
1039 | m->mf_name, at, sm_errstring(save_errno)); |
---|
1040 | CurHostName = p; |
---|
1041 | (void) close(sock); |
---|
1042 | |
---|
1043 | /* try next address */ |
---|
1044 | if (hp != NULL && hp->h_addr_list[addrno] != NULL) |
---|
1045 | { |
---|
1046 | switch (addr.sa.sa_family) |
---|
1047 | { |
---|
1048 | # if NETINET |
---|
1049 | case AF_INET: |
---|
1050 | memmove(&addr.sin.sin_addr, |
---|
1051 | hp->h_addr_list[addrno++], |
---|
1052 | INADDRSZ); |
---|
1053 | break; |
---|
1054 | # endif /* NETINET */ |
---|
1055 | |
---|
1056 | # if NETINET6 |
---|
1057 | case AF_INET6: |
---|
1058 | memmove(&addr.sin6.sin6_addr, |
---|
1059 | hp->h_addr_list[addrno++], |
---|
1060 | IN6ADDRSZ); |
---|
1061 | break; |
---|
1062 | # endif /* NETINET6 */ |
---|
1063 | |
---|
1064 | default: |
---|
1065 | if (tTd(64, 5)) |
---|
1066 | sm_dprintf("X%s: Unknown protocol for %s (%d)\n", |
---|
1067 | m->mf_name, at, |
---|
1068 | hp->h_addrtype); |
---|
1069 | if (MilterLogLevel > 0) |
---|
1070 | sm_syslog(LOG_ERR, e->e_id, |
---|
1071 | "Milter (%s): Unknown protocol for %s (%d)", |
---|
1072 | m->mf_name, at, |
---|
1073 | hp->h_addrtype); |
---|
1074 | milter_error(m, e); |
---|
1075 | # if NETINET6 |
---|
1076 | freehostent(hp); |
---|
1077 | # endif /* NETINET6 */ |
---|
1078 | return -1; |
---|
1079 | } |
---|
1080 | continue; |
---|
1081 | } |
---|
1082 | p = CurHostName; |
---|
1083 | CurHostName = at; |
---|
1084 | if (tTd(64, 5)) |
---|
1085 | sm_dprintf("X%s: error connecting to filter: %s\n", |
---|
1086 | m->mf_name, sm_errstring(save_errno)); |
---|
1087 | if (MilterLogLevel > 0) |
---|
1088 | sm_syslog(LOG_ERR, e->e_id, |
---|
1089 | "Milter (%s): error connecting to filter: %s", |
---|
1090 | m->mf_name, sm_errstring(save_errno)); |
---|
1091 | CurHostName = p; |
---|
1092 | milter_error(m, e); |
---|
1093 | # if NETINET6 |
---|
1094 | if (hp != NULL) |
---|
1095 | freehostent(hp); |
---|
1096 | # endif /* NETINET6 */ |
---|
1097 | return -1; |
---|
1098 | } |
---|
1099 | m->mf_state = SMFS_OPEN; |
---|
1100 | # if NETINET6 |
---|
1101 | if (hp != NULL) |
---|
1102 | { |
---|
1103 | freehostent(hp); |
---|
1104 | hp = NULL; |
---|
1105 | } |
---|
1106 | # endif /* NETINET6 */ |
---|
1107 | return sock; |
---|
1108 | } |
---|
1109 | |
---|
1110 | static void |
---|
1111 | milter_connect_timeout() |
---|
1112 | { |
---|
1113 | /* |
---|
1114 | ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD |
---|
1115 | ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE |
---|
1116 | ** DOING. |
---|
1117 | */ |
---|
1118 | |
---|
1119 | errno = ETIMEDOUT; |
---|
1120 | longjmp(MilterConnectTimeout, 1); |
---|
1121 | } |
---|
1122 | /* |
---|
1123 | ** MILTER_SETUP -- setup structure for a mail filter |
---|
1124 | ** |
---|
1125 | ** Parameters: |
---|
1126 | ** line -- the options line. |
---|
1127 | ** |
---|
1128 | ** Returns: |
---|
1129 | ** none |
---|
1130 | */ |
---|
1131 | |
---|
1132 | void |
---|
1133 | milter_setup(line) |
---|
1134 | char *line; |
---|
1135 | { |
---|
1136 | char fcode; |
---|
1137 | register char *p; |
---|
1138 | register struct milter *m; |
---|
1139 | STAB *s; |
---|
1140 | |
---|
1141 | /* collect the filter name */ |
---|
1142 | for (p = line; |
---|
1143 | *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); |
---|
1144 | p++) |
---|
1145 | continue; |
---|
1146 | if (*p != '\0') |
---|
1147 | *p++ = '\0'; |
---|
1148 | if (line[0] == '\0') |
---|
1149 | { |
---|
1150 | syserr("name required for mail filter"); |
---|
1151 | return; |
---|
1152 | } |
---|
1153 | m = (struct milter *) xalloc(sizeof *m); |
---|
1154 | memset((char *) m, '\0', sizeof *m); |
---|
1155 | m->mf_name = newstr(line); |
---|
1156 | m->mf_state = SMFS_READY; |
---|
1157 | m->mf_sock = -1; |
---|
1158 | m->mf_timeout[SMFTO_CONNECT] = (time_t) 300; |
---|
1159 | m->mf_timeout[SMFTO_WRITE] = (time_t) 10; |
---|
1160 | m->mf_timeout[SMFTO_READ] = (time_t) 10; |
---|
1161 | m->mf_timeout[SMFTO_EOM] = (time_t) 300; |
---|
1162 | |
---|
1163 | /* now scan through and assign info from the fields */ |
---|
1164 | while (*p != '\0') |
---|
1165 | { |
---|
1166 | char *delimptr; |
---|
1167 | |
---|
1168 | while (*p != '\0' && |
---|
1169 | (*p == ',' || (isascii(*p) && isspace(*p)))) |
---|
1170 | p++; |
---|
1171 | |
---|
1172 | /* p now points to field code */ |
---|
1173 | fcode = *p; |
---|
1174 | while (*p != '\0' && *p != '=' && *p != ',') |
---|
1175 | p++; |
---|
1176 | if (*p++ != '=') |
---|
1177 | { |
---|
1178 | syserr("X%s: `=' expected", m->mf_name); |
---|
1179 | return; |
---|
1180 | } |
---|
1181 | while (isascii(*p) && isspace(*p)) |
---|
1182 | p++; |
---|
1183 | |
---|
1184 | /* p now points to the field body */ |
---|
1185 | p = munchstring(p, &delimptr, ','); |
---|
1186 | |
---|
1187 | /* install the field into the filter struct */ |
---|
1188 | switch (fcode) |
---|
1189 | { |
---|
1190 | case 'S': /* socket */ |
---|
1191 | if (p == NULL) |
---|
1192 | m->mf_conn = NULL; |
---|
1193 | else |
---|
1194 | m->mf_conn = newstr(p); |
---|
1195 | break; |
---|
1196 | |
---|
1197 | case 'F': /* Milter flags configured on MTA */ |
---|
1198 | for (; *p != '\0'; p++) |
---|
1199 | { |
---|
1200 | if (!(isascii(*p) && isspace(*p))) |
---|
1201 | setbitn(bitidx(*p), m->mf_flags); |
---|
1202 | } |
---|
1203 | break; |
---|
1204 | |
---|
1205 | case 'T': /* timeouts */ |
---|
1206 | milter_parse_timeouts(p, m); |
---|
1207 | break; |
---|
1208 | |
---|
1209 | default: |
---|
1210 | syserr("X%s: unknown filter equate %c=", |
---|
1211 | m->mf_name, fcode); |
---|
1212 | break; |
---|
1213 | } |
---|
1214 | p = delimptr; |
---|
1215 | } |
---|
1216 | |
---|
1217 | /* early check for errors */ |
---|
1218 | (void) milter_open(m, true, CurEnv); |
---|
1219 | |
---|
1220 | /* enter the filter into the symbol table */ |
---|
1221 | s = stab(m->mf_name, ST_MILTER, ST_ENTER); |
---|
1222 | if (s->s_milter != NULL) |
---|
1223 | syserr("X%s: duplicate filter definition", m->mf_name); |
---|
1224 | else |
---|
1225 | s->s_milter = m; |
---|
1226 | } |
---|
1227 | /* |
---|
1228 | ** MILTER_CONFIG -- parse option list into an array and check config |
---|
1229 | ** |
---|
1230 | ** Called when reading configuration file. |
---|
1231 | ** |
---|
1232 | ** Parameters: |
---|
1233 | ** spec -- the filter list. |
---|
1234 | ** list -- the array to fill in. |
---|
1235 | ** max -- the maximum number of entries in list. |
---|
1236 | ** |
---|
1237 | ** Returns: |
---|
1238 | ** none |
---|
1239 | */ |
---|
1240 | |
---|
1241 | void |
---|
1242 | milter_config(spec, list, max) |
---|
1243 | char *spec; |
---|
1244 | struct milter **list; |
---|
1245 | int max; |
---|
1246 | { |
---|
1247 | int numitems = 0; |
---|
1248 | register char *p; |
---|
1249 | |
---|
1250 | /* leave one for the NULL signifying the end of the list */ |
---|
1251 | max--; |
---|
1252 | |
---|
1253 | for (p = spec; p != NULL; ) |
---|
1254 | { |
---|
1255 | STAB *s; |
---|
1256 | |
---|
1257 | while (isascii(*p) && isspace(*p)) |
---|
1258 | p++; |
---|
1259 | if (*p == '\0') |
---|
1260 | break; |
---|
1261 | spec = p; |
---|
1262 | |
---|
1263 | if (numitems >= max) |
---|
1264 | { |
---|
1265 | syserr("Too many filters defined, %d max", max); |
---|
1266 | if (max > 0) |
---|
1267 | list[0] = NULL; |
---|
1268 | return; |
---|
1269 | } |
---|
1270 | #if _FFR_MILTER_PERDAEMON |
---|
1271 | p = strpbrk(p, ";,"); |
---|
1272 | #else /* _FFR_MILTER_PERDAEMON */ |
---|
1273 | p = strpbrk(p, ","); |
---|
1274 | #endif /* _FFR_MILTER_PERDAEMON */ |
---|
1275 | if (p != NULL) |
---|
1276 | *p++ = '\0'; |
---|
1277 | |
---|
1278 | s = stab(spec, ST_MILTER, ST_FIND); |
---|
1279 | if (s == NULL) |
---|
1280 | { |
---|
1281 | syserr("InputFilter %s not defined", spec); |
---|
1282 | ExitStat = EX_CONFIG; |
---|
1283 | return; |
---|
1284 | } |
---|
1285 | list[numitems++] = s->s_milter; |
---|
1286 | } |
---|
1287 | list[numitems] = NULL; |
---|
1288 | |
---|
1289 | /* if not set, set to LogLevel */ |
---|
1290 | if (MilterLogLevel == -1) |
---|
1291 | MilterLogLevel = LogLevel; |
---|
1292 | } |
---|
1293 | /* |
---|
1294 | ** MILTER_PARSE_TIMEOUTS -- parse timeout list |
---|
1295 | ** |
---|
1296 | ** Called when reading configuration file. |
---|
1297 | ** |
---|
1298 | ** Parameters: |
---|
1299 | ** spec -- the timeout list. |
---|
1300 | ** m -- milter to set. |
---|
1301 | ** |
---|
1302 | ** Returns: |
---|
1303 | ** none |
---|
1304 | */ |
---|
1305 | |
---|
1306 | static void |
---|
1307 | milter_parse_timeouts(spec, m) |
---|
1308 | char *spec; |
---|
1309 | struct milter *m; |
---|
1310 | { |
---|
1311 | char fcode; |
---|
1312 | register char *p; |
---|
1313 | |
---|
1314 | p = spec; |
---|
1315 | |
---|
1316 | /* now scan through and assign info from the fields */ |
---|
1317 | while (*p != '\0') |
---|
1318 | { |
---|
1319 | char *delimptr; |
---|
1320 | |
---|
1321 | while (*p != '\0' && |
---|
1322 | (*p == ';' || (isascii(*p) && isspace(*p)))) |
---|
1323 | p++; |
---|
1324 | |
---|
1325 | /* p now points to field code */ |
---|
1326 | fcode = *p; |
---|
1327 | while (*p != '\0' && *p != ':') |
---|
1328 | p++; |
---|
1329 | if (*p++ != ':') |
---|
1330 | { |
---|
1331 | syserr("X%s, T=: `:' expected", m->mf_name); |
---|
1332 | return; |
---|
1333 | } |
---|
1334 | while (isascii(*p) && isspace(*p)) |
---|
1335 | p++; |
---|
1336 | |
---|
1337 | /* p now points to the field body */ |
---|
1338 | p = munchstring(p, &delimptr, ';'); |
---|
1339 | |
---|
1340 | /* install the field into the filter struct */ |
---|
1341 | switch (fcode) |
---|
1342 | { |
---|
1343 | case 'C': |
---|
1344 | m->mf_timeout[SMFTO_CONNECT] = convtime(p, 's'); |
---|
1345 | if (tTd(64, 5)) |
---|
1346 | sm_dprintf("X%s: %c=%lu\n", |
---|
1347 | m->mf_name, fcode, |
---|
1348 | (unsigned long) m->mf_timeout[SMFTO_CONNECT]); |
---|
1349 | break; |
---|
1350 | |
---|
1351 | case 'S': |
---|
1352 | m->mf_timeout[SMFTO_WRITE] = convtime(p, 's'); |
---|
1353 | if (tTd(64, 5)) |
---|
1354 | sm_dprintf("X%s: %c=%lu\n", |
---|
1355 | m->mf_name, fcode, |
---|
1356 | (unsigned long) m->mf_timeout[SMFTO_WRITE]); |
---|
1357 | break; |
---|
1358 | |
---|
1359 | case 'R': |
---|
1360 | m->mf_timeout[SMFTO_READ] = convtime(p, 's'); |
---|
1361 | if (tTd(64, 5)) |
---|
1362 | sm_dprintf("X%s: %c=%lu\n", |
---|
1363 | m->mf_name, fcode, |
---|
1364 | (unsigned long) m->mf_timeout[SMFTO_READ]); |
---|
1365 | break; |
---|
1366 | |
---|
1367 | case 'E': |
---|
1368 | m->mf_timeout[SMFTO_EOM] = convtime(p, 's'); |
---|
1369 | if (tTd(64, 5)) |
---|
1370 | sm_dprintf("X%s: %c=%lu\n", |
---|
1371 | m->mf_name, fcode, |
---|
1372 | (unsigned long) m->mf_timeout[SMFTO_EOM]); |
---|
1373 | break; |
---|
1374 | |
---|
1375 | default: |
---|
1376 | if (tTd(64, 5)) |
---|
1377 | sm_dprintf("X%s: %c unknown\n", |
---|
1378 | m->mf_name, fcode); |
---|
1379 | syserr("X%s: unknown filter timeout %c", |
---|
1380 | m->mf_name, fcode); |
---|
1381 | break; |
---|
1382 | } |
---|
1383 | p = delimptr; |
---|
1384 | } |
---|
1385 | } |
---|
1386 | /* |
---|
1387 | ** MILTER_SET_OPTION -- set an individual milter option |
---|
1388 | ** |
---|
1389 | ** Parameters: |
---|
1390 | ** name -- the name of the option. |
---|
1391 | ** val -- the value of the option. |
---|
1392 | ** sticky -- if set, don't let other setoptions override |
---|
1393 | ** this value. |
---|
1394 | ** |
---|
1395 | ** Returns: |
---|
1396 | ** none. |
---|
1397 | */ |
---|
1398 | |
---|
1399 | /* set if Milter sub-option is stuck */ |
---|
1400 | static BITMAP256 StickyMilterOpt; |
---|
1401 | |
---|
1402 | static struct milteropt |
---|
1403 | { |
---|
1404 | char *mo_name; /* long name of milter option */ |
---|
1405 | unsigned char mo_code; /* code for option */ |
---|
1406 | } MilterOptTab[] = |
---|
1407 | { |
---|
1408 | # define MO_MACROS_CONNECT 0x01 |
---|
1409 | { "macros.connect", MO_MACROS_CONNECT }, |
---|
1410 | # define MO_MACROS_HELO 0x02 |
---|
1411 | { "macros.helo", MO_MACROS_HELO }, |
---|
1412 | # define MO_MACROS_ENVFROM 0x03 |
---|
1413 | { "macros.envfrom", MO_MACROS_ENVFROM }, |
---|
1414 | # define MO_MACROS_ENVRCPT 0x04 |
---|
1415 | { "macros.envrcpt", MO_MACROS_ENVRCPT }, |
---|
1416 | # define MO_LOGLEVEL 0x05 |
---|
1417 | { "loglevel", MO_LOGLEVEL }, |
---|
1418 | { NULL, 0 }, |
---|
1419 | }; |
---|
1420 | |
---|
1421 | void |
---|
1422 | milter_set_option(name, val, sticky) |
---|
1423 | char *name; |
---|
1424 | char *val; |
---|
1425 | bool sticky; |
---|
1426 | { |
---|
1427 | int nummac = 0; |
---|
1428 | register struct milteropt *mo; |
---|
1429 | char *p; |
---|
1430 | char **macros = NULL; |
---|
1431 | |
---|
1432 | if (tTd(37, 2) || tTd(64, 5)) |
---|
1433 | sm_dprintf("milter_set_option(%s = %s)", name, val); |
---|
1434 | |
---|
1435 | if (name == NULL) |
---|
1436 | { |
---|
1437 | syserr("milter_set_option: invalid Milter option, must specify suboption"); |
---|
1438 | return; |
---|
1439 | } |
---|
1440 | |
---|
1441 | for (mo = MilterOptTab; mo->mo_name != NULL; mo++) |
---|
1442 | { |
---|
1443 | if (sm_strcasecmp(mo->mo_name, name) == 0) |
---|
1444 | break; |
---|
1445 | } |
---|
1446 | |
---|
1447 | if (mo->mo_name == NULL) |
---|
1448 | { |
---|
1449 | syserr("milter_set_option: invalid Milter option %s", name); |
---|
1450 | return; |
---|
1451 | } |
---|
1452 | |
---|
1453 | /* |
---|
1454 | ** See if this option is preset for us. |
---|
1455 | */ |
---|
1456 | |
---|
1457 | if (!sticky && bitnset(mo->mo_code, StickyMilterOpt)) |
---|
1458 | { |
---|
1459 | if (tTd(37, 2) || tTd(64,5)) |
---|
1460 | sm_dprintf(" (ignored)\n"); |
---|
1461 | return; |
---|
1462 | } |
---|
1463 | |
---|
1464 | if (tTd(37, 2) || tTd(64,5)) |
---|
1465 | sm_dprintf("\n"); |
---|
1466 | |
---|
1467 | switch (mo->mo_code) |
---|
1468 | { |
---|
1469 | case MO_LOGLEVEL: |
---|
1470 | MilterLogLevel = atoi(val); |
---|
1471 | break; |
---|
1472 | |
---|
1473 | case MO_MACROS_CONNECT: |
---|
1474 | if (macros == NULL) |
---|
1475 | macros = MilterConnectMacros; |
---|
1476 | /* FALLTHROUGH */ |
---|
1477 | |
---|
1478 | case MO_MACROS_HELO: |
---|
1479 | if (macros == NULL) |
---|
1480 | macros = MilterHeloMacros; |
---|
1481 | /* FALLTHROUGH */ |
---|
1482 | |
---|
1483 | case MO_MACROS_ENVFROM: |
---|
1484 | if (macros == NULL) |
---|
1485 | macros = MilterEnvFromMacros; |
---|
1486 | /* FALLTHROUGH */ |
---|
1487 | |
---|
1488 | case MO_MACROS_ENVRCPT: |
---|
1489 | if (macros == NULL) |
---|
1490 | macros = MilterEnvRcptMacros; |
---|
1491 | |
---|
1492 | p = newstr(val); |
---|
1493 | while (*p != '\0') |
---|
1494 | { |
---|
1495 | char *macro; |
---|
1496 | |
---|
1497 | /* Skip leading commas, spaces */ |
---|
1498 | while (*p != '\0' && |
---|
1499 | (*p == ',' || (isascii(*p) && isspace(*p)))) |
---|
1500 | p++; |
---|
1501 | |
---|
1502 | if (*p == '\0') |
---|
1503 | break; |
---|
1504 | |
---|
1505 | /* Find end of macro */ |
---|
1506 | macro = p; |
---|
1507 | while (*p != '\0' && *p != ',' && |
---|
1508 | isascii(*p) && !isspace(*p)) |
---|
1509 | p++; |
---|
1510 | if (*p != '\0') |
---|
1511 | *p++ = '\0'; |
---|
1512 | |
---|
1513 | if (nummac >= MAXFILTERMACROS) |
---|
1514 | { |
---|
1515 | syserr("milter_set_option: too many macros in Milter.%s (max %d)", |
---|
1516 | name, MAXFILTERMACROS); |
---|
1517 | macros[nummac] = NULL; |
---|
1518 | break; |
---|
1519 | } |
---|
1520 | macros[nummac++] = macro; |
---|
1521 | } |
---|
1522 | macros[nummac] = NULL; |
---|
1523 | break; |
---|
1524 | |
---|
1525 | default: |
---|
1526 | syserr("milter_set_option: invalid Milter option %s", name); |
---|
1527 | break; |
---|
1528 | } |
---|
1529 | if (sticky) |
---|
1530 | setbitn(mo->mo_code, StickyMilterOpt); |
---|
1531 | } |
---|
1532 | /* |
---|
1533 | ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody) |
---|
1534 | ** |
---|
1535 | ** Parameters: |
---|
1536 | ** e -- current envelope. |
---|
1537 | ** |
---|
1538 | ** Returns: |
---|
1539 | ** 0 if succesful, -1 otherwise |
---|
1540 | */ |
---|
1541 | |
---|
1542 | static int |
---|
1543 | milter_reopen_df(e) |
---|
1544 | ENVELOPE *e; |
---|
1545 | { |
---|
1546 | char dfname[MAXPATHLEN]; |
---|
1547 | |
---|
1548 | (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); |
---|
1549 | |
---|
1550 | /* |
---|
1551 | ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so |
---|
1552 | ** close and reopen writable (later close and reopen |
---|
1553 | ** read only again). |
---|
1554 | ** |
---|
1555 | ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the |
---|
1556 | ** buffered file I/O descriptor, still open for writing |
---|
1557 | ** so there isn't as much work to do, just truncate it |
---|
1558 | ** and go. |
---|
1559 | */ |
---|
1560 | |
---|
1561 | if (SuperSafe == SAFE_REALLY) |
---|
1562 | { |
---|
1563 | /* close read-only data file */ |
---|
1564 | if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) |
---|
1565 | { |
---|
1566 | (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); |
---|
1567 | e->e_flags &= ~EF_HAS_DF; |
---|
1568 | } |
---|
1569 | |
---|
1570 | /* open writable */ |
---|
1571 | if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, |
---|
1572 | SM_IO_RDWR, NULL)) == NULL) |
---|
1573 | { |
---|
1574 | MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s"); |
---|
1575 | return -1; |
---|
1576 | } |
---|
1577 | } |
---|
1578 | else if (e->e_dfp == NULL) |
---|
1579 | { |
---|
1580 | /* shouldn't happen */ |
---|
1581 | errno = ENOENT; |
---|
1582 | MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)"); |
---|
1583 | return -1; |
---|
1584 | } |
---|
1585 | return 0; |
---|
1586 | } |
---|
1587 | /* |
---|
1588 | ** MILTER_RESET_DF -- re-open read-only the data file (for replbody) |
---|
1589 | ** |
---|
1590 | ** Parameters: |
---|
1591 | ** e -- current envelope. |
---|
1592 | ** |
---|
1593 | ** Returns: |
---|
1594 | ** 0 if succesful, -1 otherwise |
---|
1595 | */ |
---|
1596 | |
---|
1597 | static int |
---|
1598 | milter_reset_df(e) |
---|
1599 | ENVELOPE *e; |
---|
1600 | { |
---|
1601 | int afd; |
---|
1602 | char dfname[MAXPATHLEN]; |
---|
1603 | |
---|
1604 | (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); |
---|
1605 | |
---|
1606 | if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 || |
---|
1607 | sm_io_error(e->e_dfp)) |
---|
1608 | { |
---|
1609 | MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s"); |
---|
1610 | return -1; |
---|
1611 | } |
---|
1612 | else if (SuperSafe != SAFE_REALLY) |
---|
1613 | { |
---|
1614 | /* skip next few clauses */ |
---|
1615 | /* EMPTY */ |
---|
1616 | } |
---|
1617 | else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0 |
---|
1618 | && fsync(afd) < 0) |
---|
1619 | { |
---|
1620 | MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s"); |
---|
1621 | return -1; |
---|
1622 | } |
---|
1623 | else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0) |
---|
1624 | { |
---|
1625 | MILTER_DF_ERROR("milter_reset_df: error closing %s: %s"); |
---|
1626 | return -1; |
---|
1627 | } |
---|
1628 | else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, |
---|
1629 | SM_IO_RDONLY, NULL)) == NULL) |
---|
1630 | { |
---|
1631 | MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s"); |
---|
1632 | return -1; |
---|
1633 | } |
---|
1634 | else |
---|
1635 | e->e_flags |= EF_HAS_DF; |
---|
1636 | return 0; |
---|
1637 | } |
---|
1638 | /* |
---|
1639 | ** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients? |
---|
1640 | ** |
---|
1641 | ** Parameters: |
---|
1642 | ** none |
---|
1643 | ** |
---|
1644 | ** Returns: |
---|
1645 | ** true if any filter deletes recipients, false otherwise |
---|
1646 | */ |
---|
1647 | |
---|
1648 | bool |
---|
1649 | milter_can_delrcpts() |
---|
1650 | { |
---|
1651 | bool can = false; |
---|
1652 | int i; |
---|
1653 | |
---|
1654 | if (tTd(64, 10)) |
---|
1655 | sm_dprintf("milter_can_delrcpts:"); |
---|
1656 | |
---|
1657 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
1658 | { |
---|
1659 | struct milter *m = InputFilters[i]; |
---|
1660 | |
---|
1661 | if (bitset(SMFIF_DELRCPT, m->mf_fflags)) |
---|
1662 | { |
---|
1663 | can = true; |
---|
1664 | break; |
---|
1665 | } |
---|
1666 | } |
---|
1667 | if (tTd(64, 10)) |
---|
1668 | sm_dprintf("%s\n", can ? "true" : "false"); |
---|
1669 | |
---|
1670 | return can; |
---|
1671 | } |
---|
1672 | /* |
---|
1673 | ** MILTER_QUIT_FILTER -- close down a single filter |
---|
1674 | ** |
---|
1675 | ** Parameters: |
---|
1676 | ** m -- milter structure of filter to close down. |
---|
1677 | ** e -- current envelope. |
---|
1678 | ** |
---|
1679 | ** Returns: |
---|
1680 | ** none |
---|
1681 | */ |
---|
1682 | |
---|
1683 | static void |
---|
1684 | milter_quit_filter(m, e) |
---|
1685 | struct milter *m; |
---|
1686 | ENVELOPE *e; |
---|
1687 | { |
---|
1688 | if (tTd(64, 10)) |
---|
1689 | sm_dprintf("milter_quit_filter(%s)\n", m->mf_name); |
---|
1690 | if (MilterLogLevel > 18) |
---|
1691 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter", |
---|
1692 | m->mf_name); |
---|
1693 | |
---|
1694 | /* Never replace error state */ |
---|
1695 | if (m->mf_state == SMFS_ERROR) |
---|
1696 | return; |
---|
1697 | |
---|
1698 | if (m->mf_sock < 0 || |
---|
1699 | m->mf_state == SMFS_CLOSED || |
---|
1700 | m->mf_state == SMFS_READY) |
---|
1701 | { |
---|
1702 | m->mf_sock = -1; |
---|
1703 | m->mf_state = SMFS_CLOSED; |
---|
1704 | return; |
---|
1705 | } |
---|
1706 | |
---|
1707 | (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0, |
---|
1708 | m->mf_timeout[SMFTO_WRITE], e); |
---|
1709 | if (m->mf_sock >= 0) |
---|
1710 | { |
---|
1711 | (void) close(m->mf_sock); |
---|
1712 | m->mf_sock = -1; |
---|
1713 | } |
---|
1714 | if (m->mf_state != SMFS_ERROR) |
---|
1715 | m->mf_state = SMFS_CLOSED; |
---|
1716 | } |
---|
1717 | /* |
---|
1718 | ** MILTER_ABORT_FILTER -- tell filter to abort current message |
---|
1719 | ** |
---|
1720 | ** Parameters: |
---|
1721 | ** m -- milter structure of filter to abort. |
---|
1722 | ** e -- current envelope. |
---|
1723 | ** |
---|
1724 | ** Returns: |
---|
1725 | ** none |
---|
1726 | */ |
---|
1727 | |
---|
1728 | static void |
---|
1729 | milter_abort_filter(m, e) |
---|
1730 | struct milter *m; |
---|
1731 | ENVELOPE *e; |
---|
1732 | { |
---|
1733 | if (tTd(64, 10)) |
---|
1734 | sm_dprintf("milter_abort_filter(%s)\n", m->mf_name); |
---|
1735 | if (MilterLogLevel > 10) |
---|
1736 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter", |
---|
1737 | m->mf_name); |
---|
1738 | |
---|
1739 | if (m->mf_sock < 0 || |
---|
1740 | m->mf_state != SMFS_INMSG) |
---|
1741 | return; |
---|
1742 | |
---|
1743 | (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0, |
---|
1744 | m->mf_timeout[SMFTO_WRITE], e); |
---|
1745 | if (m->mf_state != SMFS_ERROR) |
---|
1746 | m->mf_state = SMFS_DONE; |
---|
1747 | } |
---|
1748 | /* |
---|
1749 | ** MILTER_SEND_MACROS -- provide macros to the filters |
---|
1750 | ** |
---|
1751 | ** Parameters: |
---|
1752 | ** m -- milter to send macros to. |
---|
1753 | ** macros -- macros to send for filter smfi_getsymval(). |
---|
1754 | ** cmd -- which command the macros are associated with. |
---|
1755 | ** e -- current envelope (for macro access). |
---|
1756 | ** |
---|
1757 | ** Returns: |
---|
1758 | ** none |
---|
1759 | */ |
---|
1760 | |
---|
1761 | static void |
---|
1762 | milter_send_macros(m, macros, cmd, e) |
---|
1763 | struct milter *m; |
---|
1764 | char **macros; |
---|
1765 | char cmd; |
---|
1766 | ENVELOPE *e; |
---|
1767 | { |
---|
1768 | int i; |
---|
1769 | int mid; |
---|
1770 | char *v; |
---|
1771 | char *buf, *bp; |
---|
1772 | char exp[MAXLINE]; |
---|
1773 | ssize_t s; |
---|
1774 | |
---|
1775 | /* sanity check */ |
---|
1776 | if (macros == NULL || macros[0] == NULL) |
---|
1777 | return; |
---|
1778 | |
---|
1779 | /* put together data */ |
---|
1780 | s = 1; /* for the command character */ |
---|
1781 | for (i = 0; macros[i] != NULL; i++) |
---|
1782 | { |
---|
1783 | mid = macid(macros[i]); |
---|
1784 | if (mid == 0) |
---|
1785 | continue; |
---|
1786 | v = macvalue(mid, e); |
---|
1787 | if (v == NULL) |
---|
1788 | continue; |
---|
1789 | expand(v, exp, sizeof(exp), e); |
---|
1790 | s += strlen(macros[i]) + 1 + strlen(exp) + 1; |
---|
1791 | } |
---|
1792 | |
---|
1793 | if (s < 0) |
---|
1794 | return; |
---|
1795 | |
---|
1796 | buf = (char *) xalloc(s); |
---|
1797 | bp = buf; |
---|
1798 | *bp++ = cmd; |
---|
1799 | for (i = 0; macros[i] != NULL; i++) |
---|
1800 | { |
---|
1801 | mid = macid(macros[i]); |
---|
1802 | if (mid == 0) |
---|
1803 | continue; |
---|
1804 | v = macvalue(mid, e); |
---|
1805 | if (v == NULL) |
---|
1806 | continue; |
---|
1807 | expand(v, exp, sizeof(exp), e); |
---|
1808 | |
---|
1809 | if (tTd(64, 10)) |
---|
1810 | sm_dprintf("milter_send_macros(%s, %c): %s=%s\n", |
---|
1811 | m->mf_name, cmd, macros[i], exp); |
---|
1812 | |
---|
1813 | (void) sm_strlcpy(bp, macros[i], s - (bp - buf)); |
---|
1814 | bp += strlen(bp) + 1; |
---|
1815 | (void) sm_strlcpy(bp, exp, s - (bp - buf)); |
---|
1816 | bp += strlen(bp) + 1; |
---|
1817 | } |
---|
1818 | (void) milter_write(m, SMFIC_MACRO, buf, s, |
---|
1819 | m->mf_timeout[SMFTO_WRITE], e); |
---|
1820 | sm_free(buf); /* XXX */ |
---|
1821 | } |
---|
1822 | |
---|
1823 | /* |
---|
1824 | ** MILTER_SEND_COMMAND -- send a command and return the response for a filter |
---|
1825 | ** |
---|
1826 | ** Parameters: |
---|
1827 | ** m -- current milter filter |
---|
1828 | ** command -- command to send. |
---|
1829 | ** data -- optional command data. |
---|
1830 | ** sz -- length of buf. |
---|
1831 | ** e -- current envelope (for e->e_id). |
---|
1832 | ** state -- return state word. |
---|
1833 | ** |
---|
1834 | ** Returns: |
---|
1835 | ** response string (may be NULL) |
---|
1836 | */ |
---|
1837 | |
---|
1838 | static char * |
---|
1839 | milter_send_command(m, command, data, sz, e, state) |
---|
1840 | struct milter *m; |
---|
1841 | char command; |
---|
1842 | void *data; |
---|
1843 | ssize_t sz; |
---|
1844 | ENVELOPE *e; |
---|
1845 | char *state; |
---|
1846 | { |
---|
1847 | char rcmd; |
---|
1848 | ssize_t rlen; |
---|
1849 | unsigned long skipflag; |
---|
1850 | char *action; |
---|
1851 | char *defresponse; |
---|
1852 | char *response; |
---|
1853 | |
---|
1854 | if (tTd(64, 10)) |
---|
1855 | sm_dprintf("milter_send_command(%s): cmd %c len %ld\n", |
---|
1856 | m->mf_name, (char) command, (long) sz); |
---|
1857 | |
---|
1858 | /* find skip flag and default failure */ |
---|
1859 | switch (command) |
---|
1860 | { |
---|
1861 | case SMFIC_CONNECT: |
---|
1862 | skipflag = SMFIP_NOCONNECT; |
---|
1863 | action = "connect"; |
---|
1864 | defresponse = "554 Command rejected"; |
---|
1865 | break; |
---|
1866 | |
---|
1867 | case SMFIC_HELO: |
---|
1868 | skipflag = SMFIP_NOHELO; |
---|
1869 | action = "helo"; |
---|
1870 | defresponse = "550 Command rejected"; |
---|
1871 | break; |
---|
1872 | |
---|
1873 | case SMFIC_MAIL: |
---|
1874 | skipflag = SMFIP_NOMAIL; |
---|
1875 | action = "mail"; |
---|
1876 | defresponse = "550 5.7.1 Command rejected"; |
---|
1877 | break; |
---|
1878 | |
---|
1879 | case SMFIC_RCPT: |
---|
1880 | skipflag = SMFIP_NORCPT; |
---|
1881 | action = "rcpt"; |
---|
1882 | defresponse = "550 5.7.1 Command rejected"; |
---|
1883 | break; |
---|
1884 | |
---|
1885 | case SMFIC_HEADER: |
---|
1886 | skipflag = SMFIP_NOHDRS; |
---|
1887 | action = "header"; |
---|
1888 | defresponse = "550 5.7.1 Command rejected"; |
---|
1889 | break; |
---|
1890 | |
---|
1891 | case SMFIC_BODY: |
---|
1892 | skipflag = SMFIP_NOBODY; |
---|
1893 | action = "body"; |
---|
1894 | defresponse = "554 5.7.1 Command rejected"; |
---|
1895 | break; |
---|
1896 | |
---|
1897 | case SMFIC_EOH: |
---|
1898 | skipflag = SMFIP_NOEOH; |
---|
1899 | action = "eoh"; |
---|
1900 | defresponse = "550 5.7.1 Command rejected"; |
---|
1901 | break; |
---|
1902 | |
---|
1903 | case SMFIC_BODYEOB: |
---|
1904 | case SMFIC_OPTNEG: |
---|
1905 | case SMFIC_MACRO: |
---|
1906 | case SMFIC_ABORT: |
---|
1907 | case SMFIC_QUIT: |
---|
1908 | /* NOTE: not handled by milter_send_command() */ |
---|
1909 | /* FALLTHROUGH */ |
---|
1910 | |
---|
1911 | default: |
---|
1912 | skipflag = 0; |
---|
1913 | action = "default"; |
---|
1914 | defresponse = "550 5.7.1 Command rejected"; |
---|
1915 | break; |
---|
1916 | } |
---|
1917 | |
---|
1918 | /* check if filter wants this command */ |
---|
1919 | if (skipflag != 0 && |
---|
1920 | bitset(skipflag, m->mf_pflags)) |
---|
1921 | return NULL; |
---|
1922 | |
---|
1923 | /* send the command to the filter */ |
---|
1924 | (void) milter_write(m, command, data, sz, |
---|
1925 | m->mf_timeout[SMFTO_WRITE], e); |
---|
1926 | if (m->mf_state == SMFS_ERROR) |
---|
1927 | { |
---|
1928 | MILTER_CHECK_ERROR(false, return NULL); |
---|
1929 | return NULL; |
---|
1930 | } |
---|
1931 | |
---|
1932 | /* get the response from the filter */ |
---|
1933 | response = milter_read(m, &rcmd, &rlen, |
---|
1934 | m->mf_timeout[SMFTO_READ], e); |
---|
1935 | if (m->mf_state == SMFS_ERROR) |
---|
1936 | { |
---|
1937 | MILTER_CHECK_ERROR(false, return NULL); |
---|
1938 | return NULL; |
---|
1939 | } |
---|
1940 | |
---|
1941 | if (tTd(64, 10)) |
---|
1942 | sm_dprintf("milter_send_command(%s): returned %c\n", |
---|
1943 | m->mf_name, (char) rcmd); |
---|
1944 | |
---|
1945 | switch (rcmd) |
---|
1946 | { |
---|
1947 | case SMFIR_REPLYCODE: |
---|
1948 | MILTER_CHECK_REPLYCODE(defresponse); |
---|
1949 | if (MilterLogLevel > 10) |
---|
1950 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject=%s", |
---|
1951 | m->mf_name, action, response); |
---|
1952 | *state = rcmd; |
---|
1953 | break; |
---|
1954 | |
---|
1955 | case SMFIR_REJECT: |
---|
1956 | if (MilterLogLevel > 10) |
---|
1957 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject", |
---|
1958 | m->mf_name, action); |
---|
1959 | *state = rcmd; |
---|
1960 | break; |
---|
1961 | |
---|
1962 | case SMFIR_DISCARD: |
---|
1963 | if (MilterLogLevel > 10) |
---|
1964 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, discard", |
---|
1965 | m->mf_name, action); |
---|
1966 | *state = rcmd; |
---|
1967 | break; |
---|
1968 | |
---|
1969 | case SMFIR_TEMPFAIL: |
---|
1970 | if (MilterLogLevel > 10) |
---|
1971 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, tempfail", |
---|
1972 | m->mf_name, action); |
---|
1973 | *state = rcmd; |
---|
1974 | break; |
---|
1975 | |
---|
1976 | case SMFIR_ACCEPT: |
---|
1977 | /* this filter is done with message/connection */ |
---|
1978 | if (command == SMFIC_HELO || |
---|
1979 | command == SMFIC_CONNECT) |
---|
1980 | m->mf_state = SMFS_CLOSABLE; |
---|
1981 | else |
---|
1982 | m->mf_state = SMFS_DONE; |
---|
1983 | if (MilterLogLevel > 10) |
---|
1984 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, accepted", |
---|
1985 | m->mf_name, action); |
---|
1986 | break; |
---|
1987 | |
---|
1988 | case SMFIR_CONTINUE: |
---|
1989 | /* if MAIL command is ok, filter is in message state */ |
---|
1990 | if (command == SMFIC_MAIL) |
---|
1991 | m->mf_state = SMFS_INMSG; |
---|
1992 | if (MilterLogLevel > 12) |
---|
1993 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, continue", |
---|
1994 | m->mf_name, action); |
---|
1995 | break; |
---|
1996 | |
---|
1997 | default: |
---|
1998 | /* Invalid response to command */ |
---|
1999 | if (MilterLogLevel > 0) |
---|
2000 | sm_syslog(LOG_ERR, e->e_id, |
---|
2001 | "milter_send_command(%s): action=%s returned bogus response %c", |
---|
2002 | m->mf_name, action, rcmd); |
---|
2003 | milter_error(m, e); |
---|
2004 | break; |
---|
2005 | } |
---|
2006 | |
---|
2007 | if (*state != SMFIR_REPLYCODE && |
---|
2008 | response != NULL) |
---|
2009 | { |
---|
2010 | sm_free(response); /* XXX */ |
---|
2011 | response = NULL; |
---|
2012 | } |
---|
2013 | return response; |
---|
2014 | } |
---|
2015 | |
---|
2016 | /* |
---|
2017 | ** MILTER_COMMAND -- send a command and return the response for each filter |
---|
2018 | ** |
---|
2019 | ** Parameters: |
---|
2020 | ** command -- command to send. |
---|
2021 | ** data -- optional command data. |
---|
2022 | ** sz -- length of buf. |
---|
2023 | ** macros -- macros to send for filter smfi_getsymval(). |
---|
2024 | ** e -- current envelope (for macro access). |
---|
2025 | ** state -- return state word. |
---|
2026 | ** |
---|
2027 | ** Returns: |
---|
2028 | ** response string (may be NULL) |
---|
2029 | */ |
---|
2030 | |
---|
2031 | static char * |
---|
2032 | milter_command(command, data, sz, macros, e, state) |
---|
2033 | char command; |
---|
2034 | void *data; |
---|
2035 | ssize_t sz; |
---|
2036 | char **macros; |
---|
2037 | ENVELOPE *e; |
---|
2038 | char *state; |
---|
2039 | { |
---|
2040 | int i; |
---|
2041 | char *response = NULL; |
---|
2042 | time_t tn = 0; |
---|
2043 | |
---|
2044 | if (tTd(64, 10)) |
---|
2045 | sm_dprintf("milter_command: cmd %c len %ld\n", |
---|
2046 | (char) command, (long) sz); |
---|
2047 | |
---|
2048 | *state = SMFIR_CONTINUE; |
---|
2049 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
2050 | { |
---|
2051 | struct milter *m = InputFilters[i]; |
---|
2052 | |
---|
2053 | /* previous problem? */ |
---|
2054 | if (m->mf_state == SMFS_ERROR) |
---|
2055 | { |
---|
2056 | MILTER_CHECK_ERROR(false, continue); |
---|
2057 | break; |
---|
2058 | } |
---|
2059 | |
---|
2060 | /* sanity check */ |
---|
2061 | if (m->mf_sock < 0 || |
---|
2062 | (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) |
---|
2063 | continue; |
---|
2064 | |
---|
2065 | /* send macros (regardless of whether we send command) */ |
---|
2066 | if (macros != NULL && macros[0] != NULL) |
---|
2067 | { |
---|
2068 | milter_send_macros(m, macros, command, e); |
---|
2069 | if (m->mf_state == SMFS_ERROR) |
---|
2070 | { |
---|
2071 | MILTER_CHECK_ERROR(false, continue); |
---|
2072 | break; |
---|
2073 | } |
---|
2074 | } |
---|
2075 | |
---|
2076 | if (MilterLogLevel > 21) |
---|
2077 | tn = curtime(); |
---|
2078 | |
---|
2079 | response = milter_send_command(m, command, data, sz, e, state); |
---|
2080 | |
---|
2081 | if (MilterLogLevel > 21) |
---|
2082 | { |
---|
2083 | /* log the time it took for the command per filter */ |
---|
2084 | sm_syslog(LOG_INFO, e->e_id, |
---|
2085 | "Milter (%s): time command (%c), %d", |
---|
2086 | m->mf_name, command, (int) (tn - curtime())); |
---|
2087 | } |
---|
2088 | |
---|
2089 | if (*state != SMFIR_CONTINUE) |
---|
2090 | break; |
---|
2091 | } |
---|
2092 | return response; |
---|
2093 | } |
---|
2094 | /* |
---|
2095 | ** MILTER_NEGOTIATE -- get version and flags from filter |
---|
2096 | ** |
---|
2097 | ** Parameters: |
---|
2098 | ** m -- milter filter structure. |
---|
2099 | ** e -- current envelope. |
---|
2100 | ** |
---|
2101 | ** Returns: |
---|
2102 | ** 0 on success, -1 otherwise |
---|
2103 | */ |
---|
2104 | |
---|
2105 | static int |
---|
2106 | milter_negotiate(m, e) |
---|
2107 | struct milter *m; |
---|
2108 | ENVELOPE *e; |
---|
2109 | { |
---|
2110 | char rcmd; |
---|
2111 | mi_int32 fvers; |
---|
2112 | mi_int32 fflags; |
---|
2113 | mi_int32 pflags; |
---|
2114 | char *response; |
---|
2115 | ssize_t rlen; |
---|
2116 | char data[MILTER_OPTLEN]; |
---|
2117 | |
---|
2118 | /* sanity check */ |
---|
2119 | if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN) |
---|
2120 | { |
---|
2121 | if (MilterLogLevel > 0) |
---|
2122 | sm_syslog(LOG_ERR, e->e_id, |
---|
2123 | "Milter (%s): negotiate, impossible state", |
---|
2124 | m->mf_name); |
---|
2125 | milter_error(m, e); |
---|
2126 | return -1; |
---|
2127 | } |
---|
2128 | |
---|
2129 | fvers = htonl(SMFI_VERSION); |
---|
2130 | fflags = htonl(SMFI_CURR_ACTS); |
---|
2131 | pflags = htonl(SMFI_CURR_PROT); |
---|
2132 | (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES); |
---|
2133 | (void) memcpy(data + MILTER_LEN_BYTES, |
---|
2134 | (char *) &fflags, MILTER_LEN_BYTES); |
---|
2135 | (void) memcpy(data + (MILTER_LEN_BYTES * 2), |
---|
2136 | (char *) &pflags, MILTER_LEN_BYTES); |
---|
2137 | (void) milter_write(m, SMFIC_OPTNEG, data, sizeof data, |
---|
2138 | m->mf_timeout[SMFTO_WRITE], e); |
---|
2139 | |
---|
2140 | if (m->mf_state == SMFS_ERROR) |
---|
2141 | return -1; |
---|
2142 | |
---|
2143 | response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e); |
---|
2144 | if (m->mf_state == SMFS_ERROR) |
---|
2145 | return -1; |
---|
2146 | |
---|
2147 | if (rcmd != SMFIC_OPTNEG) |
---|
2148 | { |
---|
2149 | if (tTd(64, 5)) |
---|
2150 | sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n", |
---|
2151 | m->mf_name, rcmd, SMFIC_OPTNEG); |
---|
2152 | if (MilterLogLevel > 0) |
---|
2153 | sm_syslog(LOG_ERR, e->e_id, |
---|
2154 | "Milter (%s): negotiate: returned %c instead of %c", |
---|
2155 | m->mf_name, rcmd, SMFIC_OPTNEG); |
---|
2156 | if (response != NULL) |
---|
2157 | sm_free(response); /* XXX */ |
---|
2158 | milter_error(m, e); |
---|
2159 | return -1; |
---|
2160 | } |
---|
2161 | |
---|
2162 | /* Make sure we have enough bytes for the version */ |
---|
2163 | if (response == NULL || rlen < MILTER_LEN_BYTES) |
---|
2164 | { |
---|
2165 | if (tTd(64, 5)) |
---|
2166 | sm_dprintf("milter_negotiate(%s): did not return valid info\n", |
---|
2167 | m->mf_name); |
---|
2168 | if (MilterLogLevel > 0) |
---|
2169 | sm_syslog(LOG_ERR, e->e_id, |
---|
2170 | "Milter (%s): negotiate: did not return valid info", |
---|
2171 | m->mf_name); |
---|
2172 | if (response != NULL) |
---|
2173 | sm_free(response); /* XXX */ |
---|
2174 | milter_error(m, e); |
---|
2175 | return -1; |
---|
2176 | } |
---|
2177 | |
---|
2178 | /* extract information */ |
---|
2179 | (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES); |
---|
2180 | |
---|
2181 | /* Now make sure we have enough for the feature bitmap */ |
---|
2182 | if (rlen != MILTER_OPTLEN) |
---|
2183 | { |
---|
2184 | if (tTd(64, 5)) |
---|
2185 | sm_dprintf("milter_negotiate(%s): did not return enough info\n", |
---|
2186 | m->mf_name); |
---|
2187 | if (MilterLogLevel > 0) |
---|
2188 | sm_syslog(LOG_ERR, e->e_id, |
---|
2189 | "Milter (%s): negotiate: did not return enough info", |
---|
2190 | m->mf_name); |
---|
2191 | if (response != NULL) |
---|
2192 | sm_free(response); /* XXX */ |
---|
2193 | milter_error(m, e); |
---|
2194 | return -1; |
---|
2195 | } |
---|
2196 | |
---|
2197 | (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, |
---|
2198 | MILTER_LEN_BYTES); |
---|
2199 | (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), |
---|
2200 | MILTER_LEN_BYTES); |
---|
2201 | sm_free(response); /* XXX */ |
---|
2202 | response = NULL; |
---|
2203 | |
---|
2204 | m->mf_fvers = ntohl(fvers); |
---|
2205 | m->mf_fflags = ntohl(fflags); |
---|
2206 | m->mf_pflags = ntohl(pflags); |
---|
2207 | |
---|
2208 | /* check for version compatibility */ |
---|
2209 | if (m->mf_fvers == 1 || |
---|
2210 | m->mf_fvers > SMFI_VERSION) |
---|
2211 | { |
---|
2212 | if (tTd(64, 5)) |
---|
2213 | sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n", |
---|
2214 | m->mf_name, m->mf_fvers, SMFI_VERSION); |
---|
2215 | if (MilterLogLevel > 0) |
---|
2216 | sm_syslog(LOG_ERR, e->e_id, |
---|
2217 | "Milter (%s): negotiate: version %d != MTA milter version %d", |
---|
2218 | m->mf_name, m->mf_fvers, SMFI_VERSION); |
---|
2219 | milter_error(m, e); |
---|
2220 | return -1; |
---|
2221 | } |
---|
2222 | |
---|
2223 | /* check for filter feature mismatch */ |
---|
2224 | if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags) |
---|
2225 | { |
---|
2226 | if (tTd(64, 5)) |
---|
2227 | sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n", |
---|
2228 | m->mf_name, m->mf_fflags, |
---|
2229 | SMFI_CURR_ACTS); |
---|
2230 | if (MilterLogLevel > 0) |
---|
2231 | sm_syslog(LOG_ERR, e->e_id, |
---|
2232 | "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx", |
---|
2233 | m->mf_name, m->mf_fflags, |
---|
2234 | (unsigned long) SMFI_CURR_ACTS); |
---|
2235 | milter_error(m, e); |
---|
2236 | return -1; |
---|
2237 | } |
---|
2238 | |
---|
2239 | /* check for protocol feature mismatch */ |
---|
2240 | if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags) |
---|
2241 | { |
---|
2242 | if (tTd(64, 5)) |
---|
2243 | sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n", |
---|
2244 | m->mf_name, m->mf_pflags, |
---|
2245 | (unsigned long) SMFI_CURR_PROT); |
---|
2246 | if (MilterLogLevel > 0) |
---|
2247 | sm_syslog(LOG_ERR, e->e_id, |
---|
2248 | "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx", |
---|
2249 | m->mf_name, m->mf_pflags, |
---|
2250 | (unsigned long) SMFI_CURR_PROT); |
---|
2251 | milter_error(m, e); |
---|
2252 | return -1; |
---|
2253 | } |
---|
2254 | |
---|
2255 | if (tTd(64, 5)) |
---|
2256 | sm_dprintf("milter_negotiate(%s): version %u, fflags 0x%x, pflags 0x%x\n", |
---|
2257 | m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags); |
---|
2258 | return 0; |
---|
2259 | } |
---|
2260 | /* |
---|
2261 | ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands |
---|
2262 | ** |
---|
2263 | ** Reduce code duplication by putting these checks in one place |
---|
2264 | ** |
---|
2265 | ** Parameters: |
---|
2266 | ** e -- current envelope. |
---|
2267 | ** |
---|
2268 | ** Returns: |
---|
2269 | ** none |
---|
2270 | */ |
---|
2271 | |
---|
2272 | static void |
---|
2273 | milter_per_connection_check(e) |
---|
2274 | ENVELOPE *e; |
---|
2275 | { |
---|
2276 | int i; |
---|
2277 | |
---|
2278 | /* see if we are done with any of the filters */ |
---|
2279 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
2280 | { |
---|
2281 | struct milter *m = InputFilters[i]; |
---|
2282 | |
---|
2283 | if (m->mf_state == SMFS_CLOSABLE) |
---|
2284 | milter_quit_filter(m, e); |
---|
2285 | } |
---|
2286 | } |
---|
2287 | /* |
---|
2288 | ** MILTER_ERROR -- Put a milter filter into error state |
---|
2289 | ** |
---|
2290 | ** Parameters: |
---|
2291 | ** m -- the broken filter. |
---|
2292 | ** |
---|
2293 | ** Returns: |
---|
2294 | ** none |
---|
2295 | */ |
---|
2296 | |
---|
2297 | static void |
---|
2298 | milter_error(m, e) |
---|
2299 | struct milter *m; |
---|
2300 | ENVELOPE *e; |
---|
2301 | { |
---|
2302 | /* |
---|
2303 | ** We could send a quit here but |
---|
2304 | ** we may have gotten here due to |
---|
2305 | ** an I/O error so we don't want |
---|
2306 | ** to try to make things worse. |
---|
2307 | */ |
---|
2308 | |
---|
2309 | if (m->mf_sock >= 0) |
---|
2310 | { |
---|
2311 | (void) close(m->mf_sock); |
---|
2312 | m->mf_sock = -1; |
---|
2313 | } |
---|
2314 | m->mf_state = SMFS_ERROR; |
---|
2315 | |
---|
2316 | if (MilterLogLevel > 0) |
---|
2317 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state", |
---|
2318 | m->mf_name); |
---|
2319 | } |
---|
2320 | /* |
---|
2321 | ** MILTER_HEADERS -- send headers to a single milter filter |
---|
2322 | ** |
---|
2323 | ** Parameters: |
---|
2324 | ** m -- current filter. |
---|
2325 | ** e -- current envelope. |
---|
2326 | ** state -- return state from response. |
---|
2327 | ** |
---|
2328 | ** Returns: |
---|
2329 | ** response string (may be NULL) |
---|
2330 | */ |
---|
2331 | |
---|
2332 | static char * |
---|
2333 | milter_headers(m, e, state) |
---|
2334 | struct milter *m; |
---|
2335 | ENVELOPE *e; |
---|
2336 | char *state; |
---|
2337 | { |
---|
2338 | char *response = NULL; |
---|
2339 | HDR *h; |
---|
2340 | |
---|
2341 | if (MilterLogLevel > 17) |
---|
2342 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send", |
---|
2343 | m->mf_name); |
---|
2344 | |
---|
2345 | for (h = e->e_header; h != NULL; h = h->h_link) |
---|
2346 | { |
---|
2347 | char *buf; |
---|
2348 | ssize_t s; |
---|
2349 | |
---|
2350 | /* don't send over deleted headers */ |
---|
2351 | if (h->h_value == NULL) |
---|
2352 | { |
---|
2353 | /* strip H_USER so not counted in milter_chgheader() */ |
---|
2354 | h->h_flags &= ~H_USER; |
---|
2355 | continue; |
---|
2356 | } |
---|
2357 | |
---|
2358 | /* skip auto-generated */ |
---|
2359 | if (!bitset(H_USER, h->h_flags)) |
---|
2360 | continue; |
---|
2361 | |
---|
2362 | if (tTd(64, 10)) |
---|
2363 | sm_dprintf("milter_headers: %s: %s\n", |
---|
2364 | h->h_field, h->h_value); |
---|
2365 | if (MilterLogLevel > 21) |
---|
2366 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s", |
---|
2367 | m->mf_name, h->h_field); |
---|
2368 | |
---|
2369 | s = strlen(h->h_field) + 1 + strlen(h->h_value) + 1; |
---|
2370 | if (s < 0) |
---|
2371 | continue; |
---|
2372 | buf = (char *) xalloc(s); |
---|
2373 | (void) sm_snprintf(buf, s, "%s%c%s", |
---|
2374 | h->h_field, '\0', h->h_value); |
---|
2375 | |
---|
2376 | /* send it over */ |
---|
2377 | response = milter_send_command(m, SMFIC_HEADER, buf, |
---|
2378 | s, e, state); |
---|
2379 | sm_free(buf); /* XXX */ |
---|
2380 | if (m->mf_state == SMFS_ERROR || |
---|
2381 | m->mf_state == SMFS_DONE || |
---|
2382 | *state != SMFIR_CONTINUE) |
---|
2383 | break; |
---|
2384 | } |
---|
2385 | if (MilterLogLevel > 17) |
---|
2386 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent", |
---|
2387 | m->mf_name); |
---|
2388 | return response; |
---|
2389 | } |
---|
2390 | /* |
---|
2391 | ** MILTER_BODY -- send the body to a filter |
---|
2392 | ** |
---|
2393 | ** Parameters: |
---|
2394 | ** m -- current filter. |
---|
2395 | ** e -- current envelope. |
---|
2396 | ** state -- return state from response. |
---|
2397 | ** |
---|
2398 | ** Returns: |
---|
2399 | ** response string (may be NULL) |
---|
2400 | */ |
---|
2401 | |
---|
2402 | static char * |
---|
2403 | milter_body(m, e, state) |
---|
2404 | struct milter *m; |
---|
2405 | ENVELOPE *e; |
---|
2406 | char *state; |
---|
2407 | { |
---|
2408 | char bufchar = '\0'; |
---|
2409 | char prevchar = '\0'; |
---|
2410 | int c; |
---|
2411 | char *response = NULL; |
---|
2412 | char *bp; |
---|
2413 | char buf[MILTER_CHUNK_SIZE]; |
---|
2414 | |
---|
2415 | if (tTd(64, 10)) |
---|
2416 | sm_dprintf("milter_body\n"); |
---|
2417 | |
---|
2418 | if (bfrewind(e->e_dfp) < 0) |
---|
2419 | { |
---|
2420 | ExitStat = EX_IOERR; |
---|
2421 | *state = SMFIR_TEMPFAIL; |
---|
2422 | syserr("milter_body: %s/%cf%s: rewind error", |
---|
2423 | qid_printqueue(e->e_qgrp, e->e_qdir), |
---|
2424 | DATAFL_LETTER, e->e_id); |
---|
2425 | return NULL; |
---|
2426 | } |
---|
2427 | |
---|
2428 | if (MilterLogLevel > 17) |
---|
2429 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send", |
---|
2430 | m->mf_name); |
---|
2431 | bp = buf; |
---|
2432 | while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF) |
---|
2433 | { |
---|
2434 | /* Change LF to CRLF */ |
---|
2435 | if (c == '\n') |
---|
2436 | { |
---|
2437 | /* Not a CRLF already? */ |
---|
2438 | if (prevchar != '\r') |
---|
2439 | { |
---|
2440 | /* Room for CR now? */ |
---|
2441 | if (bp + 2 > &buf[sizeof buf]) |
---|
2442 | { |
---|
2443 | /* No room, buffer LF */ |
---|
2444 | bufchar = c; |
---|
2445 | |
---|
2446 | /* and send CR now */ |
---|
2447 | c = '\r'; |
---|
2448 | } |
---|
2449 | else |
---|
2450 | { |
---|
2451 | /* Room to do it now */ |
---|
2452 | *bp++ = '\r'; |
---|
2453 | prevchar = '\r'; |
---|
2454 | } |
---|
2455 | } |
---|
2456 | } |
---|
2457 | *bp++ = (char) c; |
---|
2458 | prevchar = c; |
---|
2459 | if (bp >= &buf[sizeof buf]) |
---|
2460 | { |
---|
2461 | /* send chunk */ |
---|
2462 | response = milter_send_command(m, SMFIC_BODY, buf, |
---|
2463 | bp - buf, e, state); |
---|
2464 | bp = buf; |
---|
2465 | if (bufchar != '\0') |
---|
2466 | { |
---|
2467 | *bp++ = bufchar; |
---|
2468 | bufchar = '\0'; |
---|
2469 | prevchar = bufchar; |
---|
2470 | } |
---|
2471 | } |
---|
2472 | if (m->mf_state == SMFS_ERROR || |
---|
2473 | m->mf_state == SMFS_DONE || |
---|
2474 | *state != SMFIR_CONTINUE) |
---|
2475 | break; |
---|
2476 | } |
---|
2477 | |
---|
2478 | /* check for read errors */ |
---|
2479 | if (sm_io_error(e->e_dfp)) |
---|
2480 | { |
---|
2481 | ExitStat = EX_IOERR; |
---|
2482 | if (*state == SMFIR_CONTINUE || |
---|
2483 | *state == SMFIR_ACCEPT) |
---|
2484 | { |
---|
2485 | *state = SMFIR_TEMPFAIL; |
---|
2486 | if (response != NULL) |
---|
2487 | { |
---|
2488 | sm_free(response); /* XXX */ |
---|
2489 | response = NULL; |
---|
2490 | } |
---|
2491 | } |
---|
2492 | syserr("milter_body: %s/%cf%s: read error", |
---|
2493 | qid_printqueue(e->e_qgrp, e->e_qdir), |
---|
2494 | DATAFL_LETTER, e->e_id); |
---|
2495 | return response; |
---|
2496 | } |
---|
2497 | |
---|
2498 | /* send last body chunk */ |
---|
2499 | if (bp > buf && |
---|
2500 | m->mf_state != SMFS_ERROR && |
---|
2501 | m->mf_state != SMFS_DONE && |
---|
2502 | *state == SMFIR_CONTINUE) |
---|
2503 | { |
---|
2504 | /* send chunk */ |
---|
2505 | response = milter_send_command(m, SMFIC_BODY, buf, bp - buf, |
---|
2506 | e, state); |
---|
2507 | bp = buf; |
---|
2508 | } |
---|
2509 | if (MilterLogLevel > 17) |
---|
2510 | sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent", |
---|
2511 | m->mf_name); |
---|
2512 | return response; |
---|
2513 | } |
---|
2514 | |
---|
2515 | /* |
---|
2516 | ** Actions |
---|
2517 | */ |
---|
2518 | |
---|
2519 | /* |
---|
2520 | ** MILTER_ADDHEADER -- Add the supplied header to the message |
---|
2521 | ** |
---|
2522 | ** Parameters: |
---|
2523 | ** response -- encoded form of header/value. |
---|
2524 | ** rlen -- length of response. |
---|
2525 | ** e -- current envelope. |
---|
2526 | ** |
---|
2527 | ** Returns: |
---|
2528 | ** none |
---|
2529 | */ |
---|
2530 | |
---|
2531 | static void |
---|
2532 | milter_addheader(response, rlen, e) |
---|
2533 | char *response; |
---|
2534 | ssize_t rlen; |
---|
2535 | ENVELOPE *e; |
---|
2536 | { |
---|
2537 | char *val; |
---|
2538 | HDR *h; |
---|
2539 | |
---|
2540 | if (tTd(64, 10)) |
---|
2541 | sm_dprintf("milter_addheader: "); |
---|
2542 | |
---|
2543 | /* sanity checks */ |
---|
2544 | if (response == NULL) |
---|
2545 | { |
---|
2546 | if (tTd(64, 10)) |
---|
2547 | sm_dprintf("NULL response\n"); |
---|
2548 | return; |
---|
2549 | } |
---|
2550 | |
---|
2551 | if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) |
---|
2552 | { |
---|
2553 | if (tTd(64, 10)) |
---|
2554 | sm_dprintf("didn't follow protocol (total len)\n"); |
---|
2555 | return; |
---|
2556 | } |
---|
2557 | |
---|
2558 | /* Find separating NUL */ |
---|
2559 | val = response + strlen(response) + 1; |
---|
2560 | |
---|
2561 | /* another sanity check */ |
---|
2562 | if (strlen(response) + strlen(val) + 2 != (size_t) rlen) |
---|
2563 | { |
---|
2564 | if (tTd(64, 10)) |
---|
2565 | sm_dprintf("didn't follow protocol (part len)\n"); |
---|
2566 | return; |
---|
2567 | } |
---|
2568 | |
---|
2569 | if (*response == '\0') |
---|
2570 | { |
---|
2571 | if (tTd(64, 10)) |
---|
2572 | sm_dprintf("empty field name\n"); |
---|
2573 | return; |
---|
2574 | } |
---|
2575 | |
---|
2576 | for (h = e->e_header; h != NULL; h = h->h_link) |
---|
2577 | { |
---|
2578 | if (sm_strcasecmp(h->h_field, response) == 0 && |
---|
2579 | !bitset(H_USER, h->h_flags) && |
---|
2580 | !bitset(H_TRACE, h->h_flags)) |
---|
2581 | break; |
---|
2582 | } |
---|
2583 | |
---|
2584 | /* add to e_msgsize */ |
---|
2585 | e->e_msgsize += strlen(response) + 2 + strlen(val); |
---|
2586 | |
---|
2587 | if (h != NULL) |
---|
2588 | { |
---|
2589 | if (tTd(64, 10)) |
---|
2590 | sm_dprintf("Replace default header %s value with %s\n", |
---|
2591 | h->h_field, val); |
---|
2592 | if (MilterLogLevel > 8) |
---|
2593 | sm_syslog(LOG_INFO, e->e_id, |
---|
2594 | "Milter change: default header %s value with %s", |
---|
2595 | h->h_field, val); |
---|
2596 | h->h_value = newstr(val); |
---|
2597 | h->h_flags |= H_USER; |
---|
2598 | } |
---|
2599 | else |
---|
2600 | { |
---|
2601 | if (tTd(64, 10)) |
---|
2602 | sm_dprintf("Add %s: %s\n", response, val); |
---|
2603 | if (MilterLogLevel > 8) |
---|
2604 | sm_syslog(LOG_INFO, e->e_id, "Milter add: header: %s: %s", |
---|
2605 | response, val); |
---|
2606 | addheader(newstr(response), val, H_USER, e); |
---|
2607 | } |
---|
2608 | } |
---|
2609 | /* |
---|
2610 | ** MILTER_CHANGEHEADER -- Change the supplied header in the message |
---|
2611 | ** |
---|
2612 | ** Parameters: |
---|
2613 | ** response -- encoded form of header/index/value. |
---|
2614 | ** rlen -- length of response. |
---|
2615 | ** e -- current envelope. |
---|
2616 | ** |
---|
2617 | ** Returns: |
---|
2618 | ** none |
---|
2619 | */ |
---|
2620 | |
---|
2621 | static void |
---|
2622 | milter_changeheader(response, rlen, e) |
---|
2623 | char *response; |
---|
2624 | ssize_t rlen; |
---|
2625 | ENVELOPE *e; |
---|
2626 | { |
---|
2627 | mi_int32 i, index; |
---|
2628 | char *field, *val; |
---|
2629 | HDR *h, *sysheader; |
---|
2630 | |
---|
2631 | if (tTd(64, 10)) |
---|
2632 | sm_dprintf("milter_changeheader: "); |
---|
2633 | |
---|
2634 | /* sanity checks */ |
---|
2635 | if (response == NULL) |
---|
2636 | { |
---|
2637 | if (tTd(64, 10)) |
---|
2638 | sm_dprintf("NULL response\n"); |
---|
2639 | return; |
---|
2640 | } |
---|
2641 | |
---|
2642 | if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) |
---|
2643 | { |
---|
2644 | if (tTd(64, 10)) |
---|
2645 | sm_dprintf("didn't follow protocol (total len)\n"); |
---|
2646 | return; |
---|
2647 | } |
---|
2648 | |
---|
2649 | /* Find separating NUL */ |
---|
2650 | (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); |
---|
2651 | index = ntohl(i); |
---|
2652 | field = response + MILTER_LEN_BYTES; |
---|
2653 | val = field + strlen(field) + 1; |
---|
2654 | |
---|
2655 | /* another sanity check */ |
---|
2656 | if (MILTER_LEN_BYTES + strlen(field) + 1 + |
---|
2657 | strlen(val) + 1 != (size_t) rlen) |
---|
2658 | { |
---|
2659 | if (tTd(64, 10)) |
---|
2660 | sm_dprintf("didn't follow protocol (part len)\n"); |
---|
2661 | return; |
---|
2662 | } |
---|
2663 | |
---|
2664 | if (*field == '\0') |
---|
2665 | { |
---|
2666 | if (tTd(64, 10)) |
---|
2667 | sm_dprintf("empty field name\n"); |
---|
2668 | return; |
---|
2669 | } |
---|
2670 | |
---|
2671 | sysheader = NULL; |
---|
2672 | for (h = e->e_header; h != NULL; h = h->h_link) |
---|
2673 | { |
---|
2674 | if (sm_strcasecmp(h->h_field, field) == 0) |
---|
2675 | { |
---|
2676 | if (bitset(H_USER, h->h_flags) && |
---|
2677 | --index <= 0) |
---|
2678 | { |
---|
2679 | sysheader = NULL; |
---|
2680 | break; |
---|
2681 | } |
---|
2682 | else if (!bitset(H_USER, h->h_flags) && |
---|
2683 | !bitset(H_TRACE, h->h_flags)) |
---|
2684 | { |
---|
2685 | /* |
---|
2686 | ** DRUMS msg-fmt draft says can only have |
---|
2687 | ** multiple occurences of trace fields, |
---|
2688 | ** so make sure we replace any non-trace, |
---|
2689 | ** non-user field. |
---|
2690 | */ |
---|
2691 | |
---|
2692 | sysheader = h; |
---|
2693 | } |
---|
2694 | } |
---|
2695 | } |
---|
2696 | |
---|
2697 | /* if not found as user-provided header at index, use sysheader */ |
---|
2698 | if (h == NULL) |
---|
2699 | h = sysheader; |
---|
2700 | |
---|
2701 | if (h == NULL) |
---|
2702 | { |
---|
2703 | if (*val == '\0') |
---|
2704 | { |
---|
2705 | if (tTd(64, 10)) |
---|
2706 | sm_dprintf("Delete (noop) %s:\n", field); |
---|
2707 | } |
---|
2708 | else |
---|
2709 | { |
---|
2710 | /* treat modify value with no existing header as add */ |
---|
2711 | if (tTd(64, 10)) |
---|
2712 | sm_dprintf("Add %s: %s\n", field, val); |
---|
2713 | addheader(newstr(field), val, H_USER, e); |
---|
2714 | } |
---|
2715 | return; |
---|
2716 | } |
---|
2717 | |
---|
2718 | if (tTd(64, 10)) |
---|
2719 | { |
---|
2720 | if (*val == '\0') |
---|
2721 | { |
---|
2722 | sm_dprintf("Delete%s %s: %s\n", |
---|
2723 | h == sysheader ? " (default header)" : "", |
---|
2724 | field, |
---|
2725 | h->h_value == NULL ? "<NULL>" : h->h_value); |
---|
2726 | } |
---|
2727 | else |
---|
2728 | { |
---|
2729 | sm_dprintf("Change%s %s: from %s to %s\n", |
---|
2730 | h == sysheader ? " (default header)" : "", |
---|
2731 | field, |
---|
2732 | h->h_value == NULL ? "<NULL>" : h->h_value, |
---|
2733 | val); |
---|
2734 | } |
---|
2735 | } |
---|
2736 | |
---|
2737 | if (MilterLogLevel > 8) |
---|
2738 | { |
---|
2739 | if (*val == '\0') |
---|
2740 | { |
---|
2741 | sm_syslog(LOG_INFO, e->e_id, |
---|
2742 | "Milter delete: header %s %s: %s", |
---|
2743 | h == sysheader ? " (default header)" : "", |
---|
2744 | field, |
---|
2745 | h->h_value == NULL ? "<NULL>" : h->h_value); |
---|
2746 | } |
---|
2747 | else |
---|
2748 | { |
---|
2749 | sm_syslog(LOG_INFO, e->e_id, |
---|
2750 | "Milter change: header %s %s: from %s to %s", |
---|
2751 | h == sysheader ? " (default header)" : "", |
---|
2752 | field, |
---|
2753 | h->h_value == NULL ? "<NULL>" : h->h_value, |
---|
2754 | val); |
---|
2755 | } |
---|
2756 | } |
---|
2757 | |
---|
2758 | if (h != sysheader && h->h_value != NULL) |
---|
2759 | { |
---|
2760 | size_t l; |
---|
2761 | |
---|
2762 | l = strlen(h->h_value); |
---|
2763 | if (l > e->e_msgsize) |
---|
2764 | e->e_msgsize = 0; |
---|
2765 | else |
---|
2766 | e->e_msgsize -= l; |
---|
2767 | /* rpool, don't free: sm_free(h->h_value); XXX */ |
---|
2768 | } |
---|
2769 | |
---|
2770 | if (*val == '\0') |
---|
2771 | { |
---|
2772 | /* Remove "Field: " from message size */ |
---|
2773 | if (h != sysheader) |
---|
2774 | { |
---|
2775 | size_t l; |
---|
2776 | |
---|
2777 | l = strlen(h->h_field) + 2; |
---|
2778 | if (l > e->e_msgsize) |
---|
2779 | e->e_msgsize = 0; |
---|
2780 | else |
---|
2781 | e->e_msgsize -= l; |
---|
2782 | } |
---|
2783 | h->h_value = NULL; |
---|
2784 | } |
---|
2785 | else |
---|
2786 | { |
---|
2787 | h->h_value = newstr(val); |
---|
2788 | h->h_flags |= H_USER; |
---|
2789 | e->e_msgsize += strlen(h->h_value); |
---|
2790 | } |
---|
2791 | } |
---|
2792 | /* |
---|
2793 | ** MILTER_ADDRCPT -- Add the supplied recipient to the message |
---|
2794 | ** |
---|
2795 | ** Parameters: |
---|
2796 | ** response -- encoded form of recipient address. |
---|
2797 | ** rlen -- length of response. |
---|
2798 | ** e -- current envelope. |
---|
2799 | ** |
---|
2800 | ** Returns: |
---|
2801 | ** none |
---|
2802 | */ |
---|
2803 | |
---|
2804 | static void |
---|
2805 | milter_addrcpt(response, rlen, e) |
---|
2806 | char *response; |
---|
2807 | ssize_t rlen; |
---|
2808 | ENVELOPE *e; |
---|
2809 | { |
---|
2810 | if (tTd(64, 10)) |
---|
2811 | sm_dprintf("milter_addrcpt: "); |
---|
2812 | |
---|
2813 | /* sanity checks */ |
---|
2814 | if (response == NULL) |
---|
2815 | { |
---|
2816 | if (tTd(64, 10)) |
---|
2817 | sm_dprintf("NULL response\n"); |
---|
2818 | return; |
---|
2819 | } |
---|
2820 | |
---|
2821 | if (*response == '\0' || |
---|
2822 | strlen(response) + 1 != (size_t) rlen) |
---|
2823 | { |
---|
2824 | if (tTd(64, 10)) |
---|
2825 | sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", |
---|
2826 | (int) strlen(response), (int) (rlen - 1)); |
---|
2827 | return; |
---|
2828 | } |
---|
2829 | |
---|
2830 | if (tTd(64, 10)) |
---|
2831 | sm_dprintf("%s\n", response); |
---|
2832 | if (MilterLogLevel > 8) |
---|
2833 | sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); |
---|
2834 | (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); |
---|
2835 | return; |
---|
2836 | } |
---|
2837 | /* |
---|
2838 | ** MILTER_DELRCPT -- Delete the supplied recipient from the message |
---|
2839 | ** |
---|
2840 | ** Parameters: |
---|
2841 | ** response -- encoded form of recipient address. |
---|
2842 | ** rlen -- length of response. |
---|
2843 | ** e -- current envelope. |
---|
2844 | ** |
---|
2845 | ** Returns: |
---|
2846 | ** none |
---|
2847 | */ |
---|
2848 | |
---|
2849 | static void |
---|
2850 | milter_delrcpt(response, rlen, e) |
---|
2851 | char *response; |
---|
2852 | ssize_t rlen; |
---|
2853 | ENVELOPE *e; |
---|
2854 | { |
---|
2855 | if (tTd(64, 10)) |
---|
2856 | sm_dprintf("milter_delrcpt: "); |
---|
2857 | |
---|
2858 | /* sanity checks */ |
---|
2859 | if (response == NULL) |
---|
2860 | { |
---|
2861 | if (tTd(64, 10)) |
---|
2862 | sm_dprintf("NULL response\n"); |
---|
2863 | return; |
---|
2864 | } |
---|
2865 | |
---|
2866 | if (*response == '\0' || |
---|
2867 | strlen(response) + 1 != (size_t) rlen) |
---|
2868 | { |
---|
2869 | if (tTd(64, 10)) |
---|
2870 | sm_dprintf("didn't follow protocol (total len)\n"); |
---|
2871 | return; |
---|
2872 | } |
---|
2873 | |
---|
2874 | if (tTd(64, 10)) |
---|
2875 | sm_dprintf("%s\n", response); |
---|
2876 | if (MilterLogLevel > 8) |
---|
2877 | sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s", |
---|
2878 | response); |
---|
2879 | (void) removefromlist(response, &e->e_sendqueue, e); |
---|
2880 | return; |
---|
2881 | } |
---|
2882 | /* |
---|
2883 | ** MILTER_REPLBODY -- Replace the current data file with new body |
---|
2884 | ** |
---|
2885 | ** Parameters: |
---|
2886 | ** response -- encoded form of new body. |
---|
2887 | ** rlen -- length of response. |
---|
2888 | ** newfilter -- if first time called by a new filter |
---|
2889 | ** e -- current envelope. |
---|
2890 | ** |
---|
2891 | ** Returns: |
---|
2892 | ** 0 upon success, -1 upon failure |
---|
2893 | */ |
---|
2894 | |
---|
2895 | static int |
---|
2896 | milter_replbody(response, rlen, newfilter, e) |
---|
2897 | char *response; |
---|
2898 | ssize_t rlen; |
---|
2899 | bool newfilter; |
---|
2900 | ENVELOPE *e; |
---|
2901 | { |
---|
2902 | static char prevchar; |
---|
2903 | int i; |
---|
2904 | |
---|
2905 | if (tTd(64, 10)) |
---|
2906 | sm_dprintf("milter_replbody\n"); |
---|
2907 | |
---|
2908 | /* If a new filter, reset previous character and truncate data file */ |
---|
2909 | if (newfilter) |
---|
2910 | { |
---|
2911 | off_t prevsize; |
---|
2912 | char dfname[MAXPATHLEN]; |
---|
2913 | |
---|
2914 | (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), |
---|
2915 | sizeof dfname); |
---|
2916 | |
---|
2917 | /* Reset prevchar */ |
---|
2918 | prevchar = '\0'; |
---|
2919 | |
---|
2920 | /* Get the current data file information */ |
---|
2921 | prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL); |
---|
2922 | if (prevsize < 0) |
---|
2923 | prevsize = 0; |
---|
2924 | |
---|
2925 | /* truncate current data file */ |
---|
2926 | if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) |
---|
2927 | { |
---|
2928 | if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0) |
---|
2929 | { |
---|
2930 | MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s"); |
---|
2931 | return -1; |
---|
2932 | } |
---|
2933 | } |
---|
2934 | else |
---|
2935 | { |
---|
2936 | int err; |
---|
2937 | |
---|
2938 | err = sm_io_error(e->e_dfp); |
---|
2939 | (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT); |
---|
2940 | |
---|
2941 | /* |
---|
2942 | ** Clear error if tried to fflush() |
---|
2943 | ** a read-only file pointer and |
---|
2944 | ** there wasn't a previous error. |
---|
2945 | */ |
---|
2946 | |
---|
2947 | if (err == 0) |
---|
2948 | sm_io_clearerr(e->e_dfp); |
---|
2949 | |
---|
2950 | /* errno is set implicitly by fseek() before return */ |
---|
2951 | err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, |
---|
2952 | 0, SEEK_SET); |
---|
2953 | if (err < 0) |
---|
2954 | { |
---|
2955 | MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s"); |
---|
2956 | return -1; |
---|
2957 | } |
---|
2958 | # if NOFTRUNCATE |
---|
2959 | /* XXX: Not much we can do except rewind it */ |
---|
2960 | errno = EINVAL; |
---|
2961 | MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)"); |
---|
2962 | return -1; |
---|
2963 | # else /* NOFTRUNCATE */ |
---|
2964 | err = ftruncate(sm_io_getinfo(e->e_dfp, |
---|
2965 | SM_IO_WHAT_FD, NULL), |
---|
2966 | 0); |
---|
2967 | if (err < 0) |
---|
2968 | { |
---|
2969 | MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s"); |
---|
2970 | return -1; |
---|
2971 | } |
---|
2972 | # endif /* NOFTRUNCATE */ |
---|
2973 | } |
---|
2974 | |
---|
2975 | if (prevsize > e->e_msgsize) |
---|
2976 | e->e_msgsize = 0; |
---|
2977 | else |
---|
2978 | e->e_msgsize -= prevsize; |
---|
2979 | } |
---|
2980 | |
---|
2981 | if (newfilter && MilterLogLevel > 8) |
---|
2982 | sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced"); |
---|
2983 | |
---|
2984 | if (response == NULL) |
---|
2985 | { |
---|
2986 | /* Flush the buffered '\r' */ |
---|
2987 | if (prevchar == '\r') |
---|
2988 | { |
---|
2989 | (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar); |
---|
2990 | e->e_msgsize++; |
---|
2991 | } |
---|
2992 | return 0; |
---|
2993 | } |
---|
2994 | |
---|
2995 | for (i = 0; i < rlen; i++) |
---|
2996 | { |
---|
2997 | /* Buffered char from last chunk */ |
---|
2998 | if (i == 0 && prevchar == '\r') |
---|
2999 | { |
---|
3000 | /* Not CRLF, output prevchar */ |
---|
3001 | if (response[i] != '\n') |
---|
3002 | { |
---|
3003 | (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, |
---|
3004 | prevchar); |
---|
3005 | e->e_msgsize++; |
---|
3006 | } |
---|
3007 | prevchar = '\0'; |
---|
3008 | } |
---|
3009 | |
---|
3010 | /* Turn CRLF into LF */ |
---|
3011 | if (response[i] == '\r') |
---|
3012 | { |
---|
3013 | /* check if at end of chunk */ |
---|
3014 | if (i + 1 < rlen) |
---|
3015 | { |
---|
3016 | /* If LF, strip CR */ |
---|
3017 | if (response[i + 1] == '\n') |
---|
3018 | i++; |
---|
3019 | } |
---|
3020 | else |
---|
3021 | { |
---|
3022 | /* check next chunk */ |
---|
3023 | prevchar = '\r'; |
---|
3024 | continue; |
---|
3025 | } |
---|
3026 | } |
---|
3027 | (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]); |
---|
3028 | e->e_msgsize++; |
---|
3029 | } |
---|
3030 | return 0; |
---|
3031 | } |
---|
3032 | |
---|
3033 | /* |
---|
3034 | ** MTA callouts |
---|
3035 | */ |
---|
3036 | |
---|
3037 | /* |
---|
3038 | ** MILTER_INIT -- open and negotiate with all of the filters |
---|
3039 | ** |
---|
3040 | ** Parameters: |
---|
3041 | ** e -- current envelope. |
---|
3042 | ** state -- return state from response. |
---|
3043 | ** |
---|
3044 | ** Returns: |
---|
3045 | ** true iff at least one filter is active |
---|
3046 | */ |
---|
3047 | |
---|
3048 | /* ARGSUSED */ |
---|
3049 | bool |
---|
3050 | milter_init(e, state) |
---|
3051 | ENVELOPE *e; |
---|
3052 | char *state; |
---|
3053 | { |
---|
3054 | int i; |
---|
3055 | |
---|
3056 | if (tTd(64, 10)) |
---|
3057 | sm_dprintf("milter_init\n"); |
---|
3058 | |
---|
3059 | *state = SMFIR_CONTINUE; |
---|
3060 | if (InputFilters[0] == NULL) |
---|
3061 | { |
---|
3062 | if (MilterLogLevel > 10) |
---|
3063 | sm_syslog(LOG_INFO, e->e_id, |
---|
3064 | "Milter: no active filter"); |
---|
3065 | return false; |
---|
3066 | } |
---|
3067 | |
---|
3068 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3069 | { |
---|
3070 | struct milter *m = InputFilters[i]; |
---|
3071 | |
---|
3072 | m->mf_sock = milter_open(m, false, e); |
---|
3073 | if (m->mf_state == SMFS_ERROR) |
---|
3074 | { |
---|
3075 | MILTER_CHECK_ERROR(true, continue); |
---|
3076 | break; |
---|
3077 | } |
---|
3078 | |
---|
3079 | if (m->mf_sock < 0 || |
---|
3080 | milter_negotiate(m, e) < 0 || |
---|
3081 | m->mf_state == SMFS_ERROR) |
---|
3082 | { |
---|
3083 | if (tTd(64, 5)) |
---|
3084 | sm_dprintf("milter_init(%s): failed to %s\n", |
---|
3085 | m->mf_name, |
---|
3086 | m->mf_sock < 0 ? "open" : |
---|
3087 | "negotiate"); |
---|
3088 | if (MilterLogLevel > 0) |
---|
3089 | sm_syslog(LOG_ERR, e->e_id, |
---|
3090 | "Milter (%s): init failed to %s", |
---|
3091 | m->mf_name, |
---|
3092 | m->mf_sock < 0 ? "open" : |
---|
3093 | "negotiate"); |
---|
3094 | |
---|
3095 | /* if negotation failure, close socket */ |
---|
3096 | milter_error(m, e); |
---|
3097 | MILTER_CHECK_ERROR(true, continue); |
---|
3098 | } |
---|
3099 | if (MilterLogLevel > 9) |
---|
3100 | sm_syslog(LOG_INFO, e->e_id, |
---|
3101 | "Milter (%s): init success to %s", |
---|
3102 | m->mf_name, |
---|
3103 | m->mf_sock < 0 ? "open" : "negotiate"); |
---|
3104 | } |
---|
3105 | |
---|
3106 | /* |
---|
3107 | ** If something temp/perm failed with one of the filters, |
---|
3108 | ** we won't be using any of them, so clear any existing |
---|
3109 | ** connections. |
---|
3110 | */ |
---|
3111 | |
---|
3112 | if (*state != SMFIR_CONTINUE) |
---|
3113 | milter_quit(e); |
---|
3114 | |
---|
3115 | return true; |
---|
3116 | } |
---|
3117 | /* |
---|
3118 | ** MILTER_CONNECT -- send connection info to milter filters |
---|
3119 | ** |
---|
3120 | ** Parameters: |
---|
3121 | ** hostname -- hostname of remote machine. |
---|
3122 | ** addr -- address of remote machine. |
---|
3123 | ** e -- current envelope. |
---|
3124 | ** state -- return state from response. |
---|
3125 | ** |
---|
3126 | ** Returns: |
---|
3127 | ** response string (may be NULL) |
---|
3128 | */ |
---|
3129 | |
---|
3130 | char * |
---|
3131 | milter_connect(hostname, addr, e, state) |
---|
3132 | char *hostname; |
---|
3133 | SOCKADDR addr; |
---|
3134 | ENVELOPE *e; |
---|
3135 | char *state; |
---|
3136 | { |
---|
3137 | char family; |
---|
3138 | unsigned short port; |
---|
3139 | char *buf, *bp; |
---|
3140 | char *response; |
---|
3141 | char *sockinfo = NULL; |
---|
3142 | ssize_t s; |
---|
3143 | # if NETINET6 |
---|
3144 | char buf6[INET6_ADDRSTRLEN]; |
---|
3145 | # endif /* NETINET6 */ |
---|
3146 | |
---|
3147 | if (tTd(64, 10)) |
---|
3148 | sm_dprintf("milter_connect(%s)\n", hostname); |
---|
3149 | if (MilterLogLevel > 9) |
---|
3150 | sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters"); |
---|
3151 | |
---|
3152 | /* gather data */ |
---|
3153 | switch (addr.sa.sa_family) |
---|
3154 | { |
---|
3155 | # if NETUNIX |
---|
3156 | case AF_UNIX: |
---|
3157 | family = SMFIA_UNIX; |
---|
3158 | port = htons(0); |
---|
3159 | sockinfo = addr.sunix.sun_path; |
---|
3160 | break; |
---|
3161 | # endif /* NETUNIX */ |
---|
3162 | |
---|
3163 | # if NETINET |
---|
3164 | case AF_INET: |
---|
3165 | family = SMFIA_INET; |
---|
3166 | port = addr.sin.sin_port; |
---|
3167 | sockinfo = (char *) inet_ntoa(addr.sin.sin_addr); |
---|
3168 | break; |
---|
3169 | # endif /* NETINET */ |
---|
3170 | |
---|
3171 | # if NETINET6 |
---|
3172 | case AF_INET6: |
---|
3173 | if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr)) |
---|
3174 | family = SMFIA_INET; |
---|
3175 | else |
---|
3176 | family = SMFIA_INET6; |
---|
3177 | port = addr.sin6.sin6_port; |
---|
3178 | sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6, |
---|
3179 | sizeof buf6); |
---|
3180 | if (sockinfo == NULL) |
---|
3181 | sockinfo = ""; |
---|
3182 | break; |
---|
3183 | # endif /* NETINET6 */ |
---|
3184 | |
---|
3185 | default: |
---|
3186 | family = SMFIA_UNKNOWN; |
---|
3187 | break; |
---|
3188 | } |
---|
3189 | |
---|
3190 | s = strlen(hostname) + 1 + sizeof(family); |
---|
3191 | if (family != SMFIA_UNKNOWN) |
---|
3192 | s += sizeof(port) + strlen(sockinfo) + 1; |
---|
3193 | |
---|
3194 | buf = (char *) xalloc(s); |
---|
3195 | bp = buf; |
---|
3196 | |
---|
3197 | /* put together data */ |
---|
3198 | (void) memcpy(bp, hostname, strlen(hostname)); |
---|
3199 | bp += strlen(hostname); |
---|
3200 | *bp++ = '\0'; |
---|
3201 | (void) memcpy(bp, &family, sizeof family); |
---|
3202 | bp += sizeof family; |
---|
3203 | if (family != SMFIA_UNKNOWN) |
---|
3204 | { |
---|
3205 | (void) memcpy(bp, &port, sizeof port); |
---|
3206 | bp += sizeof port; |
---|
3207 | |
---|
3208 | /* include trailing '\0' */ |
---|
3209 | (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1); |
---|
3210 | } |
---|
3211 | |
---|
3212 | response = milter_command(SMFIC_CONNECT, buf, s, |
---|
3213 | MilterConnectMacros, e, state); |
---|
3214 | sm_free(buf); /* XXX */ |
---|
3215 | |
---|
3216 | /* |
---|
3217 | ** If this message connection is done for, |
---|
3218 | ** close the filters. |
---|
3219 | */ |
---|
3220 | |
---|
3221 | if (*state != SMFIR_CONTINUE) |
---|
3222 | { |
---|
3223 | if (MilterLogLevel > 9) |
---|
3224 | sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending"); |
---|
3225 | milter_quit(e); |
---|
3226 | } |
---|
3227 | else |
---|
3228 | milter_per_connection_check(e); |
---|
3229 | |
---|
3230 | /* |
---|
3231 | ** SMFIR_REPLYCODE can't work with connect due to |
---|
3232 | ** the requirements of SMTP. Therefore, ignore the |
---|
3233 | ** reply code text but keep the state it would reflect. |
---|
3234 | */ |
---|
3235 | |
---|
3236 | if (*state == SMFIR_REPLYCODE) |
---|
3237 | { |
---|
3238 | if (response != NULL && |
---|
3239 | *response == '4') |
---|
3240 | { |
---|
3241 | #if _FFR_MILTER_421 |
---|
3242 | if (strncmp(response, "421 ", 4) == 0) |
---|
3243 | *state = SMFIR_SHUTDOWN; |
---|
3244 | else |
---|
3245 | #endif /* _FFR_MILTER_421 */ |
---|
3246 | *state = SMFIR_TEMPFAIL; |
---|
3247 | } |
---|
3248 | else |
---|
3249 | *state = SMFIR_REJECT; |
---|
3250 | if (response != NULL) |
---|
3251 | { |
---|
3252 | sm_free(response); /* XXX */ |
---|
3253 | response = NULL; |
---|
3254 | } |
---|
3255 | } |
---|
3256 | return response; |
---|
3257 | } |
---|
3258 | /* |
---|
3259 | ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters |
---|
3260 | ** |
---|
3261 | ** Parameters: |
---|
3262 | ** helo -- argument to SMTP HELO/EHLO command. |
---|
3263 | ** e -- current envelope. |
---|
3264 | ** state -- return state from response. |
---|
3265 | ** |
---|
3266 | ** Returns: |
---|
3267 | ** response string (may be NULL) |
---|
3268 | */ |
---|
3269 | |
---|
3270 | char * |
---|
3271 | milter_helo(helo, e, state) |
---|
3272 | char *helo; |
---|
3273 | ENVELOPE *e; |
---|
3274 | char *state; |
---|
3275 | { |
---|
3276 | int i; |
---|
3277 | char *response; |
---|
3278 | |
---|
3279 | if (tTd(64, 10)) |
---|
3280 | sm_dprintf("milter_helo(%s)\n", helo); |
---|
3281 | |
---|
3282 | /* HELO/EHLO can come at any point */ |
---|
3283 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3284 | { |
---|
3285 | struct milter *m = InputFilters[i]; |
---|
3286 | |
---|
3287 | switch (m->mf_state) |
---|
3288 | { |
---|
3289 | case SMFS_INMSG: |
---|
3290 | /* abort in message filters */ |
---|
3291 | milter_abort_filter(m, e); |
---|
3292 | /* FALLTHROUGH */ |
---|
3293 | |
---|
3294 | case SMFS_DONE: |
---|
3295 | /* reset done filters */ |
---|
3296 | m->mf_state = SMFS_OPEN; |
---|
3297 | break; |
---|
3298 | } |
---|
3299 | } |
---|
3300 | |
---|
3301 | response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1, |
---|
3302 | MilterHeloMacros, e, state); |
---|
3303 | milter_per_connection_check(e); |
---|
3304 | return response; |
---|
3305 | } |
---|
3306 | /* |
---|
3307 | ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters |
---|
3308 | ** |
---|
3309 | ** Parameters: |
---|
3310 | ** args -- SMTP MAIL command args (args[0] == sender). |
---|
3311 | ** e -- current envelope. |
---|
3312 | ** state -- return state from response. |
---|
3313 | ** |
---|
3314 | ** Returns: |
---|
3315 | ** response string (may be NULL) |
---|
3316 | */ |
---|
3317 | |
---|
3318 | char * |
---|
3319 | milter_envfrom(args, e, state) |
---|
3320 | char **args; |
---|
3321 | ENVELOPE *e; |
---|
3322 | char *state; |
---|
3323 | { |
---|
3324 | int i; |
---|
3325 | char *buf, *bp; |
---|
3326 | char *response; |
---|
3327 | ssize_t s; |
---|
3328 | |
---|
3329 | if (tTd(64, 10)) |
---|
3330 | { |
---|
3331 | sm_dprintf("milter_envfrom:"); |
---|
3332 | for (i = 0; args[i] != NULL; i++) |
---|
3333 | sm_dprintf(" %s", args[i]); |
---|
3334 | sm_dprintf("\n"); |
---|
3335 | } |
---|
3336 | |
---|
3337 | /* sanity check */ |
---|
3338 | if (args[0] == NULL) |
---|
3339 | { |
---|
3340 | *state = SMFIR_REJECT; |
---|
3341 | if (MilterLogLevel > 10) |
---|
3342 | sm_syslog(LOG_INFO, e->e_id, |
---|
3343 | "Milter: reject, no sender"); |
---|
3344 | return NULL; |
---|
3345 | } |
---|
3346 | |
---|
3347 | /* new message, so ... */ |
---|
3348 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3349 | { |
---|
3350 | struct milter *m = InputFilters[i]; |
---|
3351 | |
---|
3352 | switch (m->mf_state) |
---|
3353 | { |
---|
3354 | case SMFS_INMSG: |
---|
3355 | /* abort in message filters */ |
---|
3356 | milter_abort_filter(m, e); |
---|
3357 | /* FALLTHROUGH */ |
---|
3358 | |
---|
3359 | case SMFS_DONE: |
---|
3360 | /* reset done filters */ |
---|
3361 | m->mf_state = SMFS_OPEN; |
---|
3362 | break; |
---|
3363 | } |
---|
3364 | } |
---|
3365 | |
---|
3366 | /* put together data */ |
---|
3367 | s = 0; |
---|
3368 | for (i = 0; args[i] != NULL; i++) |
---|
3369 | s += strlen(args[i]) + 1; |
---|
3370 | |
---|
3371 | if (s < 0) |
---|
3372 | { |
---|
3373 | *state = SMFIR_TEMPFAIL; |
---|
3374 | return NULL; |
---|
3375 | } |
---|
3376 | |
---|
3377 | buf = (char *) xalloc(s); |
---|
3378 | bp = buf; |
---|
3379 | for (i = 0; args[i] != NULL; i++) |
---|
3380 | { |
---|
3381 | (void) sm_strlcpy(bp, args[i], s - (bp - buf)); |
---|
3382 | bp += strlen(bp) + 1; |
---|
3383 | } |
---|
3384 | |
---|
3385 | if (MilterLogLevel > 14) |
---|
3386 | sm_syslog(LOG_INFO, e->e_id, "Milter: senders: %s", buf); |
---|
3387 | |
---|
3388 | /* send it over */ |
---|
3389 | response = milter_command(SMFIC_MAIL, buf, s, |
---|
3390 | MilterEnvFromMacros, e, state); |
---|
3391 | sm_free(buf); /* XXX */ |
---|
3392 | |
---|
3393 | /* |
---|
3394 | ** If filter rejects/discards a per message command, |
---|
3395 | ** abort the other filters since we are done with the |
---|
3396 | ** current message. |
---|
3397 | */ |
---|
3398 | |
---|
3399 | MILTER_CHECK_DONE_MSG(); |
---|
3400 | if (MilterLogLevel > 10 && *state == SMFIR_REJECT) |
---|
3401 | sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders"); |
---|
3402 | return response; |
---|
3403 | } |
---|
3404 | /* |
---|
3405 | ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters |
---|
3406 | ** |
---|
3407 | ** Parameters: |
---|
3408 | ** args -- SMTP MAIL command args (args[0] == recipient). |
---|
3409 | ** e -- current envelope. |
---|
3410 | ** state -- return state from response. |
---|
3411 | ** |
---|
3412 | ** Returns: |
---|
3413 | ** response string (may be NULL) |
---|
3414 | */ |
---|
3415 | |
---|
3416 | char * |
---|
3417 | milter_envrcpt(args, e, state) |
---|
3418 | char **args; |
---|
3419 | ENVELOPE *e; |
---|
3420 | char *state; |
---|
3421 | { |
---|
3422 | int i; |
---|
3423 | char *buf, *bp; |
---|
3424 | char *response; |
---|
3425 | ssize_t s; |
---|
3426 | |
---|
3427 | if (tTd(64, 10)) |
---|
3428 | { |
---|
3429 | sm_dprintf("milter_envrcpt:"); |
---|
3430 | for (i = 0; args[i] != NULL; i++) |
---|
3431 | sm_dprintf(" %s", args[i]); |
---|
3432 | sm_dprintf("\n"); |
---|
3433 | } |
---|
3434 | |
---|
3435 | /* sanity check */ |
---|
3436 | if (args[0] == NULL) |
---|
3437 | { |
---|
3438 | *state = SMFIR_REJECT; |
---|
3439 | if (MilterLogLevel > 10) |
---|
3440 | sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt"); |
---|
3441 | return NULL; |
---|
3442 | } |
---|
3443 | |
---|
3444 | /* put together data */ |
---|
3445 | s = 0; |
---|
3446 | for (i = 0; args[i] != NULL; i++) |
---|
3447 | s += strlen(args[i]) + 1; |
---|
3448 | |
---|
3449 | if (s < 0) |
---|
3450 | { |
---|
3451 | *state = SMFIR_TEMPFAIL; |
---|
3452 | return NULL; |
---|
3453 | } |
---|
3454 | |
---|
3455 | buf = (char *) xalloc(s); |
---|
3456 | bp = buf; |
---|
3457 | for (i = 0; args[i] != NULL; i++) |
---|
3458 | { |
---|
3459 | (void) sm_strlcpy(bp, args[i], s - (bp - buf)); |
---|
3460 | bp += strlen(bp) + 1; |
---|
3461 | } |
---|
3462 | |
---|
3463 | if (MilterLogLevel > 14) |
---|
3464 | sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf); |
---|
3465 | |
---|
3466 | /* send it over */ |
---|
3467 | response = milter_command(SMFIC_RCPT, buf, s, |
---|
3468 | MilterEnvRcptMacros, e, state); |
---|
3469 | sm_free(buf); /* XXX */ |
---|
3470 | return response; |
---|
3471 | } |
---|
3472 | /* |
---|
3473 | ** MILTER_DATA -- send message headers/body and gather final message results |
---|
3474 | ** |
---|
3475 | ** Parameters: |
---|
3476 | ** e -- current envelope. |
---|
3477 | ** state -- return state from response. |
---|
3478 | ** |
---|
3479 | ** Returns: |
---|
3480 | ** response string (may be NULL) |
---|
3481 | ** |
---|
3482 | ** Side effects: |
---|
3483 | ** - Uses e->e_dfp for access to the body |
---|
3484 | ** - Can call the various milter action routines to |
---|
3485 | ** modify the envelope or message. |
---|
3486 | */ |
---|
3487 | |
---|
3488 | # define MILTER_CHECK_RESULTS() \ |
---|
3489 | if (*state == SMFIR_ACCEPT || \ |
---|
3490 | m->mf_state == SMFS_DONE || \ |
---|
3491 | m->mf_state == SMFS_ERROR) \ |
---|
3492 | { \ |
---|
3493 | if (m->mf_state != SMFS_ERROR) \ |
---|
3494 | m->mf_state = SMFS_DONE; \ |
---|
3495 | continue; /* to next filter */ \ |
---|
3496 | } \ |
---|
3497 | if (*state != SMFIR_CONTINUE) \ |
---|
3498 | { \ |
---|
3499 | m->mf_state = SMFS_DONE; \ |
---|
3500 | goto finishup; \ |
---|
3501 | } |
---|
3502 | |
---|
3503 | char * |
---|
3504 | milter_data(e, state) |
---|
3505 | ENVELOPE *e; |
---|
3506 | char *state; |
---|
3507 | { |
---|
3508 | bool replbody = false; /* milter_replbody() called? */ |
---|
3509 | bool replfailed = false; /* milter_replbody() failed? */ |
---|
3510 | bool rewind = false; /* rewind data file? */ |
---|
3511 | bool dfopen = false; /* data file open for writing? */ |
---|
3512 | bool newfilter; /* reset on each new filter */ |
---|
3513 | char rcmd; |
---|
3514 | int i; |
---|
3515 | int save_errno; |
---|
3516 | char *response = NULL; |
---|
3517 | time_t eomsent; |
---|
3518 | ssize_t rlen; |
---|
3519 | |
---|
3520 | if (tTd(64, 10)) |
---|
3521 | sm_dprintf("milter_data\n"); |
---|
3522 | |
---|
3523 | *state = SMFIR_CONTINUE; |
---|
3524 | |
---|
3525 | /* |
---|
3526 | ** XXX: Should actually send body chunks to each filter |
---|
3527 | ** a chunk at a time instead of sending the whole body to |
---|
3528 | ** each filter in turn. However, only if the filters don't |
---|
3529 | ** change the body. |
---|
3530 | */ |
---|
3531 | |
---|
3532 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3533 | { |
---|
3534 | struct milter *m = InputFilters[i]; |
---|
3535 | |
---|
3536 | if (*state != SMFIR_CONTINUE && |
---|
3537 | *state != SMFIR_ACCEPT) |
---|
3538 | { |
---|
3539 | /* |
---|
3540 | ** A previous filter has dealt with the message, |
---|
3541 | ** safe to stop processing the filters. |
---|
3542 | */ |
---|
3543 | |
---|
3544 | break; |
---|
3545 | } |
---|
3546 | |
---|
3547 | /* Now reset state for later evaluation */ |
---|
3548 | *state = SMFIR_CONTINUE; |
---|
3549 | newfilter = true; |
---|
3550 | |
---|
3551 | /* previous problem? */ |
---|
3552 | if (m->mf_state == SMFS_ERROR) |
---|
3553 | { |
---|
3554 | MILTER_CHECK_ERROR(false, continue); |
---|
3555 | break; |
---|
3556 | } |
---|
3557 | |
---|
3558 | /* sanity checks */ |
---|
3559 | if (m->mf_sock < 0 || |
---|
3560 | (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) |
---|
3561 | continue; |
---|
3562 | |
---|
3563 | m->mf_state = SMFS_INMSG; |
---|
3564 | |
---|
3565 | /* check if filter wants the headers */ |
---|
3566 | if (!bitset(SMFIP_NOHDRS, m->mf_pflags)) |
---|
3567 | { |
---|
3568 | response = milter_headers(m, e, state); |
---|
3569 | MILTER_CHECK_RESULTS(); |
---|
3570 | } |
---|
3571 | |
---|
3572 | /* check if filter wants EOH */ |
---|
3573 | if (!bitset(SMFIP_NOEOH, m->mf_pflags)) |
---|
3574 | { |
---|
3575 | if (tTd(64, 10)) |
---|
3576 | sm_dprintf("milter_data: eoh\n"); |
---|
3577 | |
---|
3578 | /* send it over */ |
---|
3579 | response = milter_send_command(m, SMFIC_EOH, NULL, 0, |
---|
3580 | e, state); |
---|
3581 | MILTER_CHECK_RESULTS(); |
---|
3582 | } |
---|
3583 | |
---|
3584 | /* check if filter wants the body */ |
---|
3585 | if (!bitset(SMFIP_NOBODY, m->mf_pflags) && |
---|
3586 | e->e_dfp != NULL) |
---|
3587 | { |
---|
3588 | rewind = true; |
---|
3589 | response = milter_body(m, e, state); |
---|
3590 | MILTER_CHECK_RESULTS(); |
---|
3591 | } |
---|
3592 | |
---|
3593 | /* send the final body chunk */ |
---|
3594 | (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, |
---|
3595 | m->mf_timeout[SMFTO_WRITE], e); |
---|
3596 | |
---|
3597 | /* Get time EOM sent for timeout */ |
---|
3598 | eomsent = curtime(); |
---|
3599 | |
---|
3600 | /* deal with the possibility of multiple responses */ |
---|
3601 | while (*state == SMFIR_CONTINUE) |
---|
3602 | { |
---|
3603 | /* Check total timeout from EOM to final ACK/NAK */ |
---|
3604 | if (m->mf_timeout[SMFTO_EOM] > 0 && |
---|
3605 | curtime() - eomsent >= m->mf_timeout[SMFTO_EOM]) |
---|
3606 | { |
---|
3607 | if (tTd(64, 5)) |
---|
3608 | sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n", |
---|
3609 | m->mf_name); |
---|
3610 | if (MilterLogLevel > 0) |
---|
3611 | sm_syslog(LOG_ERR, e->e_id, |
---|
3612 | "milter_data(%s): EOM ACK/NAK timeout", |
---|
3613 | m->mf_name); |
---|
3614 | milter_error(m, e); |
---|
3615 | MILTER_CHECK_ERROR(false, break); |
---|
3616 | break; |
---|
3617 | } |
---|
3618 | |
---|
3619 | response = milter_read(m, &rcmd, &rlen, |
---|
3620 | m->mf_timeout[SMFTO_READ], e); |
---|
3621 | if (m->mf_state == SMFS_ERROR) |
---|
3622 | break; |
---|
3623 | |
---|
3624 | if (tTd(64, 10)) |
---|
3625 | sm_dprintf("milter_data(%s): state %c\n", |
---|
3626 | m->mf_name, (char) rcmd); |
---|
3627 | |
---|
3628 | switch (rcmd) |
---|
3629 | { |
---|
3630 | case SMFIR_REPLYCODE: |
---|
3631 | MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected"); |
---|
3632 | if (MilterLogLevel > 12) |
---|
3633 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s", |
---|
3634 | m->mf_name, response); |
---|
3635 | *state = rcmd; |
---|
3636 | m->mf_state = SMFS_DONE; |
---|
3637 | break; |
---|
3638 | |
---|
3639 | case SMFIR_REJECT: /* log msg at end of function */ |
---|
3640 | if (MilterLogLevel > 12) |
---|
3641 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject", |
---|
3642 | m->mf_name); |
---|
3643 | *state = rcmd; |
---|
3644 | m->mf_state = SMFS_DONE; |
---|
3645 | break; |
---|
3646 | |
---|
3647 | case SMFIR_DISCARD: |
---|
3648 | if (MilterLogLevel > 12) |
---|
3649 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard", |
---|
3650 | m->mf_name); |
---|
3651 | *state = rcmd; |
---|
3652 | m->mf_state = SMFS_DONE; |
---|
3653 | break; |
---|
3654 | |
---|
3655 | case SMFIR_TEMPFAIL: |
---|
3656 | if (MilterLogLevel > 12) |
---|
3657 | sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail", |
---|
3658 | m->mf_name); |
---|
3659 | *state = rcmd; |
---|
3660 | m->mf_state = SMFS_DONE; |
---|
3661 | break; |
---|
3662 | |
---|
3663 | case SMFIR_CONTINUE: |
---|
3664 | case SMFIR_ACCEPT: |
---|
3665 | /* this filter is done with message */ |
---|
3666 | if (replfailed) |
---|
3667 | *state = SMFIR_TEMPFAIL; |
---|
3668 | else |
---|
3669 | *state = SMFIR_ACCEPT; |
---|
3670 | m->mf_state = SMFS_DONE; |
---|
3671 | break; |
---|
3672 | |
---|
3673 | case SMFIR_PROGRESS: |
---|
3674 | break; |
---|
3675 | |
---|
3676 | # if _FFR_QUARANTINE |
---|
3677 | case SMFIR_QUARANTINE: |
---|
3678 | if (!bitset(SMFIF_QUARANTINE, m->mf_fflags)) |
---|
3679 | { |
---|
3680 | if (MilterLogLevel > 9) |
---|
3681 | sm_syslog(LOG_WARNING, e->e_id, |
---|
3682 | "milter_data(%s): lied about quarantining, honoring request anyway", |
---|
3683 | m->mf_name); |
---|
3684 | } |
---|
3685 | if (response == NULL) |
---|
3686 | response = newstr(""); |
---|
3687 | if (MilterLogLevel > 3) |
---|
3688 | sm_syslog(LOG_INFO, e->e_id, |
---|
3689 | "milter=%s, quarantine=%s", |
---|
3690 | m->mf_name, response); |
---|
3691 | e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, |
---|
3692 | response); |
---|
3693 | macdefine(&e->e_macro, A_PERM, |
---|
3694 | macid("{quarantine}"), e->e_quarmsg); |
---|
3695 | break; |
---|
3696 | # endif /* _FFR_QUARANTINE */ |
---|
3697 | |
---|
3698 | case SMFIR_ADDHEADER: |
---|
3699 | if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) |
---|
3700 | { |
---|
3701 | if (MilterLogLevel > 9) |
---|
3702 | sm_syslog(LOG_WARNING, e->e_id, |
---|
3703 | "milter_data(%s): lied about adding headers, honoring request anyway", |
---|
3704 | m->mf_name); |
---|
3705 | } |
---|
3706 | milter_addheader(response, rlen, e); |
---|
3707 | break; |
---|
3708 | |
---|
3709 | case SMFIR_CHGHEADER: |
---|
3710 | if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) |
---|
3711 | { |
---|
3712 | if (MilterLogLevel > 9) |
---|
3713 | sm_syslog(LOG_WARNING, e->e_id, |
---|
3714 | "milter_data(%s): lied about changing headers, honoring request anyway", |
---|
3715 | m->mf_name); |
---|
3716 | } |
---|
3717 | milter_changeheader(response, rlen, e); |
---|
3718 | break; |
---|
3719 | |
---|
3720 | case SMFIR_ADDRCPT: |
---|
3721 | if (!bitset(SMFIF_ADDRCPT, m->mf_fflags)) |
---|
3722 | { |
---|
3723 | if (MilterLogLevel > 9) |
---|
3724 | sm_syslog(LOG_WARNING, e->e_id, |
---|
3725 | "milter_data(%s) lied about adding recipients, honoring request anyway", |
---|
3726 | m->mf_name); |
---|
3727 | } |
---|
3728 | milter_addrcpt(response, rlen, e); |
---|
3729 | break; |
---|
3730 | |
---|
3731 | case SMFIR_DELRCPT: |
---|
3732 | if (!bitset(SMFIF_DELRCPT, m->mf_fflags)) |
---|
3733 | { |
---|
3734 | if (MilterLogLevel > 9) |
---|
3735 | sm_syslog(LOG_WARNING, e->e_id, |
---|
3736 | "milter_data(%s): lied about removing recipients, honoring request anyway", |
---|
3737 | m->mf_name); |
---|
3738 | } |
---|
3739 | milter_delrcpt(response, rlen, e); |
---|
3740 | break; |
---|
3741 | |
---|
3742 | case SMFIR_REPLBODY: |
---|
3743 | if (!bitset(SMFIF_MODBODY, m->mf_fflags)) |
---|
3744 | { |
---|
3745 | if (MilterLogLevel > 9) |
---|
3746 | sm_syslog(LOG_ERR, e->e_id, |
---|
3747 | "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", |
---|
3748 | m->mf_name); |
---|
3749 | replfailed = true; |
---|
3750 | break; |
---|
3751 | } |
---|
3752 | |
---|
3753 | /* already failed in attempt */ |
---|
3754 | if (replfailed) |
---|
3755 | break; |
---|
3756 | |
---|
3757 | if (!dfopen) |
---|
3758 | { |
---|
3759 | if (milter_reopen_df(e) < 0) |
---|
3760 | { |
---|
3761 | replfailed = true; |
---|
3762 | break; |
---|
3763 | } |
---|
3764 | dfopen = true; |
---|
3765 | rewind = true; |
---|
3766 | } |
---|
3767 | |
---|
3768 | if (milter_replbody(response, rlen, |
---|
3769 | newfilter, e) < 0) |
---|
3770 | replfailed = true; |
---|
3771 | newfilter = false; |
---|
3772 | replbody = true; |
---|
3773 | break; |
---|
3774 | |
---|
3775 | default: |
---|
3776 | /* Invalid response to command */ |
---|
3777 | if (MilterLogLevel > 0) |
---|
3778 | sm_syslog(LOG_ERR, e->e_id, |
---|
3779 | "milter_data(%s): returned bogus response %c", |
---|
3780 | m->mf_name, rcmd); |
---|
3781 | milter_error(m, e); |
---|
3782 | break; |
---|
3783 | } |
---|
3784 | if (rcmd != SMFIR_REPLYCODE && response != NULL) |
---|
3785 | { |
---|
3786 | sm_free(response); /* XXX */ |
---|
3787 | response = NULL; |
---|
3788 | } |
---|
3789 | |
---|
3790 | if (m->mf_state == SMFS_ERROR) |
---|
3791 | break; |
---|
3792 | } |
---|
3793 | |
---|
3794 | if (replbody && !replfailed) |
---|
3795 | { |
---|
3796 | /* flush possible buffered character */ |
---|
3797 | milter_replbody(NULL, 0, !replbody, e); |
---|
3798 | replbody = false; |
---|
3799 | } |
---|
3800 | |
---|
3801 | if (m->mf_state == SMFS_ERROR) |
---|
3802 | { |
---|
3803 | MILTER_CHECK_ERROR(false, continue); |
---|
3804 | goto finishup; |
---|
3805 | } |
---|
3806 | } |
---|
3807 | |
---|
3808 | finishup: |
---|
3809 | /* leave things in the expected state if we touched it */ |
---|
3810 | if (replfailed) |
---|
3811 | { |
---|
3812 | if (*state == SMFIR_CONTINUE || |
---|
3813 | *state == SMFIR_ACCEPT) |
---|
3814 | { |
---|
3815 | *state = SMFIR_TEMPFAIL; |
---|
3816 | SM_FREE_CLR(response); |
---|
3817 | } |
---|
3818 | |
---|
3819 | if (dfopen) |
---|
3820 | { |
---|
3821 | (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); |
---|
3822 | e->e_dfp = NULL; |
---|
3823 | e->e_flags &= ~EF_HAS_DF; |
---|
3824 | dfopen = false; |
---|
3825 | } |
---|
3826 | rewind = false; |
---|
3827 | } |
---|
3828 | |
---|
3829 | if ((dfopen && milter_reset_df(e) < 0) || |
---|
3830 | (rewind && bfrewind(e->e_dfp) < 0)) |
---|
3831 | { |
---|
3832 | save_errno = errno; |
---|
3833 | ExitStat = EX_IOERR; |
---|
3834 | |
---|
3835 | /* |
---|
3836 | ** If filter told us to keep message but we had |
---|
3837 | ** an error, we can't really keep it, tempfail it. |
---|
3838 | */ |
---|
3839 | |
---|
3840 | if (*state == SMFIR_CONTINUE || |
---|
3841 | *state == SMFIR_ACCEPT) |
---|
3842 | { |
---|
3843 | *state = SMFIR_TEMPFAIL; |
---|
3844 | SM_FREE_CLR(response); |
---|
3845 | } |
---|
3846 | |
---|
3847 | errno = save_errno; |
---|
3848 | syserr("milter_data: %s/%cf%s: read error", |
---|
3849 | qid_printqueue(e->e_qgrp, e->e_qdir), |
---|
3850 | DATAFL_LETTER, e->e_id); |
---|
3851 | } |
---|
3852 | |
---|
3853 | MILTER_CHECK_DONE_MSG(); |
---|
3854 | if (MilterLogLevel > 10 && *state == SMFIR_REJECT) |
---|
3855 | sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data"); |
---|
3856 | return response; |
---|
3857 | } |
---|
3858 | /* |
---|
3859 | ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s) |
---|
3860 | ** |
---|
3861 | ** Parameters: |
---|
3862 | ** e -- current envelope. |
---|
3863 | ** |
---|
3864 | ** Returns: |
---|
3865 | ** none |
---|
3866 | */ |
---|
3867 | |
---|
3868 | void |
---|
3869 | milter_quit(e) |
---|
3870 | ENVELOPE *e; |
---|
3871 | { |
---|
3872 | int i; |
---|
3873 | |
---|
3874 | if (tTd(64, 10)) |
---|
3875 | sm_dprintf("milter_quit(%s)\n", e->e_id); |
---|
3876 | |
---|
3877 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3878 | milter_quit_filter(InputFilters[i], e); |
---|
3879 | } |
---|
3880 | /* |
---|
3881 | ** MILTER_ABORT -- informs the filter(s) that we are aborting current message |
---|
3882 | ** |
---|
3883 | ** Parameters: |
---|
3884 | ** e -- current envelope. |
---|
3885 | ** |
---|
3886 | ** Returns: |
---|
3887 | ** none |
---|
3888 | */ |
---|
3889 | |
---|
3890 | void |
---|
3891 | milter_abort(e) |
---|
3892 | ENVELOPE *e; |
---|
3893 | { |
---|
3894 | int i; |
---|
3895 | |
---|
3896 | if (tTd(64, 10)) |
---|
3897 | sm_dprintf("milter_abort\n"); |
---|
3898 | |
---|
3899 | for (i = 0; InputFilters[i] != NULL; i++) |
---|
3900 | { |
---|
3901 | struct milter *m = InputFilters[i]; |
---|
3902 | |
---|
3903 | /* sanity checks */ |
---|
3904 | if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG) |
---|
3905 | continue; |
---|
3906 | |
---|
3907 | milter_abort_filter(m, e); |
---|
3908 | } |
---|
3909 | } |
---|
3910 | #endif /* MILTER */ |
---|