Sendmail 8.13.3 Programmer’s Guide HP-UX 11i v1 and HP-UX 11i v2 Manufacturing Part Number: 5991-0705 February 2005 United States © Copyright 2005 Hewlett-Packard Development Company L.P.
Legal Notices The information in this document is subject to change without notice. Hewlett-Packard makes no warranty of any kind with regard to this manual, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. Hewlett-Packard shall not be held liable for errors contained herein or direct, indirect, special, incidental or consequential damages in connection with the furnishing, performance, or use of this material.
Contents About This Document 1. Introduction Milter Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Milter-Related Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Contents The smfi_quarantine() API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The xxfi_connect() Callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The xxfi_helo() Callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Contents v
Contents vi
Contents vii
Contents viii
About This Document This document describes how to use Milter APIs with Sendmail 8.13.3 on your HP-UX 11i v1 and HP-UX 11i v2 operating systems. It is assumed that the HP-UX 11i v1 or the HP-UX 11i v2 operating system software and the appropriate files, scripts, and subsets are installed on your system. Intended Audience This manual is intended for application developers who are responsible for developing filter applications using the Milter APIs.
Table 1 Document Contents (Continued) Chapter Description Milter APIs Describes all Milter APIs. Sample Program Includes a sample filter program. Related Documents For more information on Sendmail 8.13.3, see the following documents: • HP-UX Mailing Services Administrator’s Guide at http://www.docs.hp.com/hpux/netcom/index.html#Internet%2 0Services. • Request for Comments (RFC) Many sections of this manual refer to RFCs for more information about networking topics.
• The version of HP-UX you are using. Please note that the HP-UX networking communications publications group does not provide technical support for HP products. If your inquiry concerns technical support for an HP product, please use the Assistance directory page located at: http://www.hp.com/ghp/assist/directory.html or call HP support at (208) 323-2551.
xii
1 Introduction This chapter provides an overview of the Milter functionality introduced in Sendmail 8.13.3. In addition, the chapter briefly describes of the Milter architecture.
Introduction This chapter discusses the following topics: NOTE 2 • “Milter Overview” on page 3 • “Milter-Related Files” on page 5 • “Implementing Filtering Policies” on page 6 • “Communication Between an MTA and Milter” on page 7 • “Before You Begin” on page 8 All occurrences of Sendmail in this document refer to Sendmail 8.13.3.
Introduction Milter Overview Milter Overview Sendmail 8.13.3 contains an advanced and effective mail filtering facility called Milter, which stands for Mail Filter. Milter is both a protocol and a library. Milter APIs provide an interface for third-party software to validate and modify messages as they pass through the mail transport system. Milter APIs enable filters to “listen in” to the SMTP conversation and modify Simple Mail Transfer Protocol (SMTP) responses.
Introduction Milter Overview 4 • At various stages of the SMTP conversation, Sendmail sends a message over the socket to the Milter program. • The Milter library invokes a callback into your code and sends a reply message to Sendmail containing the return value from your callback.
Introduction Milter-Related Files Milter-Related Files The Sendmail 8.13.3 depot contains C header files, libraries, and example programs. You can download the Sendmail 8.13 software depot, supported on HP-UX 11i v1 and HP-UX 11i v2, from the following URL: http://www.software.hp.com When you install the depot on your system, the depot installs the milter-related libraries and header files on your system. The milter-related library and header files supplied with Sendmail 8.13.
Introduction Implementing Filtering Policies Implementing Filtering Policies Milter enables a system administrator to combine third-party filters with Sendmail to implement a desired mail filtering policy. For example, if a system administrator wants to perform the following tasks: • Scan incoming mail for viruses on different platforms. • Eliminate unsolicited commercial mail message.
Introduction Communication Between an MTA and Milter Communication Between an MTA and Milter Filter applications run as separate processes outside the Sendmail address space. The benefits of filter applications running as separate processes are as follows: • Filter applications do not need to run with "root" permissions, thereby, avoiding a large family of potential security problems. • Failures in a particular filter do not affect Sendmail or other filters.
Introduction Before You Begin Before You Begin Ensure that you have installed the Sendmail 8.13.3 depot from http://www.software.hp.com on your system. The Sendmail 8.13.3 depot contains the Milter archive library, libmilter.a, which you can use to build filter applications. For more information on configuring and building filter applications, see “Configuring and Compiling Milter APIs” on page 55.
2 Milter APIs This chapter discusses the different Milter APIs that Sendmail 8.13.3 includes.
Milter APIs 10 • “Library Control APIs” on page 11 • “Data Access APIs” on page 18 • “Message Modification APIs” on page 25 • “Other Message Handling APIs” on page 34 • “Callbacks” on page 36 Chapter 2
Milter APIs Library Control APIs Library Control APIs This section describes the library control APIs that Sendmail 8.13.3 includes. Filter applications use the library control APIs to provide the required information to Sendmail. Each of the library control APIs returns either MI_SUCCESS or MI_FAILURE to indicate the status of the operation. The library control APIs do not directly communicate with Sendmail, but they alter the state of the library.
Milter APIs Library Control APIs Arguments You must call smfi_register() with the following argument: descr Specifies a filter descriptor of type smfiDesc, which describes the functions of the filter.
Milter APIs Library Control APIs Table 2-1 describes the bitwise OR of zero or more values, which the xxfi_flags field can contain. The table also describes the possible actions of the filter. Table 2-1 The xxfi_flags Field Values Flag Description SMFIF_ADDHDRS Adds headers. SMFIF_CHGHDRS Changes and deletes headers. SMFIF_CHGBODY Replaces the body of the messageduring filtering. This can have significant performance impact if other filters filter the body after this filter.
Milter APIs Library Control APIs If you use the Sendmail RunAsUser option, you must set the permissions for UNIX or local sockets to 0600 (read/write permission only for the owner of the socket) or 0660 (read/write permission for the owner and group of the socket). To determine the permission for a UNIX or local domain socket, you can use the umask command and set umask to 007 or 077.
Milter APIs Library Control APIs otimeout Specifies the timeout value in seconds. You must specify a timeout value greater than 0 (zero). A value of 0 signifies that a filter does not to wait and, it does not signify that a filter must wait forever. Return Value The smfi_settimeout() API always returns MI_SUCCESS to the filter program. The smfi_main() API You can use the smfi_main() API to transfer control to the libmilter event loop. You must call smfi_main() after initializing a filter.
Milter APIs Library Control APIs #include int smfi_opensocket( bool rmsocket ); Arguments You must call smfi_opensocket() with the following argument smfi_opensocket Specifies the flag that indicates whether the library must try to remove any existing UNIX domain socket before trying to create a new one. Return Value smfi_opensocket() fails and returns MI_FAILURE because of the following reasons: • The interface socket is not created.
Milter APIs Library Control APIs By default, smfi_setdbg() returns MI_SUCCESS to the filter application. The smfi_stop() API You can use the smfi_stop() API to start an orderly shutdown of the Milter program. You can call smfi_stop() from any of the callbacks or any of the error-handling routines at any time. smfi_stop() causes each thread to finish its current connection and then exit the connection.
Milter APIs Data Access APIs Data Access APIs You can call the data access APIs from within the filter-defined callbacks to access information about the current connection or message. Following are the data access APIs: • smfi_getsymval() • smfi_getpriv() • smfi_setpriv() • smfi_setreply() • smfi_setmlreply() The following sections discuss the data access functions in detail. The smfi_getsymval() API You can use the smfi_getsymval() API to get the value of a Sendmail macro.
Milter APIs Data Access APIs Table 2-2 Sendmail Macros (Continued) xxfi_* Callbacks Sendmail Macros xxfi_envfrom() i, auth_type, auth_authen, auth_ssf, auth_author, mail_mailer, mail_host, mail_addr xxfi_envrcpt() rcpt_mailer, rcpt_host, rcpt_addr All macros specified with the xxfi_connect() and xxfi_helo() callbacks are active from the point they are received until the end of the connection.
Milter APIs Data Access APIs #include void* smfi_getpriv( SMFICTX *ctx ); Argument You must call smfi_getpriv() with the argument ctx, which specifies an opaque context structure. Return Value smfi_getpriv() returns the private data pointer stored by an earlier call to the smfi_setpriv() API, or NULL if none has been set. The smfi_setpriv() API You can use smfi_setpriv() to set the private data pointer for a connection. You can call smfi_setpriv() in any of the xxfi_* callbacks.
Milter APIs Data Access APIs The smfi_setreply() API You can use the smfi_setreply() API to set the default SMTP error reply code. Only 4xx and 5xx replies are accepted. You can call smfi_setreply() from any of the xxfi_* callbacks other than the xxfi_connect() callback. smfi_setreply() directly sets the SMTP error reply code for a connection. If subsequent error occurs because of an action taken by the filter, analyze the error code to identify the problem.
Milter APIs Data Access APIs • If the Milter program returns SMFI_TEMPFAIL and sets the reply code to 421, the SMTP server terminates the SMTP session with a 421 error code. Arguments You must call smfi_setreply() with the following arguments: ctx Specifies an opaque context structure. rcode Specifies a 3-digit (RFC 821 or RFC 2821) SMTP reply code as a null terminated string. You must not assign rcode to NULL, and rcode must be a valid 4XX or 5XX reply code.
Milter APIs Data Access APIs #include int smfi_setmlreply( SMFICTX *ctx, char *rcode, char *xcode, ... ); Following are some points to consider regarding smfi_setmlreply(): • Values passed to smfi_setmlreply() are not checked for standards compliance. • The message parameter must contain only printable characters; other characters can result in a undefined behavior.
Milter APIs Data Access APIs xcode Specifies the extended reply code as specified in RFC 1893 (Enhanced Mail System Status Codes) or 2034 (SMTP Service Extension for Returning Enhanced Error Codes). If xcode is NULL, an extended code is not used; otherwise, xcode must conform to RFC 1893 or RFC 2034. ... Specifies the remaining arguments, that are single lines of text (upto 32 arguments), which is used as the text part of the SMTP reply. The list must be NULL terminated.
Milter APIs Message Modification APIs Message Modification APIs The message modification APIs change the contents and attributes of a message. These APIs include additional communication with the MTA and return either MI_SUCCESS or MI_FAILURE to indicate the status of the operation. You can call these APIs only in the xxfi_eom() callback. A filter program must set the appropriate flag in the description passed to the smfi_register() API to call any message modification function.
Milter APIs Message Modification APIs int smfi_addheader( SMFICTX *ctx, char *headerf, char *headerv ); Following are some points to consider regarding smfi_addheader(): • smfi_addheader() does not change existing headers of a message. To change the current value of a header, use smfi_chgheader(). • A filter which calls smfi_addheader() must set the SMFIF_ADDHDRS flag in the smfiDesc_str passed to the smfi_register() API. • For smfi_addheader(), the order of the filter program is important.
Milter APIs Message Modification APIs • headerf or headerv value is NULL. • Adding headers in the current connection state is invalid. • Memory allocation fails. • Network error occurs. • SMFIF_ADDHDRS is not set when the smfi_register() API is called. smfi_addheader() returns MI_SUCCESS on success. Example Following is an example for smfi_addheader(): int ret; SMFICTX *ctx; ...
Milter APIs Message Modification APIs • The filter order is important for the smfi_chgheader() API. A filter application placed later in the sequence observes the changes already done by earlier filters. • The filter program does not check the name and the value of the header for standards compliance. However, each line of the header must be less than 2048 characters. If you require longer headers, use multiline headers.
Milter APIs Message Modification APIs smfi_chgheader() returns MI_SUCCESS on success. Example Following is an example of smfi_chgheader(): int ret; SMFICTX *ctx; ... ret = smfi_chgheader(ctx, "Content-Type", 1, "multipart/mixed;\n\tboundary='foobar'"); The smfi_insheader() API You can use the smfi_insheader() API to prepend a header to the current message. You can call smfi_insheader() only from the xxfi_eom() callback. The declaration of smfi_insheader() is as follows: #include
Milter APIs Message Modification APIs characters. If you need longer headers, use a multiline header. To make a multiline header, insert a LF (an ASCII 0x0a character, or \n in C) followed by at least one white space character, such as, a space (an ASCII 0x20 character) or tab (an ASCII 0x09 character, or \n in C). You must precede the LF with a CR (an ASCII 0x0d character) because the MTA adds this automatically. You must ensure that you do not violate any standards.
Milter APIs Message Modification APIs ... ret = smfi_insheader(ctx, 0, "First", "See me?"); The smfi_addrcpt() API You can use the smfi_addrcpt() API to add a recipient for the current message. You can call smfi_addrcpt() only from the xxfi_eom() callback. The declaration for smfi_addrcpt() is as follows: #include
Milter APIs Message Modification APIs The declaration for smfi_delrctp() is as follows: #include int smfi_delrcpt( SMFICTX *ctx; char *rcpt; ); The address is not deleted if an address and its expanded form do not match. Arguments You must call smfi_delrcpt() with the following arguments: ctx Specifies an opaque context structure. rcpt Specifies the recipient address to be removed. The recipient address is a non-NULL, null-terminated string.
Milter APIs Message Modification APIs #include int smfi_replacebody( SMFICTX *ctx, unsigned char *bodyp, int bodylen ); Following are some points to consider regarding smfi_replacebody(): • As the message body can be very large, setting SMFIF_CHGBODY can significantly affect the performance of the filter program. • If a filter program sets SMFIF_CHGBODY but does not call smfi_replacebody(), the original body remains unchanged. • The filter order is important for smfi_replacebody().
Milter APIs Other Message Handling APIs Other Message Handling APIs The following APIs provide special case handling instructions for the Milter API or the MTA, without altering the content or status of the message: • smfi_progress() • smfi_quarantine() You can call these APIs only in the xxfi_eom() callback. These APIs can invoke additional communication with the MTA. They return either MI_SUCCESS or MI_FAILURE to indicate the status of the operation.
Milter APIs Other Message Handling APIs The smfi_quarantine() API You can use the smfi_quarantine() API to quarantine the message using the specific reason. You can call smfi_quarantine() only from the xxfi_eom() callback. The declaration of smfi_quarantine() is as follows: #include int smfi_quarantine( SMFICTX *ctx; char *reason; ); Arguments You must call smfi_quarantine() with the following arguments: ctx Specifies an opaque context structure.
Milter APIs Callbacks Callbacks A filter application must implement one or more of the following callbacks, which are registered through the smfi_register() API: NOTE • xxfi_connect() • xxfi_helo() • xxfi_envfrom() • xxfi_envrcpt() • xxfi_header() • xxfi_eoh() • xxfi_body() • xxfi_eom() • xxfi_abort() • xxfi_close() You can replace the xx portion in the callback name with the name of your Milter program. The following sections discuss these callbacks in detail.
Milter APIs Callbacks If an earlier filter application rejects a connection in its xxfi_connect() callback, the current filter does not call xxfi_connect(). Arguments You must call xxfi_connect() with the following arguments: ctx Specifies an opaque context structure. hostname Specifies the host name of the message sender, as determined by a reverse lookup on the host address. If the reverse lookup fails, hostname contains the IP address of the message sender enclosed in square brackets. For example, [a.
Milter APIs Callbacks The xxfi_envfrom() Callback The xxfi_envfrom() callback handles the envelope FROM command. xxfi_envfrom() returns the SMFIS_CONTINUE value to the calling filter application. xxfi_envfrom() is called once during the beginning of each message and before calling the xxfi_envrcpt() callback. The declaration of xxfi_envfrom() is as follows: #include
Milter APIs Callbacks SMFIF_ACCEPT Accepts the message. The filter application does not call the xxfi_abort() callback to abort the message. The xxfi_envrcpt() Callback The xxfi_envrcpt() API handles the envelope RCTP command. xxfi_envrcpt() returns SMFIS_CONTINUE to the calling filter application. You can call xxfi_envrcpt() once for every recipient. If a message contains multiple recipients, you can call xxfi_envrcpt() multiple times, immediately after the xxfi_envfrom() callback.
Milter APIs Callbacks SMFIS_DISCARD Accepts and discards the message. The filter application does not call the xxfi_abort() callback to abort the message. SMFIS_ACCEPT Accepts the recipient. The filter application does not call the xxfi_abort() callback to abort the message. The xxfi_header() Callback The xxfi_header() handles the message header and returns the SMFIS_CONTINUE value to the calling filter application.
Milter APIs Callbacks You must call xxfi_eoh() with the ctx argument, which specifies an opaque context structure. The xxfi_body() Callback The xxfi_body() callback handles a portion of message body and returns the SMFIS_CONTINUE value to the calling filter application. The filter application calls xxfi_body() multiple times after calling the xxfi_eoh() callback and before calling the xxfi_eom() callback. The declaration of xxfi_body() is as follows: #include
Milter APIs Callbacks bodyp Specifies a pointer to the beginning of a block of body data. bodyp is not valid outside a call to the xxfi_body() callback. len Specifies the amount of data pointed by bodyp. The xxfi_eom() Callback The xxfi_eom() callback denotes the end of a message and returns the SMFIS_CONTINUE value to the calling filter application. xxfi_eom() is called once after all calls to the xxfi_body() callback for a given message.
Milter APIs Callbacks • xxfi_abort() must reclaim any resource allocated on a per-message basis and must be tolerant of being called between any two message-oriented callbacks. • Calls to xxfi_abort() and xxfi_eom() are mutually exclusive. • xxfi_abort() is not responsible for reclaiming connection-specific data because xxfi_close() is always called when a connection is closed. • Because xxfi_abort() aborts the message, the filter application ignores the return value of xxfi_abort().
Milter APIs Callbacks data to the filter application until the client closes down the connection. This is this time when xxfi_close() is called to close the connection. • xxfi_close() is called on close even if the previous mail transaction was aborted. • xxfi_close() is responsible for freeing any resource allocated on a per-connection basis. • The filter application ignores the return value of xxfi_close() because after the connection is closed, the return value does not hold any importance.
3 Control Flow of Milter APIs This chapter discusses the call order sequence and resource management techniques for Milter APIs. It also discusses the control flow, and performance enhancement of Milter APIs.
Control Flow of Milter APIs It discusses the following topics: 46 • “Call Order Sequence” on page 47 • “Initialization Parameters for Filter Applications” on page 49 • “Sample Filter Pseudocode” on page 50 • “Multithreading” on page 52 • “Resource Management” on page 53 • “Signal Handling” on page 54 Chapter 3
Control Flow of Milter APIs Call Order Sequence Call Order Sequence Figure 3-1 illustrates the sequence in which the filter applications are called in a Milter program.
Control Flow of Milter APIs Call Order Sequence A filter application cannot process any message untill it registers its callbacks with Sendmail. A filter application initiates a filter session using the smfi_setconn() API. The filter application initiates the session once and before calling the smfi_main() API. The smfi_setconn() API sets the socket through which the filter application communicates with Sendmail.
Control Flow of Milter APIs Initialization Parameters for Filter Applications Initialization Parameters for Filter Applications In addition to initializing libmilter, a filter application must initialize the following parameters before calling the smfi_main() API: • The callbacks the filter program requires to call and the types of message modification you intend to perform. You must initializing these parameters. For more information, see “The smfi_register() API” on page 11.
Control Flow of Milter APIs Sample Filter Pseudocode Sample Filter Pseudocode The following pseudocode describes the filtering process from the perspective of a set of N MTAS, each corresponding to an SMTP connection.
Control Flow of Milter APIs Sample Filter Pseudocode To write a filter application, you must invoke different callbacks to process relevant parts of a message transaction. The Milter library then controls all sequencing, threading, and protocol exchange with Sendmail. Table 3-1 outlines the control flow for a filter process and denotes different callbacks invoked during an SMTP transaction.
Control Flow of Milter APIs Multithreading Multithreading A single filter process can handle any number of connections simultaneously. All the filtering callbacks must therefore be reentrant and they must use appropriate external synchronization methods to access global data.
Control Flow of Milter APIs Resource Management Resource Management You must deallocate per-connection resources because filter applications exist for a long time and they handle many connections. The lifetime of a connection depends on calls to the callbacks xxfi_connect() and xxfi_close(). For more information on message-oriented and connection-oriented APIs, see “Message Modification APIs” on page 25 and “Data Access APIs” on page 18, respectively.
Control Flow of Milter APIs Signal Handling Signal Handling The Milter library, libmilter.a, manages signal handling, and the signals do not directly influence filter applications. Sendmail 8.13.3 includes the following signal handlers: 54 • Stop – Specifies that new connections from the MTA are not accepted but existing connections are allowed to continue. • Abort – Specifies that all filter applications will be stopped after the next communication with Sendmail happens.
4 Configuring and Compiling Milter APIs This chapter discusses how to configure Milter APIs and to compile them with Sendmail.
Configuring and Compiling Milter APIs This chapter discusses the following topics: 56 • “Compiling and Installing Your Filter” on page 57 • “Configuring Milter in Sendmail” on page 58 Chapter 4
Configuring and Compiling Milter APIs Compiling and Installing Your Filter Compiling and Installing Your Filter To compile a filter, you must complete the following steps: 1. Insert the include and Sendmail directories in your include path. For example, -I/path/to/include -I path/to/sendmail. 2. Ensure that the libmilter.a file is in your library path and link your filter application with this file. For example, you can use the -lmilter option to link your the filter application with this file. 3.
Configuring and Compiling Milter APIs Configuring Milter in Sendmail Configuring Milter in Sendmail You must define a filter in your Sendmail configuration file and compile Sendmail. To define a filter application in your Sendmail configuratin file, complete the following steps: 1. You must add filters to your /usr/contrib/sendmail/etc/mail/cf/cf/generic-hpux-10.mc file. You can use the following commands to configure filters in the .
Configuring and Compiling Milter APIs Configuring Milter in Sendmail Table 4-1 lists the different mf variables and cf options. Table 4-1 The mf Variables and cf Options The .mc File The .cf File Default Value confMILTER_MACROS_CO NNECT Milter.macros .connect j, _, {daemon_name}, {if_name}, {if_addr} confMILTER_MACROS_HE LO Milter.macros .helo {tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer} confMILTER_MACROS_EN VFROM Milter.macros .
Configuring and Compiling Milter APIs Configuring Milter in Sendmail Sendmail 8.13.3 continues with the normal handling of the current connection. For every new connection, Sendmail 8.13.3 attempts to contact the filter application again. Table 4-3 lists and describes the different fields in the T= equate. Table 4-3 The T= Equate Values Flag Description C Specifies the timeout value for connecting to a filter application. If you set C to 0, the system connect() timeout value is used.
Configuring and Compiling Milter APIs Configuring Milter in Sendmail Run the following command to generate the configuration file, myconfig.cf: m4 ../m4/cf.m4 myconfig.mc > myconfig.cf These macros add the following entries to your Sendmail configuration file (sendmail.cf): Xfilter1, S=unix:/var/run/f1.sock, F=R Xfilter2, S=unix:/var/run/f2.sock, F=T, T=S:1s;R:1s;E:5m Xfilter3, S=inet:999@localhost, T=C:2m O InputMailFilters=filter2,filter1,filter3 By default, the filters run in the order defined in the .
Configuring and Compiling Milter APIs Configuring Milter in Sendmail 62 Chapter 4
5 Sample Program This chapter contains a sample C program for a filter application.
Sample Program Milter Sample Program Milter Sample Program Following is a sample filter program. #include #include #include #include #include #include #include #include #include "libmilter/mfapi.
Sample Program Milter Sample Program struct mlfiPriv *priv; char *ident; /* 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); /* save the private data */ smfi_setpriv(ctx, priv); ident = smfi_getsymval(ctx, "_"); if (ident == NULL) ident = "???"; if ((priv->mlfi_connectfrom = strdup(ident)) == NULL) { (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue process
Sample Program Milter Sample Program (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } snprintf(buf, len, "%s, %s", helohost, tls); if (priv->mlfi_helofrom != NULL) free(priv->mlfi_helofrom); priv->mlfi_helofrom = buf; /* continue processing */ return SMFIS_CONTINUE; } sfsistat mlfi_envfrom(ctx, argv) SMFICTX *ctx; char **argv; { int fd = -1; int argc = 0; struct mlfiPriv *priv = MLFIPRIV; char *mailaddr = smfi_getsymval(ctx, "{mail_addr}"); /* open a file to store this message */ if ((priv->mlfi_fn
Sample Program Milter Sample Program /* log the connection information we stored earlier: */ if (fprintf(priv->mlfi_fp, "Connect from %s (%s)\n\n", priv->mlfi_helofrom, priv->mlfi_connectfrom) == EOF) { (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* log the sender */ if (fprintf(priv->mlfi_fp, "FROM %s (%d argument%s)\n", mailaddr ? mailaddr : "???", argc, (argc == 1) ? "" : "s") == EOF) { (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue processing */ return SMFIS_CONTINUE
Sample Program Milter Sample Program rcptaddr ? rcptaddr : "???", argc, (argc == 1) ? "" : "s") == EOF) { (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue processing */ return SMFIS_CONTINUE; } sfsistat mlfi_header(ctx, headerf, headerv) SMFICTX *ctx; char *headerf; unsigned char *headerv; { /* write the header to the log file */ if (fprintf(MLFIPRIV->mlfi_fp, "%s: %s\n", headerf,\ headerv) == EOF) { (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue processing */ ret
Sample Program Milter Sample Program SMFICTX *ctx; unsigned char *bodyp; size_t bodylen; { struct mlfiPriv *priv = MLFIPRIV; /* output body block to log file */ if (fwrite(bodyp, bodylen, 1, priv->mlfi_fp) != 1) { /* write failed */ fprintf(stderr, "Couldn’t write file %s: %s\n", priv->mlfi_fname, strerror(errno)); (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue processing */ return SMFIS_CONTINUE; } sfsistat mlfi_eom(ctx) SMFICTX *ctx; { bool ok = TRUE; /* change recipients, if reques
Sample Program Milter Sample Program 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 */ fprintf(stderr, "Couldn’t close archive file %s: %s\n", priv->mlfi_fname, strerror(errno)); 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) snpri
Sample Program Milter Sample Program /* release private memory */ if (priv->mlfi_fname != NULL) free(priv->mlfi_fname); /* return status */ return rstat; } sfsistat mlfi_close(ctx) SMFICTX *ctx; { struct mlfiPriv *priv = MLFIPRIV; if (priv == NULL) return SMFIS_CONTINUE; if (priv->mlfi_connectfrom != NULL) free(priv->mlfi_connectfrom); if (priv->mlfi_helofrom != NULL) free(priv->mlfi_helofrom); free(priv); smfi_setpriv(ctx, NULL); return SMFIS_CONTINUE; } struct smfiDesc smfilter = { "SampleFilter",/* filte
Sample Program Milter Sample Program { fprintf(stderr, "Usage: %s -p socket-addr [-t timeout] [-r reject-addr] [-a add-addr]\n", prog); } int main(argc, argv) int argc; char **argv; { bool setconn = FALSE; int c; const char *args = "p:t:r:a:h"; extern char *optarg; /* 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); if (smfi_setconn(optarg)==MI_F
Sample Program Milter Sample Program break; case ’t’: if (optarg == NULL || *optarg == ’\0’) { (void) fprintf(stderr, "Illegal timeout: %s\n", optarg); exit(EX_USAGE); } if (smfi_settimeout(atoi(optarg)) == MI_FAILURE) { (void) fprintf(stderr, "smfi_settimeout failed\n"); exit(EX_SOFTWARE); } break; case ’r’: if (optarg == NULL) { (void) fprintf(stderr, "Illegal reject rcpt: %s\n",optarg); exit(EX_USAGE); } reject = optarg; break; case ’a’: if (optarg == NULL) { (void) fprintf(stderr, "Illegal add rcpt: %s\
Sample Program Milter Sample Program { fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); usage(argv[0]); exit(EX_USAGE); } if (smfi_register(smfilter) == MI_FAILURE) { fprintf(stderr, "smfi_register failed\n"); exit(EX_UNAVAILABLE); } return smfi_main(); } /* eof */ This sample program logs each message to a separate temporary file, adds a recipient given with the -a flag, and rejects a disallowed recipient address given with the -r flag.