Chapter 23 - Environment for running local transports
Local transports handle deliveries to files and pipes. (The autoreply transport can be thought of as similar to a pipe.) Exim always runs transports in subprocesses, under specified uids and gids. Typical deliveries to local mailboxes run under the uid and gid of the local user.
Exim also sets a specific current directory while running the transport; for some transports a home directory setting is also relevant. The pipe transport is the only one that sets up environment variables; see section 29.4 for details.
The values used for the uid, gid, and the directories may come from several different places. In many cases, the router that handles the address associates settings with that address as a result of its check_local_user, group, or user options. However, values may also be given in the transport’s own configuration, and these override anything that comes from the router.
1. Concurrent deliveries
If two different messages for the same local recipient arrive more or less simultaneously, the two delivery processes are likely to run concurrently. When the appendfile transport is used to write to a file, Exim applies locking rules to stop concurrent processes from writing to the same file at the same time.
However, when you use a pipe transport, it is up to you to arrange any locking that is needed. Here is a silly example:
my_transport: driver = pipe command = /bin/sh -c 'cat >>/some/file'
This is supposed to write the message at the end of the file. However, if two messages arrive at the same time, the file will be scrambled. You can use the exim_lock utility program (see section 53.15) to lock a file using the same algorithm that Exim itself uses.
2. Uids and gids
All transports have the options group and user. If group is set, it overrides any group that the router set in the address, even if user is not set for the transport. This makes it possible, for example, to run local mail delivery under the uid of the recipient (set by the router), but in a special group (set by the transport). For example:
# Routers ... # User/group are set by check_local_user in this router local_users: driver = accept check_local_user transport = group_delivery # Transports ... # This transport overrides the group group_delivery: driver = appendfile file = /var/spool/mail/$local_part group = mail
If user is set for a transport, its value overrides what is set in the address by the router. If user is non-numeric and group is not set, the gid associated with the user is used. If user is numeric, group must be set.
When the uid is taken from the transport’s configuration, the initgroups() function is called for the groups associated with that uid if the initgroups option is set for the transport. When the uid is not specified by the transport, but is associated with the address by a router, the option for calling initgroups() is taken from the router configuration.
The pipe transport contains the special option pipe_as_creator. If this is set and user is not set, the uid of the process that called Exim to receive the message is used, and if group is not set, the corresponding original gid is also used.
This is the detailed preference order for obtaining a gid; the first of the following that is set is used:
-
A group setting of the transport;
-
A group setting of the router;
-
A gid associated with a user setting of the router, either as a result of check_local_user or an explicit non-numeric user setting;
-
The group associated with a non-numeric user setting of the transport;
-
In a pipe transport, the creator’s gid if deliver_as_creator is set and the uid is the creator’s uid;
-
The Exim gid if the Exim uid is being used as a default.
If, for example, the user is specified numerically on the router and there are no group settings, no gid is available. In this situation, an error occurs. This is different for the uid, for which there always is an ultimate default. The first of the following that is set is used:
-
A user setting of the transport;
-
In a pipe transport, the creator’s uid if deliver_as_creator is set;
-
A user setting of the router;
-
A check_local_user setting of the router;
-
The Exim uid.
Of course, an error will still occur if the uid that is chosen is on the never_users list.
3. Current and home directories
Routers may set current and home directories for local transports by means of the transport_current_directory and transport_home_directory options. However, if the transport’s current_directory or home_directory options are set, they override the router’s values. In detail, the home directory for a local transport is taken from the first of these values that is set:
-
The home_directory option on the transport;
-
The transport_home_directory option on the router;
-
The password data if check_local_user is set on the router;
-
The router_home_directory option on the router.
The current directory is taken from the first of these values that is set:
-
The current_directory option on the transport;
-
The transport_current_directory option on the router.
If neither the router nor the transport sets a current directory, Exim uses the value of the home directory, if it is set. Otherwise it sets the current directory to / before running a local transport.
4. Expansion variables derived from the address
Normally a local delivery is handling a single address, and in that case the variables such as $domain and $local_part are set during local deliveries. However, in some circumstances more than one address may be handled at once (for example, while writing batch SMTP for onward transmission by some other means). In this case, the variables associated with the local part are never set, $domain is set only if all the addresses have the same domain, and $original_domain is never set.