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