@c This file is part of the Mailfromd manual.
@c Copyright (C) 2008--2025 Sergey Poznyakoff
@c See file mailfromd.texi for copying conditions.
@c *******************************************************************
@cindex @command{pmult}, described
@pindex pmult
  @command{Pmult} is a @dfn{Pmilter--Milter multiplexer}, i.e. a
program that acts as a mediator between the @i{Pmilter} server
and one or several @i{Milter} clients.   Usually, the former is
an instance of @command{smtps} from MeTA1, and the latter are running
@command{mailfromd} instances.  @command{Pmult} receives Pmilter
commands from the server, translates them into equivalent Milter
commands and passes the translated requests to a preconfigured set of
Milter filters.  When the filters reply, the reverse operation is performed:
Milter responses are translated into their Pmilter equivalents and
are sent back to the server.

@example
@group
                                            +-----------------+ 
                                     +----->| Milter Client 1 |
                                     |      +-----------------+ 
                                     |       
   +-----------+       +---------+   |      +-----------------+ 
   |   MeTA1   |<=====>|  Pmult  |<--+----->| Milter Client 1 | 
   +-----------+       +---------+   |      +-----------------+ 
                                     |
                                     +--------->    //
                                     |
                                     |      +-----------------+  
                                     +----->| Milter Client N | 
                                            +-----------------+
@end group
@end example

@cindex @command{pies}                                            
  Due to the specifics nature of the threaded MeTA1 libraries,
@command{pmult} does not detach from the controlling terminal
(i.e. does not become a daemon).  To run it as a background process,
we recommend to use @command{pies} daemon.  @samp{Pies} is a powerful
utility that allows you to launch several foreground-designed programs
in the background and control their execution.  @xref{Top, Pies Manual,
Pies, pies, Pies Manual}, for a detailed description of the program.
For a practical advice on how to use it with @command{pmult}, see 
@ref{Simple Pies, Using Pies to Run Pmult,, pies, Pies Manual}.  For
a description on how to start both @command{pmult} and MeTA1 from
the same @command{pies} configuration file, see @ref{Hairy Pies, Using
Pies to Run Pmult and MeTA1 ,, pies, Pies Manual}.

@menu
* pmult configuration::
* pmult example::
* pmult invocation::
@end menu

@node pmult configuration
@section Pmult Configuration
  @command{Pmult} reads its configuration from the main configuration 
file @file{/etc/mailfromd.conf}.  Unless it is the only component of
the @samp{Mailfromd} package that is being run, its configuration
should be explicitly marked as such by using either @code{program} or
@code{include} statement, as described in @ref{Mailfromd Configuration}.

The following standard Mailutils statements are understood:

@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug @tab @xref{debug statement, Mailutils Configuration File,,
mailutils, GNU Mailutils Manual}.
@item logging @tab @xref{logging statement, Mailutils Configuration File,,
mailutils, GNU Mailutils Manual}.
@item include @tab @xref{include, Mailutils Configuration File,,
mailutils, GNU Mailutils Manual}.
@end multitable

@menu
* pmult-conf::     Multiplexer Configuration.
* pmult-macros::   Translating MeTA1 macros.
* pmult-client::   Pmult Client Configuration.
* pmult-debug::    Debugging Pmult.
@end menu

@node pmult-conf
@subsection Multiplexer Configuration.
@cindex debugging, pmult
@cindex pmult debugging
  @command{Pmult} listens for Pmilter requests on a socket, configured
using @code{listen} statement:

@deffn {Pmult Conf} listen @var{url}
Listen on the given @var{url}.  Argument is a valid Mailutils
@acronym{URL}.  @xref{milter port specification}, for a description of
@var{url}. 
@end deffn

  Since @command{pmult} runs as a foreground program, it does not write
its PID number to a file by default.  If this behavior is required, it
can be enabled using the following statement:

@deffn {Pmult Conf} pidfile @var{file}
Store PID of the @command{pmult} process in @var{file}.
@end deffn

The following three limits require MeTA1 version @samp{PreAlpha30.0}
or later.

@deffn {Pmult Conf} max-threads-soft @var{n}
``Soft'' limit on the number of @samp{pmilter} threads.  Default is 2.
@end deffn

@deffn {Pmult Conf} max-threads-hard @var{n}
``Hard'' limit on the number of @samp{pmilter} threads.  This is
roughly equivalent to the number of emails @command{pmult} is able
to handle simultaneously.  The default value is 6.  Raise this limit
if you experience long delays when connecting to the @acronym{SMTP} port.
@end deffn

@deffn {Pmult Conf} max-pmilter-fd @var{n}
Maximum number of file descriptors @samp{pmilter} library is allowed
to open simultaneously.  Default is 10. 
@end deffn

@node pmult-macros
@subsection Translating MeTA1 macros.
@cindex macros, MeTA1
@cindex meta1 macros
  MeTA1's notion of macros differs considerably from that of Sendmail.
Macros in MeTA1 are identified by integer numbers and only a limited
number of macros can be provided for each @dfn{Pmilter stage}.
Pmilter stages mostly correspond to Milter states (@pxref{handler
names}), except that there are no distinct header and body stages,
instead these two are combined into a single @samp{data} stage.  This
comes unnoticed to mailfromd scripts, because @command{pmult} takes
care to invoke right Milter handlers within the single @samp{data}
Pmilter state.  Therefore in the discussion that follows we will refer
to Mailfromd handlers, rather than to Pmilter stages.

@cindex i, @command{Sendmail} macro in @command{MeTA1}
The most important standard Milter macros are always provided by
@command{pmult} itself.  These are:

@table @asis
@item client_addr
The IP address of the SMTP client.  As of version @value{VERSION},
only IPv4 addresses are supported.  Defined in all handlers.

@item client_port
The port number of the SMTP client.  Defined in all handlers.

@item i
MeTA1 session ID.  Defined in all handlers.

@item f
The envelope sender (from) address.  Defined in @code{envfrom} and
subsequent handlers.

@item nbadrcpts
The number of bad recipients for a single message.  Defined in
@code{envfrom} and @code{envrcpt} handlers.
           
@item ntries
The number of delivery attempts.  As of version @value{VERSION} it is
always @samp{1}.  Defined in @code{envfrom} and subsequent handlers.

@item nrcpts
The number of validated recipients for a single message.  Defined in
@code{envfrom} and @code{envrcpt} handlers.

@item r
Protocol used to receive the message.  The value of this macro is
always @samp{SMTP}.  Defined in all handlers.

@item rcpt_host
The host from the resolved triple of the address given for the SMTP
RCPT command.  Defined in @code{envrcpt} handler.

@item rcpt_addr
The address part of the resolved triple of the address given for the
SMTP RCPT command.  Defined in @code{envrcpt} handler.

@item s
Sender's helo domain (parameter to @code{EHLO} or @code{HELO}
command).
@end table

Two additional macros are provided for all handlers that allow to
identify whether the message is processed via @command{pmult}:

@table @asis
@item multiplexer
Canonical name of the multiplexer program, i.e.@: @samp{pmult}.  

@item mult_version
Version of @command{pmult}.
@end table

These macros can be used in mailfromd filters to provide alternative
processing for messages coming from a MeTA1 server.

Macros defined in MeTA1 can be made available in Mailfromd handlers
using the @code{define-macros} statement.

@deffn {Pmult Conf} define-macros @var{handler} @var{macros}
Define a set of Sendmail macros for the given Mailfromd handler.
Allowed values for @var{handler} are: @samp{connect}, @samp{helo},
@samp{mail} (or @samp{envfrom}), @samp{rcpt} (or @samp{envrcpt}),
@samp{data} (or @samp{header} or @samp{body}), @samp{dot}
(@samp{eom}).  A list of these values is also accepted, in which case
@var{macros} are defined for each handler from the list.

The second argument specifies a list of names of the macros that
should be defined in this handler.  Allowed macro names are:

@table @asis
@item hostname
Hostname of SMTP server.

@item client_resolve
Result of client lookup.

@item tls_version
TLS/SSL version used.

@item tls_cipher_suite
TLS cipher suite used.

@item tls_cipher_bits
Effective key length of the symmetric encryption algorithm.

@item tls_cert_subject
The DN (distinguished name) of the presented certificate.

@item tls_cert_issuer
The DN (distinguished name) of the CA (certificate authority) that
signed the presented certificate (the cert issuer).

@item tls_alg_bits
Maximum key length of the symmetric encryption algorithm.  This may be
less than the effective key length for export controlled algorithms.

@item tls_vrfy
The result of the verification of the presented cert.

@item tls_cn_subject
@itemx cn_subject
The CN (common name) of the presented certificate.

@item tls_cn_issuer
@itemx cn_issuer
The CN (common name) of the CA that signed the presented certificate.

@item auth_type
The  mechanism used for SMTP authentication (only set if successful).
           
@item auth_authen
The client's authentication credentials as determined by
authentication (only set if successful).  The actual format depends on
the mechanism used, it might be just @samp{user}, or
@samp{user@@realm}, or something similar.
                                            
@item auth_author      
The authorization identity, i.e. the @samp{AUTH=} parameter of the
SMTP MAIL command if supplied.

@item taid             
MeTA1 transaction id.

@item msgid
Message-Id of the message.

@item c                
The hop count.  Basically, this is the number of @samp{Received:} headers.
@end table

Notice the following limitations:

@enumerate 1
@item @samp{taid} cannot be requested before @samp{mail} stage.
@item @samp{msgid} can be requested only in @samp{dot} stage.
@item All @samp{tls_*} macros are valid only after a @code{STARTTLS}
command.
@item The number of MeTA1 macros per stage is limited by
@code{PM_MAX_MACROS} define in @file{include/sm/pmfdef.h}.  In MeTA1
versions up to and including 1.0.PreAlpha28.0, this number is 8.  If
you need more macros, increase this number and recompile MeTA1.
@end enumerate
@end deffn

@deffn {Pmult Conf} auth-macros @var{bool}
If @var{bool} is @code{true} (@pxref{Statements,boolean,,mailutils,
GNU Mailutils Manual}), pass auth macros to mailfromd @samp{mail}
handler.  It is equivalent to:

@example
define-macros mail (auth_type, auth_authen, auth_author);
@end example
@end deffn

@node pmult-client
@subsection Pmult Client Configuration.
  In @command{pmult} terminology, remote Milters are @dfn{clients}.
The number of clients @command{pmult} is able to handle is not
limited.  Each client is declared using @code{client} statement:

@example
client [@var{ident}] @{
  # @r{Set remote protocol type.}
  type @var{protocol-type};
  # @r{Set remote client URL.}
  url @var{arg};
  # @r{Set write timeout.}
  write-timeout @var{duration};
  # @r{Set read timeout.}
  read-timeout @var{duration};
  # @r{Set timeout for EOM.}
  eom-timeout @var{duration};
  # @r{Set connect timeout.}
  connect-timeout @var{duration};
  # @r{Set log verbosity level.}
  log-level @var{level};
@};
@end example

@deffn {Pmult Conf} client [@var{ident}] @{ @var{statements} @}
Declare a Milter client.  Optional @var{ident} gives the identifier of
this client, which will be used in diagnostics messages.

@var{Statements} are described below.
@end deffn

@deffn {Pmult Conf} type @var{typestr}
This statement is reserved for future use.  In version @value{VERSION}
it is a no-op.

If given, the value of @var{typestr} must be @samp{milter}.

In future versions this statement will declare the protocol to be used
to interact with this client.  The syntax for @var{typestr} is

@example
  @var{type} [@var{version}]
@end example

@noindent
where @var{type} is either @samp{milter} or @samp{pmilter}, and
optional @var{version} is minimal protocol version.
@end deffn

@deffn {Pmult Conf} url @var{arg}
Set remote client @acronym{URL}.  @xref{milter port specification}, for a
description of @var{url}.
@end deffn
  
@deffn {Pmult Conf} connect-timeout @var{interval}
Configure Milter initial connection timeout.  Default is
@value{GACOPYZ_CONNECT_TIMEOUT}.

@xref{time interval specification}, for information on @var{interval} format.  
@end deffn
  
@deffn {Pmult Conf} write-timeout @var{interval}
Configure Milter write timeout.  Default is @value{GACOPYZ_WRITE_TIMEOUT}.

@xref{time interval specification}, for information on @var{interval} format.  
@end deffn
  
@deffn {Pmult Conf} read-timeout @var{interval}
Configure Milter read timeout.  Default is @value{GACOPYZ_READ_TIMEOUT}.

@xref{time interval specification}, for information on @var{interval} format.  
@end deffn
  
@deffn {Pmult Conf} eom-timeout @var{interval}
Configure Milter end of message timeout.  Default is
@value{GACOPYZ_EOM_TIMEOUT}.

@xref{time interval specification}, for information on @var{interval} format.  
@end deffn
  
@deffn {Pmult Conf} log-level @var{arg}
Set Milter log verbosity level for this client.  Argument is a list of
items separated by commas or whitespace.  Each item is a log level
optionally prefixed with @samp{!} to indicate ``any level except this'',
@samp{<}, meaning ``all levels up to and including this'', or with
@samp{>}, meaning ``all levels starting from this''.

Log levels in order of increasing priority are: @samp{proto}, @samp{debug},
@samp{info}, @samp{warn}, @samp{err}, @samp{fatal}.  The first two
levels are needed for debugging @code{libgacopyz} and Milter protocol.
@xref{Gacopyz}, for the description of the @code{libgacopyz} library.
See also the following subsection.
@end deffn

@node pmult-debug
@subsection Debugging Pmult
  If needed, @command{pmult} can be instructed to provide additional
debugging information.  The amount of this information is configured
by three configuration statements.  First of all, the standard
@code{debug} block statement controls debugging of the underlying GNU
Mailutils libraries (@pxref{Debug Statement, Mailutils Configuration
File,, mailutils, GNU Mailutils Manual}).  Secondly, the @code{debug}
statement controls debugging output of the @command{pmult} utility
itself.  The @code{pmilter-debug} statement controls debugging output
of the underlying MeTA1 libraries, and, finally, the @code{log-level}
statement, described in the previous subsection, defines debugging
level for the Milter library (@code{libgacopyz}).
  
@deffn {Pmult Conf} debug @var{spec}
Set debugging level for the @command{pmult} code.  @xref{Debug
Statement, Mailutils Configuration File,, mailutils, GNU Mailutils
Manual}, for a description of @var{spec} syntax.  Multiplexor-specific
debugging is enabled by the @samp{pmult} category.  The following
levels are used:

@table @asis
@item pmult.trace1
Prints the following information:

@itemize @bullet
@item opening and closing incoming connections;
@item entering particular Pmilter stage handlers;
@item received requests with unknown command code;
@item header modification requests that does not match any headers.
@end itemize

@item pmult.trace2
Information about milter to Pmilter request translation.

@item pmult.trace7
Detailed dump of message body chunks received during Pmilter
@samp{DATA} stage.

@item pmult.error
Logs bad recipient addresses.
@end table

This information is printed using the output channel defined in the
@command{logging} statement (@pxref{Logging Statement,
Mailutils Configuration File,, mailutils, GNU Mailutils Manual}).
@end deffn

@deffn {Pmult Conf} pmilter-debug @var{level}
Set debug verbosity level for the Pmilter library.  Argument is a
positive integer between zero (no debugging, the default),
and 100 (maximum debugging).

Pmilter debugging information is printed on the standard error.  Use
@command{pies} @code{stderr} statement to capture this stream and
redirect it to the syslog or file (@pxref{Output Redirectors,,,pies,
Pies Manual}).
@end deffn

@node pmult example
@section Pmult Example
  The following is an example of a working @command{pmult}
configuration.  The multiplexer listens on localhost, port
@samp{3333}.  It prints its diagnostics using syslog facility
@code{local2}.  A single Mailfromd client is declared, which
listens on @acronym{UNIX} socket
@file{/usr/local/var/mailfromd/mailfrom}.  The log verbosity level 
for this client is set to @samp{info} and higher, i.e.: @samp{info},
@samp{warn}, @samp{err} and @samp{fatal}. 

@example
listen inet://127.0.0.1:3333;

logging @{
   facility local2;
@};

debug @{
   level "pmult.trace7";
@}

define-macros envmail (auth_type, auth_authen, auth_author, tls_vrfy);
define-macros envrcpt (auth_type, auth_authen, auth_author);

client @{
   type milter;
   url /usr/local/var/mailfromd/mailfrom;
   log-level ">info";
   # Set write timeout.
   write-timeout 30 seconds;
   # Set read timeout.
   read-timeout 5 minutes;
   # Set timeout for EOM.
   eom-timeout 5 minutes;
@}
@end example

@node pmult invocation
@section Pmult Invocation
  Normally, @command{pmult} is invoked without command line
arguments.  However, it does support several command line options.
First of all, the common GNU Mailutils options are understood, which
are useful for checking @command{pmult} configuration file for syntax
errors.  @xref{Common Options, Common Options, , mailutils, GNU
Mailutils Manual}, for a detailed description of these.

The rest of command line options supported by @command{pmult} is
useful mostly for debugging.  These options are summarized in the
table below:

@table @option
@item --log-tag=@var{string}
Set the identifier used in syslog messages to @var{string}.  This
option mostly is for debugging purposes.  We advise
to use @code{logging} configuration statement for this purpose
(@pxref{Logging Statement, Logging Statement, , mailutils,
GNU Mailutils Manual}).

@item --no-signal-handler
Disable signal handling in the main thread.  This is for debugging
purposes.

@item --syslog
Log to the syslog.  This is the default.  @xref{Logging Statement, Logging
Statement, , mailutils, GNU Mailutils Manual}, for information on how
to configure syslog logging.

@item -s
@itemx --stderr
Log to the standard error stream.

@item --url=@var{url}
Listen on the given @var{url}.  This overrides the @code{url}
configuration statement (@pxref{pmult-client,url}).

@item -x
@itemx --debug=@var{level}
Set debug verbosity level.  This overrides the @code{debug}
configuration statement.  @xref{pmult-debug}, for more information.
@end table

