Introduce mysqld socket stream forwarding with nginx for chroot jails

This commit is contained in:
Daniel Winzen
2019-01-01 13:47:30 +01:00
parent 0f38bd2449
commit 55bc8cd757
9 changed files with 48 additions and 22 deletions

View File

@ -25,7 +25,7 @@ To get the latest mariadb version, you should follow these instructions to add t
The following command will install all required packages: The following command will install all required packages:
``` ```
apt-get --no-install-recommends install apt-transport-tor aspell clamav-daemon clamav-freshclam clamav-milter composer curl dovecot-imapd dovecot-pop3d git dnsmasq haveged hunspell iptables locales-all logrotate mariadb-server nano nginx-light postfix postfix-mysql \ apt-get --no-install-recommends install apt-transport-tor aspell clamav-daemon clamav-freshclam clamav-milter composer curl dovecot-imapd dovecot-pop3d git dnsmasq haveged hunspell iptables locales-all logrotate mariadb-server nano nginx-full postfix postfix-mysql \
php7.3-bcmath php7.3-bz2 php7.3-cli php7.3-curl php7.3-dba php7.3-enchant php7.3-fpm php7.3-gd php7.3-gmp php7.3-imap php7.3-intl php7.3-json php7.3-mbstring php7.3-mysql php7.3-opcache php7.3-pspell php7.3-readline php7.3-recode php7.3-soap php7.3-sqlite3 php7.3-tidy php7.3-xml php7.3-xmlrpc php7.3-xsl php7.3-zip \ php7.3-bcmath php7.3-bz2 php7.3-cli php7.3-curl php7.3-dba php7.3-enchant php7.3-fpm php7.3-gd php7.3-gmp php7.3-imap php7.3-intl php7.3-json php7.3-mbstring php7.3-mysql php7.3-opcache php7.3-pspell php7.3-readline php7.3-recode php7.3-soap php7.3-sqlite3 php7.3-tidy php7.3-xml php7.3-xmlrpc php7.3-xsl php7.3-zip \
phpmyadmin php-apcu php-gnupg php-imagick quota quotatool rsync sasl2-bin ssh subversion tor unzip vim vsftpd wget zip && apt-get --no-install-recommends install adminer phpmyadmin php-apcu php-gnupg php-imagick quota quotatool rsync sasl2-bin ssh subversion tor unzip vim vsftpd wget zip && apt-get --no-install-recommends install adminer
``` ```

View File

@ -26,3 +26,6 @@ fastcgi_param SERVER_NAME $server_name;
fastcgi_param REDIRECT_STATUS 200; fastcgi_param REDIRECT_STATUS 200;
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
fastcgi_param HTTP_PROXY ""; fastcgi_param HTTP_PROXY "";
#running in chroots
fastcgi_param SCRIPT_FILENAME /www/$fastcgi_script_name;

View File

@ -100,3 +100,7 @@ http {
include /etc/nginx/sites-enabled/*; include /etc/nginx/sites-enabled/*;
} }
stream {
include /etc/nginx/streams-enabled/*;
}

View File

@ -18,5 +18,6 @@ SystemCallArchitectures=native
BindPaths=/var/log/nginx/ BindPaths=/var/log/nginx/
BindPaths=/var/lib/nginx/ BindPaths=/var/lib/nginx/
BindPaths=/var/run/ BindPaths=/var/run/
BindPaths=/var/www/var/run/
BindPaths=/run/ BindPaths=/run/
InaccessiblePaths=/root/ InaccessiblePaths=/root/

View File

@ -1,6 +1,6 @@
<?php <?php
require_once(__DIR__ . '/vendor/autoload.php'); require_once(__DIR__ . '/vendor/autoload.php');
const DBHOST='127.0.0.1'; // Database host const DBHOST='localhost'; // Database host
const DBUSER='hosting'; // Database user const DBUSER='hosting'; // Database user
const DBPASS='MY_PASSWORD'; // Database password const DBPASS='MY_PASSWORD'; // Database password
const DBNAME='hosting'; // Database const DBNAME='hosting'; // Database
@ -15,7 +15,8 @@ const SERVERS=[ //servers and ports we are running on
const EMAIL_TO=''; //Send email notifications about new registrations to this address const EMAIL_TO=''; //Send email notifications about new registrations to this address
const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considdered as unchanged for deletion const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considdered as unchanged for deletion
'd41d8cd98f00b204e9800998ecf8427e', //empty file 'd41d8cd98f00b204e9800998ecf8427e', //empty file
'7ae7e9bac6be76f00e0d95347111f037' //default file '7ae7e9bac6be76f00e0d95347111f037', //default file
'703fac6634bf637f942db8906092d0ab', //new default file
]; ];
const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false
const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface
@ -63,14 +64,14 @@ server {
try_files $uri $uri/ =404; try_files $uri $uri/ =404;
location ~ \.php$ { location ~ \.php$ {
include snippets/fastcgi-php.conf; include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME html/$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME /html$fastcgi_script_name;
fastcgi_pass unix:/var/run/php/7.3-hosting; fastcgi_pass unix:/var/run/php/7.3-hosting;
} }
} }
location /squirrelmail { location /squirrelmail {
location ~ \.php$ { location ~ \.php$ {
include snippets/fastcgi-php.conf; include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php/7.3-squirrelmail; fastcgi_pass unix:/var/run/php/7.3-squirrelmail;
} }
} }
@ -78,7 +79,7 @@ server {
root /usr/share; root /usr/share;
location ~ \.php$ { location ~ \.php$ {
include snippets/fastcgi-php.conf; include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/7.3-phpmyadmin; fastcgi_pass unix:/run/php/7.3-phpmyadmin;
} }
} }
@ -86,7 +87,7 @@ server {
root /usr/share/adminer; root /usr/share/adminer;
location ~ \.php$ { location ~ \.php$ {
include snippets/fastcgi-php.conf; include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/7.3-adminer; fastcgi_pass unix:/run/php/7.3-adminer;
} }
} }
@ -415,9 +416,19 @@ function rewrite_nginx_config(PDO $db){
} }
"; ";
file_put_contents("/etc/nginx/sites-enabled/hosted_sites", $nginx);
exec("service nginx reload");
} }
file_put_contents("/etc/nginx/sites-enabled/hosted_sites", $nginx);
$nginx='';
$stmt=$db->query("SELECT users.system_account, users.php, users.autoindex, onions.onion FROM users INNER JOIN onions ON (onions.user_id=users.id) WHERE onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;");
while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
$nginx.="server {
listen unix:/home/$tmp[system_account]/var/run/mysqld/mysqld.sock;
proxy_pass unix:/var/run/mysqld/mysqld.sock;
}
";
}
file_put_contents("/etc/nginx/streams-enabled/hosted_sites", $nginx);
exec("service nginx reload");
} }
function rewrite_php_config(PDO $db, string $key){ function rewrite_php_config(PDO $db, string $key){

View File

@ -140,7 +140,7 @@ foreach($accounts as $account){
$drop_user->execute([$account[2]]); $drop_user->execute([$account[2]]);
$stmt->execute([$account[1]]); $stmt->execute([$account[1]]);
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){ while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
$db->exec("DROP DATABASE IF EXISTS `$tmp[0]`;"); $db->exec('DROP DATABASE IF EXISTS `'.preg_replace('/[^a-z0-9]/i', '', $tmp[0]).'`;');
} }
$db->exec('FLUSH PRIVILEGES;'); $db->exec('FLUSH PRIVILEGES;');
//delete user from user database //delete user from user database

View File

@ -77,7 +77,7 @@ echo '<tr><th>Database</th><th>Host</th><th>User</th></tr>';
$stmt=$db->prepare('SELECT mysql_database FROM mysql_databases WHERE user_id=?;'); $stmt=$db->prepare('SELECT mysql_database FROM mysql_databases WHERE user_id=?;');
$stmt->execute([$user['id']]); $stmt->execute([$user['id']]);
while($mysql=$stmt->fetch(PDO::FETCH_ASSOC)){ while($mysql=$stmt->fetch(PDO::FETCH_ASSOC)){
echo "<tr><td>$mysql[mysql_database]</td><td>127.0.0.1</td><td>$user[mysql_user]</td></tr>"; echo "<tr><td>$mysql[mysql_database]</td><td>localhost</td><td>$user[mysql_user]</td></tr>";
} }
echo '</table>'; echo '</table>';
echo '<p><a href="password.php?type=sql">Change MySQL password</a></p>'; echo '<p><a href="password.php?type=sql">Change MySQL password</a></p>';

View File

@ -35,7 +35,6 @@ if(!@$version=$db->query("SELECT value FROM settings WHERE setting='version';"))
$db->exec('CREATE TABLE settings (setting varchar(50) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL PRIMARY KEY, value text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;'); $db->exec('CREATE TABLE settings (setting varchar(50) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL PRIMARY KEY, value text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$stmt=$db->prepare("INSERT INTO settings (setting, value) VALUES ('version', ?);"); $stmt=$db->prepare("INSERT INTO settings (setting, value) VALUES ('version', ?);");
$stmt->execute([DBVERSION]); $stmt->execute([DBVERSION]);
exec('/var/www/setup_chroot.sh /var/www');
echo "Database and files have successfully been set up\n"; echo "Database and files have successfully been set up\n";
}else{ }else{
$version=$version->fetch(PDO::FETCH_NUM)[0]; $version=$version->fetch(PDO::FETCH_NUM)[0];
@ -122,8 +121,6 @@ if(!@$version=$db->query("SELECT value FROM settings WHERE setting='version';"))
// some software may break when absolute installation path changes, add symlinks to prevent that // some software may break when absolute installation path changes, add symlinks to prevent that
symlink('.', '/home/'.$tmp['system_account'].'/home'); symlink('.', '/home/'.$tmp['system_account'].'/home');
symlink('.', '/home/'.$tmp['system_account'].'/'.$tmp['system_account']); symlink('.', '/home/'.$tmp['system_account'].'/'.$tmp['system_account']);
exec('/var/www/setup_chroot.sh ' . escapeshellarg('/home/'.$tmp['system_account']));
exec('grep ' . escapeshellarg($tmp['system_account']) . ' /etc/passwd >> ' . escapeshellarg("/home/$tmp[system_account]/etc/passwd"));
$firstchar=substr($tmp['system_account'], 0, 1); $firstchar=substr($tmp['system_account'], 0, 1);
//delete config files //delete config files
foreach(array_replace(PHP_VERSIONS, DISABLED_PHP_VERSIONS) as $v){ foreach(array_replace(PHP_VERSIONS, DISABLED_PHP_VERSIONS) as $v){
@ -139,9 +136,7 @@ if(!@$version=$db->query("SELECT value FROM settings WHERE setting='version';"))
if(file_exists("/etc/nginx/sites-enabled/$tmp[system_account]")){ if(file_exists("/etc/nginx/sites-enabled/$tmp[system_account]")){
unlink("/etc/nginx/sites-enabled/$tmp[system_account]"); unlink("/etc/nginx/sites-enabled/$tmp[system_account]");
} }
exec('/var/www/setup_chroot.sh /var/www');
} }
$db->exec('UPDATE service_instances SET reload=1;');
} }
$stmt=$db->prepare("UPDATE settings SET value=? WHERE setting='version';"); $stmt=$db->prepare("UPDATE settings SET value=? WHERE setting='version';");
$stmt->execute([DBVERSION]); $stmt->execute([DBVERSION]);
@ -235,11 +230,22 @@ php_admin_value[open_basedir] = /usr/share/adminer:/tmp
file_put_contents("/etc/php/$version/fpm/pool.d/www.conf", $pool_config); file_put_contents("/etc/php/$version/fpm/pool.d/www.conf", $pool_config);
exec("service php$version-fpm@default reload"); exec("service php$version-fpm@default reload");
} }
file_put_contents('/etc/nginx/sites-enabled/default', NGINX_DEFAULT); echo "Updating chroots, this might take a while…\n";
exec("service nginx reload"); exec('/var/www/setup_chroot.sh /var/www');
if(DBVERSION!=$version){ $stmt=$db->query('SELECT system_account FROM users;');
echo "Database and files have successfully been updated to the latest version\n"; while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
}else{ exec('/var/www/setup_chroot.sh ' . escapeshellarg('/home/'.$tmp['system_account']));
echo "Database and files already up-to-date\n"; exec('grep ' . escapeshellarg($tmp['system_account']) . ' /etc/passwd >> ' . escapeshellarg("/home/$tmp[system_account]/etc/passwd"));
} }
file_put_contents('/etc/nginx/sites-enabled/default', NGINX_DEFAULT);
if(!file_exists("/etc/nginx/streams-enabled/")){
mkdir("/etc/nginx/streams-enabled/", 0755, true);
}
file_put_contents('/etc/nginx/streams-enabled/default', "server {
listen unix:/var/www/var/run/mysqld/mysqld.sock;
proxy_pass unix:/var/run/mysqld/mysqld.sock;
}");
exec("service nginx reload");
$db->exec('UPDATE service_instances SET reload=1;');
echo "Done - Database and files have been updated to the latest version :)\n";
} }

View File

@ -61,6 +61,7 @@ CHROOT_DIRECTORY_STRUCTURE=(
'/usr/sbin' '/usr/sbin'
'/var' '/var'
'/var/run' '/var/run'
'/var/run/mysqld'
) )
BINARIES_GENERAL=( BINARIES_GENERAL=(
'/usr/lib/openssh/sftp-server' '/usr/lib/openssh/sftp-server'