== Some notes on Apache's suexec We've recently been wrestling with suexec in an attempt to get it to do something that it seemed that suexec would do. As a result of that learning experience, I feel like writing down some things about suexec. You may wish to also read [[the official Apache documentation on suexec https://httpd.apache.org/docs/2.4/suexec.html]], but note that you may have to pay close attention to some of the things that it says (and a few things appear to be outright wrong). Suexec has two modes: # Running _/~/..._ CGIs as the particular user involved. This needs no special extra configuration for suexec and simply just happens. Per-user CGIs must be located under a specific subdirectory in the user's Unix home directory, by default ((public_html)); suexec documentation calls this subdirectory name the *userdir*. # Running CGIs for a virtual host as a particular user and group. This must be configured with the _SuexecUserGroup_ directive. All virtual host CGIs must be located under a specific top level directory, by default often _/var/www_; suexec documentation calls this directory the *docroot*. (Suexec also does various ownership and permissions checks on the CGIs and the directory they are directly in. Those are beyond the scope of these notes.) The first important thing here is that the suexec *docroot* and *userdir* are not taken from the Apache _DocumentRoot_ and _UserDir_ settings; instead, they're hard coded into suexec itself. Any time that suexec logs errors like 'command not in docroot', the docroot it means is not the Apache _DocumentRoot_ you've configured. It pretty much follows that if your Apache settings do not match the hardcoded suexec settings, suexec will thumb its nose at you. (Also, the only form of _UserDir_ directive that will ever work with suexec is '_UserDir somename_'. You cannot use either '_UserDir /some/dir_' or '_UserDir /some/*/subdir_' with suexec. The suexec documentation notes this.) The second important thing is that Apache and suexec explicitly distinguish between the two modes based on the incoming request itself, not the final paths involved, and *these two modes are exclusive*. If you make a request for a CGI via a _/~user/..._ URL, the only thing that matters is if the eventual path is under the user's home directory plus the suexec *userdir*. If you make a request to a virtual host with a _SuexecUserGroup_ directive, the only thing that matters is if the eventual path is under the suexec *docroot*. In particular, you cannot configure a virtual host for a user, point its _DocumentRoot_ to that user's userdir, and have suexec run CGIs. This path would be perfectly acceptable if the CGIs were invoked via /~user/... URLs, but when invoked for a plain virtual host, suexec will reject these requests because the paths aren't under its *docroot*. (Mechanically, Apache prefixes the user name it passes to the suexec binary with a _~_ if it is a UserDir request. This is undocumented behavior reverse engineered from the code, so you shouldn't count on it.) The third important thing is that suexec ignores symlinks in all of this checking; it uses only the 'real' physical paths, after symlinks have been traversed. As a result you cannot fool suexec by, for example, putting symlinks to elsewhere under what it considers its *docroot*. However it is fine for user _/etc/passwd_ entries to include symlinks ([[as we do ../unix/SlashU]]); suexec will not be upset by that. Normally the suexec *docroot* and *userdir* are set when suexec is compiled and are fixed afterwards, which obviously creates some problems if you need something different. Debian and Ubuntu provide a second version of suexec that can look these up at runtime from a configuration file (this is the apache2-suexec-custom package). Failing this, well, you'll be arranging (somehow) for all of your virtual hosts to appear under _/var/www_ (or at least all of the ones that need CGIs). (You can determine the *userdir* and *docroot* settings for your suexec with '_suexec -V_' as root. You want ((AP_DOC_ROOT)) and ((AP_USERDIR_SUFFIX)).) === Sidebar: what 'command not in docroot' really means The suexec error 'command not in docroot' is actually generic and is used for both modes of requests. So what suexec means by 'docroot' here is either the actual *docroot*, for a virtual host request, or the user's home directory plus the *userdir* subdirectory, for a /~user/... request. Unfortunately you cannot tell from suexec's log messages whether it was invoked for what it thought was a user home directory request or for a virtual host request; that has to be obtained from the Apache logs. The check is done by a simple brute force method: first, _chdir()_ to the CGI's directory and do a _getcwd()_. Then _chdir()_ to either the *docroot* or the user's home directory plus the *userdir* and do another _getcwd()_. Compare the two directory paths and fail if the first is not underneath the second. Because it uses _getcwd()_, all symlinks involved in either path will wind up getting fully expanded.