The right-hand side of an alias entry can take four forms:
local
:user
local
:/file
local
: |program
local
: :include:list
The
user
specifies final delivery to a user's mail spool file (via the
~/.forward
file), delivery to a new address (e.g.
user@newsite
), or one step in further aliasing. 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.
Any address in the list of addresses to the right of the colon that does not begin with a
/
character or a
|
character is considered the address of a user. The address can be local or remote.
If a user address is prefixed with a backslash character (
\
) [1] and the address is a local one, all further aliasing is suppressed (including reading the user's
~/.forward
file). The message is delivered with the
local
delivery agent.
[1] Actually, a backslash anywhere in the name causes the same immediate delivery.
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 most configuration files but not with others. If your configuration file does not automatically recognize a leading
/
character, you will need to add a new rule near the end of your rule set 0 (see
Section 29.6, "Rule Set 0"
). For example,
R/$+ $@ $#local $: /$1
Beginning with V8.7
sendmail
, any delivery agent for which the
F=/
flag (see
Section 30.8.9, 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 name of a file. [2]
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 primarily in
sendmail
so that failed mail may 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 optimum, as you will see.
[2] Note that an @host prevents this interpretation. That is, /a is a file, but /a@host is not. This distinction is necessary for X.400 addresses to be handled correctly. Note that this works only if the
smtp
delivery agent omits theF=/
flag.
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 0666. Under V8.7 the decision to use
stat
(2) versus
lstat
(2) to obtain the permissions is determined by the
SafeFileEnvironment
option (see
Section 34.8.58, SafeFileEnvironment
).
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
suid
and
sgid
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 may be specified in the
qf
file (see
Section 23.9.2, C line
).
Then the queue
df
file (see
Section 23.9.3, 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 opendf
forfile
fromsender
Here, the
df
is the name of the queue data file 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
Section 34.8.58
) 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, whether the
df
file is opened or not,
sendmail
changes its
gid
:
If there is a controlling user, sendmail sets its gid to that of the controlling user.
Otherwise, if the sgid 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 (see
Section 30.4.13, 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
(
g
) option (see
Section 34.8.15, DefaultUser (g)(u)
).
After this,
sendmail
changes its
uid
, using the same rules that it used for the
gid
except that the last step uses the
DefaultUser
(
u
) option.
The file (and possibly the path to it) is then checked to see whether it is safe to write to. This is done by using the internal
safefile
() subroutine. See the
-d44
debugging switch (
Section 37.5.159, -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, it is attempted 10 more times (sleeping progressively longer between each try) [3] on the assumption that on busy systems there may 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.
[3] The progression is 0 seconds for the first sleep, then 10 seconds, then 20 seconds, then 30 seconds, and so on.
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
Section 30.8.28, F=l (lowercase L)
) marks this as final delivery.
If any write error occurs, sendmail prints the following error message and continues:
I/O error
Finally, the file's permissions are restored to those that were saved above, and the file is closed with fclose (3). If the suid or sgid bits were stripped because there was a controlling user, they are restored here. [4] If the file didn't originally exist, its permissions become 0666.
[4] This is because some paranoid systems, such as BSD UNIX, turn off the suid / sgid bits when a file is written to other than by root .
In general, the file form of an alias is a poor way to save mail messages to a file. Instead, the use of a separate program procmail (8) is recommended (see Section 25.7.5.2, "The procmail program" ).
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 most configuration files but not with others. If your configuration file does not automatically recognize a leading
|
character, you will need to add a new rule near the end of your rule set 0 (see
Section 29.6
). For example,
R|$+ $@ $#local $: |$1
Beginning with V8.7
sendmail
, any delivery agent for which the
F=|
flag (see
Section 30.8.8, 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 25.7.4, "Piping Through Programs" ) 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 may 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 one of the following:
/bin/sh -c /bin/smrsh -c
These tell
sendmail
to run
/bin/sh
(the Bourne shell) or
/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, there are many things that can go wrong. Failure usually results in the mail message being bounced.
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 execprogram
Failure can be caused by a wide range of problems. If one occurs and the delivery agent is
local
, the message is queued for a later try. Otherwise, requeueing occurs only if the error return value is a transient one defined in
transienterror
() in
conf.c
. [5]
[5] Because of a bug in all but the IDA and V8 versions, the message is silently discarded without being requeued or bounced.
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.