diff --git a/var/www/common.php b/var/www/common.php index 88f0811..b8426e0 100644 --- a/var/www/common.php +++ b/var/www/common.php @@ -5,9 +5,10 @@ const DBUSER='hosting'; // Database user const DBPASS='MY_PASSWORD'; // Database password const DBNAME='hosting'; // Database const PERSISTENT=true; // Use persistent database conection true/false -const DBVERSION=13; //database layout version +const DBVERSION=14; //database layout version const CAPTCHA=0; // Captcha difficulty (0=off, 1=simple, 2=moderate, 3=extreme) const ADDRESS='dhosting4xxoydyaivckq7tsmtgi4wfs3flpeyitekkmqwu4v4r46syd.onion'; // our own address +const CANONICAL_URL='https://hosting.danwin1210.me'; // our preferred domain for search engines const SERVERS=[ //servers and ports we are running on 'dhosting4xxoydyaivckq7tsmtgi4wfs3flpeyitekkmqwu4v4r46syd.onion'=>['sftp'=>22, 'ftp'=>21, 'pop3'=>'110', 'imap'=>'143', 'smtp'=>'25'], 'hosting.danwin1210.me'=>['sftp'=>22, 'ftp'=>21, 'pop3'=>'995', 'imap'=>'993', 'smtp'=>'465'] @@ -21,7 +22,7 @@ const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considd const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false const ENABLE_SHELL_ACCESS=true; //allows users to login via ssh, when disabled only (s)ftp is allowed - run setup.php to migrate existing accounts const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface -const SERVICE_INSTANCES=['2', '3', '4', '5', '6', '7', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; +const SERVICE_INSTANCES=['2', '3', '4', '5', '6', '7', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; //one character per instance - run multiple tor+php-fpm instances for load balancing, remove all but one instance if you expect less than 100 accounts. Adding new instances is always possible at a later time, just removing one takes some manual cleanup for now - run setup.php after change const DISABLED_PHP_VERSIONS=[]; //php versions still installed on the system but no longer offered for new accounts const PHP_VERSIONS=[4 => '7.3']; //currently active php versions const DEFAULT_PHP_VERSION='7.3'; //default php version @@ -316,8 +317,8 @@ NumEntryGuards 6 NumDirectoryGuards 6 NumPrimaryGuards 6 "; - $stmt=$db->prepare('SELECT onions.onion, users.system_account, onions.num_intros, onions.enable_smtp, onions.version, onions.max_streams, onions.enabled FROM onions LEFT JOIN users ON (users.id=onions.user_id) WHERE onions.onion LIKE ? AND onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;'); - $stmt->execute(["$key%"]); + $stmt=$db->prepare('SELECT onions.onion, users.system_account, onions.num_intros, onions.enable_smtp, onions.version, onions.max_streams, onions.enabled FROM onions LEFT JOIN users ON (users.id=onions.user_id) WHERE onions.instance = ? AND onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;'); + $stmt->execute([$key]); while($tmp=$stmt->fetch(PDO::FETCH_NUM)){ if($tmp[6]==1){ $socket=$tmp[1]; @@ -507,9 +508,9 @@ function rewrite_nginx_config(PDO $db){ } function rewrite_php_config(PDO $db, string $key){ - $stmt=$db->prepare("SELECT system_account FROM users WHERE system_account LIKE ? AND php=? AND todelete!=1 AND id NOT IN (SELECT user_id FROM new_account);"); + $stmt=$db->prepare("SELECT system_account FROM users WHERE instance = ? AND php=? AND todelete!=1 AND id NOT IN (SELECT user_id FROM new_account);"); foreach(array_replace(PHP_VERSIONS, DISABLED_PHP_VERSIONS) as $php_key => $version){ - $stmt->execute(["$key%", $php_key]); + $stmt->execute([$key, $php_key]); $php = "[www] user = www-data group = www-data @@ -595,6 +596,11 @@ function del_user_db(PDO $db, int $user_id, string $mysql_db) { } } +function add_user_onion(PDO $db, int $user_id, string $onion, string $priv_key, int $onion_version) { + $stmt=$db->prepare('INSERT INTO onions (user_id, onion, private_key, version, enabled, instance) VALUES (?, ?, ?, ?, 2, ?);'); + $stmt->execute([$user_id, $onion, $priv_key, $onion_version, SERVICE_INSTANCES[array_rand(SERVICE_INSTANCES)]]); +} + function del_user_onion(PDO $db, int $user_id, string $onion) { $stmt = $db->prepare('SELECT null FROM onions WHERE user_id = ? AND onion = ? AND enabled IN (0, 1);'); $stmt->execute([$user_id, $onion]); @@ -646,3 +652,12 @@ function check_csrf_error(){ } return false; } + +function enqueue_instance_reload($db, $instance = null){ + if($instance === null){ + $stmt=$db->prepare('UPDATE service_instances SET reload = 1 LIMIT 1;'); + }else{ + $stmt=$db->prepare('UPDATE service_instances SET reload = 1 WHERE id = ?;'); + $stmt->execute([$instance]); + } +} diff --git a/var/www/cron.php b/var/www/cron.php index 095433c..f9a8744 100644 --- a/var/www/cron.php +++ b/var/www/cron.php @@ -18,12 +18,12 @@ $db->query('UPDATE service_instances SET reload=0 WHERE reload=1;'); $del=$db->prepare("DELETE FROM new_account WHERE user_id=?;"); $enable_onion=$db->prepare("UPDATE onions SET enabled=2 WHERE onion=?;"); $approval = REQUIRE_APPROVAL ? 'WHERE new_account.approved=1': ''; -$stmt=$db->query("SELECT users.system_account, users.username, new_account.password, users.php, users.autoindex, users.id, onions.onion FROM new_account INNER JOIN users ON (users.id=new_account.user_id) INNER JOIN onions ON (onions.user_id=users.id) $approval LIMIT 100;"); +$stmt=$db->query("SELECT users.system_account, users.username, new_account.password, users.php, users.autoindex, users.id, onions.onion, users.instance FROM new_account INNER JOIN users ON (users.id=new_account.user_id) INNER JOIN onions ON (onions.user_id=users.id) $approval LIMIT 100;"); while($id=$stmt->fetch(PDO::FETCH_NUM)){ $onion=$id[6]; $system_account=$id[0]; - $firstchar=substr($system_account, 0, 1); - $reload[$firstchar]=true; + $instance=$id[7]; + $reload[$instance]=true; $enable_onion->execute([$id[6]]); //add and manage rights of system user $shell = ENABLE_SHELL_ACCESS ? '/bin/bash' : '/usr/sbin/nologin'; @@ -46,11 +46,11 @@ while($id=$stmt->fetch(PDO::FETCH_NUM)){ //add hidden services to tor $update_onion=$db->prepare('UPDATE onions SET private_key=?, enabled=1 WHERE onion=?;'); -$stmt=$db->query('SELECT onion, private_key, version FROM onions WHERE enabled=2;'); +$stmt=$db->query('SELECT onion, private_key, version, instance FROM onions WHERE enabled=2;'); $onions=$stmt->fetchAll(PDO::FETCH_NUM); foreach($onions as $onion){ - $firstchar=substr($onion[0], 0, 1); - $reload[$firstchar]=true; + $instance = $onion[3]; + $reload[$instance] = true; if($onion[2]==2){ //php openssl implementation has some issues, re-export using native openssl $pkey=openssl_pkey_get_private($onion[1]); @@ -58,57 +58,57 @@ foreach($onions as $onion){ openssl_pkey_free($pkey); $priv_key=shell_exec('echo ' . escapeshellarg($exported) . ' | openssl rsa'); //save hidden service - mkdir("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion", 0700); - file_put_contents("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/private_key", $priv_key); - chmod("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/private_key", 0600); - chown("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/", "_tor-$firstchar"); - chown("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/private_key", "_tor-$firstchar"); - chgrp("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/", "_tor-$firstchar"); - chgrp("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/private_key", "_tor-$firstchar"); + mkdir("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion", 0700); + file_put_contents("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/private_key", $priv_key); + chmod("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/private_key", 0600); + chown("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/", "_tor-$instance"); + chown("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/private_key", "_tor-$instance"); + chgrp("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/", "_tor-$instance"); + chgrp("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/private_key", "_tor-$instance"); $update_onion->execute([$priv_key, $onion[0]]); }elseif($onion[2]==3){ $priv_key=base64_decode($onion[1]); //save hidden service - mkdir("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion", 0700); - file_put_contents("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/hs_ed25519_secret_key", $priv_key); - chmod("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/hs_ed25519_secret_key", 0600); - chown("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/", "_tor-$firstchar"); - chown("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/hs_ed25519_secret_key", "_tor-$firstchar"); - chgrp("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/", "_tor-$firstchar"); - chgrp("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/hs_ed25519_secret_key", "_tor-$firstchar"); + mkdir("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion", 0700); + file_put_contents("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/hs_ed25519_secret_key", $priv_key); + chmod("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/hs_ed25519_secret_key", 0600); + chown("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/", "_tor-$instance"); + chown("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/hs_ed25519_secret_key", "_tor-$instance"); + chgrp("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/", "_tor-$instance"); + chgrp("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/hs_ed25519_secret_key", "_tor-$instance"); $update_onion->execute([$onion[1], $onion[0]]); } } //delete old accounts $del=$db->prepare("DELETE FROM users WHERE id=?;"); -$stmt=$db->query("SELECT system_account, id, mysql_user FROM users WHERE todelete=1 LIMIT 100;"); +$stmt=$db->query("SELECT system_account, id, mysql_user, instance FROM users WHERE todelete=1 LIMIT 100;"); $accounts=$stmt->fetchAll(PDO::FETCH_NUM); $mark_onions=$db->prepare('UPDATE onions SET enabled=-1 WHERE user_id=? AND enabled!=-2;'); foreach($accounts as $account){ - $firstchar=substr($account[0], 0, 1); - $reload[$firstchar]=true; + $instance=$account[3]; + $reload[$instance]=true; $mark_onions->execute([$account[1]]); } //delete hidden services from tor $del_onions=$db->prepare('DELETE FROM onions WHERE onion=?;'); -$stmt=$db->query('SELECT onion FROM onions WHERE enabled=-1;'); +$stmt=$db->query('SELECT onion, instance FROM onions WHERE enabled=-1;'); $onions=$stmt->fetchAll(PDO::FETCH_NUM); foreach($onions as $onion){ - $firstchar=substr($onion[0], 0, 1); - $reload[$firstchar]=true; - if(file_exists("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/")){ - if(file_exists("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/authorized_clients/")){ - foreach(glob("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/authorized_clients/*") as $file){ + $instance = $onion[1]; + $reload[$instance] = true; + if(file_exists("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/")){ + if(file_exists("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/authorized_clients/")){ + foreach(glob("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/authorized_clients/*") as $file){ unlink($file); } - rmdir("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/authorized_clients"); + rmdir("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/authorized_clients"); } - foreach(glob("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/*") as $file){ + foreach(glob("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/*") as $file){ unlink($file); } - rmdir("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/"); + rmdir("/var/lib/tor-instances/$instance/hidden_service_$onion[0].onion/"); } $del_onions->execute([$onion[0]]); } diff --git a/var/www/html/admin.php b/var/www/html/admin.php index 6da576e..a00280c 100644 --- a/var/www/html/admin.php +++ b/var/www/html/admin.php @@ -15,6 +15,7 @@ echo '