Previous Section Next Section

4.2 Configure with m4

The process of building a sendmail configuration file begins by creating a file of m4 statements. Traditionally, the suffix for such files is .mc. The cf/cf directory contains examples of many .mc files. Of special interest are those that begin with generic, for these can serve as boilerplates in developing your own .mc files:

generic-bsd4.4.mc    generic-mpeix.mc        generic-sunos4.1.mc
generic-hpux10.mc    generic-nextstep3.3.mc  generic-ultrix4.mc
generic-hpux9.mc     generic-osf1.mc
generic-linux.mc     generic-solaris.mc

All .mc files require specific minimal statements. For a SunOS 4.1.4 site on the Internet, for example, the following are minimal:

OSTYPE(sunos4.1)dnl      see Section 4.2.2.1
MAILER(local)dnl         see Section 4.2.2.2
MAILER(smtp)dnl          see Section 4.2.2.2

To build a configuration file from these statements, you would place them into a file—say, localsun.mc—then run the following command:

% ./Build localsun.cf
Using M4=/usr/5bin/m4
rm -f localsun.cf
/usr/5bin/m4 ../m4/cf.m4 localsun.mc > localsun.cf || ( rm -f localsun.cf && exit 1 )
chmod 444 localsun.cf

Here, you run the Build[1] script found in the cf/cf directory. You pass it the name of your mc file with the ".mc" suffix changed to a ".cf" suffix. The Build script uses m4 to expand your mc file into a full-fledged configuration file.

[1] This is not the same Build script that is documented in Section 5.1. It is a small shell script that works only in the cf/cf directory, and that can be used only to build configuration files. You can use make in its place, but make will not automatically find the correct version of m4 for you.

Another way to build a configuration file is by running m4 by hand:

% m4  ../m4/cf.m4 localsun.mc >  sendmail.cf

Here, the ../m4/cf.m4 tells m4 where to look for its default configuration file information.

If you are using an old version of m4, the following error message will be printed:

You need a newer version of M4, at least as new as
System V or GNU
m4: file not found: NoSuchFile

Just as the message says, you need a newer version of m4. (The third line is just a result of forcing m4 to fail and can be safely ignored.) Thus, we would need to rerun our second localsun.mc example (earlier) as:

% /usr/5bin/m4  ../m4/cf.m4 localsun.mc >  sendmail.cf 
             
   System V version of m4

Another cause of failure could be that the ../m4/cf.m4 file was not where you thought it was. Various versions of m4 print this error in different ways:

/usr/5bin/m4:-:1 can't open file             SysV m4
m4: ../m4/cf.m4: No such file or directory   GNU m4
m4: file not found: ../m4/cf.m4              BSD m4

One possible reason for this error might be that you are developing your .mc file somewhere other than in the cf/cf directory.[2] The solution is to use a full pathname to cf.m4 or to replace that expression on the command line with a shell variable.

[2] This is actually a good idea. It prevents new sendmail distributions from clobbering your .mc files.

After you have successfully produced a "first draft" of your configuration file, you can edit localsun.mc and add features as you need them. Many possibilities are described in the rest of this chapter.

4.2.1 The _CF_DIR_ m4 Macro

It can be advantageous to maintain all the files that make up your local m4 configuration separately from the sendmail distribution. This prevents new releases of sendmail from clobbering your source files. It also allows you to maintain configuration information more conveniently (perhaps under rcs(1) control) and to use programs such as make(1) to simplify configuring and installation.

Most modern versions of m4 allow you to define m4 macros on the command line, and one such m4 macro is recognized internally by the m4 technique:

_CF_DIR_

This command-line m4 macro tells m4 where the m4/cf.m4 file described earlier is located. It needs to have its value set to be the cf directory under the sendmail source distribution, and it needs to end in a slash character. For example, GNU m4 version 1.2 allows this:

% setenv CFDIR /usr/local/src/mail/sendmail/cf/
% /usr/local/gnu/bin/m4 -D_CF_DIR_=${CFDIR} ${CFDIR}m4/cf.m4 localsun.mc \
    > sendmail.cf

Notice that we store the value for _CF_DIR_ in an environment variable. Note that GNU m4 can figure out the _CF_DIR_ path itself from the path of the cf.m4 file. We include _CF_DIR_ here merely as an example. If your version of m4 lacks this ability, you should consider upgrading.

With the _CF_DIR_ m4 macro, we can further simplify configuration and installation by using make(1). To illustrate, consider the following few lines from a Makefile on a SunOS system:

M4=/usr/local/gnu/bin/m4
CFDIR=/usr/local/src/mail/sendmail/cf/
localsun: localsun.mc
        $(M4) -D_CF_DIR_=$(CFDIR) $(CFDIR)/m4/cf.m4 localsun.mc > sendmail.cf

With this Makefile the two complex command lines shown earlier are reduced to a single, simple command line:

% make

4.2.2 The Minimal mc File

Every mc file requires minimal information. Table 4-1 shows which m4 items are required and lists two that are recommended. We show them in the order that they should be declared (OSTYPE first and MAILER last), then describe the mandatory and recommended information.

Table 4-1. Required and recommended m4 items

Item

§

 

Description

OSTYPE( )

Section 4.2.2.1

Required

Support for your operating system

DOMAIN( )

Section 4.2.2.3

Recommended

Common domain-wide information

FEATURE( )

Section 4.2.2.4

Recommended

Solutions to special needs

MAILER( )

Section 4.2.2.2

Required

Necessary delivery agents

Note that what is minimally required for a workstation differs from what is minimally required for a central mail server. We suggest that you use these recommendations as a jumping-off point and then investigate all the m4 macros and features that are available.

4.2.2.1 OSTYPE( ) m4 macro

Support for various operating systems is supplied with the OSTYPE m4 command. Every .mc file must declare the operating system with this command, and this command must be the first in your mc file.[3] The available support is supplied by files in the _CF_DIR_/ostype directory. A listing of those files looks something like this:

[3] We fudge for simplicity. Actually OSTYPE can legally be preceded by VERSION (Section 4.2.3.1) and m4 comments.

a-ux.m4         bsdi2.0.m4     hpux9.m4        openbsd.m4       solaris2.ml.m4
aix3.m4         darwin.m4      irix4.m4        osf1.m4          solaris2.pre5.m4
aix4.m4         dgux.m4        irix5.m4        powerux.m4       solaris8.m4
aix5.m4         domainos.m4    irix6.m4        ptx2.m4          sunos3.5.m4
altos.m4        dynix3.2.m4    isc4.1.m4       qnx.m4           sunos4.1.m4
amdahl-uts.m4   freebsd4.m4    linux.m4        riscos4.5.m4     svr4.m4
bsd4.3.m4       freebsd5.m4    maxion.m4       sco-uw-2.1.m4    ultrix4.m4
bsd4.4.m4       gnu.m4         mklinux.m4      sco3.2.m4        unixware7.m4
bsdi.m4         hpux10.m4      mpeix.m4        sinix.m4         unknown.m4
bsdi1.0.m4      hpux11.m4      nextstep.m4     solaris2.m4      uxpds.m4

To include support, select the file that best describes your operating system, delete the .m4 suffix from its name, and include the resulting name in an OSTYPE declaration:

OSTYPE(`ultrix4')

Here, support for the DEC Ultrix operating system is defined. Note that some of these are not entirely accurate. For example, ultrix4.m4 includes support for Ultrix versions 4.2 and 4.3, and sunos4.1.m4 includes support for SunOS versions 4.1.2, 4.1.3., and 4.1.4.

If you pick a name for which no file exists, or if you misspell the name of the file, an error similar to the following will print:

m4: Can't open ../ostype/ultrux4.1.m4: No such file or directory

If you omit the OSTYPE declaration entirely, you will get the following error:

*** ERROR: No system type defined (use OSTYPE macro)
4.2.2.2 MAILER( ) m4 macro

Delivery agents are not automatically declared. Instead, you must specify which ones you want to support and which ones you want to ignore. Support is included by using the MAILER definition:

MAILER(`local')

This causes support for both the local and prog delivery agents to be included. This is the minimal declaration (even if you don't intend to perform local or program delivery).

The MAILER definition must always be last in your mc configuration file.[4] If you include MAILER definitions for procmail(1), maildrop(1), or uucp, those definitions must always follow the definition for smtp. Any modification of a MAILER definition (as, for example, with LOCAL_MAILER_MAX) must precede that MAILER definition:

[4] Although it can and probably should be followed by rule set declarations, as for example, LOCAL_RULESET_0.

define(`LOCAL_MAILER_MAX', `1000000')       here
MAILER(`local')
define(`LOCAL_MAILER_MAX', `1000000')       not here

A minimal mc file for an average machine on the Internet would contain two MAILER definitions:

MAILER(`local')
MAILER(`smtp')

The first you have already seen. The second includes support for sending email to other hosts on the Internet. If this minimal mc is all you think you'll need, you can continue on to the rest of this chapter. If, on the other hand, you expect to support any variations on mail receipt and delivery beyond the basics, you should leap ahead to Chapter 20, study that chapter, then return here. (See Table 20-1 in Section 20.3 for a list of all the available delivery agents.)

All delivery agent equates, such as F= and M=, can be modified with the .m4 configuration technique. Table 20-18 (Section 20.5) lists all the equates and shows where to find further information about each of them. By investigating those sections, you can discover how to tune particular equates with the m4 technique. For example, the following mc lines define the program used for local delivery to be mail.local:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_PATH', `/usr/local/bin/mail.local')
MAILER(local)

Note that all modifications to equates must precede the corresponding MAILER( ) definition.

4.2.2.3 DOMAIN( ) m4 macro

For large sites it can be advantageous to gather into a single file all configuration decisions that are common to the entire domain. The directory to hold domain information files is called domain. The configuration information in those files is accessed by using the DOMAIN( ) m4 technique. For example:

DOMAIN(`uofa.edu')

This line in any of your mc files causes the file domain/uofa.edu.m4 to be included at that point. Examples that come with the distribution illustrate subdomains under Berkeley.EDU. One boilerplate file, named generic.m4, can be used as a starting point for your own domainwide file. For example, if all hosts at your site masquerade behind one email name, you might want to put MASQUERADE_AS (Section 4.4.2) in your domain file. Domain files also form a natural location for the definition of site-specific relays (Section 4.5).

If the domain that is specified does not exist or is misspelled, an error similar to the following will be printed:

m4: Can't open ../domain/generik.m4: No such file or directory

The use of DOMAIN( ) is not mandatory but is recommended. Note that problems can arise because the items inside your domain file will determine where the DOMAIN( ) declaration must go in the mc file. If, for example, the domain file contains MAILER( ) definitions, DOMAIN( ) should appear near the end of the mc file with the MAILER( ) definitions. If the domain file contains rules and rule sets, the DOMAIN( ) must be last in the mc file, but if the domain file contains OSTYPE( ), DOMAIN( ) must be first in the mc file. So, consider well what you place in your domain file. Avoid defining anything in your domain file that restricts where the DOMAIN( ) definition must go in your mc file.

In the event that your domain file contains many position-dependent commands, such as rule sets and an OSTYPE( ) command, you might need to split that file into pieces. You can split it something like this:

DOMAIN(`our.domain.sun')
DOMAIN(`our.domain.rules')

Here, the first line causes the file our.domain.sun.m4 to be read. That file contains the OSTYPE( ) declaration for all your Sun workstations. This DOMAIN( ) entry would appear at the top of your mc file.

The second line causes the file our.domain.rules.m4 to be read. That file might contain antispam rule sets. This second DOMAIN( ) entry would appear near the end of your mc file, perhaps under LOCAL_RULESETS.

4.2.2.4 FEATURE( ) m4 macro

V8 sendmail offers a number of features that you might find very useful. To use a feature, include an m4 command such as one of the following in your mc file:

FEATURE(keyword)
FEATURE(keyword,  argument)  
FEATURE(keyword,  argument,   argument,  ... etc. ) 

These declarations cause a file of the name feature/keyword.m4 to be read at that place in your mc file. The available keyword files are summarized in Table 4-7 of Section 4.8, and each is explained in the section at the end of this chapter. Note that some keywords require additional arguments.

4.2.3 The Order of mc Lines

As you have seen, some mc lines must precede others. This is necessary partly because m4(1) is a one-pass program, and partly because the order of items in the final sendmail.cf file is also critical. The recommended order is:

VERSIONID( )         see Section 4.2.3.1
OSTYPE( )            see Section 4.2.2.1
DOMAIN( )            see Section 4.2.2.3
option definitions  see Section 24.4 
FEATURE( )           see Section 4.8
macro definitions   see Section 21.7
MAILER( )            see Section 4.2.2.2
ruleset definitions see Section 19.1.7

If in doubt about where some particular item should go, look in the many example files in cf/cf. Some of them (especially the file knecht.mc) will also give you good ideas about how you can improve your own mc file.

4.2.3.1 VERSIONID m4 macro

The VERSIONID m4 macro is used to insert an identifier into each mc and m4 file that becomes a part of your final .cf file. Each file that is supplied with sendmail already has such an identifier. You should include a similar identifier in each of your mc files:

VERSIONID(`$Id$')

Here, the VERSIONID m4 macro is used to insert an RCS-style revision number. The $Id: ch04,v 1.53 2002/12/12 21:54:32 judyh Exp judyh $ becomes an actual version number when the file is checked in with ci(1). Arbitrary text can appear between the single quotes. You can use RCS, SCCS, or any other kind of revision identification system. The text cannot contain a newline because the text appears in the .cf file as a comment:

#####  $Id: ch04.xml,v 1.7 2003/03/28 19:05:54 becki Exp $ #####

Use of VERSIONID and revision control in general is recommended.

4.2.3.2 HACK( ) m4 macro

Some things just can't be called features. To make this clear, they go in the hack directory and are referenced using the HACK m4 macro. They tend to be site-dependent:

HACK(`cssubdomain')

This illustrates use of the Berkeley-dependent cssubdomain hack (that makes sendmail accept local names in either Berkeley.EDU or CS.Berkeley.EDU).

Another way to think of a hack is as a transient feature. Create and use HACK as a temporary solution to a temporary problem. If a solution becomes permanent, move it to the FEATURE directory and reference it there.

    Previous Section Next Section