mod_privsep
Synopsis
mod_privsep addresses the problem of the Apache WebDAV (mod_dav) virtual server limitation of only being able to write files as a single user id (usually something like 'nobody' or 'www').
mod_privsep addresses this problem in a secure way by adding privilege separation to the Apache web server (conceptually similar to ssh privilege separation).
A privilege separated Apache can be used to allow WebDAV write access to users' home directories while both preserving and honouring unix permissions and allowing the use of unix quotas and PAM authentication.
Architecture
In Privilege Separation mode Apache continues to run as an unprivileged user although an additional secure process runs as 'root'.
The apache worker processes communicate with the 'root' privileged separated process via unix sockets to carry out system authentication and privileged file system operations. Namely:
- Responding to PAM authentication requests. pam_unix authentication is not normally possible in apache due to the unprivileged process not being able to access the shadow file. Due to the privilege separated design this is now possible. Authentication responses include a cryptographic token which encodes the users credentials and is verified in successive privileged filesystem requests made to the privsep process.
- Performing privileged filesystem operations on behalf of the unprivileged apache worker processes with the privileges of the authenticated user. The cryptographic token is verified and then the effective userid is set and the filesystem operation is performed. Certain auditable points in the apache core code (core.c, request.c), mod_autoindex and mod_dav code have been changed to use the privilege separated file io calls which communicate via unix sockets to the privileged daemon. File descriptors are passed back over unix sockets for open calls.
Interfaces
APR file IO calls are modified to use the privsep versions which take an additional context argument (privsep_token_t*):
ap_privsep_stat
ap_privsep_file_perms_set
ap_privsep_file_open
ap_privsep_dir_open
ap_privsep_dir_read
ap_privsep_dir_close
ap_privsep_dir_make
ap_privsep_dir_remove
ap_privsep_file_remove
ap_privsep_file_rename
The privsep versions use a token fetched from from r->notes. If the privsep token exists then the request is dispatched to the privilege separated daemon, otherwise the file IO method is executed directly in the regular way.
One special case exists for the apr_stat calls made from ap_directory_walk. This is called before map_to_storage has been done and any authentication hooks run. This special case needs the apr_stat calls to be executed as root to know if the path actually exists. The security leak potential is minimised by making apr_stat the only call that is able to be made as uid 0 and ap_directory_walk is the only routine that calls ap_privsep_stat with the special ap_preauth_stat_token.
Portability
mod_privsep has been tested on Linux and FreeBSD.
apr interfaces have been used where possible but mod_privsep relies on unix sockets (socketpair,sendmsg,recvmsg) and the ability to send file descriptors over unix sockets. It also currently depends on PAM.
It should be relatively easily ported to other unix-like OS.
NOTE: the opendir implementation relies on platform specific details. Specifically, that directories can be opened as file descriptors and also that the file descriptor is the first structure member of the private DIR* structure (changed to fdopendir in latest patch).
It is potentially possible to implement this feature for Windows as a preliminary investigation shows that it is possible to pass file handles between processes. More investigation is needed.
Building
# apply patch
# run buildconf to pick up configure.in change
./buildconf
./configure \
--enable-dav \
--enable-privsep \
--enable-authn-privsep
Configuration
- Example configuration:
# Output error log messages for privileged accesses
LogLevel info
PrivilegeSeparationDebug On
<Directory "/opt/apache2.2/uploads/">
# Enable WebDAV and privilege separation for this directory
Dav On
PrivilegeSeparation On
# System authentication through privilege separated PAM
AuthType Basic
AuthName DAV-upload
AuthBasicProvider privsep
Options Indexes
AllowOverride None
Require valid-user
# Workaround for WebDAV PROPFIND bug on dirs with index files
DirectoryIndex /no_directory_index
</Directory>
Design Issues
- Single privileged separated process seriliazes stat/lstat/open
- Potential solution: change to a pool of privsep processes
- Overhead of PAM authentication for each request
- Potential solution: cache authentication
- Overhead of setgroups in each privileged operation
- Route requests to a pooled process that is already switched
- to the required user
- Route requests to a pooled process that is already switched
Credits
Michael Clark <michael at metaparadigm dot com>
Jamie Clark <jamie at zeroth dot org>
Iain Wade <iain dot wade at gmail dot com>