Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Dec 2000 19:35:30 -0600 (CST)
From:      "Scot W. Hetzel" <hetzels@westbend.net>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        gshapiro@freebsd.org, hetzels@westbend.net
Subject:   bin/23811: Sendmail Mail Filter (Milter)
Message-ID:  <200012240135.eBO1ZUT01117@spare.westbend.net>
Resent-Message-ID: <200012240140.eBO1e1H29108@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         23811
>Category:       bin
>Synopsis:       Patch to Sendmail Mail Filter (Milter) API
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Dec 23 17:40:00 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Scot W. Hetzel
>Release:        FreeBSD 4.2-STABLE i386
>Organization:
West Bend Internet
>Environment:


>Description:

The sendmail Mail Filter API (Milter) is designed to allow third-party
programs access to mail messages as they are being processed in order to
filter meta-information and content. (from libmilter/README)

While there is a way to enable the Milter API within sendmail, the
libmilter, libsmutil and header files needed to build a Milter daemon are
not installed.

A Milter daemon can be used for:

    - Filtering messages for viruses
    - changing extentions on attachements to prevent them from
      being accidenlty executed by the user.
    - Achiving messages sent/received thru the server
    - Append company disclaimer to all outgoing messages.

I was able to compile libmilter as a shared library.  But when I compiled
libsmutil as a shared library and tried to compile the sample.c from
libmilter/README, it gave me the following error:

cc -I/usr/include/sendmail -o sample sample.c -lmilter -lsmutil -pthread
/usr/lib/libsmutil.so: undefined reference to `message'
/usr/lib/libsmutil.so: undefined reference to `syserr'

both of these are defined in /usr/include/sendmail/sendmail.h.

Due to the above error with a shared libsmutil, the attached patch doesn't
build a shared libsmutil.

I had no problem building sample.c with:

cc -I/usr/include/sendmail -o sample sample.c -lmilter /usr/lib/libsmutil.a -pthread

I tested the sample milter dameon (w/shared libmilter) and sendmail.  The
sample milter dameon wrote the incoming message to a file in /tmp and
delivered it to the recipent mailbox (as described in libmilter/README).

NOTE: to use a milter daemon with sendmail, the *.mc file needs to define
_FFR_MILTER, as well as specifying the milter daemon (see libmilter/README).

    define(_FFR_MILTER)dnl
    INPUT_MAIL_FILTER(`sample', `S=local:/var/run/f1.sock')dnl

>How-To-Repeat:


>Fix:

The attached patch makes it so that the Milter API is compiled in to
Sendmail, and that the proper libraries and header files are installed.

Milter daemons need to start before sendmail is started.  A new startup
directory rc.milter is created in $PREFIX/etc/.  This directory should
contain milter startup scripts (similar to the scripts in rc.d).
rc/rc.shutdown have been modified to start/stop the milter daemon before/after
sendmail is started/stopped.


    Changed Files:                    New Files:
        Makefile                          lib/libmilter/Makefile
        etc/defaults/make.conf            lib/libmilter/sample.c
        etc/defaults/rc.conf              lib/libmilter/sample.sh
	etc/mtree/BSD.include.dist
	etc/mtree/BSD.local.dist
        etc/rc
        etc/rc.shutdown
        lib/Makefile
        lib/libsmutil/Makefile
        src/usr.sbin/sendmail/Makefile

NOTE: This patch was created on 4.2-STABLE, but does apply to a
    5.0-CURRENT source tree (with a little fuzziness on some files).

diff -ruN src.orig/Makefile.inc1 src/Makefile.inc1
--- src.orig/Makefile.inc1	Fri Dec 15 23:08:54 2000
+++ src/Makefile.inc1	Fri Dec 22 20:53:30 2000
@@ -208,6 +208,10 @@
 INCDIRS=	arpa g++/std objc protocols readline rpc rpcsvc openssl \
 		security ss
 
+.if defined(SENDMAIL_MILTER)
+INCDIRS+=	sendmail/libmilter sendmail/sendmail
+.endif
+
 #
 # buildworld
 #
diff -ruN src.orig/etc/defaults/make.conf src/etc/defaults/make.conf
--- src.orig/etc/defaults/make.conf	Mon Nov 20 23:16:23 2000
+++ src/etc/defaults/make.conf	Sat Dec 16 01:21:38 2000
@@ -314,3 +314,18 @@
 #SENDMAIL_LDFLAGS=
 #SENDMAIL_LDADD=
 #SENDMAIL_DPADD=
+#
+# Sendmail Mail Filter API (Experimental):
+#
+# The sendmail Mail Filter API (Milter) is designed to allow third-party
+# programs access to mail messages as they are being processed in order to
+# filter meta-information and content.
+#
+# see src/contrib/sendmail/libmilter/README for more information.
+#
+# By enableing the following variable, the sendmail daemon is built so that
+# it can talk to the mail filter daemons. libmilter.a, libsmutils.a and
+# the sendmail headers are installed, so that mail filter daemons can be
+# built.
+#
+#SENDMAIL_MILTER=	yes
diff -ruN src.orig/etc/defaults/rc.conf src/etc/defaults/rc.conf
--- src.orig/etc/defaults/rc.conf	Fri Dec 15 23:14:24 2000
+++ src/etc/defaults/rc.conf	Sat Dec 16 14:58:19 2000
@@ -302,6 +302,7 @@
 usbd_flags=""		# Flags to usbd (if enabled).
 sendmail_enable="YES"	# Run the sendmail daemon (or NO).
 sendmail_flags="-bd -q30m" # Flags to sendmail (if enabled)
+sendmail_milter_startup="/usr/local/etc/rc.milter" # milter startup script dirs.
 dumpdev="NO"		# Device name to crashdump to (or NO).
 enable_quotas="NO"      # turn on quotas on startup (or NO).
 check_quotas="YES"	# Check quotas on startup (or NO).
diff -ruN src.orig/etc/mtree/BSD.include.dist src/etc/mtree/BSD.include.dist
--- src.orig/etc/mtree/BSD.include.dist	Sun Nov  5 06:30:01 2000
+++ src/etc/mtree/BSD.include.dist	Sat Dec 16 14:32:03 2000
@@ -77,6 +77,12 @@
     ..
     security
     ..
+    sendmail
+        libmilter
+        ..
+        sendmail
+        ..
+    ..
     ss
     ..
     sys
diff -ruN src.orig/etc/mtree/BSD.local.dist src/etc/mtree/BSD.local.dist
--- src.orig/etc/mtree/BSD.local.dist	Sat Sep 16 17:26:07 2000
+++ src/etc/mtree/BSD.local.dist	Sat Dec 16 15:49:48 2000
@@ -10,6 +10,8 @@
     etc
         rc.d
         ..
+        rc.milter
+        ..
     ..
     include
     ..
diff -ruN src.orig/etc/rc src/etc/rc
--- src.orig/etc/rc	Fri Dec 15 23:14:26 2000
+++ src/etc/rc	Sat Dec 23 14:48:07 2000
@@ -442,6 +442,31 @@
 case ${sendmail_enable} in
 [Yy][Ee][Ss])
 	if [ -r /etc/mail/sendmail.cf ]; then
+		# For each valid dir in $sendmail_milter_startup,
+		# search for init scripts matching *.sh
+		#
+		# (Hmm.. maybe this code should be turned into a function
+		# and shared between local_startup & sendmail_milter_startup)
+		#
+		case ${sendmail_milter_startup} in
+		[Nn][Oo] | '')
+			;;
+		*)
+		#	echo -n 'Sendmail Milter initialization:'
+			for dir in ${sendmail_milter_startup}; do
+				if [ -d "${dir}" ]; then
+					for script in ${dir}/*.sh; do
+						if [ -x "${script}" ]; then
+							(set -T
+							 trap 'exit 1' 2
+							 ${script} start)
+						fi
+					done
+				fi
+			done
+		#	echo .
+			;;
+		esac
 		echo -n ' sendmail';	/usr/sbin/sendmail ${sendmail_flags}
 	fi
 	;;
diff -ruN src.orig/etc/rc.shutdown src/etc/rc.shutdown
--- src.orig/etc/rc.shutdown	Thu Nov  2 13:27:06 2000
+++ src/etc/rc.shutdown	Sat Dec 16 15:27:01 2000
@@ -91,6 +91,41 @@
 	;;
 esac
 
+case ${sendmail_enable} in
+[Yy][Ee][Ss])
+	# Should we shutdown sendmail daemon here also?
+#	killall -TERM sendmail
+
+	# for each valid dir in $sendmail_milter_startup, search for init scripts matching *.sh
+	case ${sendmail_milter_startup} in
+	[Nn][Oo] | '')
+		;;
+	*)
+		for dir in ${sendmail_milter_startup}; do
+			if [ -d "${dir}" ]; then
+				for script in ${dir}/*.sh; do
+					if [ -x "${script}" ]; then
+						grep -wq stop "${script}" || \
+						    oldmilterscripts="${oldmilterscripts} ${script}"
+# XXX not yet
+#						(set -T
+#						 trap 'exit 1' 2
+#						 ${script} stop)
+					fi
+				done
+			fi
+		done
+		if [ ! -z "${oldmilterscripts}" ]; then
+			echo 'You still seem to have old-style rc.milter scripts:'
+			echo ${oldmilterscripts}
+			echo 'Please change them to recognize the "stop" option.'
+		fi
+		echo .
+		;;
+	esac
+	;;
+esac
+
 # Insert other shutdown procedures here
 
 echo '.'
diff -ruN src.orig/lib/Makefile src/lib/Makefile
--- src.orig/lib/Makefile	Fri Oct 27 20:43:31 2000
+++ src/lib/Makefile	Sat Dec 16 01:21:38 2000
@@ -28,6 +28,10 @@
 	libposix1e libresolv librpcsvc libsmdb libsmutil libss \
 	libstand ${_libtelnet} libusb ${_libvgl} libwrap libxpg4 liby libz
 
+.if defined(SENDMAIL_MILTER)
+SUBDIR+= libmilter
+.endif
+
 .if exists(${.CURDIR}/csu/${MACHINE_ARCH}-${OBJFORMAT})
 _csu=csu/${MACHINE_ARCH}-${OBJFORMAT}
 .elif exists(${.CURDIR}/csu/${MACHINE_ARCH})
diff -ruN src.orig/lib/libmilter/Makefile src/lib/libmilter/Makefile
--- src.orig/lib/libmilter/Makefile	Wed Dec 31 18:00:00 1969
+++ src/lib/libmilter/Makefile	Sat Dec 23 14:57:27 2000
@@ -0,0 +1,51 @@
+# $FreeBSD$
+
+MAINTAINER=	gshapiro@FreeBSD.org
+
+SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
+.PATH:	${SENDMAIL_DIR}/libmilter
+
+CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include
+CFLAGS+=-DNEWDB -DNIS -DMAP_REGEX -DNOT_SENDMAIL -D_FFR_MILTER
+
+# User customizations to the sendmail build environment
+CFLAGS+=${SENDMAIL_CFLAGS}
+
+LIB=	milter
+
+SRCS+=	comm.c engine.c handler.c listener.c main.c signal.c \
+	sm_gethost.c smfi.c
+
+SM_HDRS=src/bf.h src/bf_portable.h src/bf_torek.h src/conf.h \
+	src/sendmail.h src/sfsasl.h src/statusd_shm.h src/timers.h
+
+M_HDRS=	libmilter/mfapi.h libmilter/milter.h
+
+SM2_HDRS=sendmail/cdefs.h sendmail/errstring.h sendmail/mailstats.h \
+	sendmail/pathnames.h sendmail/sendmail.h sendmail/useful.h
+
+.for h in ${SM_HDRS}
+SENDMAIL_HDRS+= ${SENDMAIL_DIR}/${h}
+.endfor
+
+.for h in ${M_HDRS}
+MILTER_HDRS+= ${SENDMAIL_DIR}/include/${h}
+.endfor
+
+.for h in ${SM2_HDRS}
+SENDMAIL2_HDRS+= ${SENDMAIL_DIR}/include/${h}
+.endfor
+
+beforeinstall:
+	${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
+	    ${SENDMAIL_HDRS} ${DESTDIR}/usr/include/sendmail
+	${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
+	    ${MILTER_HDRS} ${DESTDIR}/usr/include/sendmail/libmilter
+	${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
+		${SENDMAIL2_HDRS} ${DESTDIR}/usr/include/sendmail/sendmail
+
+sample:
+	cc -I/usr/include/sendmail -o sample sample.c -lmilter \
+		/usr/lib/libsmutil.a -pthread
+
+.include <bsd.lib.mk>
diff -ruN src.orig/lib/libmilter/sample.c src/lib/libmilter/sample.c
--- src.orig/lib/libmilter/sample.c	Wed Dec 31 18:00:00 1969
+++ src/lib/libmilter/sample.c	Sat Dec 23 14:56:17 2000
@@ -0,0 +1,233 @@
+/* A trivial filter that logs all email to a file. */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "libmilter/mfapi.h"
+
+typedef int bool;
+
+#ifndef FALSE
+# define FALSE	0
+#endif /* ! FALSE*/
+#ifndef TRUE
+# define TRUE	1
+#endif /* ! TRUE*/
+
+struct mlfiPriv
+{
+	char	*mlfi_fname;
+	FILE	*mlfi_fp;
+};
+
+#define MLFIPRIV	((struct mlfiPriv *) smfi_getpriv(ctx))
+
+extern sfsistat	 mlfi_cleanup(SMFICTX *, bool);
+
+sfsistat
+mlfi_envfrom(ctx, envfrom)
+	SMFICTX *ctx;
+	char **envfrom;
+{
+	struct mlfiPriv *priv;
+	int fd;
+
+	/* allocate some private memory */
+	priv = malloc(sizeof *priv);
+	if (priv == NULL)
+	{
+		/* can't accept this message right now */
+		return SMFIS_TEMPFAIL;
+	}
+	memset(priv, '\0', sizeof *priv);
+
+	/* open a file to store this message */
+	priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX");
+	if (priv->mlfi_fname == NULL)
+	{
+		free(priv);
+		return SMFIS_TEMPFAIL;
+	}
+	if ((fd = mkstemp(priv->mlfi_fname)) < 0 ||
+	    (priv->mlfi_fp = fdopen(fd, "w+")) == NULL)
+	{
+		free(priv->mlfi_fname);
+		free(priv);
+		return SMFIS_TEMPFAIL;
+	}
+
+	/* save the private data */
+	smfi_setpriv(ctx, priv);
+
+	/* continue processing */
+	return SMFIS_CONTINUE;
+}
+
+sfsistat
+mlfi_header(ctx, headerf, headerv)
+	SMFICTX *ctx;
+	char *headerf;
+	char *headerv;
+{
+	/* write the header to the log file */
+	fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv);
+
+	/* continue processing */
+	return SMFIS_CONTINUE;
+}
+
+sfsistat
+mlfi_eoh(ctx)
+	SMFICTX *ctx;
+{
+	/* output the blank line between the header and the body */
+	fprintf(MLFIPRIV->mlfi_fp, "\r\n");
+
+	/* continue processing */
+	return SMFIS_CONTINUE;
+}
+
+sfsistat
+mlfi_body(ctx, bodyp, bodylen)
+	SMFICTX *ctx;
+	u_char *bodyp;
+	size_t bodylen;
+{
+	/* output body block to log file */
+	if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0)
+	{
+		/* write failed */
+		(void) mlfi_cleanup(ctx, FALSE);
+		return SMFIS_TEMPFAIL;
+	}
+
+	/* continue processing */
+	return SMFIS_CONTINUE;
+}
+
+sfsistat
+mlfi_eom(ctx)
+	SMFICTX *ctx;
+{
+	return mlfi_cleanup(ctx, TRUE);
+}
+
+sfsistat
+mlfi_close(ctx)
+	SMFICTX *ctx;
+{
+	return SMFIS_ACCEPT;
+}
+
+sfsistat
+mlfi_abort(ctx)
+	SMFICTX *ctx;
+{
+	return mlfi_cleanup(ctx, FALSE);
+}
+
+sfsistat
+mlfi_cleanup(ctx, ok)
+	SMFICTX *ctx;
+	bool ok;
+{
+	sfsistat rstat = SMFIS_CONTINUE;
+	struct mlfiPriv *priv = MLFIPRIV;
+	char *p;
+	char host[512];
+	char hbuf[1024];
+
+	if (priv == NULL)
+		return rstat;
+
+	/* close the archive file */
+	if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF)
+	{
+		/* failed; we have to wait until later */
+		rstat = SMFIS_TEMPFAIL;
+		(void) unlink(priv->mlfi_fname);
+	}
+	else if (ok)
+	{
+		/* add a header to the message announcing our presence */
+		if (gethostname(host, sizeof host) < 0)
+			strlcpy(host, "localhost", sizeof host);
+		p = strrchr(priv->mlfi_fname, '/');
+		if (p == NULL)
+			p = priv->mlfi_fname;
+		else
+			p++;
+		snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
+		smfi_addheader(ctx, "X-Archived", hbuf);
+	}
+	else
+	{
+		/* message was aborted -- delete the archive file */
+		(void) unlink(priv->mlfi_fname);
+	}
+
+	/* release private memory */
+	free(priv->mlfi_fname);
+	free(priv);
+	smfi_setpriv(ctx, NULL);
+
+	/* return status */
+	return rstat;
+}
+
+struct smfiDesc smfilter =
+{
+	"SampleFilter",	/* filter name */
+	SMFI_VERSION,	/* version code -- do not change */
+	SMFIF_ADDHDRS,	/* flags */
+	NULL,		/* connection info filter */
+	NULL,		/* SMTP HELO command filter */
+	mlfi_envfrom,	/* envelope sender filter */
+	NULL,		/* envelope recipient filter */
+	mlfi_header,	/* header filter */
+	mlfi_eoh,	/* end of header */
+	mlfi_body,	/* body block filter */
+	mlfi_eom,	/* end of message */
+	mlfi_abort,	/* message aborted */
+	mlfi_close	/* connection cleanup */
+};
+
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int c;
+	const char *args = "p:";
+
+	/* Process command line options */
+	while ((c = getopt(argc, argv, args)) != -1)
+	{
+		switch (c)
+		{
+		  case 'p':
+			if (optarg == NULL || *optarg == '\0')
+			{
+				(void) fprintf(stderr, "Illegal conn: %s\n",
+					       optarg);
+				exit(EX_USAGE);
+			}
+			(void) smfi_setconn(optarg);
+			break;
+
+		}
+	}
+	if (smfi_register(smfilter) == MI_FAILURE)
+	{
+		fprintf(stderr, "smfi_register failed\n");
+		exit(EX_UNAVAILABLE);
+	}
+	return smfi_main();
+}
+
+/* eof */
diff -ruN src.orig/lib/libmilter/sample.sh src/lib/libmilter/sample.sh
--- src.orig/lib/libmilter/sample.sh	Wed Dec 31 18:00:00 1969
+++ src/lib/libmilter/sample.sh	Sat Dec 23 15:14:19 2000
@@ -0,0 +1,20 @@
+#!/bin/sh
+# Sample Filter Startup Scipt
+#
+# $FreeBSD$
+#
+
+case "$1" in
+
+start)
+	# We need to remove the old sock connection
+	# otherwise ./sample will not run.
+	if [ -S /var/run/f1.sock ]
+	then
+		rm /var/run/f1.sock
+	fi
+	./sample -p local:/var/run/f1.sock &
+	echo -n ' sample'
+
+stop)
+	killall -TERM sample
diff -ruN src.orig/lib/libsmutil/Makefile src/lib/libsmutil/Makefile
--- src.orig/lib/libsmutil/Makefile	Thu Oct 26 18:05:12 2000
+++ src/lib/libsmutil/Makefile	Sat Dec 23 14:51:45 2000
@@ -15,8 +15,11 @@
 
 SRCS+=	debug.c errstring.c lockfile.c safefile.c snprintf.c strl.c
 
-INTERNALLIB=		true
 NOPIC=			true
+
+.if !defined(SENDMAIL_MILTER)
+INTERNALLIB=		true
 INTERNALSTATICLIB=	true
+.endif
 
 .include <bsd.lib.mk>
diff -ruN src.orig/usr.sbin/sendmail/Makefile src/usr.sbin/sendmail/Makefile
--- src.orig/usr.sbin/sendmail/Makefile	Tue Oct 31 11:04:10 2000
+++ src/usr.sbin/sendmail/Makefile	Sat Dec 16 01:21:39 2000
@@ -23,6 +23,10 @@
 CFLAGS+=-I${SMDIR} -I${SENDMAIL_DIR}/include
 CFLAGS+=${DBMDEF} ${NIS} -DNETINET6 -DTCPWRAPPERS ${MAPS}
 
+.if defined(SENDMAIL_MILTER)
+CFLAGS+= -D_FFR_MILTER
+.endif
+
 SRCS=	alias.c arpadate.c bf_torek.c clock.c collect.c conf.c control.c \
 	convtime.c daemon.c deliver.c domain.c envelope.c err.c headers.c \
 	macro.c main.c map.c mci.c milter.c mime.c parseaddr.c queue.c \

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200012240135.eBO1ZUT01117>