12.2 Forms of Alias Delivery
Addresses in the righthand side of an alias entry can take four forms:
LHS: user
LHS: /file
LHS: |program
LHS: :include: file
The user specifies final delivery to a
user's mail spool file (subject to change by the
user's ~/.forward file), or
delivery to a new address (e.g., newuser or
user@newsite). The
/file specifies delivery by appending to a
file. The |program
specifies delivery by piping the message through a program. The
:include: specifies processing of a mailing list.
The first three are covered here. The last is covered in the next
chapter.
These righthand sides can be combined on a single line, where one is
separated from another by a comma. For example:
LHS: user, /file
12.2.1 Delivery to Users
Any address in the list of addresses to the
right of the colon that does not begin with a /,
|, or : character is considered the address of a
user. The address can be local or remote.
If that user address to the right of the colon is prefixed with a
backslash character (\) and the address is a local one, all
further aliasing is suppressed (including reading the
user's ~/.forward file), and
the message is delivered with the local delivery
agent.
12.2.2 Delivery to Files
When
any of the addresses to the right of a colon in the alias list begins
with a / character, delivery is made by appending
the mail message to a file. This is automatic with all modern
configuration files, but there are exceptions. Beginning with V8.7 sendmail, any
delivery agent for which the F=/ flag (F=/ (forward slash)) is set can also append messages to files. If
you want to disable this ability, delete the F=/
flag from all delivery agent declarations in your configuration file.
In the list of addresses to the right of the colon,
sendmail considers any local address that begins
with the / character to be the name of a
file.
Whenever the recipient address is a file,
sendmail attempts to deliver the mail message by
appending it to the file. This ability to deliver mail to files is
included in sendmail primarily so that failed
mail can be saved to a user's
~/dead.letter file. It can also be used (through
use of aliases) to deliver mail to other files, but that use is less
than optimal, as you will see.
To deliver to a file, sendmail first performs a
fork(2) and gives the child the task of
delivery. The fork is necessary so that
sendmail can change its effective
uid and gid, as we will
show. The child then performs a stat(3) on the
file. If the file exists, its file permissions are saved for later
use. If it doesn't exist, the saved permissions are
defaulted to 0600. Under V8.7 the decision to use
stat(2) versus lstat(2) to
obtain the permissions is determined by the
SafeFileEnvironment option (SafeFileEnvironment). Beginning with V8.9, the decision to use
stat(2) versus lstat(2)
depends on the FileDeliveryToSymLink setting
(See this section) for the
DontBlameSendmail option.
If the saved permissions have any execute bit set, the child exits
with EX_CANTCREAT as defined in
<sysexits.h>. If the file has a
controlling user associated with it, any
set-user-id and
set-group-id bits are stripped from the saved
permissions. If the file was listed in a
~/.forward file, the controlling user is the
owner of the ~/.forward file. If it was listed
in a :include:'d file, the
controlling user is the owner of the included file. If the message is
being processed from the queue, the controlling user can be specified
in the qf file (C line).
Then, the queue df file (D line) is opened for reading (if it is not already
open). If that file cannot be opened, sendmail
prints the following error message but continues to attempt delivery:
mailfile: Cannot open df for file from sender
Here, the df is the name of the queue
datafile that cannot be opened. The file
is the name of the file to which sendmail is
attempting to deliver the message. The
sender is the address of the sender of the
mail message.
Next, if the
SafeFileEnvironment option (see SafeFileEnvironment) was declared, sendmail
performs a chroot(2) into the directory
specified. If the chroot(2) fails,
sendmail prints and logs the following error and
the child exits with EX_CANTCREAT:
mailfile: Cannot chroot(directory)
Next, regardless of whether the df file is opened,
sendmail changes its gid:
If there is a controlling user, sendmail sets
its gid to that of the controlling user.
Otherwise, if the set-group-id bit is set in the
file's saved permissions,
sendmail changes its gid to
that of the group of the file.
Otherwise, sendmail checks to see whether the
U= equate is set for this delivery agent (U=). If the U= equate is set,
sendmail changes its gid to
that specified.
Otherwise, sendmail changes its
gid to that specified by the
DefaultUser option (DefaultUser).
After this, sendmail changes its
uid, using the same rules that it used for the
gid.
The file (and possibly the path to it) is then checked to see whether
it is safe to write to. See the -d44 debugging
switch (-d44.4) for a description of this
process.
If safe, file is then opened for writing in
append mode. If sendmail cannot open the file,
it prints the following error message, and the child exits with
EX_CANTCREAT:
cannot open: reason for error here
If an open fails for a retryable reason, it is attempted 10 more
times (sleeping progressively longer between each try) on the assumption that on busy systems there might be a
temporary lack of resources (such as file descriptors). The open
includes file locking with flock(2) or
fcntl(2) to prevent simultaneous writes.
Once the file is opened, the header and body of the mail message are
written to it. Note that translations are controlled by the
F= flags of the prog delivery
agent for all but V8 sendmail. V8
sendmail uses the F= flags of
the *file* delivery agent. For example,
F=l (see F=l (lowercase L)) marks this
as final delivery.
If any write error occurs, sendmail prints the
following error message, truncates the file to its length before any
writes started, and quits trying to write to that file:
I/O error
Finally, the file's permissions are restored to
those that were saved earlier, and the file is closed with
fclose(3). If the
set-user-id or set-group-id
bits were stripped because there was a controlling user, they are
restored here. If the file
didn't originally exist, its permissions become
0600.
12.2.3 Delivery via Programs
When any of the addresses to the right of
a colon in the alias list begins with a |
character, delivery is made by piping the mail message through a
program. This is automatic with modern configuration files. Beginning with V8.7 sendmail, any
delivery agent for which the F=| flag (F=| (vertical bar)) is set can also pipe messages through
programs. To disable this ability, simply remove the
F=| flag from all delivery agent declarations in
your configuration file.
The forms that a program address can legally take in the
aliases(5) file (or
~/.forward file; see Section 13.7.4) are as follows:
|prg
"|prg args"
|"prg args"
Here, prg is the full path of the program to be
run (the environment variable PATH is not available). If command-line
arguments are needed for the program, they must follow
prg, and the entire expression must be quoted. The
leading full quotation mark can either precede or follow the
|. If the address is quoted with full quotation
marks, the leading quotation mark is ignored in determining the
leading | character.
To execute the program, sendmail executes the
command in the P= equate of the
prog delivery agent. That command is usually one
of the following:
/bin/sh -c
/usr/bin/smrsh -c
These tell sendmail to run
/bin/sh (the Bourne shell) or
/usr/bin/smrsh (the
sendmail restricted shell) to execute the
program specified by prg. The
-c tells that shell to take any arguments that
follow and execute them as though they were commands typed
interactively to the shell. These arguments are constructed by
removing the leading | from the program address
and appending what remains, quotation marks and all, to the
P= command. For example, if an alias looked like
this:
jim: "|/etc/local/relo jim@otherhost"
the Bourne shell would be executed with the following command line:
/bin/sh -c "/etc/local/relo jim@otherhost"
The result of all this is that sendmail runs the
Bourne shell and then the Bourne shell runs the
/etc/local/relo program.
Mail is delivered under this scheme by attaching the output of
sendmail to the standard input of the shell and
attaching the standard output and standard error output of the shell
to the input of sendmail. The
sendmail program simply prints the mail message
to the shell and reads any errors that the shell prints in return.
Although this process appears to be fairly straightforward, many
things can go wrong. Failure usually results in the mail message
being bounced.
12.2.3.1 Possible failures
To communicate with the
P= program (the Bourne shell),
sendmail creates two communications channels
using pipe(2). This can fail because the system
is out of file descriptors or because the system file table is full.
Failure results in one of the following errors:
openmailer: pipe (to mailer)
openmailer: pipe (from mailer)
Next, sendmail executes a
fork(2). The child later becomes the
P= program. This can fail because the system limit
on the maximum allowable number of processes has been exceeded or
because virtual memory has been exhausted. Failure causes the
following error message to be printed:
openmailer: cannot fork
In establishing a communications channel, the
sendmail child process creates a copy of its
standard input file descriptor. This can fail because the system
limit on available file descriptors has been exceeded. When this
happens, the following message is printed (note that not all
dup(2) failures produce error messages):
Cannot dup to zero!
Finally, the child transforms itself into the A=
program with execve(2). If that transformation
fails, the following error message is produced, where
program is argv[0] for the
A= program (in this case, usually
/bin/sh):
Cannot exec program
Failure can be caused by a wide range of problems. If a retryable
error occurs, the message is queued for a later try.
Programs in the aliases file are run with the
prog delivery agent. As a consequence, that
delivery agent should have the F=s (strip quotes)
flag set.
|