suexec

最後更新: 2015-07-15

介紹

suEXEC is based on a setuid "wrapper" program that is called by the main Apache web server.

This wrapper is called when an HTTP request is made for a CGI or SSI program

that the administrator has designated to run as a userid other than that of the main server.

When such a request is made, Apache provides the suEXEC wrapper with the program's name and

the user and group IDs under which the program is to execute.

條件:

* suEXEC does not allow root to execute CGI/SSI programs.
* target userid/groupid  ABOVE the minimum ID number (AP_UID_MIN)
* target user/group the same as the program's user/group
* target program / directory NOT writable by anyone (所以 wrapper 既 permission 要係 755)
* Only one user (the Apache user) is allowed to execute this program. (AP_HTTPD_USER)
* safe hierarchical (AP_DOC_ROOT) (target CGI or SSI program's path 不可以有 a leading '/' or have a '..')

 


Apache:

httpd -V | grep suexec

-D SUEXEC_BIN="/usr/sbin/suexec"    

The binary image suexec is installed in the directory defined by the --sbindir option.

(Default location is "/usr/local/apache2/bin/suexec")

在 httpd.conf 要有

LoadModule suexec_module modules/mod_suexec.so

 


suexec

 

suexec -V    # displays the compile options

 * For security reasons all configuration options are changeable only at compile time.

 -D AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=100
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_EXEC="/var/log/httpd/suexec.log"
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=500
 -D AP_USERDIR_SUFFIX="public_html"

* suExec does not allow symlinks

不能用 FcgidWrapper /usr/bin/php-cgi .php          <-- 因為 CGI program 不在 AP_DOC_ROOT 內

解決方案:

Create a wrapper script for each web site in a subdirectory of /var/www;

the wrapper script will then call the PHP binary /usr/lib/cgi-bin/php

 * For security and efficiency reasons, all suEXEC requests must remain

within either a top-level document root for virtual host requests, or one top-level personal document root for userdir requests.

 
 


準備

 

groupadd webuser1

useradd -s /bin/false -d /var/www/webuser1 -m -g web1 webuser1

mkdir -p /var/www/webuser1/web

# owner

chown webuser1:webuser1 /var/www/webuser1/web

# 放 CGI wrapper 的 Folder 都要有嚴格的 permission, 否則會有

[2014-07-23 14:59:40]: uid: (3334/???) gid: (3334/???) cmd: ???.sh
[2014-07-23 14:59:40]: target uid/gid (3334/3334) mismatch with directory (0/0) or program (3334/3334)

# 因為 .htaccess 要有 1

chmod 771 /var/www/webuser1/web

public_html 的 permission 要是 701

否則會有

(13)Permission denied: /home/vhosts/???/public_html/.htaccess pcfg_openfile: 
unable to check htaccess file, ensure it is readable

 


Apache Configure

 

/etc/httpd/conf.d/fcgid.conf

# Use FastCGI to process .fcg .fcgi & .fpl scripts
AddHandler fcgid-script fcg fcgi fpl

# Sane place to put sockets and shared memory file
FcgidIPCDir /run/mod_fcgid
FcgidProcessTableFile /run/mod_fcgid/fcgid_shm

# vhost example

<VirtualHost *>

    # suexe
    SuexecUserGroup user_account user_group

    # We run a single PHP FastCGI server
    # which will launch as many children
    # as necessary.

    <Directory ... >
      Options ... ExecCGI ...
    </Directory>

    # fcgid
    FCGIWrapper /var/www/php-fcgi-scripts/suexec/webuser1/mywrapper .php
    AddHandler fcgid-script .php

</VirtualHost>

# ispconfig example

<IfModule mod_fcgid.c>

  DocumentRoot    /var/www/ispconfig/
  SuexecUserGroup ispconfig ispconfig
  IPCCommTimeout  7200
  MaxRequestLen   15728640

  <Directory /var/www/ispconfig/>
    Options -Indexes +FollowSymLinks +MultiViews +ExecCGI
    AllowOverride AuthConfig Indexes Limit Options FileInfo
    <FilesMatch "\.php$">
        SetHandler fcgid-script
    </FilesMatch>
    FCGIWrapper /var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter .php
    Require all granted
  </Directory>

</IfModule>

/var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter

#!/bin/sh
PHPRC=/etc/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=1
exec /usr/bin/php-cgi -d magic_quotes_gpc=off -d session.save_path=/usr/local/ispconfig/interface/temp

 


Wrapper

 

cd /var/www/php-fcgi-scripts/suexec

mkdir webuser1

chmod 755 webuser1

vi mywrapper

#!/bin/sh
export PHP_FCGI_MAX_REQUESTS=1000
exec /usr/bin/php-cgi

chown user_account:user_group mywrapper

chmod 755 mywrapper

 


Configuring & Installing suEXEC

 

--enable-suexec
    enables the suEXEC feature

--enable-suexec-capabilities
    # suexec binary will instead be installed with only the setuid/setgid "capability" bits
    # ( subset of full root priviliges )
    # Default: "setuid/setgid root" <-- full privileges of the root user

--with-suexec-bin=PATH
    The path to the suexec binary must be hard-coded in the server for security reasons.
    (/usr/sbin/suexec)

--with-suexec-caller=UID
    The username under which Apache normally runs. This is the only user allowed to execute this program.

--with-suexec-docroot=DIR
    Define as the DocumentRoot set for Apache.

--with-suexec-safepath=PATH
    Default: "/usr/local/bin:/usr/bin:/bin"

-with-suexec-userdir=DIR
    processed by mod_userdir
    Define to be the subdirectory under users' home directories where suEXEC access should be allowed.
    All executables under this directory will be executable by suEXEC as the user so they should be "safe" programs.
    Default value is "public_html"

--with-suexec-safepath=PATH
    Define a safe PATH environment to pass to CGI executables. Default value is "/usr/local/bin:/usr/bin:/bin".

--with-suexec-logfile
--with-suexec-syslog
    suEXEC wrapper will write log information to this file
 


Testing

 

whoami.php

<?php
    system("id -a");
?>

# 沒有 suexec 時 uid=48(apache) "gid=48(apache) groups=48(apache)"

 

順利行到會見在 /var/log/httpd/suexec.log 內有

[2014-07-23 16:44:27]: uid: (3334/???) gid: (3334/???) cmd: wrapper

ps aux | grep 3334

3334     22663  0.0  0.2  58160 12228 ?        S    17:08   0:00 /usr/bin/php-cgi

 


Custom php.ini for Each Web Site

 

cp /etc/php5/cgi/php.ini /var/www/web1/

chown web1:web1 /var/www/web1/php.ini

vi /var/www/php-fcgi-scripts/web1/php-fcgi-starter

#!/bin/sh
export PHP_INI_SCAN_DIR=/home/user/domain/conf
export PHPRC=/home/user/conf
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/lib/cgi-bin/php

reload php.ini:

killall php-cgi