[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter discusses a number of issues concerned with security, some of which are also covered in other parts of this manual.
For reasons that this author does not understand, some people have promoted Exim as a "particularly secure" mailer. Perhaps it is because of the existence of this chapter in the documentation. However, the intent of the chapter is simply to describe the way Exim works in relation to certain security concerns, not to make any specific claims about the effectiveness of its security as compared with other MTAs.
What follows is a description of the way Exim is supposed to be. Best efforts have been made to try to ensure that the code agrees with the theory, but an absence of bugs can never be guaranteed. Any that are reported will get fixed as soon as possible.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are a number of build-time options that can be set in ‘Local/Makefile’ to create Exim binaries that are "harder" to attack, in particular by a rogue Exim administrator who does not have the root password, or by someone who has penetrated the Exim (but not the root) account. These options are as follows:
-C
option. When it is set, these file
names are also not allowed to contain the sequence "/../". (However, if the
value of the -C
option is identical to the value of CONFIGURE_FILE in
‘Local/Makefile’, Exim ignores -C
and proceeds as usual.) There is no
default setting for ALT_CONFIG_PREFIX
.
If the permitted configuration files are confined to a directory to which only root has access, this guards against someone who has broken into the Exim account from running a privileged Exim with an arbitrary configuration file, and using it to break into other accounts.
-C
and -D
only if the caller of Exim is root. Without it, the Exim user may
also use -C
and -D
and retain privilege. Setting this option locks out
the possibility of testing a configuration using -C
right through message
reception and delivery, even if the caller is root. The reception works, but by
that time, Exim is running as the Exim user, so when it re-execs to regain
privilege for the delivery, the use of -C
causes privilege to be lost.
However, root can test reception and delivery using two separate commands.
ALT_CONFIG_ROOT_ONLY is not set by default.
-D
command line option
is disabled.
never_users
runtime
option, but it cannot be overridden; the runtime option adds additional users
to the list. The default setting is "root"; this prevents a non-root user who
is permitted to modify the runtime file from using Exim as a way to get root.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The Exim binary is normally setuid to root, which means that it gains root privilege (runs as root) when it starts execution. In some special cases (for example, when the daemon is not in use and there are no local deliveries), it may be possible to run Exim setuid to some user other than root. This is discussed in the next section. However, in most installations, root privilege is required for two things:
It is not necessary to be root to do any of the other things Exim does, such as receiving messages and delivering them externally over SMTP, and it is obviously more secure if Exim does not run as root except when necessary. For this reason, a user and group for Exim to use must be defined in ‘Local/Makefile’. These are known as "the Exim user" and "the Exim group". Their values can be changed by the run time configuration, though this is not recommended. Often a user called exim is used, but some sites use mail or another user name altogether.
Exim uses setuid()
whenever it gives up root privilege. This is a permanent
abdication; the process cannot regain root afterwards. Prior to release 4.00,
seteuid()
was used in some circumstances, but this is no longer the case.
After a new Exim process has interpreted its command line options, it changes uid and gid in the following cases:
-C
option is used to specify an alternate configuration file, or if
the -D
option is used to define macro values for the configuration, and the
calling process is not running as root or the Exim user, the uid and gid are
changed to those of the calling process.
However, if ALT_CONFIG_ROOT_ONLY is defined in ‘Local/Makefile’, only
root callers may use -C
and -D
without losing privilege, and if
DISABLE_D_OPTION is set, the -D
option may not be used at all.
-be
) or one of the filter testing options
(-bf
or -bF
) are used, the uid and gid are changed to those of the
calling process.
-bt
), the
uid and gid are changed to the Exim user and group. This means that Exim always
runs under its own uid and gid when receiving messages. This also applies when
testing address verification
(the -bv
option) and testing incoming message policy controls (the -bh
option).
The processes that initially retain root privilege behave as follows:
initgroups()
function is called, so that if the Exim user is in any additional groups, they
will be used during message reception.
While the recipient addresses in a message are being routed, the delivery
process runs as root. However, if a user's filter file has to be processed,
this is done in a subprocess that runs under the individual user's uid and
gid. A system filter is run as root unless system_filter_user
is set.
-bt
option) runs as root so that
the routing is done in the same environment as a message delivery.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some installations like to run Exim in an unprivileged state for more of its
operation, for added security. Support for this mode of operation is provided
by the global option deliver_drop_privilege
. When this is set, the uid and
gid are changed to the Exim user and group at the start of a delivery process
(and also queue runner and address testing processes). This means that address
routing is no longer run as root, and the deliveries themselves cannot change
to any other uid.
Leaving the binary setuid to root, but setting deliver_drop_privilege
means
that the daemon can still be started in the usual way, and it can respond
correctly to SIGHUP because the re-invocation regains root privilege.
An alternative approach is to make Exim setuid to the Exim user and also setgid to the Exim group. If you do this, the daemon must be started from a root process. (Calling Exim from a root process makes it behave in the way it does when it is setuid root.) However, the daemon cannot restart itself after a SIGHUP signal because it cannot regain privilege.
It is still useful to set deliver_drop_privilege
in this case, because it
stops Exim from trying to re-invoke itself to do a delivery after a message has
been received. Such a re-invocation is a waste of resources because it has no
effect.
If restarting the daemon is not an issue (for example, if mua_wrapper
is
set, or inetd is being used instead of a daemon), having the binary setuid
to the Exim user seems a clean approach, but there is one complication:
In this style of operation, Exim is running with the real uid and gid set to those of the calling process, and the effective uid/gid set to Exim's values. Ideally, any association with the calling process' uid/gid should be dropped, that is, the real uid/gid should be reset to the effective values so as to discard any privileges that the caller may have. While some operating systems have a function that permits this action for a non-root effective uid, quite a number of them do not. Because of this lack of standardization, Exim does not address this problem at this time.
For this reason, the recommended approach for "mostly unprivileged" running
is to keep the Exim binary setuid to root, and to set
deliver_drop_privilege
. This also has the advantage of allowing a daemon to
be used in the most straightforward way.
If you configure Exim not to run delivery processes as root, there are a number of restrictions on what you can do:
user
and group
options to override routers or local transports that
normally deliver as the recipient. This makes sure that configurations that
work in this mode function the same way in normal mode. Any implicit or
explicit specification of another user causes an error.
mode
in the appendfile configuration, as well as the
mode of the mailbox files themselves.
no_check_owner
, since most or all of the files will not be
owned by the Exim user.
file_must_exist
, because Exim cannot set the owner correctly
on a newly created mailbox when unprivileged. This also implies that new
mailboxes need to be created manually.
These restrictions severely restrict what can be done in local deliveries.
However, there are no restrictions on remote deliveries. If you are running a
gateway host that does no local deliveries, setting deliver_drop_privilege
gives more security at essentially no cost.
If you are using the mua_wrapper
facility (see chapter
Using Exim as a non-queueing client), deliver_drop_privilege
is forced to be true.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Full details of the checks applied by appendfile
before it writes to a file
are given in chapter The appendfile transport.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Many operating systems suppress IP source-routed packets in the kernel, but some cannot be made to do this, so Exim does its own check. It logs incoming IPv4 source-routed TCP calls, and then drops them. Things are all different in IPv6. No special checking is currently done.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Support for these SMTP commands is disabled by default. If required, they can be enabled by defining suitable ACLs.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Exim recognizes two sets of users with special privileges. Trusted users are able to submit new messages to Exim locally, but supply their own sender addresses and information about a sending host. For other users submitting local messages, Exim sets up the sender address from the uid, and doesn't permit a remote host to be specified.
However, an untrusted user is permitted to use the -f
command line option
in the special form -f <>
to indicate that a delivery failure for the
message should not cause an error report. This affects the message's envelope,
but it does not affect the Sender: header. Untrusted users may also be
permitted to use specific forms of address with the -f
option by setting
the untrusted_set_sender
option.
Trusted users are used to run processes that receive mail messages from some
other mail domain and pass them on to Exim for delivery either locally, or over
the Internet. Exim trusts a caller that is running as root, as the Exim user,
as any user listed in the trusted_users
configuration option, or under any
group listed in the trusted_groups
option.
Admin users are permitted to do things to the messages on Exim's queue. They can freeze or thaw messages, cause them to be returned to their senders, remove them entirely, or modify them in various ways. In addition, admin users can run the Exim monitor and see all the information it is capable of providing, which includes the contents of files on the spool.
By default, the use of the -M
and -q
options to cause Exim to attempt
delivery of messages on its queue is restricted to admin users. This
restriction can be relaxed by setting the no_prod_requires_admin
option.
Similarly, the use of -bp
(and its variants) to list the contents of the
queue is also restricted to admin users. This restriction can be relaxed by
setting no_queue_list_requires_admin
.
Exim recognizes an admin user if the calling process is running as root or as the Exim user or if any of the groups associated with the calling process is the Exim group. It is not necessary actually to be running under the Exim group. However, if admin users who are not root or the Exim user are to access the contents of files on the spool via the Exim monitor (which runs unprivileged), Exim must be built to allow group read access to its spool files.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Exim's spool directory and everything it contains is owned by the Exim user and set to the Exim group. The mode for spool files is defined in the ‘Local/Makefile’ configuration file, and defaults to 0640. This means that any user who is a member of the Exim group can access these files.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Exim examines the last component of argv[0]
, and if it matches one of a set
of specific strings, Exim assumes certain options. For example, calling Exim
with the last component of argv[0]
set to "rsmtp" is exactly equivalent
to calling it with the option -bS
. There are no security implications in
this.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The only use made of "%f" by Exim is in formatting load average values. These are actually stored in integer variables as 1000 times the load average. Consequently, their range is limited and so therefore is the length of the converted output.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Exim uses its own path name, which is embedded in the code, only when it needs to re-exec in order to regain root privilege. Therefore, it is not root when it does so. If some bug allowed the path to get overwritten, it would lead to an arbitrary program's being run as exim, not as root.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A large number of occurrences of "sprintf" in the code are actually calls to string_sprintf(), a function that returns the result in malloc'd store. The intermediate formatting is done into a large fixed buffer by a function that runs through the format string itself, and checks the length of each conversion before performing it, thus preventing buffer overruns.
The remaining uses of sprintf()
happen in controlled circumstances where
the output buffer is known to be sufficiently long to contain the converted
string.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Arbitrary strings are passed to both these functions, but they do their formatting by calling the function string_vformat(), which runs through the format string itself, and checks the length of each conversion.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These are used only in cases where the output buffer is known to be large enough to hold the result.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on March, 28 2009 using texi2html 1.78.