1 /* This file is part of Mailfromd.
2 Copyright (C) 2005-2021 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <syslog.h>
27 #include <signal.h>
28 #include <pwd.h>
29 #include <grp.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34
35 #include <mailutils/mailutils.h>
36 #include <mailutils/daemon.h>
37
38 #include "mailfromd.h"
39 #include "srvman.h"
40 #include "srvcfg.h"
41
42
43 static const char *ctx_getsym(void *data, const char *str);
44 static int ctx_setreply(void *data, char *code, char *xcode, char *message);
45
46 /* Per-message data */
47
48 struct message_data {
49 eval_environ_t env; /* Evaluation environment */
50 char *helostr; /* Domain name obtained in HELO phase */
51 char msgid[64]; /* Message ID */
52 };
53 static struct message_data *test_message_data;
54
55 void
test_message_data_init(eval_environ_t env)56 test_message_data_init(eval_environ_t env)
57 {
58 test_message_data = mu_alloc(sizeof(*test_message_data));
59 test_message_data->env = env;
60 test_message_data->helostr = NULL;
61 test_message_data->msgid[0] = 0;
62 }
63
64 static struct message_data *
priv_get(SMFICTX * ctx)65 priv_get(SMFICTX *ctx)
66 {
67 struct message_data *md;
68
69 if (mode == MAILFROMD_TEST)
70 md = test_message_data;
71 else
72 md = (struct message_data*) gacopyz_getpriv(ctx);
73
74 if (!md) {
75 md = malloc(sizeof(*md));
76 if (!md)
77 mu_error(_("not enough memory"));
78 else {
79 milter_sockaddr_t addr;
80 socklen_t len = sizeof(addr);
81
82 md->env = create_environment(ctx,
83 ctx_getsym,
84 ctx_setreply,
85 NULL,
86 ctx);
87 clear_rcpt_count(md->env);
88 md->helostr = NULL;
89 md->msgid[0] = 0;
90 gacopyz_setpriv(ctx, md);
91 env_init(md->env);
92 if (gacopyz_server_sockname(ctx, &addr, &len) == 0)
93 set_milter_server_address(md->env, &addr, len);
94 set_milter_server_id(md->env, gacopyz_getclosure(ctx));
95 if (gacopyz_client_sockname(ctx, &addr, &len) == 0)
96 set_milter_client_address(md->env, &addr, len);
97
98 xeval(md->env, smtp_state_begin);
99 }
100 }
101 if (!md->msgid[0]) {
102 /* FIXME: Cannot use env_get_macro here, because it
103 would create a recursion. */
104 const char *p = gacopyz_getsymval(ctx, "i");
105 if (p) {
106 size_t len = strlen(p);
107 if (len > sizeof md->msgid - 3)
108 len = sizeof md->msgid - 3;
109 memcpy(md->msgid, p, len);
110 md->msgid[len++] = ':';
111 md->msgid[len++] = ' ';
112 md->msgid[len] = 0;
113 }
114 }
115 return md;
116 }
117
118 const char *
mailfromd_msgid(SMFICTX * ctx)119 mailfromd_msgid(SMFICTX *ctx)
120 {
121 struct message_data *md = priv_get(ctx);
122 return md->msgid;
123 }
124
125
126 /* Run-time execution */
127
128 static const char *
ctx_getsym(void * data,const char * str)129 ctx_getsym(void *data, const char *str)
130 {
131 const char *ret = gacopyz_getsymval(data, str);
132 if (!ret) {
133 struct message_data *md = priv_get(data);
134 if (strcmp (str, "s") == 0)
135 ret = md->helostr;
136 }
137 return ret;
138 }
139
140 static int
ctx_setreply(void * data,char * code,char * xcode,char * message)141 ctx_setreply(void *data, char *code, char *xcode, char *message)
142 {
143 if (code)
144 return gacopyz_setreply(data, code, xcode, message);
145 return 0;
146 }
147
148
149 /* Message capturing functions */
150 static int capture_enabled;
151
152 void
capture_on()153 capture_on()
154 {
155 milter_enable_state(smtp_state_helo);
156 milter_enable_state(smtp_state_envfrom);
157 milter_enable_state(smtp_state_header);
158 milter_enable_state(smtp_state_eoh);
159 milter_enable_state(smtp_state_body);
160 milter_enable_state(smtp_state_eom);
161 capture_enabled = 1;
162 }
163
164 static void
capture_from(eval_environ_t env,const char * str)165 capture_from(eval_environ_t env, const char *str)
166 {
167 if (capture_enabled) {
168 time_t t;
169 struct tm *tm;
170 char datebuf[26];
171
172 env_capture_start(env);
173
174 t = time(NULL);
175 tm = localtime(&t);
176 mu_strftime(datebuf, sizeof datebuf,
177 "%a %b %d %H:%M:%S %Y", tm);
178
179 env_capture_write_args(env,
180 "From ", str, " ", datebuf, "\n", NULL);
181 }
182 }
183
184 static void
capture_header(eval_environ_t env,const char * hf,const char * hv)185 capture_header(eval_environ_t env, const char *hf, const char *hv)
186 {
187 env_capture_write_args(env, hf, ": ", hv, "\n", NULL);
188 }
189
190 static void
capture_eoh(eval_environ_t env)191 capture_eoh(eval_environ_t env)
192 {
193 env_capture_write_args(env, "\n", NULL);
194 }
195
196 static void
capture_body(eval_environ_t env,unsigned char * bodyp,size_t len)197 capture_body(eval_environ_t env, unsigned char *bodyp, size_t len)
198 {
199 env_capture_write(env, (char*) bodyp, len);
200 }
201
202 static void
capture_eom(eval_environ_t env)203 capture_eom(eval_environ_t env)
204 {
205 }
206
207
208 /* Cleanup functions */
209 void
filter_cleanup(SMFICTX * ctx)210 filter_cleanup(SMFICTX *ctx)
211 {
212 struct message_data *md = priv_get(ctx);
213 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE9, ("cleaning up"));
214 if (md) {
215 env_init(md->env);
216 xeval(md->env, smtp_state_end);
217 free(md->helostr);
218 destroy_environment(md->env);
219 free(md);
220 gacopyz_setpriv(ctx, NULL);
221 }
222 }
223
224
225 /* Milter interface functions */
226
227 int
xeval(eval_environ_t env,enum smtp_state tag)228 xeval(eval_environ_t env, enum smtp_state tag)
229 {
230 int rc;
231
232 rc = eval_environment(env, entry_point[tag]);
233 if (rc)
234 mu_error(_("execution of the filter program was not finished"));
235 if (tag == smtp_state_begin)
236 env_save_catches(env);
237
238 return rc;
239 }
240
241 sfsistat
mlfi_eval(SMFICTX * ctx,enum smtp_state tag)242 mlfi_eval(SMFICTX *ctx, enum smtp_state tag)
243 {
244 int rc;
245 sfsistat status;
246 struct message_data *md = priv_get(ctx);
247
248 rc = xeval(md->env, tag);
249 if (rc == 0)
250 status = environment_get_status(md->env);
251 else {
252 gacopyz_setreply(ctx, "410", NULL,
253 "Local configuration error; please try again later");
254 status = SMFIS_TEMPFAIL;
255 }
256 log_status(status, ctx);
257 return status;
258 }
259
260 sfsistat
mlfi_connect(SMFICTX * ctx,char * hostname,_SOCK_ADDR * hostaddr)261 mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
262 {
263 sfsistat status;
264 struct message_data *md = priv_get(ctx);
265 int port;
266 char *addrstr;
267 int family;
268
269 if (!hostaddr) {
270 family = MFAM_STDIO;
271 port = 0;
272 addrstr = "";
273 } else switch (hostaddr->sa.sa_family) {
274 case PF_INET:
275 family = MFAM_INET;
276 port = ntohs(hostaddr->sin.sin_port);
277 addrstr = inet_ntoa(hostaddr->sin.sin_addr);
278 break;
279
280 #ifdef GACOPYZ_IPV6
281 case PF_INET6: {
282 char host[NI_MAXHOST];
283
284 family = MFAM_INET6;
285 port = ntohs(hostaddr->sin6.sin6_port);
286 if (getnameinfo(&hostaddr->sa, sizeof(hostaddr->sin6),
287 host, sizeof host,
288 NULL, 0,
289 NI_NUMERICHOST) == 0)
290 addrstr = host;
291 else
292 addrstr = "[unresolved]";
293 break;
294 }
295 #endif
296
297 case PF_UNIX:
298 family = MFAM_UNIX;
299 port = 0;
300 addrstr = hostaddr->sunix.sun_path;
301 break;
302
303 default:
304 mu_error(_("mlfi_connect: unsupported address family: %d"),
305 hostaddr->sa.sa_family);
306 gacopyz_setreply(ctx, "410", NULL,
307 "Local configuration error; please try again later");
308 return SMFIS_TEMPFAIL;
309 }
310 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
311 ("Processing xxfi_connect: %s, %d, %s, %u",
312 hostname, family, addrstr, port));
313 mf_proctitle_format("Connect: %s, %d, %s, %u",
314 hostname, family, addrstr, port);
315
316 env_init(md->env);
317 env_push_string(md->env, addrstr);
318 env_push_number(md->env, port);
319 env_push_number(md->env, family);
320 env_push_string(md->env, hostname);
321 env_make_frame(md->env);
322 status = mlfi_eval(ctx, smtp_state_connect);
323 env_leave_frame(md->env, 4);
324 return status;
325 }
326
327 sfsistat
mlfi_helo(SMFICTX * ctx,char * helohost)328 mlfi_helo(SMFICTX *ctx, char *helohost)
329 {
330 sfsistat status;
331 struct message_data *md = priv_get(ctx);
332
333 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
334 ("Processing xxfi_helo: %s", helohost));
335 mf_proctitle_format("%sHELO %s", md->msgid, helohost);
336
337 if (md->helostr)
338 free (md->helostr);
339 md->helostr = mu_strdup(helohost);
340 env_init(md->env);
341 env_push_string(md->env, md->helostr);
342 env_make_frame(md->env);
343 status = mlfi_eval(ctx, smtp_state_helo);
344 env_leave_frame(md->env, 1);
345 return status;
346 }
347
348 static char *
concat_args(char ** argv)349 concat_args(char **argv)
350 {
351 size_t argc;
352 char *p = NULL;
353
354 for (argc = 0; argv[argc]; argc++)
355 ;
356 mu_argcv_string(argc, argv, &p);
357 return p;
358 }
359
360 sfsistat
mlfi_envfrom(SMFICTX * ctx,char ** argv)361 mlfi_envfrom(SMFICTX *ctx, char **argv)
362 {
363 sfsistat status;
364 struct message_data *md = priv_get(ctx);
365 char *p = concat_args(argv + 1);
366
367 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
368 ("Processing xxfi_envfrom: %s %s", argv[0], p));
369 mf_proctitle_format("%sMAIL FROM %s %s", md->msgid, argv[0], p);
370
371 env_init(md->env);
372 capture_from(md->env, argv[0]);
373 env_push_string(md->env, p);
374 free(p);
375 env_push_string(md->env, argv[0]);
376 env_make_frame(md->env);
377 status = mlfi_eval(ctx, smtp_state_envfrom);
378 env_leave_frame(md->env, 2);
379 return status;
380 }
381
382 sfsistat
mlfi_envrcpt(SMFICTX * ctx,char ** argv)383 mlfi_envrcpt(SMFICTX *ctx, char ** argv)
384 {
385 sfsistat status;
386 struct message_data *md = priv_get(ctx);
387 char *p = concat_args(argv + 1);
388
389 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
390 ("Processing xxfi_envrcpt: %s %s", argv[0], p));
391 mf_proctitle_format("%sRCPT TO %s %s", md->msgid, argv[0], p);
392 env_init(md->env);
393 env_push_string(md->env, p);
394 free(p);
395 env_push_string(md->env, argv[0]);
396 env_make_frame(md->env);
397 incr_rcpt_count(md->env);
398 status = mlfi_eval(ctx, smtp_state_envrcpt);
399 env_leave_frame(md->env, 2);
400 return status;
401 }
402
403 sfsistat
mlfi_data(SMFICTX * ctx)404 mlfi_data(SMFICTX *ctx)
405 {
406 sfsistat status;
407 struct message_data *md = priv_get(ctx);
408
409 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7, ("Processing xxfi_data:"));
410 mf_proctitle_format("%sDATA", md->msgid);
411 env_init(md->env);
412 env_make_frame(md->env);
413 status = mlfi_eval(ctx, smtp_state_data);
414 env_leave_frame(md->env, 1);
415 return status;
416 }
417
418 sfsistat
mlfi_header(SMFICTX * ctx,char * headerf,char * headerv)419 mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
420 {
421 sfsistat status;
422 struct message_data *md = priv_get(ctx);
423
424 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
425 ("Processing xxfi_header:"));
426 mf_proctitle_format("%sHeader", md->msgid);
427 env_init(md->env);
428 capture_header(md->env, headerf, headerv);
429 env_push_string(md->env, headerv);
430 env_push_string(md->env, headerf);
431 env_make_frame(md->env);
432 status = mlfi_eval(ctx, smtp_state_header);
433 env_leave_frame(md->env, 2);
434 return status;
435 }
436
437 sfsistat
mlfi_eoh(SMFICTX * ctx)438 mlfi_eoh(SMFICTX *ctx)
439 {
440 sfsistat status;
441 struct message_data *md = priv_get(ctx);
442 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7, ("Processing xxfi_eoh"));
443 mf_proctitle_format("%sEOH", md->msgid);
444 env_init(md->env);
445 capture_eoh(md->env);
446 env_make_frame(md->env);
447 status = mlfi_eval(ctx, smtp_state_eoh);
448 env_leave_frame(md->env, 0);
449 return status;
450 }
451
452 sfsistat
mlfi_body(SMFICTX * ctx,unsigned char * bodyp,size_t len)453 mlfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len)
454 {
455 sfsistat status;
456 struct message_data *md = priv_get(ctx);
457 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
458 ("Processing xxfi_body: %lu", (unsigned long) len));
459 mf_proctitle_format("%sBODY", md->msgid);
460 env_init(md->env);
461 capture_body(md->env, bodyp, len);
462 env_push_number(md->env, len);
463 /* Push bodyp as generic pointer to avoid unnecessary stack allocation.
464 User can then convert it to string using the body_string() call.
465 */
466 env_push_pointer(md->env, bodyp);
467 env_make_frame(md->env);
468 status = mlfi_eval(ctx, smtp_state_body);
469 env_leave_frame(md->env, 2);
470 return status;
471 }
472
473 size_t
mem_search(const char * str,int c,size_t size)474 mem_search(const char *str, int c, size_t size)
475 {
476 const char *p;
477
478 if (size == 0)
479 return 0;
480 p = memchr(str, c, size);
481 if (p)
482 return p - str;
483 return size;
484 }
485
486 int
xlate_and_replace_body(SMFICTX * ctx,const char * value,size_t size)487 xlate_and_replace_body(SMFICTX *ctx, const char *value, size_t size)
488 {
489 int rc;
490 mu_opool_t pool;
491
492 if ((rc = mu_opool_create(&pool, MU_OPOOL_DEFAULT))) {
493 mu_error(_("cannot create opool: %s"), mu_strerror(rc));
494 return 1;
495 }
496
497 while (size) {
498 size_t n = mem_search(value, '\n', size);
499 size_t off;
500
501 if (value[n] == '\n') {
502 off = n + 1;
503 if (n > 0 && value[n-1] == '\r')
504 n--;
505 } else
506 off = n;
507
508 if ((rc = mu_opool_append(pool, value, n)) != 0
509 || (rc = mu_opool_append(pool, "\r\n", 2)) != 0) {
510 mu_error(_("failed to append to opool: %s"),
511 mu_strerror(rc));
512 break;
513 }
514
515 value += off;
516 size -= off;
517 }
518
519 if (rc == 0) {
520 mu_iterator_t itr;
521 rc = mu_opool_get_iterator(pool, &itr);
522 if (rc) {
523 mu_error(_("%s failed: %s"),
524 "mu_opool_iterator_create",
525 mu_strerror(rc));
526 } else {
527 for (mu_iterator_first (itr);
528 !mu_iterator_is_done (itr);
529 mu_iterator_next (itr)) {
530 const char *ptr;
531 size_t len;
532 mu_iterator_current_kv (itr,
533 (const void**)&len,
534 (void **)&ptr);
535 rc = gacopyz_replace_body(ctx,
536 (const unsigned char*)ptr,
537 len);
538 if (rc) {
539 mu_error(_("%s failed: %s"),
540 "gacopyz_replace_body",
541 mu_strerror(errno));
542 break;
543 }
544 }
545 mu_iterator_destroy (&itr);
546 }
547 }
548 mu_opool_destroy (&pool);
549 return rc;
550 }
551
552 static int
run_msgmod(void * item,void * data)553 run_msgmod(void *item, void *data)
554 {
555 struct msgmod_closure *hdr = item;
556 SMFICTX *ctx = data;
557
558 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE6,
559 ("%s %s: %s %u",
560 msgmod_opcode_str(hdr->opcode),
561 SP(hdr->name), SP(hdr->value), hdr->idx));
562
563 switch (hdr->opcode) {
564 case header_add:
565 gacopyz_add_header(ctx, hdr->name, hdr->value);
566 break;
567
568 case header_replace:
569 gacopyz_change_header(ctx, hdr->idx, hdr->name, hdr->value);
570 break;
571
572 case header_delete:
573 gacopyz_change_header(ctx, hdr->idx, hdr->name, NULL);
574 break;
575
576 case header_insert:
577 gacopyz_insert_header(ctx, hdr->idx, hdr->name, hdr->value);
578 break;
579
580 case rcpt_add:
581 gacopyz_add_rcpt(ctx, hdr->name);
582 break;
583
584 case rcpt_delete:
585 gacopyz_del_rcpt(ctx, hdr->name);
586 break;
587
588 case quarantine:
589 gacopyz_quarantine(ctx, hdr->name);
590 break;
591
592 case body_repl:
593 xlate_and_replace_body(ctx, hdr->value, strlen(hdr->value));
594 break;
595
596 case body_repl_fd:
597 if (gacopyz_replace_body_fd(ctx, hdr->idx) != MI_SUCCESS) {
598 mu_error(_("%s failed: %s"),
599 "gacopyz_replace_body_fd",
600 mu_strerror(errno));
601 break;
602 }
603 break;
604
605 case set_from:
606 gacopyz_chgfrom(ctx, hdr->name, hdr->value);
607 break;
608
609 default:
610 abort();
611 }
612 return 0;
613 }
614
615 sfsistat
mlfi_eom(SMFICTX * ctx)616 mlfi_eom(SMFICTX *ctx)
617 {
618 sfsistat status;
619 struct message_data *md = priv_get(ctx);
620
621 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7, ("Processing xxfi_eom"));
622 mf_proctitle_format("%sEOM", md->msgid);
623
624 env_init(md->env);
625 capture_eom(md->env);
626 env_make_frame(md->env);
627 status = mlfi_eval(ctx, smtp_state_eom);
628 env_leave_frame(md->env, 0);
629 if ((status == SMFIS_ACCEPT || status == SMFIS_CONTINUE)
630 && env_msgmod_count(md->env) > 0) {
631 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE6,
632 ("flushing message modification queue"));
633 env_msgmod_apply(md->env, run_msgmod, ctx);
634 }
635
636 mf_proctitle_format("%sfinished", md->msgid);
637 clear_rcpt_count(md->env);
638 env_msgmod_clear(md->env);
639
640 return status;
641 }
642
643 sfsistat
mlfi_abort(SMFICTX * ctx)644 mlfi_abort(SMFICTX *ctx)
645 {
646 struct message_data *md = priv_get(ctx);
647
648 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7, ("Abort"));
649 mf_proctitle_format("%saborting", md->msgid);
650 env_msgmod_clear(md->env);
651 md->msgid[0] = 0;
652 /* Note: the value of helostr is not discarded: RFC 2822,
653 section 4.1.1.5 states that RSET issued immediately
654 after EHLO is effectively equivalent to a NOOP. */
655 env_init_dataseg(md->env);
656 return SMFIS_CONTINUE;
657 }
658
659 sfsistat
mlfi_close(SMFICTX * ctx)660 mlfi_close(SMFICTX *ctx)
661 {
662 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7, ("Close"));
663 mf_proctitle_format("closing");
664 filter_cleanup(ctx);
665 return SMFIS_CONTINUE;
666 }
667
668 static int
child_start()669 child_start()
670 {
671 signal(SIGPIPE, SIG_IGN);
672 signal(SIGALRM, SIG_IGN);
673 mf_proctitle_format("startup");
674 return 0;
675 }
676
677 enum smtp_state first_used_state = smtp_state_end;
678
679 sfsistat
mlfi_negotiate(SMFICTX * ctx,unsigned long mta_actions,unsigned long mta_capa,unsigned long unused1,unsigned long unused2,unsigned long * filter_actions,unsigned long * filter_capa,unsigned long * unused4,unsigned long * unused5)680 mlfi_negotiate(SMFICTX *ctx,
681 unsigned long mta_actions,
682 unsigned long mta_capa,
683 unsigned long unused1,
684 unsigned long unused2,
685 unsigned long *filter_actions,
686 unsigned long *filter_capa,
687 unsigned long *unused4,
688 unsigned long *unused5)
689 {
690 enum gacopyz_stage i;
691
692 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE7,
693 ("Negotiate: mta_actions=%#lx, mta_capa=%#lx, "
694 "filter_actions=%#lx, filter_capa=%#lx",
695 mta_actions, mta_capa, *filter_actions, *filter_capa));
696
697 if (first_used_state > smtp_state_first
698 && first_used_state < smtp_state_end) {
699 mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE6,
700 ("Registering \"i\" macro for state %s",
701 state_to_string(first_used_state)));
702 register_macro(first_used_state, "i");
703 }
704
705 for (i = 0; i < gacopyz_stage_max; i++) {
706 char *str = get_stage_macro_string(i);
707 gacopyz_setsymlist(ctx, i, str);
708 free(str);
709 }
710 return SMFIS_CONTINUE;
711 }
712
713 static struct smfiDesc smfilter =
714 {
715 "MailfromFilter",
716 SMFI_VERSION,
717 SMFI_V2_ACTS|SMFIF_CHGFROM, /* FIXME: Add flags as needed */
718 NULL, /* connection info filter */
719 NULL, /* SMTP HELO command filter */
720 NULL, /* envelope sender filter */
721 NULL, /* envelope recipient filter */
722 NULL, /* header filter */
723 NULL, /* end of header */
724 NULL, /* body block filter */
725 mlfi_eom, /* end of message */
726 mlfi_abort, /* message aborted */
727 mlfi_close, /* connection cleanup */
728 #ifdef GACOPYZ_VERSION_MAJOR
729 NULL, /* unknown command handler */
730 NULL, /* data handler */
731 mlfi_negotiate, /* negotiate */
732
733 child_start, /* child start */
734 NULL, /* child finish */
735 NULL, /* idle callback */
736 NULL /* Accept connection callback */
737 #endif
738 };
739
740
741 /* Milter server functions */
742
743 static void
setprocid(const char * id)744 setprocid(const char *id)
745 {
746 char *tag;
747
748 logger_close();
749 tag = mu_alloc(strlen(mu_log_tag) + 1 + strlen(id) + 1);
750 strcpy(tag, mu_log_tag);
751 strcat(tag, "#");
752 strcat(tag, id);
753 mu_log_tag = tag;
754 mf_server_log_setup();
755 }
756
757 int
milter_session_server(const char * id,int fd,struct sockaddr const * sa,socklen_t len,void * server_data,void * srvman_data)758 milter_session_server(const char *id, int fd,
759 struct sockaddr const *sa, socklen_t len,
760 void *server_data, void *srvman_data)
761 {
762 setprocid(id);
763 gacopyz_context_loop(fd, &smfilter, (milter_sockaddr_t*) sa, len,
764 (void*) id);
765 return 0;
766 }
767
768 int
mfd_callout_session_server(const char * id,int fd,struct sockaddr const * sa,socklen_t len,void * server_data,void * srvman_data)769 mfd_callout_session_server(const char *id, int fd,
770 struct sockaddr const *sa, socklen_t len,
771 void *server_data, void *srvman_data)
772 {
773 setprocid(id);
774 return callout_session_server(id, fd, sa, len,
775 server_data, srvman_data);
776 }
777
778 void
milter_setlogmask(int mask)779 milter_setlogmask(int mask)
780 {
781 smfilter.logmask = mask;
782 }
783
784 void
milter_settimeout(time_t t)785 milter_settimeout(time_t t)
786 {
787 smfilter.ctx_timeout.tv_sec = t;
788 smfilter.ctx_timeout.tv_usec = 0;
789 }
790
791
792 void
milter_enable_state(enum smtp_state state)793 milter_enable_state(enum smtp_state state)
794 {
795 if (state > smtp_state_first && state < smtp_state_end
796 && state < first_used_state)
797 first_used_state = state;
798
799 switch (state) {
800 case smtp_state_connect:
801 smfilter.xxfi_connect = mlfi_connect;
802 break;
803
804 case smtp_state_helo:
805 smfilter.xxfi_helo = mlfi_helo;
806 break;
807
808 case smtp_state_envfrom:
809 smfilter.xxfi_envfrom = mlfi_envfrom;
810 break;
811
812 case smtp_state_envrcpt:
813 smfilter.xxfi_envrcpt = mlfi_envrcpt;
814 break;
815
816 case smtp_state_data:
817 smfilter.xxfi_data = mlfi_data;
818 break;
819
820 case smtp_state_header:
821 smfilter.xxfi_header = mlfi_header;
822 break;
823
824 case smtp_state_eoh:
825 smfilter.xxfi_eoh = mlfi_eoh;
826 break;
827
828 case smtp_state_body:
829 smfilter.xxfi_body = mlfi_body;
830 break;
831
832 default:
833 break;
834 }
835 }
836
837