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.