"Fossies" - the Fresh Open Source Software Archive

Member "ispconfig3_install/install/lib/installer_base.lib.php" (8 Jun 2021, 183657 Bytes) of package /linux/privat/ISPConfig-3.2.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "installer_base.lib.php": 3.2.4_vs_3.2.5.

    1 <?php
    2 
    3 /*
    4 Copyright (c) 2007-2019, Till Brehm, projektfarm GmbH
    5 All rights reserved.
    6 
    7 Redistribution and use in source and binary forms, with or without modification,
    8 are permitted provided that the following conditions are met:
    9 
   10     * Redistributions of source code must retain the above copyright notice,
   11       this list of conditions and the following disclaimer.
   12     * Redistributions in binary form must reproduce the above copyright notice,
   13       this list of conditions and the following disclaimer in the documentation
   14       and/or other materials provided with the distribution.
   15     * Neither the name of ISPConfig nor the names of its contributors
   16       may be used to endorse or promote products derived from this software without
   17       specific prior written permission.
   18 
   19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29 */
   30 
   31 class installer_base {
   32 
   33     var $wb = array();
   34     var $language = 'en';
   35     var $db;
   36     public $install_ispconfig_interface = true;
   37     public $is_update = false; // true if it is an update, false if it is a new install
   38     protected $mailman_group = 'list';
   39 
   40 
   41     public function __construct() {
   42         global $conf; //TODO: maybe $conf  should be passed to constructor
   43     }
   44 
   45     private function install_acme() {
   46         $install_cmd = 'wget -O -  https://get.acme.sh | sh';
   47         $ret = null;
   48         $val = 0;
   49         exec($install_cmd . ' 2>&1', $ret, $val);
   50 
   51         return ($val == 0 ? true : false);
   52     }
   53 
   54     public function update_acme() {
   55         $acme = explode("\n", shell_exec('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh'));
   56         $acme = reset($acme);
   57         $val = 0;
   58 
   59         if($acme && is_executable($acme)) {
   60             $cmd = $acme . ' --upgrade --auto-upgrade ; ' . $acme . ' --set-default-ca --server letsencrypt';
   61             $ret = null;
   62             $val = 0;
   63             exec($cmd. ' 2>&1', $ret, $val);
   64         }
   65 
   66         return ($val == 0 ? true : false);
   67     }
   68 
   69     //: TODO  Implement the translation function and language files for the installer.
   70     public function lng($text) {
   71         return $text;
   72     }
   73 
   74     public function error($msg) {
   75         die('ERROR: '.$msg."\n");
   76     }
   77 
   78     public function warning($msg) {
   79         echo 'WARNING: '.$msg."\n";
   80     }
   81 
   82     public function simple_query($query, $answers, $default, $name = '') {
   83         global $autoinstall, $autoupdate;
   84         $finished = false;
   85         do {
   86             if($name != '' && $autoinstall[$name] != '') {
   87                 if($autoinstall[$name] == 'default') {
   88                     $input = $default;
   89                 } else {
   90                     $input = $autoinstall[$name];
   91                 }
   92             } elseif($name != '' && $autoupdate[$name] != '') {
   93                 if($autoupdate[$name] == 'default') {
   94                     $input = $default;
   95                 } else {
   96                     $input = $autoupdate[$name];
   97                 }
   98             } else {
   99                 $answers_str = implode(',', $answers);
  100                 swrite($this->lng($query).' ('.$answers_str.') ['.$default.']: ');
  101                 $input = sread();
  102             }
  103 
  104             //* Stop the installation
  105             if($input == 'quit') {
  106                 swriteln($this->lng("Installation terminated by user.\n"));
  107                 die();
  108             }
  109 
  110             //* Select the default
  111             if($input == '') {
  112                 $answer = $default;
  113                 $finished = true;
  114             }
  115 
  116             //* Set answer id valid
  117             if(in_array($input, $answers)) {
  118                 $answer = $input;
  119                 $finished = true;
  120             }
  121 
  122         } while ($finished == false);
  123         swriteln();
  124         return $answer;
  125     }
  126 
  127     public function free_query($query, $default, $name = '') {
  128         global $autoinstall, $autoupdate;
  129         if($name != '' && $autoinstall[$name] != '') {
  130             if($autoinstall[$name] == 'default') {
  131                 $input = $default;
  132             } else {
  133                 $input = $autoinstall[$name];
  134             }
  135         } elseif($name != '' && $autoupdate[$name] != '') {
  136             if($autoupdate[$name] == 'default') {
  137                 $input = $default;
  138             } else {
  139                 $input = $autoupdate[$name];
  140             }
  141         } else {
  142             swrite($this->lng($query).' ['.$default.']: ');
  143             $input = sread();
  144         }
  145 
  146         //* Stop the installation
  147         if($input == 'quit') {
  148             swriteln($this->lng("Installation terminated by user.\n"));
  149             die();
  150         }
  151 
  152         $answer =  ($input == '') ? $default : $input;
  153         swriteln();
  154         return $answer;
  155     }
  156 
  157     /*
  158     // TODO: this function is not used atmo I think - pedro
  159     function request_language(){
  160 
  161         swriteln(lng('Enter your language'));
  162         swriteln(lng('de, en'));
  163 
  164     }
  165     */
  166 
  167     public function set_immutable($path, $enable = true) {
  168         if($path != '' && $path != '/' && strlen($path) > 6 && strpos($path, '..') === false && (is_file($path) || is_dir($path))) {
  169             if($enable) {
  170                 exec('chattr +i ' . escapeshellarg($path));
  171             } else {
  172                 exec('chattr -i ' . escapeshellarg($path));
  173             }
  174         }
  175     }
  176 
  177     public function crypt_password($cleartext_password, $charset = 'UTF-8') {
  178         if($charset != 'UTF-8') {
  179             $cleartext_password = mb_convert_encoding($cleartext_password, $charset, 'UTF-8');
  180         }
  181 
  182         if(defined('CRYPT_SHA512') && CRYPT_SHA512 == 1) {
  183             $salt = '$6$rounds=5000$';
  184             $salt_length = 16;
  185         } elseif(defined('CRYPT_SHA256') && CRYPT_SHA256 == 1) {
  186             $salt = '$5$rounds=5000$';
  187             $salt_length = 16;
  188         } else {
  189             $salt = '$1$';
  190             $salt_length = 12;
  191         }
  192 
  193         if(function_exists('openssl_random_pseudo_bytes')) {
  194             $salt .= substr(bin2hex(openssl_random_pseudo_bytes($salt_length)), 0, $salt_length);
  195         } else {
  196             $base64_alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
  197             for($n = 0; $n < $salt_length; $n++) {
  198                 $salt .= $base64_alphabet[mt_rand(0, 63)];
  199             }
  200         }
  201         $salt .= "$";
  202         return crypt($cleartext_password, $salt);
  203     }
  204 
  205     //** Detect installed applications
  206     public function find_installed_apps() {
  207         global $conf;
  208 
  209         if(is_installed('mysql') || is_installed('mysqld')) $conf['mysql']['installed'] = true;
  210         if(is_installed('postfix')) $conf['postfix']['installed'] = true;
  211         if(is_installed('postgrey')) $conf['postgrey']['installed'] = true;
  212         if(is_installed('mailman') || is_installed('mmsitepass')) $conf['mailman']['installed'] = true;
  213         if(is_installed('apache') || is_installed('apache2') || is_installed('httpd') || is_installed('httpd2')) $conf['apache']['installed'] = true;
  214         if(is_installed('getmail')) $conf['getmail']['installed'] = true;
  215         if(is_installed('courierlogger')) $conf['courier']['installed'] = true;
  216         if(is_installed('dovecot')) $conf['dovecot']['installed'] = true;
  217         if(is_installed('saslauthd')) $conf['saslauthd']['installed'] = true;
  218         if(is_installed('amavisd-new') || is_installed('amavisd')) $conf['amavis']['installed'] = true;
  219         if(is_installed('rspamd')) $conf['rspamd']['installed'] = true;
  220         if(is_installed('clamdscan')) $conf['clamav']['installed'] = true;
  221         if(is_installed('pure-ftpd') || is_installed('pure-ftpd-wrapper')) $conf['pureftpd']['installed'] = true;
  222         if(is_installed('mydns') || is_installed('mydns-ng')) $conf['mydns']['installed'] = true;
  223         if(is_installed('jk_chrootsh')) $conf['jailkit']['installed'] = true;
  224         if(is_installed('pdns_server') || is_installed('pdns_control')) $conf['powerdns']['installed'] = true;
  225         if(is_installed('named') || is_installed('bind') || is_installed('bind9')) $conf['bind']['installed'] = true;
  226         if(is_installed('squid')) $conf['squid']['installed'] = true;
  227         if(is_installed('nginx')) $conf['nginx']['installed'] = true;
  228         if(is_installed('iptables') && is_installed('ufw')) {
  229             $conf['ufw']['installed'] = true;
  230         } elseif(is_installed('iptables')) {
  231             $conf['firewall']['installed'] = true;
  232         }
  233         if(is_installed('fail2ban-server')) $conf['fail2ban']['installed'] = true;
  234         if(is_installed('vzctl')) $conf['openvz']['installed'] = true;
  235         if(is_installed('metronome') && is_installed('metronomectl')) $conf['xmpp']['installed'] = true;
  236         if(is_installed('spamassassin')) $conf['spamassassin']['installed'] = true;
  237         // if(is_installed('vlogger')) $conf['vlogger']['installed'] = true;
  238         // ISPConfig ships with vlogger, so it is always installed.
  239         $conf['vlogger']['installed'] = true;
  240         if(is_installed('crontab')) $conf['cron']['installed'] = true;
  241 
  242         if (($conf['apache']['installed'] && is_file($conf['apache']["vhost_conf_enabled_dir"]."/000-ispconfig.vhost")) || ($conf['nginx']['installed'] && is_file($conf['nginx']["vhost_conf_enabled_dir"]."/000-ispconfig.vhost"))) $this->ispconfig_interface_installed = true;
  243     }
  244 
  245     //** Check prerequisites
  246     public function check_prerequisites() {
  247         $msg = '';
  248 
  249         if(version_compare(phpversion(), '5.4', '<')) $msg .= "PHP Version 5.4 or newer is required. The currently used PHP version is ".phpversion().".\n";
  250         if(!function_exists('curl_init')) $msg .= "PHP Curl Module is missing.\n";
  251         if(!function_exists('mysqli_connect')) $msg .= "PHP MySQLi Module is nmissing.\n";
  252         if(!function_exists('mb_detect_encoding')) $msg .= "PHP Multibyte Module (MB) is missing.\n";
  253 
  254         if($msg != '') die($msg);
  255     }
  256 
  257     public function force_configure_app($service, $enable_force=true) {
  258         $force = false;
  259         if(AUTOINSTALL == true) return false;
  260         if($enable_force == true) {
  261             swriteln("[WARN] autodetect for $service failed");
  262         } else {
  263             swriteln("[INFO] service $service not detected");
  264         }
  265         if($enable_force) {
  266             if(strtolower($this->simple_query("Force configure $service", array('y', 'n'), 'n') ) == 'y') {
  267                 $force = true;
  268             } else swriteln("Skipping $service\n");
  269         }
  270         return $force;
  271     }
  272 
  273     public function reconfigure_app($service, $reconfigure_services_answer) {
  274         $reconfigure = false;
  275         if ($reconfigure_services_answer != 'selected') {
  276             $reconfigure = true;
  277         } else {
  278             if(strtolower($this->simple_query("Reconfigure $service", array('y', 'n'), 'y') ) == 'y') {
  279                 $reconfigure = true;
  280             } else {
  281                 swriteln("Skip reconfigure $service\n");
  282             }
  283         }
  284         return $reconfigure;
  285     }
  286 
  287     /** Create the database for ISPConfig */
  288 
  289 
  290     public function configure_database() {
  291         global $conf;
  292 
  293         //** Check for unwanted plugins
  294         if ($this->db->getDatabaseType() == 'mysql' && $this->db->getDatabaseVersion(true) >= 8) {
  295             // component approach since MySQL 8.0
  296             $unwanted_components = [
  297                 'file://component_validate_password',
  298             ];
  299             $sql_components = $this->db->queryAllRecords("SELECT * FROM mysql.component where component_urn IN ?", $unwanted_components);
  300             if(is_array($sql_components) && !empty($sql_components)) {
  301                 foreach ($sql_components as $component) {
  302                     $component_name = parse_url($component['component_urn'], PHP_URL_HOST);
  303                     echo "Login in to MySQL and disable '{$component_name}' with:\n\n    UNINSTALL COMPONENT '{$component['component_urn']}';\n\n";
  304                 }
  305                 die();
  306             }
  307         } else {
  308             $unwanted_sql_plugins = array('validate_password');
  309             $sql_plugins = $this->db->queryAllRecords("SELECT plugin_name FROM information_schema.plugins WHERE plugin_status='ACTIVE' AND plugin_name IN ?", $unwanted_sql_plugins);
  310             if(is_array($sql_plugins) && !empty($sql_plugins)) {
  311                 foreach ($sql_plugins as $plugin) echo "Login in to MySQL and disable $plugin[plugin_name] with:\n\n    UNINSTALL PLUGIN $plugin[plugin_name];";
  312                 die();
  313             }
  314         }
  315 
  316         //** Create the database
  317         if(!$this->db->query('CREATE DATABASE IF NOT EXISTS ?? DEFAULT CHARACTER SET ?', $conf['mysql']['database'], $conf['mysql']['charset'])) {
  318             $this->error('Unable to create MySQL database: '.$conf['mysql']['database'].'.');
  319         }
  320 
  321         //* Set the database name in the DB library
  322         $this->db->setDBName($conf['mysql']['database']);
  323 
  324         //* Load the database dump into the database, if database contains no tables
  325         $db_tables = $this->db->getTables();
  326         if(count($db_tables) > 0) {
  327             $this->error('Stopped: Database already contains some tables.');
  328         } else {
  329             if($conf['mysql']['admin_password'] == '') {
  330                 caselog("mysql --default-character-set=".escapeshellarg($conf['mysql']['charset'])." -h ".escapeshellarg($conf['mysql']['host'])." -u ".escapeshellarg($conf['mysql']['admin_user'])." -P ".escapeshellarg($conf['mysql']['port'])." ".escapeshellarg($conf['mysql']['database'])." < '".ISPC_INSTALL_ROOT."/install/sql/ispconfig3.sql' &> /dev/null",
  331                     __FILE__, __LINE__, 'read in ispconfig3.sql', 'could not read in ispconfig3.sql');
  332             } else {
  333                 caselog("mysql --default-character-set=".escapeshellarg($conf['mysql']['charset'])." -h ".escapeshellarg($conf['mysql']['host'])." -u ".escapeshellarg($conf['mysql']['admin_user'])." -p".escapeshellarg($conf['mysql']['admin_password'])." -P ".escapeshellarg($conf['mysql']['port'])." ".escapeshellarg($conf['mysql']['database'])." < '".ISPC_INSTALL_ROOT."/install/sql/ispconfig3.sql' &> /dev/null",
  334                     __FILE__, __LINE__, 'read in ispconfig3.sql', 'could not read in ispconfig3.sql');
  335             }
  336             $db_tables = $this->db->getTables();
  337             if(count($db_tables) == 0) {
  338                 $this->error('Unable to load SQL-Dump into database table.');
  339             }
  340 
  341             //* Load system.ini into the sys_ini table
  342             $system_ini = rf('tpl/system.ini.master');
  343             $this->db->query("UPDATE sys_ini SET config = ? WHERE sysini_id = 1", $system_ini);
  344 
  345         }
  346     }
  347 
  348     //** Create the server record in the database
  349     public function add_database_server_record() {
  350 
  351         global $conf;
  352 
  353         if($conf['mysql']['host'] == 'localhost') {
  354             $from_host = 'localhost';
  355         } else {
  356             $from_host = $conf['hostname'];
  357         }
  358 
  359         // Delete ISPConfig user in the local database, in case that it exists
  360         $this->db->query("DROP USER ?@?", $conf['mysql']['ispconfig_user'], $from_host);
  361         $this->db->query("DROP DATABASE IF EXISTS ?", $conf['mysql']['database']);
  362 
  363         //* Create the ISPConfig database user and grant permissions in the local database
  364         $query = 'CREATE USER ?@? IDENTIFIED BY ?';
  365         if(!$this->db->query($query, $conf['mysql']['ispconfig_user'], $from_host, $conf['mysql']['ispconfig_password'])) {
  366             $this->error('Unable to create database user: '.$conf['mysql']['ispconfig_user'].' Error: '.$this->db->errorMessage);
  367         }
  368         $query = 'GRANT SELECT, INSERT, UPDATE, DELETE ON ?? TO ?@?';
  369         if(!$this->db->query($query, $conf['mysql']['database'] . ".*", $conf['mysql']['ispconfig_user'], $from_host)) {
  370             $this->error('Unable to grant databse permissions to user: '.$conf['mysql']['ispconfig_user'].' Error: '.$this->db->errorMessage);
  371         }
  372 
  373         // add correct administrative rights to IPSConfig user (SUPER is deprecated and unnecessarily powerful)
  374          if ($this->db->getDatabaseType() == 'mysql' && $this->db->getDatabaseVersion(true) >= 8) {
  375             // there might be more needed on replicated db environments, this was not tested
  376             $query = 'GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO ?@?';
  377             if(!$this->db->query($query, $conf['mysql']['ispconfig_user'], $from_host)) {
  378                 $this->error('Unable to grant administrative permissions to user: '.$conf['mysql']['ispconfig_user'].' Error: '.$this->db->errorMessage);
  379             }
  380         }
  381 
  382         //* Set the database name in the DB library
  383         $this->db->setDBName($conf['mysql']['database']);
  384 
  385         $tpl_ini_array = ini_to_array(rf('tpl/server.ini.master'));
  386 
  387         //* Update further distribution specific parameters for server config here
  388         //* HINT: Every line added here has to be added in update.lib.php too!!
  389         $tpl_ini_array['web']['vhost_conf_dir'] = $conf['apache']['vhost_conf_dir'];
  390         $tpl_ini_array['web']['vhost_conf_enabled_dir'] = $conf['apache']['vhost_conf_enabled_dir'];
  391         $tpl_ini_array['jailkit']['jailkit_chroot_app_programs'] = $conf['jailkit']['jailkit_chroot_app_programs'];
  392         $tpl_ini_array['fastcgi']['fastcgi_phpini_path'] = $conf['fastcgi']['fastcgi_phpini_path'];
  393         $tpl_ini_array['fastcgi']['fastcgi_starter_path'] = $conf['fastcgi']['fastcgi_starter_path'];
  394         $tpl_ini_array['fastcgi']['fastcgi_bin'] = $conf['fastcgi']['fastcgi_bin'];
  395         $tpl_ini_array['server']['hostname'] = $conf['hostname'];
  396         $tpl_ini_array['server']['ip_address'] = @gethostbyname($conf['hostname']);
  397         $tpl_ini_array['server']['firewall'] = ($conf['ufw']['installed'] == true)?'ufw':'bastille';
  398         $tpl_ini_array['web']['website_basedir'] = $conf['web']['website_basedir'];
  399         $tpl_ini_array['web']['website_path'] = $conf['web']['website_path'];
  400         $tpl_ini_array['web']['website_symlinks'] = $conf['web']['website_symlinks'];
  401         $tpl_ini_array['cron']['crontab_dir'] = $conf['cron']['crontab_dir'];
  402         $tpl_ini_array['web']['security_level'] = 20;
  403         $tpl_ini_array['web']['user'] = $conf['apache']['user'];
  404         $tpl_ini_array['web']['group'] = $conf['apache']['group'];
  405         $tpl_ini_array['web']['php_ini_path_apache'] = $conf['apache']['php_ini_path_apache'];
  406         $tpl_ini_array['web']['php_ini_path_cgi'] = $conf['apache']['php_ini_path_cgi'];
  407         $tpl_ini_array['mail']['pop3_imap_daemon'] = ($conf['dovecot']['installed'] == true)?'dovecot':'courier';
  408         $tpl_ini_array['mail']['mail_filter_syntax'] = ($conf['dovecot']['installed'] == true)?'sieve':'maildrop';
  409         $tpl_ini_array['mail']['content_filter'] = @($conf['rspamd']['installed']) ? 'rspamd' : 'amavisd';
  410         $tpl_ini_array['mail']['rspamd_available'] = @($conf['rspamd']['installed']) ? 'y' : 'n';
  411         $tpl_ini_array['dns']['bind_user'] = $conf['bind']['bind_user'];
  412         $tpl_ini_array['dns']['bind_group'] = $conf['bind']['bind_group'];
  413         $tpl_ini_array['dns']['bind_zonefiles_dir'] = $conf['bind']['bind_zonefiles_dir'];
  414         $tpl_ini_array['dns']['named_conf_path'] = $conf['bind']['named_conf_path'];
  415         $tpl_ini_array['dns']['named_conf_local_path'] = $conf['bind']['named_conf_local_path'];
  416 
  417         $tpl_ini_array['web']['nginx_vhost_conf_dir'] = $conf['nginx']['vhost_conf_dir'];
  418         $tpl_ini_array['web']['nginx_vhost_conf_enabled_dir'] = $conf['nginx']['vhost_conf_enabled_dir'];
  419         $tpl_ini_array['web']['nginx_user'] = $conf['nginx']['user'];
  420         $tpl_ini_array['web']['nginx_group'] = $conf['nginx']['group'];
  421         $tpl_ini_array['web']['nginx_cgi_socket'] = $conf['nginx']['cgi_socket'];
  422         $tpl_ini_array['web']['php_fpm_init_script'] = $conf['nginx']['php_fpm_init_script'];
  423         $tpl_ini_array['web']['php_fpm_ini_path'] = $conf['nginx']['php_fpm_ini_path'];
  424         $tpl_ini_array['web']['php_fpm_pool_dir'] = $conf['nginx']['php_fpm_pool_dir'];
  425         $tpl_ini_array['web']['php_fpm_start_port'] = $conf['nginx']['php_fpm_start_port'];
  426         $tpl_ini_array['web']['php_fpm_socket_dir'] = $conf['nginx']['php_fpm_socket_dir'];
  427 
  428         if ($conf['nginx']['installed'] == true) {
  429             $tpl_ini_array['web']['server_type'] = 'nginx';
  430             $tpl_ini_array['global']['webserver'] = 'nginx';
  431         }
  432 
  433         if (array_key_exists('awstats', $conf)) {
  434             foreach ($conf['awstats'] as $aw_sett => $aw_value) {
  435                 $tpl_ini_array['web']['awstats_'.$aw_sett] = $aw_value;
  436             }
  437         }
  438 
  439         // preserve needed values in $conf  (should just array_merge $tpl_ini_array into $conf?)
  440         $conf['mail']['content_filter'] = $tpl_ini_array['mail']['content_filter'];
  441 
  442         $server_ini_content = array_to_ini($tpl_ini_array);
  443 
  444         $mail_server_enabled = ($conf['services']['mail'])?1:0;
  445         $web_server_enabled = ($conf['services']['web'])?1:0;
  446         $dns_server_enabled = ($conf['services']['dns'])?1:0;
  447         $file_server_enabled = ($conf['services']['file'])?1:0;
  448         $db_server_enabled = ($conf['services']['db'])?1:0;
  449         $vserver_server_enabled = ($conf['openvz']['installed'])?1:0;
  450         $proxy_server_enabled = (isset($conf['services']['proxy']) && $conf['services']['proxy'])?1:0;
  451         $firewall_server_enabled = (isset($conf['services']['firewall']) && $conf['services']['firewall'])?1:0;
  452 
  453         //** Get the database version number based on the patchfiles
  454         $found = true;
  455         $current_db_version = 1;
  456         while($found == true) {
  457             $next_db_version = intval($current_db_version + 1);
  458             $patch_filename = realpath(dirname(__FILE__).'/../').'/sql/incremental/upd_'.str_pad($next_db_version, 4, '0', STR_PAD_LEFT).'.sql';
  459             if(is_file($patch_filename)) {
  460                 $current_db_version = $next_db_version;
  461             } else {
  462                 $found = false;
  463             }
  464         }
  465         $current_db_version = intval($current_db_version);
  466 
  467 
  468         if($conf['mysql']['master_slave_setup'] == 'y') {
  469 
  470             //* Insert the server record in master DB
  471             $sql = "INSERT INTO `server` (`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_name`, `mail_server`, `web_server`, `dns_server`, `file_server`, `db_server`, `vserver_server`, `config`, `updated`, `active`, `dbversion`,`firewall_server`,`proxy_server`) VALUES (1, 1, 'riud', 'riud', 'r', ?, ?, ?, ?, ?, ?, ?, ?, 0, 1, ?, ?, ?);";
  472             $this->dbmaster->query($sql, $conf['hostname'], $mail_server_enabled, $web_server_enabled, $dns_server_enabled, $file_server_enabled, $db_server_enabled, $vserver_server_enabled, $server_ini_content, $current_db_version, $proxy_server_enabled, $firewall_server_enabled);
  473             $conf['server_id'] = $this->dbmaster->insertID();
  474             $conf['server_id'] = $conf['server_id'];
  475 
  476             //* Insert the same record in the local DB
  477             $sql = "INSERT INTO `server` (`server_id`, `sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_name`, `mail_server`, `web_server`, `dns_server`, `file_server`, `db_server`, `vserver_server`, `config`, `updated`, `active`, `dbversion`,`firewall_server`,`proxy_server`) VALUES (?,1, 1, 'riud', 'riud', 'r', ?, ?, ?, ?, ?, ?, ?, ?, 0, 1, ?, ?, ?);";
  478             $this->db->query($sql, $conf['server_id'], $conf['hostname'], $mail_server_enabled, $web_server_enabled, $dns_server_enabled, $file_server_enabled, $db_server_enabled, $vserver_server_enabled, $server_ini_content, $current_db_version, $proxy_server_enabled, $firewall_server_enabled);
  479 
  480             //* username for the ispconfig user
  481             $conf['mysql']['master_ispconfig_user'] = 'ispcsrv'.$conf['server_id'];
  482 
  483             $this->grant_master_database_rights();
  484 
  485         } else {
  486             //* Insert the server, if its not a mster / slave setup
  487             $sql = "INSERT INTO `server` (`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_name`, `mail_server`, `web_server`, `dns_server`, `file_server`, `db_server`, `vserver_server`, `config`, `updated`, `active`, `dbversion`,`firewall_server`,`proxy_server`) VALUES (1, 1, 'riud', 'riud', 'r', ?, ?, ?, ?, ?, ?, ?, ?, 0, 1, ?, ?, ?);";
  488             $this->db->query($sql, $conf['hostname'], $mail_server_enabled, $web_server_enabled, $dns_server_enabled, $file_server_enabled, $db_server_enabled, $vserver_server_enabled, $server_ini_content, $current_db_version, $proxy_server_enabled, $firewall_server_enabled);
  489             $conf['server_id'] = $this->db->insertID();
  490             $conf['server_id'] = $conf['server_id'];
  491         }
  492 
  493 
  494     }
  495 
  496     public function get_host_ips() {
  497         $out = array();
  498         exec('hostname --all-ip-addresses', $ret, $val);
  499         if($val == 0) {
  500             if(is_array($ret) && !empty($ret)){
  501                 $temp = (explode(' ', $ret[0]));
  502                 foreach($temp as $ip) {
  503                     $out[] = $ip;
  504                 }
  505             }
  506         }
  507 
  508         return $out;
  509     }
  510 
  511     public function detect_ips(){
  512         global $conf;
  513 
  514         $output = $this->get_host_ips();
  515 
  516         if(is_array($output) && !empty($output)){
  517             foreach($output as $line){
  518                 $ip_type = '';
  519                 if (filter_var($line, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
  520                     $ip_type = 'IPv4';
  521                 }
  522                 if (filter_var($line, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
  523                     $ip_type = 'IPv6';
  524                 }
  525                 if($ip_type == '') continue;
  526                 if($this->db->dbHost != $this->dbmaster->dbHost){
  527                     $this->dbmaster->query('INSERT INTO server_ip (
  528                         sys_userid, sys_groupid, sys_perm_user, sys_perm_group,
  529                         sys_perm_other, server_id, client_id, ip_type, ip_address,
  530                         virtualhost, virtualhost_port
  531                     ) VALUES (
  532                         1,
  533                         1,
  534                         "riud",
  535                         "riud",
  536                         "",
  537                         ?,
  538                         0,
  539                         ?,
  540                         ?,
  541                         "n",
  542                         "80,443"
  543                     )', $conf['server_id'], $ip_type, $line);
  544                     $server_ip_id = $this->dbmaster->insertID();
  545                     $this->db->query('INSERT INTO server_ip (
  546                         server_php_id, sys_userid, sys_groupid, sys_perm_user, sys_perm_group,
  547                         sys_perm_other, server_id, client_id, ip_type, ip_address,
  548                         virtualhost, virtualhost_port
  549                     ) VALUES (
  550                         ?,
  551                         1,
  552                         1,
  553                         "riud",
  554                         "riud",
  555                         "",
  556                         ?,
  557                         0,
  558                         ?,
  559                         ?,
  560                         "n",
  561                         "80,443"
  562                     )', $server_ip_id, $conf['server_id'], $ip_type, $line);
  563                 } else {
  564                     $this->db->query('INSERT INTO server_ip (
  565                         sys_userid, sys_groupid, sys_perm_user, sys_perm_group,
  566                         sys_perm_other, server_id, client_id, ip_type, ip_address,
  567                         virtualhost, virtualhost_port
  568                     ) VALUES (
  569                         1,
  570                         1,
  571                         "riud",
  572                         "riud",
  573                         "",
  574                         ?,
  575                         0,
  576                         ?,
  577                         ?,
  578                         "n",
  579                         "80,443"
  580                     )', $conf['server_id'], $ip_type, $line);
  581                 }
  582             }
  583         }
  584     }
  585 
  586     public function grant_master_database_rights($verbose = false) {
  587         global $conf;
  588 
  589         /*
  590          * The following code is a little bit tricky:
  591          * * If we HAVE a master-slave - Setup then the client has to grant the rights for himself
  592          *   at the master.
  593          * * If we DO NOT have a master-slave - Setup then we have two possibilities
  594          *   1) it is a single server
  595          *   2) it is the MASTER of n clients
  596         */
  597         $hosts = array();
  598 
  599         if($conf['mysql']['master_slave_setup'] == 'y') {
  600             /*
  601              * it is a master-slave - Setup so the slave has to grant its rights in the master
  602              * database
  603              */
  604 
  605             //* insert the ispconfig user in the remote server
  606             $from_host = $conf['hostname'];
  607             $hosts[$from_host]['user'] = $conf['mysql']['master_ispconfig_user'];
  608             $hosts[$from_host]['db'] = $conf['mysql']['master_database'];
  609             $hosts[$from_host]['pwd'] = $conf['mysql']['master_ispconfig_password'];
  610 
  611             $host_ips = $this->get_host_ips();
  612             if(is_array($host_ips) && !empty($host_ips)) {
  613                 foreach($host_ips as $ip) {
  614                     $hosts[$ip]['user'] = $conf['mysql']['master_ispconfig_user'];
  615                     $hosts[$ip]['db'] = $conf['mysql']['master_database'];
  616                     $hosts[$ip]['pwd'] = $conf['mysql']['master_ispconfig_password'];
  617                 }
  618             } else {
  619                 $from_ip = gethostbyname($conf['hostname']);
  620                 $hosts[$from_ip]['user'] = $conf['mysql']['master_ispconfig_user'];
  621                 $hosts[$from_ip]['db'] = $conf['mysql']['master_database'];
  622                 $hosts[$from_ip]['pwd'] = $conf['mysql']['master_ispconfig_password'];
  623             }
  624         } else{
  625             /*
  626              * it is NOT a master-slave - Setup so we have to find out all clients and their
  627              * host
  628              */
  629             $query = "SELECT Host, User FROM mysql.user WHERE User like 'ispcsrv%' ORDER BY User, Host";
  630             $data = $this->dbmaster->queryAllRecords($query);
  631             if($data === false) {
  632                 $this->error('Unable to get the user rights: '.$value['db'].' Error: '.$this->dbmaster->errorMessage);
  633             }
  634             foreach ($data as $item){
  635                 $hosts[$item['Host']]['user'] = $item['User'];
  636                 $hosts[$item['Host']]['db'] = $conf['mysql']['master_database'];
  637                 $hosts[$item['Host']]['pwd'] = ''; // the user already exists, so we need no pwd!
  638             }
  639         }
  640 
  641         if(count($hosts) > 0) {
  642             foreach($hosts as $host => $value) {
  643                 /*
  644              * If a pwd exists, this means, we have to add the new user (and his pwd).
  645              * if not, the user already exists and we do not need the pwd
  646              */
  647                 if ($value['pwd'] != ''){
  648                     $query = "CREATE USER ?@? IDENTIFIED BY ?";
  649                     if ($verbose){
  650                         echo "\n\n" . $query ."\n";
  651                     }
  652                     $this->dbmaster->query($query, $value['user'], $host, $value['pwd']); // ignore the error
  653                 }
  654 
  655                 /*
  656              *  Try to delete all rights of the user in case that it exists.
  657              *  In Case that it will not exist, do nothing (ignore the error!)
  658              */
  659                 $query = "REVOKE ALL PRIVILEGES, GRANT OPTION FROM ?@?";
  660                 if ($verbose){
  661                     echo "\n\n" . $query ."\n";
  662                 }
  663                 $this->dbmaster->query($query, $value['user'], $host); // ignore the error
  664 
  665                 //* Create the ISPConfig database user in the remote database
  666                 $query = "GRANT SELECT ON ?? TO ?@?";
  667                 if ($verbose){
  668                     echo $query ."\n";
  669                 }
  670                 if(!$this->dbmaster->query($query, $value['db'] . '.server', $value['user'], $host)) {
  671                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  672                 }
  673 
  674                 $query = "GRANT SELECT, INSERT ON ?? TO ?@?";
  675                 if ($verbose){
  676                     echo $query ."\n";
  677                 }
  678                 if(!$this->dbmaster->query($query, $value['db'] . '.sys_log', $value['user'], $host)) {
  679                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  680                 }
  681 
  682                 $query = "GRANT SELECT, UPDATE(`status`, `error`) ON ?? TO ?@?";
  683                 if ($verbose){
  684                     echo $query ."\n";
  685                 }
  686                 if(!$this->dbmaster->query($query, $value['db'] . '.sys_datalog', $value['user'], $host)) {
  687                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  688                 }
  689 
  690                 $query = "GRANT SELECT, UPDATE(`status`) ON ?? TO ?@?";
  691                 if ($verbose){
  692                     echo $query ."\n";
  693                 }
  694 
  695                 $query = "GRANT SELECT, UPDATE(`updated`) ON ?? TO ?@?";
  696                 if ($verbose){
  697                     echo $query ."\n";
  698                 }
  699                 if(!$this->dbmaster->query($query, $value['db'] . '.server', $value['user'], $host)) {
  700                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  701                 }
  702 
  703                 $query = "GRANT SELECT, UPDATE (`ssl`, `ssl_letsencrypt`, `ssl_request`, `ssl_cert`, `ssl_action`, `ssl_key`) ON ?? TO ?@?";
  704                 if ($verbose){
  705                     echo $query ."\n";
  706                 }
  707                 if(!$this->dbmaster->query($query, $value['db'] . '.web_domain', $value['user'], $host)) {
  708                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  709                 }
  710 
  711                 $query = "GRANT SELECT ON ?? TO ?@?";
  712                 if ($verbose){
  713                     echo $query ."\n";
  714                 }
  715                 if(!$this->dbmaster->query($query, $value['db'] . '.web_database', $value['user'], $host)) {
  716                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  717                 }
  718 
  719                 $query = "GRANT SELECT ON ?? TO ?@?";
  720                 if ($verbose){
  721                     echo $query ."\n";
  722                 }
  723                 if(!$this->dbmaster->query($query, $value['db'] . '.sys_group', $value['user'], $host)) {
  724                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  725                 }
  726 
  727                 $query = "GRANT SELECT, UPDATE (`action_state`, `response`) ON ?? TO ?@?";
  728                 if ($verbose){
  729                     echo $query ."\n";
  730                 }
  731                 if(!$this->dbmaster->query($query, $value['db'] . '.sys_remoteaction', $value['user'], $host)) {
  732                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  733                 }
  734 
  735                 $query = "GRANT SELECT, INSERT , DELETE ON ?? TO ?@?";
  736                 if ($verbose){
  737                     echo $query ."\n";
  738                 }
  739                 if(!$this->dbmaster->query($query, $value['db'] . '.monitor_data', $value['user'], $host)) {
  740                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  741                 }
  742 
  743                 $query = "GRANT SELECT, INSERT, UPDATE ON ?? TO ?@?";
  744                 if ($verbose){
  745                     echo $query ."\n";
  746                 }
  747                 if(!$this->dbmaster->query($query, $value['db'] . '.mail_traffic', $value['user'], $host)) {
  748                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  749                 }
  750 
  751                 $query = "GRANT SELECT, INSERT, UPDATE ON ?? TO ?@?";
  752                 if ($verbose){
  753                     echo $query ."\n";
  754                 }
  755                 if(!$this->dbmaster->query($query, $value['db'] . '.web_traffic', $value['user'], $host)) {
  756                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  757                 }
  758 
  759                 $query = "GRANT SELECT, UPDATE, DELETE ON ?? TO ?@?";
  760                 if ($verbose){
  761                     echo $query ."\n";
  762                 }
  763                 if(!$this->dbmaster->query($query, $value['db'] . '.aps_instances', $value['user'], $host)) {
  764                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  765                 }
  766 
  767                 $query = "GRANT SELECT, DELETE ON ?? TO ?@?";
  768                 if ($verbose){
  769                     echo $query ."\n";
  770                 }
  771                 if(!$this->dbmaster->query($query, $value['db'] . '.aps_instances_settings', $value['user'], $host)) {
  772                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  773                 }
  774 
  775                 $query = "GRANT SELECT, INSERT, DELETE ON ?? TO ?@?";
  776                 if ($verbose){
  777                     echo $query ."\n";
  778                 }
  779                 if(!$this->dbmaster->query($query, $value['db'] . '.web_backup', $value['user'], $host)) {
  780                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  781                 }
  782 
  783                 $query = "GRANT SELECT, INSERT, DELETE ON ?? TO ?@?";
  784                 if ($verbose){
  785                     echo $query ."\n";
  786                 }
  787                 if(!$this->dbmaster->query($query, $value['db'] . '.mail_backup', $value['user'], $host)) {
  788                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  789                 }
  790 
  791                 $query = "GRANT SELECT, UPDATE(`dnssec_initialized`, `dnssec_info`, `dnssec_last_signed`) ON ?? TO ?@?";
  792                 if ($verbose){
  793                     echo $query ."\n";
  794                 }
  795                 if(!$this->dbmaster->query($query, $value['db'] . '.dns_soa', $value['user'], $host)) {
  796                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  797                 }
  798 
  799                 $query = "GRANT SELECT, INSERT, UPDATE ON ?? TO ?@?";
  800                 if ($verbose){
  801                     echo $query ."\n";
  802                 }
  803                 if(!$this->dbmaster->query($query, $value['db'] . '.ftp_traffic', $value['user'], $host)) {
  804                     $this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
  805                 }
  806 
  807             }
  808 
  809         }
  810 
  811     }
  812 
  813     //** writes postfix configuration files
  814     public function process_postfix_config($configfile) {
  815         global $conf;
  816 
  817         $config_dir = $conf['postfix']['config_dir'].'/';
  818         $postfix_group = $conf['postfix']['group'];
  819         $full_file_name = $config_dir.$configfile;
  820 
  821         //* Backup exiting file
  822         if(is_file($full_file_name)) {
  823             copy($full_file_name, $config_dir.$configfile.'~');
  824             chmod($config_dir.$configfile.'~',0600);
  825         }
  826 
  827         exec('postconf -h recipient_delimiter 2>/dev/null', $out);
  828         if (strlen($out[0]) > 0) {
  829             // build string like:  CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX('%u', '%%', 1), '+', 1), '@%d')
  830             $addr_cleanup = "'%u'";
  831             foreach (str_split($out[0]) as $delim) {
  832                 $recipient_delimiter = $this->db->escape( str_replace('%', '%%', $delim) );
  833                 $addr_cleanup = "SUBSTRING_INDEX(${addr_cleanup}, '${recipient_delimiter}', 1)";
  834             }
  835             $no_addr_extension = "CONCAT(${addr_cleanup}, '@%d')";
  836         } else {
  837             $no_addr_extension = "''";
  838         }
  839         unset($out);
  840 
  841         //* Replace variables in config file template
  842         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
  843         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
  844         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
  845         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
  846         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
  847         $content = str_replace('{server_id}', $conf['server_id'], $content);
  848         $content = str_replace('{address_without_extension}', $no_addr_extension, $content);
  849         wf($full_file_name, $content);
  850 
  851         //* Changing mode and group of the new created config file
  852         caselog('chmod u=rw,g=r,o= '.escapeshellarg($full_file_name).' &> /dev/null',
  853             __FILE__, __LINE__, 'chmod on '.$full_file_name, 'chmod on '.$full_file_name.' failed');
  854         caselog('chgrp '.escapeshellarg($postfix_group).' '.escapeshellarg($full_file_name).' &> /dev/null',
  855             __FILE__, __LINE__, 'chgrp on '.$full_file_name, 'chgrp on '.$full_file_name.' failed');
  856 
  857     }
  858 
  859     public function configure_jailkit() {
  860         global $conf;
  861 
  862         $cf = $conf['jailkit'];
  863         $config_dir = $cf['config_dir'];
  864         $jk_init = $cf['jk_init'];
  865         $jk_chrootsh = $cf['jk_chrootsh'];
  866 
  867         if (is_dir($config_dir)) {
  868             if(is_file($config_dir.'/'.$jk_init)) copy($config_dir.'/'.$jk_init, $config_dir.'/'.$jk_init.'~');
  869             if(is_file($config_dir.'/'.$jk_chrootsh.'.master')) copy($config_dir.'/'.$jk_chrootsh.'.master', $config_dir.'/'.$jk_chrootsh.'~');
  870 
  871             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$jk_init.'.master')) {
  872                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$jk_init.'.master', $config_dir.'/'.$jk_init);
  873             } else {
  874                 copy('tpl/'.$jk_init.'.master', $config_dir.'/'.$jk_init);
  875             }
  876             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$jk_chrootsh.'.master')) {
  877                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$jk_chrootsh.'.master', $config_dir.'/'.$jk_chrootsh);
  878             } else {
  879                 copy('tpl/'.$jk_chrootsh.'.master', $config_dir.'/'.$jk_chrootsh);
  880             }
  881         }
  882 
  883         //* help jailkit fo find its ini files
  884         if(!is_link('/usr/jk_socketd.ini')) exec('ln -s /etc/jailkit/jk_socketd.ini /usr/jk_socketd.ini');
  885         if(!is_link('/usr/jk_init.ini')) exec('ln -s /etc/jailkit/jk_init.ini /usr/jk_init.ini');
  886 
  887     }
  888 
  889     public function configure_mailman($status = 'insert') {
  890         global $conf;
  891 
  892         $config_dir = $conf['mailman']['config_dir'].'/';
  893         $full_file_name = $config_dir.'mm_cfg.py';
  894         //* Backup exiting file
  895         if(is_file($full_file_name)) {
  896             copy($full_file_name, $config_dir.'mm_cfg.py~');
  897         }
  898 
  899         // load files
  900         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/mm_cfg.py.master', 'tpl/mm_cfg.py.master');
  901         $old_file = rf($full_file_name);
  902 
  903         $old_options = array();
  904         $lines = explode("\n", $old_file);
  905         foreach ($lines as $line)
  906         {
  907             if (trim($line) != '' && substr($line, 0, 1) != '#')
  908             {
  909                 @list($key, $value) = @explode("=", $line);
  910                 if (isset($value) && $value !== '')
  911                 {
  912                     $key = rtrim($key);
  913                     $old_options[$key] = trim($value);
  914                 }
  915             }
  916         }
  917 
  918         $virtual_domains = '';
  919         if($status == 'update')
  920         {
  921             // create virtual_domains list
  922             $domainAll = $this->db->queryAllRecords("SELECT domain FROM mail_mailinglist GROUP BY domain");
  923 
  924             if(is_array($domainAll)) {
  925                 foreach($domainAll as $domain)
  926                 {
  927                     if ($domainAll[0]['domain'] == $domain['domain'])
  928                         $virtual_domains .= "'".$domain['domain']."'";
  929                     else
  930                         $virtual_domains .= ", '".$domain['domain']."'";
  931                 }
  932             }
  933         }
  934         else
  935             $virtual_domains = "' '";
  936 
  937         $content = str_replace('{hostname}', $conf['hostname'], $content);
  938         if(!isset($old_options['DEFAULT_SERVER_LANGUAGE']) || $old_options['DEFAULT_SERVER_LANGUAGE'] == '') $old_options['DEFAULT_SERVER_LANGUAGE'] = "'en'";
  939         $content = str_replace('{default_language}', $old_options['DEFAULT_SERVER_LANGUAGE'], $content);
  940         $content = str_replace('{virtual_domains}', $virtual_domains, $content);
  941 
  942         wf($full_file_name, $content);
  943 
  944         //* Write virtual_to_transport.sh script
  945         $config_dir = $conf['mailman']['config_dir'].'/';
  946         $full_file_name = $config_dir.'virtual_to_transport.sh';
  947 
  948         //* Backup exiting virtual_to_transport.sh script
  949         if(is_file($full_file_name)) {
  950             copy($full_file_name, $config_dir.'virtual_to_transport.sh~');
  951         }
  952 
  953         if(is_dir('/etc/mailman')) {
  954             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/mailman-virtual_to_transport.sh')) {
  955                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/mailman-virtual_to_transport.sh', $full_file_name);
  956             } else {
  957                 copy('tpl/mailman-virtual_to_transport.sh', $full_file_name);
  958             }
  959             chgrp($full_file_name, $this->mailman_group);
  960             chmod($full_file_name, 0755);
  961         }
  962 
  963         //* Create aliasaes
  964         if($status == 'install') exec('/usr/lib/mailman/bin/genaliases 2>/dev/null');
  965 
  966         if(!is_file('/var/lib/mailman/data/transport-mailman')) touch('/var/lib/mailman/data/transport-mailman');
  967         exec('/usr/sbin/postmap /var/lib/mailman/data/transport-mailman');
  968     }
  969 
  970     public function get_postfix_service($service, $type) {
  971         global $conf;
  972 
  973         exec("postconf -M 2> /dev/null", $out, $ret);
  974 
  975         if ($ret === 0) { //* with postfix >= 2.9 we can detect configured services with postconf
  976             unset($out);
  977             exec ("postconf -M $service/$type 2> /dev/null", $out, $ret); //* Postfix >= 2.11
  978             if (!isset($out[0])) { //* try Postfix 2.9
  979                 exec ("postconf -M $service.$type 2> /dev/null", $out, $ret);
  980             }
  981             $postfix_service = @($out[0]=='')?false:true;
  982         } else { //* fallback - Postfix < 2.9
  983             $content = rf($conf['postfix']['config_dir'].'/master.cf');
  984             $quoted_regex = "^((?!#)".preg_quote($service, '/').".*".preg_quote($type, '/').".*)$";
  985             $postfix_service = @(preg_match("/$quoted_regex/m", $content))?true:false;
  986         }
  987 
  988         return $postfix_service;
  989     }
  990 
  991     public function remove_postfix_service( $service, $type ) {
  992         global $conf;
  993 
  994         // nothing to do if the service isn't even defined.
  995         if (! $this->get_postfix_service( $service, $type ) ) {
  996             return true;
  997         }
  998 
  999         $postfix_version = `postconf -d mail_version 2>/dev/null`;
 1000         $postfix_version = preg_replace( '/mail_version\s*=\s*(.*)\s*/', '$1', $postfix_version );
 1001 
 1002         if ( version_compare( $postfix_version, '2.11', '>=' ) ) {
 1003 
 1004             exec("postconf -X -M $service/$type 2> /dev/null", $out, $ret);
 1005 
 1006             # reduce 3 or more newlines to 2
 1007             $content = rf($conf['postfix']['config_dir'].'/master.cf');
 1008             $content = preg_replace( '/(\r?\n){3,}/', '$1$1', $content );
 1009             wf( $conf['postfix']['config_dir'].'/master.cf', $content );
 1010 
 1011         } else { //* fallback - Postfix < 2.11
 1012 
 1013             if ( ! $cf = fopen( $conf['postfix']['config_dir'].'/master.cf', 'r' ) ) {
 1014                 return false;
 1015             }
 1016 
 1017             $out = "";
 1018             $reading_service = false;
 1019 
 1020             while ( !feof( $cf ) ) {
 1021                 $line = fgets( $cf );
 1022 
 1023                 $quoted_regex = '^'.preg_quote($service, '/').'\s+'.preg_quote($type, '/');
 1024                 if ( $reading_service ) {
 1025                     # regex matches a new service or "empty" (whitespace) line
 1026                     if ( preg_match( '/^([^\s#]+.*|\s*)$/', $line ) &&
 1027                        ! preg_match( "/$quoted_regex/", $line ) ) {
 1028                         $out .= $line;
 1029                         $reading_service = false;
 1030                     }
 1031 
 1032                     # $skipped_lines .= $line;
 1033 
 1034                 # regex matches definition matching service to be removed
 1035                 } else if ( preg_match( "/$quoted_regex/", $line ) ) {
 1036 
 1037                     $reading_service = true;
 1038                     # $skipped_lines .= $line;
 1039 
 1040                 } else {
 1041                     $out .= $line;
 1042                 }
 1043             }
 1044             fclose( $cf );
 1045 
 1046             $out = preg_replace( '/(\r?\n){3,}/', '$1$1', $out ); # reduce 3 or more newlines to 2
 1047 
 1048             return wf( $conf['postfix']['config_dir'].'/master.cf', $out );
 1049         }
 1050 
 1051         return true;
 1052     }
 1053 
 1054     public function configure_postfix($options = '') {
 1055         global $conf,$autoinstall;
 1056         $cf = $conf['postfix'];
 1057         $config_dir = $cf['config_dir'];
 1058 
 1059         if(!is_dir($config_dir)) {
 1060             $this->error("The postfix configuration directory '$config_dir' does not exist.");
 1061         }
 1062 
 1063         //* Get postfix version
 1064         exec('postconf -d mail_version 2>&1', $out);
 1065         $postfix_version = preg_replace('/.*=\s*/', '', $out[0]);
 1066         unset($out);
 1067 
 1068         //* Install virtual mappings
 1069         foreach (glob('tpl/mysql-virtual_*.master') as $filename) {
 1070             $this->process_postfix_config( basename($filename, '.master') );
 1071         }
 1072 
 1073         //* mysql-verify_recipients.cf
 1074         $this->process_postfix_config('mysql-verify_recipients.cf');
 1075 
 1076         // test if lmtp if available
 1077         $configure_lmtp = $this->get_postfix_service('lmtp','unix');
 1078 
 1079         //* postfix-dkim
 1080         $filename='tag_as_originating.re';
 1081         $full_file_name=$config_dir.'/'.$filename;
 1082         if(is_file($full_file_name)) copy($full_file_name, $full_file_name.'~');
 1083         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/postfix-'.$filename.'.master', 'tpl/postfix-'.$filename.'.master');
 1084         if($configure_lmtp) {
 1085             $content = preg_replace('/amavis:/', 'lmtp:', $content);
 1086         }
 1087         wf($full_file_name, $content);
 1088 
 1089         $filename='tag_as_foreign.re';
 1090         $full_file_name=$config_dir.'/'.$filename;
 1091         if(is_file($full_file_name)) copy($full_file_name, $full_file_name.'~');
 1092         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/postfix-'.$filename.'.master', 'tpl/postfix-'.$filename.'.master');
 1093         if($configure_lmtp) {
 1094             $content = preg_replace('/amavis:/', 'lmtp:', $content);
 1095         }
 1096         wf($full_file_name, $content);
 1097 
 1098         //* Creating virtual mail user and group
 1099         $command = 'groupadd -g '.$cf['vmail_groupid'].' '.$cf['vmail_groupname'];
 1100         if(!is_group($cf['vmail_groupname'])) caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1101 
 1102         $command = 'useradd -g '.$cf['vmail_groupname'].' -u '.$cf['vmail_userid'].' '.$cf['vmail_username'].' -d '.$cf['vmail_mailbox_base'].' -m';
 1103         if(!is_user($cf['vmail_username'])) caselog("$command &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1104 
 1105         //* These postconf commands will be executed on installation and update
 1106         $server_ini_rec = $this->db->queryOneRecord("SELECT config FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . '.server', $conf['server_id']);
 1107         $server_ini_array = ini_to_array(stripslashes($server_ini_rec['config']));
 1108         unset($server_ini_rec);
 1109 
 1110         //* If there are RBL's defined, format the list and add them to smtp_recipient_restrictions to prevent removeal after an update
 1111         $rbl_list = '';
 1112         if (@isset($server_ini_array['mail']['realtime_blackhole_list']) && $server_ini_array['mail']['realtime_blackhole_list'] != '') {
 1113             $rbl_hosts = explode(",", str_replace(" ", "", $server_ini_array['mail']['realtime_blackhole_list']));
 1114             foreach ($rbl_hosts as $key => $value) {
 1115                 $rbl_list .= ", reject_rbl_client ". $value;
 1116             }
 1117         }
 1118         unset($rbl_hosts);
 1119 
 1120         //* If Postgrey is installed, configure it
 1121         $greylisting = '';
 1122         if($conf['postgrey']['installed'] == true) {
 1123             $greylisting = ', check_recipient_access mysql:/etc/postfix/mysql-virtual_policy_greylist.cf';
 1124         }
 1125 
 1126         $reject_sender_login_mismatch = '';
 1127         $reject_authenticated_sender_login_mismatch = '';
 1128         if (isset($server_ini_array['mail']['reject_sender_login_mismatch']) && ($server_ini_array['mail']['reject_sender_login_mismatch'] == 'y')) {
 1129             $reject_sender_login_mismatch = ',reject_sender_login_mismatch,';
 1130             $reject_authenticated_sender_login_mismatch = 'reject_authenticated_sender_login_mismatch, ';
 1131         }
 1132 
 1133         # placeholder includes comment char
 1134         $stress_adaptive_placeholder = '#{stress_adaptive}';
 1135         $stress_adaptive = (isset($server_ini_array['mail']['stress_adaptive']) && ($server_ini_array['mail']['stress_adaptive'] == 'y')) ? '' : $stress_adaptive_placeholder;
 1136 
 1137         $reject_unknown_client_hostname='';
 1138         if (isset($server_ini_array['mail']['reject_unknown']) && ($server_ini_array['mail']['reject_unknown'] == 'client' || $server_ini_array['mail']['reject_unknown'] == 'client_helo')) {
 1139             $reject_unknown_client_hostname=',reject_unknown_client_hostname';
 1140         }
 1141         $reject_unknown_helo_hostname='';
 1142         if ((!isset($server_ini_array['mail']['reject_unknown'])) || $server_ini_array['mail']['reject_unknown'] == 'helo' || $server_ini_array['mail']['reject_unknown'] == 'client_helo') {
 1143             $reject_unknown_helo_hostname=',reject_unknown_helo_hostname';
 1144         }
 1145 
 1146         unset($server_ini_array);
 1147 
 1148         $myhostname = str_replace('.','\.',$conf['hostname']);
 1149 
 1150         $postconf_placeholders = array('{config_dir}' => $config_dir,
 1151             '{vmail_mailbox_base}' => $cf['vmail_mailbox_base'],
 1152             '{vmail_userid}' => $cf['vmail_userid'],
 1153             '{vmail_groupid}' => $cf['vmail_groupid'],
 1154             '{rbl_list}' => $rbl_list,
 1155             '{greylisting}' => $greylisting,
 1156             '{reject_slm}' => $reject_sender_login_mismatch,
 1157             '{reject_aslm}' => $reject_authenticated_sender_login_mismatch,
 1158             '{myhostname}' => $myhostname,
 1159             $stress_adaptive_placeholder => $stress_adaptive,
 1160             '{reject_unknown_client_hostname}' => $reject_unknown_client_hostname,
 1161             '{reject_unknown_helo_hostname}' => $reject_unknown_helo_hostname,
 1162         );
 1163 
 1164         $postconf_tpl = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_postfix.conf.master', 'tpl/debian_postfix.conf.master');
 1165         $postconf_tpl = strtr($postconf_tpl, $postconf_placeholders);
 1166         $postconf_commands = array_filter(explode("\n", $postconf_tpl)); // read and remove empty lines
 1167 
 1168         //* Merge version-specific postfix config
 1169         if(version_compare($postfix_version , '2.5', '>=')) {
 1170             $configfile = 'postfix_2-5.conf';
 1171             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1172             $content = strtr($content, $postconf_placeholders);
 1173             $postconf_commands = array_merge($postconf_commands, array_filter(explode("\n", $content)));
 1174         }
 1175         if(version_compare($postfix_version , '2.10', '>=')) {
 1176             $configfile = 'postfix_2-10.conf';
 1177             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1178             $content = strtr($content, $postconf_placeholders);
 1179             $postconf_commands = array_merge($postconf_commands, array_filter(explode("\n", $content)));
 1180         }
 1181         if(version_compare($postfix_version , '3.0', '>=')) {
 1182             $configfile = 'postfix_3-0.conf';
 1183             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1184             $content = strtr($content, $postconf_placeholders);
 1185             $postconf_commands = array_merge($postconf_commands, array_filter(explode("\n", $content)));
 1186         }
 1187         if(version_compare($postfix_version , '3.3', '>=')) {
 1188             $configfile = 'postfix_3-3.conf';
 1189             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1190             $content = strtr($content, $postconf_placeholders);
 1191             $postconf_commands = array_merge($postconf_commands, array_filter(explode("\n", $content)));
 1192         }
 1193         $configfile = 'postfix_custom.conf';
 1194         if(file_exists($conf['ispconfig_install_dir'].'/server/conf-custom/install/' . $configfile . '.master')) {
 1195             $content = file_get_contents($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master');
 1196             $content = strtr($content, $postconf_placeholders);
 1197             $postconf_commands = array_merge($postconf_commands, array_filter(explode("\n", $content)));
 1198         }
 1199 
 1200         // Remove comment lines, these would give fatal errors when passed to postconf.
 1201         $postconf_commands = array_filter($postconf_commands, function($line) { return preg_match('/^[^#]/', $line); });
 1202 
 1203         //* These postconf commands will be executed on installation only
 1204         if($this->is_update == false) {
 1205             $postconf_commands = array_merge($postconf_commands, array(
 1206                     'myhostname = '.$conf['hostname'],
 1207                     'mydestination = '.$conf['hostname'].', localhost, localhost.localdomain',
 1208                     'mynetworks = 127.0.0.0/8 [::1]/128'
 1209                 ));
 1210         }
 1211 
 1212         //* Create the header and body check files
 1213         touch($config_dir.'/header_checks');
 1214         touch($config_dir.'/mime_header_checks');
 1215         touch($config_dir.'/nested_header_checks');
 1216         touch($config_dir.'/body_checks');
 1217         touch($config_dir.'/sasl_passwd');
 1218 
 1219         //* Create the mailman files
 1220         if(!is_dir('/var/lib/mailman/data')) exec('mkdir -p /var/lib/mailman/data');
 1221         if(!is_file('/var/lib/mailman/data/aliases')) touch('/var/lib/mailman/data/aliases');
 1222         exec('postalias /var/lib/mailman/data/aliases');
 1223         if(!is_file('/var/lib/mailman/data/virtual-mailman')) touch('/var/lib/mailman/data/virtual-mailman');
 1224         exec('postmap /var/lib/mailman/data/virtual-mailman');
 1225         if(!is_file('/var/lib/mailman/data/transport-mailman')) touch('/var/lib/mailman/data/transport-mailman');
 1226         exec('/usr/sbin/postmap /var/lib/mailman/data/transport-mailman');
 1227 
 1228         //* Create auxillary postfix conf files
 1229         $configfile = 'helo_access';
 1230         if(is_file($config_dir.'/'.$configfile)) {
 1231             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 1232             chmod($config_dir.'/'.$configfile.'~', 0400);
 1233         }
 1234         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1235         $content = strtr($content, $postconf_placeholders);
 1236         # todo: look up this server's ip addrs and loop through each
 1237         # todo: look up domains hosted on this server and loop through each
 1238         wf($config_dir.'/'.$configfile, $content);
 1239 
 1240         $configfile = 'blacklist_helo';
 1241         if(is_file($config_dir.'/'.$configfile)) {
 1242             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 1243             chmod($config_dir.'/'.$configfile.'~', 0400);
 1244         }
 1245         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1246         $content = strtr($content, $postconf_placeholders);
 1247         wf($config_dir.'/'.$configfile, $content);
 1248 
 1249         //* Make a backup copy of the main.cf file
 1250         copy($config_dir.'/main.cf', $config_dir.'/main.cf~');
 1251 
 1252         //* Executing the postconf commands
 1253         foreach($postconf_commands as $cmd) {
 1254             $command = "postconf -e '$cmd'";
 1255             caselog($command." &> /dev/null", __FILE__, __LINE__, 'EXECUTED: '.$command, 'Failed to execute the command '.$command);
 1256         }
 1257 
 1258         if(!stristr($options, 'dont-create-certs')) {
 1259             //* Create the SSL certificate
 1260             if(AUTOINSTALL){
 1261                 $command = 'cd '.$config_dir.'; '
 1262                     ."openssl req -new -subj '/C=".escapeshellcmd($autoinstall['ssl_cert_country'])."/ST=".escapeshellcmd($autoinstall['ssl_cert_state'])."/L=".escapeshellcmd($autoinstall['ssl_cert_locality'])."/O=".escapeshellcmd($autoinstall['ssl_cert_organisation'])."/OU=".escapeshellcmd($autoinstall['ssl_cert_organisation_unit'])."/CN=".escapeshellcmd($autoinstall['ssl_cert_common_name'])."' -outform PEM -out smtpd.cert -newkey rsa:4096 -nodes -keyout smtpd.key -keyform PEM -days 3650 -x509";
 1263             } else {
 1264                 $command = 'cd '.$config_dir.'; '
 1265                     .'openssl req -new -outform PEM -out smtpd.cert -newkey rsa:4096 -nodes -keyout smtpd.key -keyform PEM -days 3650 -x509';
 1266             }
 1267             exec($command);
 1268 
 1269             $command = 'chmod o= '.$config_dir.'/smtpd.key';
 1270             caselog($command.' &> /dev/null', __FILE__, __LINE__, 'EXECUTED: '.$command, 'Failed to execute the command '.$command);
 1271         }
 1272 
 1273         //** We have to change the permissions of the courier authdaemon directory to make it accessible for maildrop.
 1274         $command = 'chmod 755  /var/run/courier/authdaemon/';
 1275         if(is_file('/var/run/courier/authdaemon/')) caselog($command.' &> /dev/null', __FILE__, __LINE__, 'EXECUTED: '.$command, 'Failed to execute the command '.$command);
 1276 
 1277         //* Check maildrop service in posfix master.cf
 1278         $quoted_regex = '^maildrop   unix.*pipe flags=DRhu user=vmail '.preg_quote('argv=/usr/bin/maildrop -d '.$cf['vmail_username'].' ${extension} ${recipient} ${user} ${nexthop} ${sender}', '/');
 1279         $configfile = $config_dir.'/master.cf';
 1280         if($this->get_postfix_service('maildrop', 'unix')) {
 1281             exec ("postconf -M maildrop.unix 2> /dev/null", $out, $ret);
 1282             $change_maildrop_flags = @(preg_match("/$quoted_regex/", $out[0]) && $out[0] !='')?false:true;
 1283         } else {
 1284             $change_maildrop_flags = @(preg_match("/$quoted_regex/", $configfile))?false:true;
 1285         }
 1286         if ($change_maildrop_flags) {
 1287             //* Change maildrop service in posfix master.cf
 1288             if(is_file($config_dir.'/master.cf')) {
 1289                 copy($config_dir.'/master.cf', $config_dir.'/master.cf~');
 1290             }
 1291             if(is_file($config_dir.'/master.cf~')) {
 1292                 chmod($config_dir.'/master.cf~', 0400);
 1293             }
 1294             $configfile = $config_dir.'/master.cf';
 1295             $content = rf($configfile);
 1296             $content =  str_replace('flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}',
 1297                         'flags=DRhu user='.$cf['vmail_username'].' argv=/usr/bin/maildrop -d '.$cf['vmail_username'].' ${extension} ${recipient} ${user} ${nexthop} ${sender}',
 1298                         $content);
 1299             wf($configfile, $content);
 1300         }
 1301 
 1302         //* Writing the Maildrop mailfilter file
 1303         $configfile = 'mailfilter';
 1304         if(is_file($cf['vmail_mailbox_base'].'/.'.$configfile)) {
 1305             copy($cf['vmail_mailbox_base'].'/.'.$configfile, $cf['vmail_mailbox_base'].'/.'.$configfile.'~');
 1306         }
 1307         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1308         $content = str_replace('{dist_postfix_vmail_mailbox_base}', $cf['vmail_mailbox_base'], $content);
 1309         wf($cf['vmail_mailbox_base'].'/.'.$configfile, $content);
 1310 
 1311         //* Create the directory for the custom mailfilters
 1312         if(!is_dir($cf['vmail_mailbox_base'].'/mailfilters')) {
 1313             $command = 'mkdir '.$cf['vmail_mailbox_base'].'/mailfilters';
 1314             caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1315         }
 1316 
 1317         //* Chmod and chown the .mailfilter file
 1318         $command = 'chown '.$cf['vmail_username'].':'.$cf['vmail_groupname'].' '.$cf['vmail_mailbox_base'].'/.mailfilter';
 1319         caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1320 
 1321         $command = 'chmod 600 '.$cf['vmail_mailbox_base'].'/.mailfilter';
 1322         caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1323 
 1324     }
 1325 
 1326     public function configure_saslauthd() {
 1327         global $conf;
 1328 
 1329         //* Get saslsauthd version
 1330         exec('saslauthd -v 2>&1', $out);
 1331         $parts = explode(' ', $out[0]);
 1332         $saslversion = $parts[1];
 1333         unset($parts);
 1334         unset($out);
 1335 
 1336         if(version_compare($saslversion , '2.1.23', '<=')) {
 1337             //* Configfile for saslauthd versions up to 2.1.23
 1338             $configfile = 'sasl_smtpd.conf';
 1339         } else {
 1340             //* Configfile for saslauthd versions 2.1.24 and newer
 1341             $configfile = 'sasl_smtpd2.conf';
 1342         }
 1343 
 1344         if(is_file($conf['postfix']['config_dir'].'/sasl/smtpd.conf')) copy($conf['postfix']['config_dir'].'/sasl/smtpd.conf', $conf['postfix']['config_dir'].'/sasl/smtpd.conf~');
 1345         if(is_file($conf['postfix']['config_dir'].'/sasl/smtpd.conf~')) chmod($conf['postfix']['config_dir'].'/sasl/smtpd.conf~', 0400);
 1346         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1347         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 1348         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 1349         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 1350         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 1351         wf($conf['postfix']['config_dir'].'/sasl/smtpd.conf', $content);
 1352 
 1353         // TODO: Chmod and chown on the config file
 1354 
 1355 
 1356         // Recursively create the spool directory
 1357         if(!@is_dir('/var/spool/postfix/var/run/saslauthd')) mkdir('/var/spool/postfix/var/run/saslauthd', 0755, true);
 1358 
 1359         // Edit the file /etc/default/saslauthd
 1360         $configfile = $conf['saslauthd']['config'];
 1361         if(is_file($configfile)) copy($configfile, $configfile.'~');
 1362         if(is_file($configfile.'~')) chmod($configfile.'~', 0400);
 1363         $content = rf($configfile);
 1364         $content = str_replace('START=no', 'START=yes', $content);
 1365         // Debian
 1366         $content = str_replace('OPTIONS="-c"', 'OPTIONS="-m /var/spool/postfix/var/run/saslauthd -r"', $content);
 1367         // Ubuntu
 1368         $content = str_replace('OPTIONS="-c -m /var/run/saslauthd"', 'OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"', $content);
 1369         wf($configfile, $content);
 1370 
 1371         // Edit the file /etc/init.d/saslauthd
 1372         $configfile = $conf['init_scripts'].'/'.$conf['saslauthd']['init_script'];
 1373         $content = rf($configfile);
 1374         $content = str_replace('PIDFILE=$RUN_DIR/saslauthd.pid', 'PIDFILE="/var/spool/postfix/var/run/${NAME}/saslauthd.pid"', $content);
 1375         wf($configfile, $content);
 1376 
 1377         // add the postfix user to the sasl group (at least necessary for Ubuntu 8.04 and most likely Debian Lenny as well.
 1378         exec('adduser postfix sasl');
 1379 
 1380 
 1381     }
 1382 
 1383     public function configure_pam() {
 1384         global $conf;
 1385         $pam = $conf['pam'];
 1386         //* configure pam for SMTP authentication agains the ispconfig database
 1387         $configfile = 'pamd_smtp';
 1388         if(is_file($pam.'/smtp'))    copy($pam.'/smtp', $pam.'/smtp~');
 1389         if(is_file($pam.'/smtp~'))   chmod($pam.'/smtp~', 0400);
 1390 
 1391         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1392         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 1393         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 1394         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 1395         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 1396         wf($pam.'/smtp', $content);
 1397         // On some OSes smtp is world readable which allows for reading database information.  Removing world readable rights should have no effect.
 1398         if(is_file($pam.'/smtp'))    exec("chmod o= $pam/smtp");
 1399         chmod($pam.'/smtp', 0660);
 1400         chown($pam.'/smtp', 'daemon');
 1401         chgrp($pam.'/smtp', 'daemon');
 1402 
 1403     }
 1404 
 1405     public function configure_courier() {
 1406         global $conf;
 1407         $config_dir = $conf['courier']['config_dir'];
 1408         //* authmysqlrc
 1409         $configfile = 'authmysqlrc';
 1410         if(is_file($config_dir.'/'.$configfile)) {
 1411             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 1412         }
 1413         chmod($config_dir.'/'.$configfile.'~', 0400);
 1414         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1415         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 1416         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 1417         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 1418         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 1419         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 1420         wf($config_dir.'/'.$configfile, $content);
 1421 
 1422         chmod($config_dir.'/'.$configfile, 0660);
 1423         chown($config_dir.'/'.$configfile, 'daemon');
 1424         chgrp($config_dir.'/'.$configfile, 'daemon');
 1425 
 1426         //* authdaemonrc
 1427         $configfile = $config_dir.'/authdaemonrc';
 1428         if(is_file($configfile)) {
 1429             copy($configfile, $configfile.'~');
 1430         }
 1431         if(is_file($configfile.'~')) {
 1432             chmod($configfile.'~', 0400);
 1433         }
 1434         $content = rf($configfile);
 1435         $content = str_replace('authmodulelist="authpam"', 'authmodulelist="authmysql"', $content);
 1436         wf($configfile, $content);
 1437     }
 1438 
 1439     public function configure_dovecot() {
 1440         global $conf;
 1441 
 1442         $virtual_transport = 'dovecot';
 1443 
 1444         $configure_lmtp = false;
 1445 
 1446         // use lmtp if installed
 1447         if($configure_lmtp = (is_file('/usr/lib/dovecot/lmtp') || is_file('/usr/libexec/dovecot/lmtp'))) {
 1448             $virtual_transport = 'lmtp:unix:private/dovecot-lmtp';
 1449         }
 1450 
 1451         // check if virtual_transport must be changed
 1452         if ($this->is_update) {
 1453             $tmp = $this->db->queryOneRecord("SELECT * FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . ".server", $conf['server_id']);
 1454             $ini_array = ini_to_array(stripslashes($tmp['config']));
 1455             // ini_array needs not to be checked, because already done in update.php -> updateDbAndIni()
 1456 
 1457             if(isset($ini_array['mail']['mailbox_virtual_uidgid_maps']) && $ini_array['mail']['mailbox_virtual_uidgid_maps'] == 'y') {
 1458                 $virtual_transport = 'lmtp:unix:private/dovecot-lmtp';
 1459                 $configure_lmtp = true;
 1460             }
 1461         }
 1462 
 1463         $config_dir = $conf['postfix']['config_dir'];
 1464         $quoted_config_dir = preg_quote($config_dir, '|');
 1465         $postfix_version = `postconf -d mail_version 2>/dev/null`;
 1466         $postfix_version = preg_replace( '/mail_version\s*=\s*(.*)\s*/', '$1', $postfix_version );
 1467 
 1468         //* Configure master.cf and add a line for deliver
 1469         if(!$this->get_postfix_service('dovecot', 'unix')) {
 1470             //* backup
 1471             if(is_file($config_dir.'/master.cf')){
 1472                 copy($config_dir.'/master.cf', $config_dir.'/master.cf~2');
 1473             }
 1474             if(is_file($config_dir.'/master.cf~')){
 1475                 chmod($config_dir.'/master.cf~2', 0400);
 1476             }
 1477             //* Configure master.cf and add a line for deliver
 1478             $content = rf($config_dir.'/master.cf');
 1479             $deliver_content = 'dovecot   unix  -       n       n       -       -       pipe'."\n".'  flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop}'."\n";
 1480             af($config_dir.'/master.cf', $deliver_content);
 1481             unset($content);
 1482             unset($deliver_content);
 1483         }
 1484 
 1485         //* Reconfigure postfix to use dovecot authentication
 1486         // Adding the amavisd commands to the postfix configuration
 1487         $postconf_commands = array (
 1488             'dovecot_destination_recipient_limit = 1',
 1489             'virtual_transport = '.$virtual_transport,
 1490             'smtpd_sasl_type = dovecot',
 1491             'smtpd_sasl_path = private/auth'
 1492         );
 1493 
 1494         // Make a backup copy of the main.cf file
 1495         copy($config_dir.'/main.cf', $config_dir.'/main.cf~3');
 1496 
 1497         $options = preg_split("/,\s*/", exec("postconf -h smtpd_recipient_restrictions"));
 1498         $new_options = array();
 1499         foreach ($options as $value) {
 1500             $value = trim($value);
 1501             if ($value == '') continue;
 1502             if (preg_match("|check_recipient_access\s+proxy:mysql:${quoted_config_dir}/mysql-verify_recipients.cf|", $value)) {
 1503                 continue;
 1504             }
 1505             $new_options[] = $value;
 1506         }
 1507         if ($configure_lmtp && $conf['mail']['content_filter'] === 'amavisd') {
 1508             for ($i = 0; isset($new_options[$i]); $i++) {
 1509                 if ($new_options[$i] == 'reject_unlisted_recipient') {
 1510                     array_splice($new_options, $i+1, 0, array("check_recipient_access proxy:mysql:${config_dir}/mysql-verify_recipients.cf"));
 1511                     break;
 1512                 }
 1513             }
 1514             # postfix < 3.3 needs this when using reject_unverified_recipient:
 1515             if(version_compare($postfix_version, 3.3, '<')) {
 1516                 $postconf_commands[] = "enable_original_recipient = yes";
 1517             }
 1518         }
 1519         $postconf_commands[] = "smtpd_recipient_restrictions = ".implode(", ", $new_options);
 1520 
 1521         // Executing the postconf commands
 1522         foreach($postconf_commands as $cmd) {
 1523             $command = "postconf -e '$cmd'";
 1524             caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1525         }
 1526 
 1527         //* backup dovecot.conf
 1528         $config_dir = $conf['dovecot']['config_dir'];
 1529         $configfile = 'dovecot.conf';
 1530         if(is_file($config_dir.'/'.$configfile)) {
 1531             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 1532         }
 1533 
 1534         //* Get the dovecot version
 1535         exec('dovecot --version', $tmp);
 1536         $dovecot_version = $tmp[0];
 1537         unset($tmp);
 1538 
 1539         //* Copy dovecot configuration file
 1540         if(version_compare($dovecot_version,1, '<=')) { //* Dovecot 1.x
 1541             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_dovecot.conf.master')) {
 1542                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_dovecot.conf.master', $config_dir.'/'.$configfile);
 1543             } else {
 1544                 copy('tpl/debian_dovecot.conf.master', $config_dir.'/'.$configfile);
 1545             }
 1546         } else {    //* Dovecot 2.x
 1547             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_dovecot2.conf.master')) {
 1548                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_dovecot2.conf.master', $config_dir.'/'.$configfile);
 1549             } else {
 1550                 copy('tpl/debian_dovecot2.conf.master', $config_dir.'/'.$configfile);
 1551             }
 1552             // Copy custom config file
 1553             if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/dovecot_custom.conf.master')) {
 1554                 if(!@is_dir($config_dir . '/conf.d')) {
 1555                     mkdir($config_dir . '/conf.d');
 1556                 }
 1557                 copy($conf['ispconfig_install_dir'].'/server/conf-custom/install/dovecot_custom.conf.master', $config_dir.'/conf.d/99-ispconfig-custom-config.conf');
 1558             }
 1559             replaceLine($config_dir.'/'.$configfile, 'postmaster_address = postmaster@example.com', 'postmaster_address = postmaster@'.$conf['hostname'], 1, 0);
 1560             replaceLine($config_dir.'/'.$configfile, 'postmaster_address = webmaster@localhost', 'postmaster_address = postmaster@'.$conf['hostname'], 1, 0);
 1561             if(version_compare($dovecot_version, 2.1, '<')) {
 1562                 removeLine($config_dir.'/'.$configfile, 'ssl_protocols =');
 1563             }
 1564             if(version_compare($dovecot_version,2.2) >= 0) {
 1565                 // Dovecot > 2.2 does not recognize !SSLv2 anymore on Debian 9
 1566                 $content = file_get_contents($config_dir.'/'.$configfile);
 1567                 $content = str_replace('!SSLv2','',$content);
 1568                 file_put_contents($config_dir.'/'.$configfile,$content);
 1569                 unset($content);
 1570             }
 1571             if(version_compare($dovecot_version,2.3) >= 0) {
 1572                 // Remove deprecated setting(s)
 1573                 removeLine($config_dir.'/'.$configfile, 'ssl_protocols =');
 1574 
 1575                 // Check if we have a dhparams file and if not, create it
 1576                 if(!file_exists('/etc/dovecot/dh.pem')) {
 1577                     swriteln('Creating new DHParams file, this takes several minutes. Do not interrupt the script.');
 1578                     if(file_exists('/var/lib/dovecot/ssl-parameters.dat')) {
 1579                         // convert existing ssl parameters file
 1580                         $command = 'dd if=/var/lib/dovecot/ssl-parameters.dat bs=1 skip=88 | openssl dhparam -inform der > /etc/dovecot/dh.pem';
 1581                         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1582                     } else {
 1583                         /*
 1584                            Create a new dhparams file. We use 2048 bit only as it simply takes too long
 1585                            on smaller systems to generate a 4096 bit dh file (> 30 minutes). If you need
 1586                            a 4096 bit file, create it manually before you install ISPConfig
 1587                         */
 1588                         $command = 'openssl dhparam -out /etc/dovecot/dh.pem 2048';
 1589                         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1590                     }
 1591                 }
 1592                 //remove #2.3+ comment
 1593                 $content = file_get_contents($config_dir.'/'.$configfile);
 1594                 $content = str_replace('#2.3+ ','',$content);
 1595                 file_put_contents($config_dir.'/'.$configfile,$content);
 1596                 unset($content);
 1597 
 1598             } else {
 1599                 // remove settings which are not supported in Dovecot < 2.3
 1600                 removeLine($config_dir.'/'.$configfile, 'ssl_min_protocol =');
 1601                 removeLine($config_dir.'/'.$configfile, 'ssl_dh =');
 1602             }
 1603         }
 1604 
 1605         $dovecot_protocols = 'imap pop3';
 1606 
 1607         //* dovecot-lmtpd
 1608         if($configure_lmtp) {
 1609             $dovecot_protocols .= ' lmtp';
 1610         }
 1611 
 1612         //* dovecot-managesieved
 1613         if(is_file('/usr/lib/dovecot/managesieve') || is_file('/usr/libexec/dovecot/managesieve')) {
 1614             $dovecot_protocols .= ' sieve';
 1615         }
 1616 
 1617         replaceLine($config_dir.'/'.$configfile, 'protocols = imap pop3', "protocols = $dovecot_protocols", 1, 0);
 1618 
 1619         //* dovecot-sql.conf
 1620         $configfile = 'dovecot-sql.conf';
 1621         if(is_file($config_dir.'/'.$configfile)) {
 1622             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 1623         }
 1624         if(is_file($config_dir.'/'.$configfile.'~')) chmod($config_dir.'/'.$configfile.'~', 0400);
 1625         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/debian_dovecot-sql.conf.master', 'tpl/debian_dovecot-sql.conf.master');
 1626         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 1627         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 1628         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 1629         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 1630         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 1631         $content = str_replace('{server_id}', $conf['server_id'], $content);
 1632         # enable iterate_query for dovecot2
 1633         if(version_compare($dovecot_version,2, '>=')) {
 1634             $content = str_replace('# iterate_query', 'iterate_query', $content);
 1635         }
 1636         wf($config_dir.'/'.$configfile, $content);
 1637 
 1638         chmod($config_dir.'/'.$configfile, 0600);
 1639         chown($config_dir.'/'.$configfile, 'root');
 1640         chgrp($config_dir.'/'.$configfile, 'root');
 1641 
 1642         // Dovecot shall ignore mounts in website directory
 1643         if(is_installed('doveadm')) exec("doveadm mount add '/var/www/*' ignore > /dev/null 2> /dev/null");
 1644 
 1645     }
 1646 
 1647     public function configure_amavis() {
 1648         global $conf;
 1649 
 1650         // amavisd user config file
 1651         $configfile = 'amavisd_user_config';
 1652         if(is_file($conf['amavis']['config_dir'].'/conf.d/50-user')) copy($conf['amavis']['config_dir'].'/conf.d/50-user', $conf['amavis']['config_dir'].'/50-user~');
 1653         if(is_file($conf['amavis']['config_dir'].'/conf.d/50-user~')) chmod($conf['amavis']['config_dir'].'/50-user~', 0400);
 1654         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 1655         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 1656         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 1657         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 1658         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 1659         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 1660         wf($conf['amavis']['config_dir'].'/conf.d/50-user', $content);
 1661         chmod($conf['amavis']['config_dir'].'/conf.d/50-user', 0640);
 1662 
 1663         // TODO: chmod and chown on the config file
 1664 
 1665         // test if lmtp if available
 1666         $configure_lmtp = $this->get_postfix_service('lmtp','unix');
 1667 
 1668         // Adding the amavisd commands to the postfix configuration
 1669         // Add array for no error in foreach and maybe future options
 1670         $postconf_commands = array ();
 1671 
 1672         // Check for amavisd -> pure webserver with postfix for mailing without antispam
 1673         if ($conf['amavis']['installed']) {
 1674             $content_filter_service = ($configure_lmtp) ? 'lmtp' : 'amavis';
 1675             $postconf_commands[] = "content_filter = ${content_filter_service}:[127.0.0.1]:10024";
 1676             $postconf_commands[] = 'receive_override_options = no_address_mappings';
 1677         }
 1678 
 1679         // Make a backup copy of the main.cf file
 1680         copy($conf['postfix']['config_dir'].'/main.cf', $conf['postfix']['config_dir'].'/main.cf~2');
 1681 
 1682         // Executing the postconf commands
 1683         foreach($postconf_commands as $cmd) {
 1684             $command = "postconf -e '$cmd'";
 1685             caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1686         }
 1687 
 1688         $config_dir = $conf['postfix']['config_dir'];
 1689 
 1690         // Adding amavis-services to the master.cf file if the service does not already exists
 1691 //      $add_amavis = !$this->get_postfix_service('amavis','unix');
 1692 //      $add_amavis_10025 = !$this->get_postfix_service('127.0.0.1:10025','inet');
 1693 //      $add_amavis_10027 = !$this->get_postfix_service('127.0.0.1:10027','inet');
 1694         //*TODO: check templates against existing postfix-services to make sure we use the template
 1695 
 1696         // Or just remove the old service definitions and add them again?
 1697         $add_amavis = $this->remove_postfix_service('amavis','unix');
 1698         $add_amavis_10025 = $this->remove_postfix_service('127.0.0.1:10025','inet');
 1699         $add_amavis_10027 = $this->remove_postfix_service('127.0.0.1:10027','inet');
 1700 
 1701         if ($add_amavis || $add_amavis_10025 || $add_amavis_10027) {
 1702             //* backup master.cf
 1703             if(is_file($config_dir.'/master.cf')) copy($config_dir.'/master.cf', $config_dir.'/master.cf~');
 1704             // adjust amavis-config
 1705             if($add_amavis) {
 1706                 $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis.master', 'tpl/master_cf_amavis.master');
 1707                 af($config_dir.'/master.cf', $content);
 1708                 unset($content);
 1709             }
 1710             if ($add_amavis_10025) {
 1711                 $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10025.master', 'tpl/master_cf_amavis10025.master');
 1712                 af($config_dir.'/master.cf', $content);
 1713                 unset($content);
 1714             }
 1715             if ($add_amavis_10027) {
 1716                 $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10027.master', 'tpl/master_cf_amavis10027.master');
 1717                 af($config_dir.'/master.cf', $content);
 1718                 unset($content);
 1719             }
 1720         }
 1721 
 1722         // Add the clamav user to the amavis group
 1723         exec('adduser clamav amavis');
 1724         // get shell-group for amavis
 1725         $amavis_group=exec('grep -o "^amavis:\|^vscan:" /etc/group');
 1726         if(!empty($amavis_group)) {
 1727             $amavis_group=rtrim($amavis_group, ":");
 1728         }
 1729         // get shell-user for amavis
 1730         $amavis_user=exec('grep -o "^amavis:\|^vscan:" /etc/passwd');
 1731         if(!empty($amavis_user)) {
 1732             $amavis_user=rtrim($amavis_user, ":");
 1733         }
 1734 
 1735         // Create the director for DKIM-Keys
 1736         if(!is_dir('/var/lib/amavis')) mkdir('/var/lib/amavis', 0750, true);
 1737         if(!empty($amavis_user)) exec('chown '.$amavis_user.' /var/lib/amavis');
 1738         if(!empty($amavis_group)) exec('chgrp '.$amavis_group.' /var/lib/amavis');
 1739         if(!is_dir('/var/lib/amavis/dkim')) mkdir('/var/lib/amavis/dkim', 0750);
 1740         if(!empty($amavis_user)) exec('chown -R '.$amavis_user.' /var/lib/amavis/dkim');
 1741         if(!empty($amavis_group)) exec('chgrp -R '.$amavis_group.' /var/lib/amavis/dkim');
 1742 
 1743     }
 1744 
 1745     public function configure_rspamd() {
 1746         global $conf;
 1747 
 1748         //* These postconf commands will be executed on installation and update
 1749         $server_ini_rec = $this->db->queryOneRecord("SELECT config FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . '.server', $conf['server_id']);
 1750         $server_ini_array = ini_to_array(stripslashes($server_ini_rec['config']));
 1751         unset($server_ini_rec);
 1752 
 1753         $mail_config = $server_ini_array['mail'];
 1754         if($mail_config['content_filter'] === 'rspamd') {
 1755             exec("postconf -X 'receive_override_options'");
 1756             exec("postconf -X 'content_filter'");
 1757 
 1758             exec("postconf -e 'smtpd_milters = inet:localhost:11332'");
 1759             exec("postconf -e 'non_smtpd_milters = inet:localhost:11332'");
 1760             exec("postconf -e 'milter_protocol = 6'");
 1761             exec("postconf -e 'milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}'");
 1762             exec("postconf -e 'milter_default_action = accept'");
 1763 
 1764             if(! isset($mail_config['reject_sender_login_mismatch'])) {
 1765                 $mail_config['reject_sender_login_mismatch'] = 'n';
 1766             }
 1767             $options = preg_split("/,\s*/", exec("postconf -h smtpd_sender_restrictions"));
 1768             $new_options = array();
 1769             foreach ($options as $key => $value) {
 1770                 $value = trim($value);
 1771                 if ($value == '') continue;
 1772                 if (preg_match('/tag_as_(originating|foreign)\.re/', $value)) {
 1773                     continue;
 1774                 }
 1775                 if (preg_match('/reject_(authenticated_)?sender_login_mismatch/', $value)) {
 1776                     continue;
 1777                 }
 1778                 $new_options[] = $value;
 1779             }
 1780             if ($mail_config['reject_sender_login_mismatch'] == 'y') {
 1781                 // insert before permit_mynetworks
 1782                 for ($i = 0; isset($new_options[$i]); $i++) {
 1783                     if ($new_options[$i] == 'permit_mynetworks') {
 1784                         array_splice($new_options, $i, 0, array('reject_authenticated_sender_login_mismatch'));
 1785                         break;
 1786                     }
 1787                 }
 1788 
 1789                 // insert before permit_sasl_authenticated
 1790                 for ($i = 0; isset($new_options[$i]); $i++) {
 1791                     if ($new_options[$i] == 'permit_sasl_authenticated') {
 1792                         array_splice($new_options, $i, 0, array('reject_sender_login_mismatch'));
 1793                         break;
 1794                     }
 1795                 }
 1796             }
 1797             exec("postconf -e 'smtpd_sender_restrictions = ".implode(", ", $new_options)."'");
 1798 
 1799             $options = preg_split("/,\s*/", exec("postconf -h smtpd_recipient_restrictions"));
 1800             $new_options = array();
 1801             foreach ($options as $value) {
 1802                 $value = trim($value);
 1803                 if ($value == '') continue;
 1804                 if (preg_match('/check_policy_service\s+inet:127.0.0.1:10023/', $value)) {
 1805                     continue;
 1806                 }
 1807                 $new_options[] = $value;
 1808             }
 1809             exec("postconf -e 'smtpd_recipient_restrictions = ".implode(", ", $new_options)."'");
 1810 
 1811         }
 1812 
 1813         if(is_user('_rspamd') && is_group('amavis')) {
 1814             exec("usermod -a -G amavis _rspamd");
 1815         } elseif(is_user('rspamd') && is_group('amavis')) {
 1816             exec("usermod -a -G amavis rspamd");
 1817         }
 1818 
 1819         if(!is_dir('/etc/rspamd/local.d/')){
 1820             mkdir('/etc/rspamd/local.d/', 0755, true);
 1821             chmod('/etc/rspamd/local.d/', 0755);
 1822         }
 1823 
 1824         if(!is_dir('/etc/rspamd/local.d/maps.d/')){
 1825             mkdir('/etc/rspamd/local.d/maps.d/', 0755, true);
 1826             chmod('/etc/rspamd/local.d/maps.d/', 0755);
 1827         }
 1828 
 1829         if(!is_dir('/etc/rspamd/override.d/')){
 1830             mkdir('/etc/rspamd/override.d/', 0755, true);
 1831             chmod('/etc/rspamd/override.d/', 0755);
 1832         }
 1833 
 1834         if ( substr($mail_config['dkim_path'], strlen($mail_config['dkim_path'])-1) == '/' ) {
 1835             $mail_config['dkim_path'] = substr($mail_config['dkim_path'], 0, strlen($mail_config['dkim_path'])-1);
 1836         }
 1837         $dkim_domains = $this->db->queryAllRecords('SELECT `dkim_selector`, `domain` FROM ?? WHERE `dkim` = ? ORDER BY `domain` ASC', $conf['mysql']['database'] . '.mail_domain', 'y');
 1838         # should move maps to local.d/maps.d/ ?
 1839         $fpp = fopen('/etc/rspamd/local.d/dkim_domains.map', 'w');
 1840         $fps = fopen('/etc/rspamd/local.d/dkim_selectors.map', 'w');
 1841         foreach($dkim_domains as $dkim_domain) {
 1842             fwrite($fpp, $dkim_domain['domain'] . ' ' . $mail_config['dkim_path'] . '/' . $dkim_domain['domain'] . '.private' . "\n");
 1843             fwrite($fps, $dkim_domain['domain'] . ' ' . $dkim_domain['dkim_selector'] . "\n");
 1844         }
 1845         fclose($fpp);
 1846         fclose($fps);
 1847         unset($dkim_domains);
 1848 
 1849         # look up values for use in template tags
 1850         $local_addrs = array();
 1851         $ips = $this->db->queryAllRecords('SELECT `ip_address`, `ip_type` FROM ?? WHERE `server_id` = ?', $conf['mysql']['database'].'.server_ip', $conf['server_id']);
 1852         if(is_array($ips) && !empty($ips)){
 1853             foreach($ips as $ip){
 1854                 $local_addrs[] = array(
 1855                     'ip' => $ip['ip_address'],
 1856                     'quoted_ip' => "\"".$ip['ip_address']."\",\n"
 1857                 );
 1858             }
 1859         }
 1860 
 1861         # local.d templates with template tags
 1862         # note: ensure these template files are in server/conf/ and symlinked in install/tpl/
 1863         $local_d = array(
 1864             'dkim_signing.conf',
 1865             'options.inc',
 1866             'redis.conf',
 1867             'classifier-bayes.conf',
 1868         );
 1869         foreach ($local_d as $f) {
 1870             $tpl = new tpl();
 1871             if (file_exists($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master")) {
 1872                 $tpl->newTemplate($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master");
 1873             } else {
 1874                 $tpl->newTemplate("rspamd_${f}.master");
 1875             }
 1876 
 1877             $tpl->setVar('dkim_path', $mail_config['dkim_path']);
 1878             $tpl->setVar('rspamd_redis_servers', $mail_config['rspamd_redis_servers']);
 1879             $tpl->setVar('rspamd_redis_password', $mail_config['rspamd_redis_password']);
 1880             $tpl->setVar('rspamd_redis_bayes_servers', $mail_config['rspamd_redis_bayes_servers']);
 1881             $tpl->setVar('rspamd_redis_bayes_password', $mail_config['rspamd_redis_bayes_password']);
 1882             if(count($local_addrs) > 0) {
 1883                 $tpl->setLoop('local_addrs', $local_addrs);
 1884             }
 1885 
 1886             wf("/etc/rspamd/local.d/${f}", $tpl->grab());
 1887         }
 1888 
 1889 
 1890         # local.d templates without template tags
 1891         $local_d = array(
 1892             'groups.conf',
 1893             'antivirus.conf',
 1894             'mx_check.conf',
 1895             'milter_headers.conf',
 1896             'neural.conf',
 1897             'neural_group.conf',
 1898             'users.conf',
 1899             'groups.conf',
 1900         );
 1901         foreach ($local_d as $f) {
 1902             if(file_exists($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master")) {
 1903                 exec('cp '.$conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master /etc/rspamd/local.d/${f}");
 1904             } else {
 1905                 exec("cp tpl/rspamd_${f}.master /etc/rspamd/local.d/${f}");
 1906             }
 1907         }
 1908 
 1909         # override.d templates without template tags
 1910         $override_d = array(
 1911             'rbl_group.conf',
 1912             'surbl_group.conf',
 1913         );
 1914         foreach ($override_d as $f) {
 1915             if(file_exists($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master")) {
 1916                 exec('cp '.$conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master /etc/rspamd/override.d/${f}");
 1917             } else {
 1918                 exec("cp tpl/rspamd_${f}.master /etc/rspamd/override.d/${f}");
 1919             }
 1920         }
 1921 
 1922         # local.d/maps.d templates without template tags
 1923         $maps_d = array(
 1924             'dkim_whitelist.inc.ispc',
 1925             'dmarc_whitelist.inc.ispc',
 1926             'spf_dkim_whitelist.inc.ispc',
 1927             'spf_whitelist.inc.ispc',
 1928         );
 1929         foreach ($maps_d as $f) {
 1930             if(file_exists($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master")) {
 1931                 exec('cp '.$conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_${f}.master /etc/rspamd/local.d/maps.d/${f}");
 1932             } else {
 1933                 exec("cp tpl/rspamd_${f}.master /etc/rspamd/local.d/maps.d/${f}");
 1934             }
 1935         }
 1936 
 1937         # rename rspamd templates we no longer use
 1938         if(file_exists("/etc/rspamd/local.d/greylist.conf")) {
 1939             rename("/etc/rspamd/local.d/greylist.conf", "/etc/rspamd/local.d/greylist.old");
 1940         }
 1941 
 1942         exec('chmod a+r /etc/rspamd/local.d/* /etc/rspamd/local.d/maps.d/* /etc/rspamd/override.d/*');
 1943         # protect passwords in these files
 1944         exec('chgrp _rspamd /etc/rspamd/local.d/redis.conf /etc/rspamd/local.d/classifier-bayes.conf /etc/rspamd/local.d/worker-controller.inc');
 1945         exec('chmod 640 /etc/rspamd/local.d/redis.conf /etc/rspamd/local.d/classifier-bayes.conf /etc/rspamd/local.d/worker-controller.inc');
 1946 
 1947         # unneccesary, since this was done above?
 1948         $command = 'usermod -a -G amavis _rspamd';
 1949         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 1950 
 1951         if(strpos(rf('/etc/rspamd/rspamd.conf'), '.include "$LOCAL_CONFDIR/local.d/users.conf"') === false){
 1952             af('/etc/rspamd/rspamd.conf', '.include "$LOCAL_CONFDIR/local.d/users.conf"');
 1953         }
 1954 
 1955         if(!isset($mail_config['rspamd_password']) || !$mail_config['rspamd_password']) {
 1956             $mail_config['rspamd_password'] = str_shuffle(bin2hex(openssl_random_pseudo_bytes(12)));
 1957 
 1958             $server_ini_array['mail']['rspamd_password'] = $mail_config['rspamd_password'];
 1959         }
 1960 
 1961         $server_ini_array['mail']['rspamd_available'] = 'y';
 1962         $server_ini_string = array_to_ini($server_ini_array);
 1963         if($this->dbmaster != $this->db) {
 1964             $this->dbmaster->query('UPDATE `server` SET `config` = ? WHERE `server_id` = ?', $server_ini_string, $conf['server_id']);
 1965         }
 1966         $this->db->query('UPDATE `server` SET `config` = ? WHERE `server_id` = ?', $server_ini_string, $conf['server_id']);
 1967         unset($server_ini_array);
 1968         unset($server_ini_string);
 1969 
 1970         $tpl = new tpl();
 1971         if (file_exists($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_worker-controller.inc.master")) {
 1972             $tpl->newTemplate($conf['ispconfig_install_dir']."/server/conf-custom/install/rspamd_worker-controller.inc.master");
 1973         } else {
 1974             $tpl->newTemplate("rspamd_worker-controller.inc.master");
 1975         }
 1976         $rspamd_password = $mail_config['rspamd_password'];
 1977         $crypted_password = trim(exec('rspamadm pw -p ' . escapeshellarg($rspamd_password)));
 1978         if($crypted_password) {
 1979             $rspamd_password = $crypted_password;
 1980         }
 1981         $tpl->setVar('rspamd_password', $rspamd_password);
 1982         wf('/etc/rspamd/local.d/worker-controller.inc', $tpl->grab());
 1983         chmod('/etc/rspamd/local.d/worker-controller.inc', 0644);
 1984     }
 1985 
 1986     public function configure_spamassassin() {
 1987         global $conf;
 1988 
 1989         //* Enable spamasasssin on debian and ubuntu
 1990         $configfile = '/etc/default/spamassassin';
 1991         if(is_file($configfile)) {
 1992             copy($configfile, $configfile.'~');
 1993         }
 1994         $content = rf($configfile);
 1995         $content = str_replace('ENABLED=0', 'ENABLED=1', $content);
 1996         wf($configfile, $content);
 1997     }
 1998 
 1999     public function configure_getmail() {
 2000         global $conf;
 2001 
 2002         $config_dir = $conf['getmail']['config_dir'];
 2003 
 2004         if(!@is_dir($config_dir)) mkdir(escapeshellcmd($config_dir), 0700, true);
 2005 
 2006         $command = 'useradd -d '.$config_dir.' getmail';
 2007         if(!is_user('getmail')) caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2008 
 2009         $command = "chown -R getmail $config_dir";
 2010         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2011 
 2012         $command = "chmod -R 700 $config_dir";
 2013         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2014     }
 2015 
 2016 
 2017     public function configure_pureftpd() {
 2018         global $conf;
 2019 
 2020         $config_dir = $conf['pureftpd']['config_dir'];
 2021 
 2022         //* configure pure-ftpd for MySQL authentication against the ispconfig database
 2023         $configfile = 'db/mysql.conf';
 2024         if(is_file($config_dir.'/'.$configfile)) {
 2025             copy($config_dir.'/'.$configfile, $config_dir.'/'.$configfile.'~');
 2026         }
 2027         if(is_file($config_dir.'/'.$configfile.'~')) {
 2028             chmod($config_dir.'/'.$configfile.'~', 0400);
 2029         }
 2030         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/pureftpd_mysql.conf.master', 'tpl/pureftpd_mysql.conf.master');
 2031         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2032         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2033         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 2034         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 2035         $content = str_replace('{server_id}', $conf['server_id'], $content);
 2036         wf($config_dir.'/'.$configfile, $content);
 2037         chmod($config_dir.'/'.$configfile, 0600);
 2038         chown($config_dir.'/'.$configfile, 'root');
 2039         chgrp($config_dir.'/'.$configfile, 'root');
 2040         // **enable chrooting
 2041         //exec('mkdir -p '.$config_dir.'/conf/ChrootEveryone');
 2042         exec('echo "yes" > '.$config_dir.'/conf/ChrootEveryone');
 2043         exec('echo "yes" > '.$config_dir.'/conf/BrokenClientsCompatibility');
 2044         exec('echo "yes" > '.$config_dir.'/conf/DisplayDotFiles');
 2045 
 2046         if(is_file('/etc/default/pure-ftpd-common')) {
 2047             replaceLine('/etc/default/pure-ftpd-common', 'STANDALONE_OR_INETD=inetd', 'STANDALONE_OR_INETD=standalone', 1, 0);
 2048             replaceLine('/etc/default/pure-ftpd-common', 'VIRTUALCHROOT=false', 'VIRTUALCHROOT=true', 1, 0);
 2049         }
 2050 
 2051         if(is_file('/etc/inetd.conf')) {
 2052             replaceLine('/etc/inetd.conf', '/usr/sbin/pure-ftpd-wrapper', '#ftp     stream  tcp     nowait  root    /usr/sbin/tcpd /usr/sbin/pure-ftpd-wrapper', 0, 0);
 2053             exec($this->getinitcommand('openbsd-inetd', 'restart'));
 2054             //if(is_file($conf['init_scripts'].'/'.'openbsd-inetd')) exec($conf['init_scripts'].'/'.'openbsd-inetd restart');
 2055         }
 2056 
 2057         if(!is_file('/etc/pure-ftpd/conf/DontResolve')) exec('echo "yes" > /etc/pure-ftpd/conf/DontResolve');
 2058     }
 2059 
 2060     public function configure_mydns() {
 2061         global $conf;
 2062 
 2063         // configure pam for SMTP authentication agains the ispconfig database
 2064         $configfile = 'mydns.conf';
 2065         if(is_file($conf['mydns']['config_dir'].'/'.$configfile)) copy($conf['mydns']['config_dir'].'/'.$configfile, $conf['mydns']['config_dir'].'/'.$configfile.'~');
 2066         if(is_file($conf['mydns']['config_dir'].'/'.$configfile.'~')) chmod($conf['mydns']['config_dir'].'/'.$configfile.'~', 0400);
 2067         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 2068         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2069         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2070         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 2071         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 2072         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 2073         $content = str_replace('{server_id}', $conf['server_id'], $content);
 2074         wf($conf['mydns']['config_dir'].'/'.$configfile, $content);
 2075         chmod($conf['mydns']['config_dir'].'/'.$configfile, 0600);
 2076         chown($conf['mydns']['config_dir'].'/'.$configfile, 'root');
 2077         chgrp($conf['mydns']['config_dir'].'/'.$configfile, 'root');
 2078 
 2079     }
 2080 
 2081     public function configure_powerdns() {
 2082         global $conf;
 2083 
 2084         //* Create the database
 2085         if(!$this->db->query('CREATE DATABASE IF NOT EXISTS ?? DEFAULT CHARACTER SET ?', $conf['powerdns']['database'], $conf['mysql']['charset'])) {
 2086             $this->error('Unable to create MySQL database: '.$conf['powerdns']['database'].'.');
 2087         }
 2088 
 2089         //* Create the ISPConfig database user in the local database
 2090         $query = "GRANT ALL ON ??.* TO ?@?";
 2091         if(!$this->db->query($query, $conf['powerdns']['database'], $conf['mysql']['ispconfig_user'], 'localhost')) {
 2092             $this->error('Unable to create user for powerdns database Error: '.$this->db->errorMessage);
 2093         }
 2094 
 2095         //* load the powerdns databse dump
 2096         if($conf['mysql']['admin_password'] == '') {
 2097             caselog("mysql --default-character-set=".$conf['mysql']['charset']." -h '".$conf['mysql']['host']."' -u '".$conf['mysql']['admin_user']."' --force '".$conf['powerdns']['database']."' < '".ISPC_INSTALL_ROOT."/install/sql/powerdns.sql' &> /dev/null",
 2098                 __FILE__, __LINE__, 'read in ispconfig3.sql', 'could not read in powerdns.sql');
 2099         } else {
 2100             caselog("mysql --default-character-set=".$conf['mysql']['charset']." -h '".$conf['mysql']['host']."' -u '".$conf['mysql']['admin_user']."' -p'".$conf['mysql']['admin_password']."' --force '".$conf['powerdns']['database']."' < '".ISPC_INSTALL_ROOT."/install/sql/powerdns.sql' &> /dev/null",
 2101                 __FILE__, __LINE__, 'read in ispconfig3.sql', 'could not read in powerdns.sql');
 2102         }
 2103 
 2104         //* Create the powerdns config file
 2105         $configfile = 'pdns.local';
 2106         if(is_file($conf['powerdns']['config_dir'].'/'.$configfile)) copy($conf['powerdns']['config_dir'].'/'.$configfile, $conf['powerdns']['config_dir'].'/'.$configfile.'~');
 2107         if(is_file($conf['powerdns']['config_dir'].'/'.$configfile.'~')) chmod($conf['powerdns']['config_dir'].'/'.$configfile.'~', 0400);
 2108         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 2109         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2110         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2111         $content = str_replace('{powerdns_database}', $conf['powerdns']['database'], $content);
 2112         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 2113         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 2114         wf($conf['powerdns']['config_dir'].'/'.$configfile, $content);
 2115         chmod($conf['powerdns']['config_dir'].'/'.$configfile, 0600);
 2116         chown($conf['powerdns']['config_dir'].'/'.$configfile, 'root');
 2117         chgrp($conf['powerdns']['config_dir'].'/'.$configfile, 'root');
 2118 
 2119 
 2120     }
 2121 
 2122     //** writes bind configuration files
 2123     public function process_bind_file($configfile, $target='/', $absolute=false) {
 2124         global $conf;
 2125 
 2126         if ($absolute) $full_file_name = $target.$configfile;
 2127         else $full_file_name = $conf['ispconfig_install_dir'].$target.$configfile;
 2128 
 2129         //* Backup exiting file
 2130         if(is_file($full_file_name)) {
 2131             copy($full_file_name, $config_dir.$configfile.'~');
 2132         }
 2133         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 2134         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2135         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2136         $content = str_replace('{mysql_server_ispconfig_database}', $conf['mysql']['database'], $content);
 2137         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 2138         $content = str_replace('{ispconfig_install_dir}', $conf['ispconfig_install_dir'], $content);
 2139         $content = str_replace('{dnssec_conffile}', $conf['ispconfig_install_dir'].'/server/scripts/dnssec-config.sh', $content);
 2140         wf($full_file_name, $content);
 2141     }
 2142 
 2143     public function configure_bind() {
 2144         global $conf;
 2145 
 2146         //* Check if the zonefile directory has a slash at the end
 2147         $content=$conf['bind']['bind_zonefiles_dir'];
 2148         if(substr($content, -1, 1) != '/') {
 2149             $content .= '/';
 2150         }
 2151 
 2152         //* Create the slave subdirectory
 2153         $content .= 'slave';
 2154         if(!@is_dir($content)) mkdir($content, 02770, true);
 2155 
 2156         //* Chown the slave subdirectory to $conf['bind']['bind_user']
 2157         chown($content, $conf['bind']['bind_user']);
 2158         chgrp($content, $conf['bind']['bind_group']);
 2159         chmod($content, 02770);
 2160 
 2161         //* Install scripts for dnssec implementation
 2162         $this->process_bind_file('named.conf.options', '/etc/bind/', true); //TODO replace hardcoded path
 2163     }
 2164 
 2165 
 2166     public function configure_xmpp($options = '') {
 2167         global $conf;
 2168 
 2169         if($conf['xmpp']['installed'] == false) return;
 2170         //* Create the logging directory for xmpp server
 2171         if(!@is_dir('/var/log/metronome')) mkdir('/var/log/metronome', 0755, true);
 2172         chown('/var/log/metronome', 'metronome');
 2173         if(!@is_dir('/var/run/metronome')) mkdir('/var/run/metronome', 0755, true);
 2174         chown('/var/run/metronome', 'metronome');
 2175         if(!@is_dir('/var/lib/metronome')) mkdir('/var/lib/metronome', 0755, true);
 2176         chown('/var/lib/metronome', 'metronome');
 2177         if(!@is_dir('/etc/metronome/hosts')) mkdir('/etc/metronome/hosts', 0755, true);
 2178         if(!@is_dir('/etc/metronome/status')) mkdir('/etc/metronome/status', 0755, true);
 2179         unlink('/etc/metronome/metronome.cfg.lua');
 2180 
 2181         $row = $this->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = ?", $conf["server_id"]);
 2182         $server_name = $row["server_name"];
 2183 
 2184         $tpl = new tpl('metronome_conf_main.master');
 2185         wf('/etc/metronome/metronome.cfg.lua', $tpl->grab());
 2186         unset($tpl);
 2187 
 2188         $tpl = new tpl('metronome_conf_global.master');
 2189         $tpl->setVar('xmpp_admins','');
 2190         wf('/etc/metronome/global.cfg.lua', $tpl->grab());
 2191         unset($tpl);
 2192 
 2193         // Copy isp libs
 2194         if(!@is_dir('/usr/lib/metronome/isp-modules')) mkdir('/usr/lib/metronome/isp-modules', 0755, true);
 2195         caselog('cp -rf apps/metronome_libs/* /usr/lib/metronome/isp-modules/', __FILE__, __LINE__);
 2196         caselog('chmod 755 /usr/lib/metronome/isp-modules/mod_auth_external/authenticate_isp.sh', __FILE__, __LINE__);
 2197         // Process db config
 2198         $full_file_name = '/usr/lib/metronome/isp-modules/mod_auth_external/db_conf.inc.php';
 2199         $content = rf($full_file_name);
 2200         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2201         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2202         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 2203         $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 2204         $content = str_replace('{server_id}', $conf['server_id'], $content);
 2205         wf($full_file_name, $content);
 2206 
 2207         if(!stristr($options, 'dont-create-certs')){
 2208             // Create SSL Certificate for localhost
 2209             // Ensure no line is left blank
 2210             echo "writing new private key to 'localhost.key'\n-----\n";
 2211             $ssl_country = $this->free_query('Country Name (2 letter code)', 'AU','ssl_cert_country');
 2212             $ssl_locality = $this->free_query('Locality Name (eg, city)', 'City Name','ssl_cert_locality');
 2213             $ssl_organisation = $this->free_query('Organization Name (eg, company)', 'Internet Widgits Pty Ltd','ssl_cert_organisation');
 2214             $ssl_organisation_unit = $this->free_query('Organizational Unit Name (eg, section)', 'Infrastructure','ssl_cert_organisation_unit');
 2215             $ssl_domain = $this->free_query('Common Name (e.g. server FQDN or YOUR name)', $conf['hostname'],'ssl_cert_common_name');
 2216             $ssl_email = $this->free_query('Email Address', 'hostmaster@'.$conf['hostname'],'ssl_cert_email');
 2217 
 2218             $tpl = new tpl('metronome_conf_ssl.master');
 2219             $tpl->setVar('ssl_country',$ssl_country);
 2220             $tpl->setVar('ssl_locality',$ssl_locality);
 2221             $tpl->setVar('ssl_organisation',$ssl_organisation);
 2222             $tpl->setVar('ssl_organisation_unit',$ssl_organisation_unit);
 2223             $tpl->setVar('domain',$ssl_domain);
 2224             $tpl->setVar('ssl_email',$ssl_email);
 2225             wf('/etc/metronome/certs/localhost.cnf', $tpl->grab());
 2226             unset($tpl);
 2227             // Generate new key, csr and cert
 2228             exec("(cd /etc/metronome/certs && make localhost.key)");
 2229             exec("(cd /etc/metronome/certs && make localhost.csr)");
 2230             exec("(cd /etc/metronome/certs && make localhost.cert)");
 2231             exec('chmod 0400 /etc/metronome/certs/localhost.key');
 2232             exec('chown metronome /etc/metronome/certs/localhost.key');
 2233 
 2234             echo "IMPORTANT:\n";
 2235             echo "Localhost Key, Csr and a self-signed Cert have been saved to /etc/metronome/certs\n";
 2236             echo "In order to work with all clients, the server must have a trusted certificate, so use the Csr\n";
 2237             echo "to get a trusted certificate from your CA or replace Key and Cert with already signed files for\n";
 2238             echo "your domain. Clients like Pidgin dont allow to use untrusted self-signed certificates.\n";
 2239             echo "\n";
 2240 
 2241         }else{
 2242             /*
 2243             echo "-----\n";
 2244             echo "Metronome XMPP SSL server certificate is not renewed. Run the following command manual as root to recreate it:\n";
 2245             echo "# (cd /etc/metronome/certs && make localhost.key && make localhost.csr && make localhost.cert && chmod 0400 localhost.key && chown metronome localhost.key)\n";
 2246             echo "-----\n";
 2247             */
 2248         }
 2249 
 2250         // Copy init script
 2251         caselog('cp -f apps/metronome-init /etc/init.d/metronome', __FILE__, __LINE__);
 2252         caselog('chmod u+x /etc/init.d/metronome', __FILE__, __LINE__);
 2253         caselog('update-rc.d metronome defaults', __FILE__, __LINE__);
 2254 
 2255         exec($this->getinitcommand($conf['xmpp']['init_script'], 'restart'));
 2256     }
 2257 
 2258 
 2259     public function configure_apache() {
 2260         global $conf;
 2261 
 2262         if($conf['apache']['installed'] == false) return;
 2263         //* Create the logging directory for the vhost logfiles
 2264         if(!@is_dir($conf['ispconfig_log_dir'].'/httpd')) mkdir($conf['ispconfig_log_dir'].'/httpd', 0755, true);
 2265 
 2266         if(is_file('/etc/suphp/suphp.conf')) {
 2267             replaceLine('/etc/suphp/suphp.conf', 'php="php:/usr/bin', 'x-httpd-suphp="php:/usr/bin/php-cgi"', 0);
 2268             //replaceLine('/etc/suphp/suphp.conf','docroot=','docroot=/var/clients',0);
 2269             replaceLine('/etc/suphp/suphp.conf', 'umask=00', 'umask=0022', 0);
 2270         }
 2271 
 2272         if(is_file('/etc/apache2/sites-enabled/000-default')) {
 2273             replaceLine('/etc/apache2/sites-available/000-default', 'NameVirtualHost *', 'NameVirtualHost *:80', 1, 0);
 2274             replaceLine('/etc/apache2/sites-available/000-default', '<VirtualHost *>', '<VirtualHost *:80>', 1, 0);
 2275         }
 2276 
 2277         if(is_file('/etc/apache2/ports.conf')) {
 2278             // add a line "Listen 443" to ports conf if line does not exist
 2279             replaceLine('/etc/apache2/ports.conf', 'Listen 443', 'Listen 443', 1);
 2280 
 2281             // Comment out the namevirtualhost lines, as they were added by ispconfig in ispconfig.conf file again
 2282             replaceLine('/etc/apache2/ports.conf', 'NameVirtualHost *:80', '# NameVirtualHost *:80', 1);
 2283             replaceLine('/etc/apache2/ports.conf', 'NameVirtualHost *:443', '# NameVirtualHost *:443', 1);
 2284         }
 2285 
 2286         if(is_file('/etc/apache2/mods-available/fcgid.conf')) {
 2287             // add or modify the parameters for fcgid.conf
 2288             replaceLine('/etc/apache2/mods-available/fcgid.conf','MaxRequestLen','MaxRequestLen 15728640',1);
 2289         }
 2290 
 2291         if(is_file('/etc/apache2/apache.conf')) {
 2292             if(hasLine('/etc/apache2/apache.conf', 'Include sites-enabled/', 1) == false) {
 2293                 if(hasLine('/etc/apache2/apache.conf', 'IncludeOptional sites-enabled/*.conf', 1) == false && hasLine('/etc/apache2/apache.conf', 'IncludeOptional sites-enabled/', 1) == false) {
 2294                     replaceLine('/etc/apache2/apache.conf', 'Include sites-enabled/', 'Include sites-enabled/', 1, 1);
 2295                 } elseif(hasLine('/etc/apache2/apache.conf', 'IncludeOptional sites-enabled/*.vhost', 1) == false) {
 2296                     replaceLine('/etc/apache2/apache.conf', 'IncludeOptional sites-enabled/*.vhost', 'IncludeOptional sites-enabled/', 1, 1);
 2297                 }
 2298             }
 2299         }
 2300 
 2301         if(is_file('/etc/apache2/apache2.conf')) {
 2302             if(hasLine('/etc/apache2/apache2.conf', 'Include sites-enabled/', 1) == false && hasLine('/etc/apache2/apache2.conf', 'IncludeOptional sites-enabled/', 1) == false) {
 2303                 if(hasLine('/etc/apache2/apache2.conf', 'Include sites-enabled/*.conf', 1) == true) {
 2304                     replaceLine('/etc/apache2/apache2.conf', 'Include sites-enabled/*.conf', 'Include sites-enabled/', 1, 1);
 2305                 } elseif(hasLine('/etc/apache2/apache2.conf', 'IncludeOptional sites-enabled/*.conf', 1) == true) {
 2306                     replaceLine('/etc/apache2/apache2.conf', 'IncludeOptional sites-enabled/*.conf', 'IncludeOptional sites-enabled/', 1, 1);
 2307                 }
 2308             }
 2309         }
 2310 
 2311         //* Copy the ISPConfig configuration include
 2312         $vhost_conf_dir = $conf['apache']['vhost_conf_dir'];
 2313         $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir'];
 2314 
 2315         $tpl = new tpl('apache_ispconfig.conf.master');
 2316         $tpl->setVar('apache_version',getapacheversion());
 2317 
 2318         if($this->is_update == true) {
 2319             $tpl->setVar('logging',get_logging_state());
 2320         } else {
 2321             $tpl->setVar('logging','yes');
 2322         }
 2323 
 2324         $records = $this->db->queryAllRecords("SELECT * FROM ?? WHERE server_id = ? AND virtualhost = 'y'", $conf['mysql']['master_database'] . '.server_ip', $conf['server_id']);
 2325         $ip_addresses = array();
 2326 
 2327         if(is_array($records) && count($records) > 0) {
 2328             foreach($records as $rec) {
 2329                 if($rec['ip_type'] == 'IPv6') {
 2330                     $ip_address = '['.$rec['ip_address'].']';
 2331                 } else {
 2332                     $ip_address = $rec['ip_address'];
 2333                 }
 2334                 $ports = explode(',', $rec['virtualhost_port']);
 2335                 if(is_array($ports)) {
 2336                     foreach($ports as $port) {
 2337                         $port = intval($port);
 2338                         if($port > 0 && $port < 65536 && $ip_address != '') {
 2339                             $ip_addresses[] = array('ip_address' => $ip_address, 'port' => $port);
 2340                         }
 2341                     }
 2342                 }
 2343             }
 2344         }
 2345 
 2346         if(count($ip_addresses) > 0) $tpl->setLoop('ip_adresses',$ip_addresses);
 2347 
 2348         wf($vhost_conf_dir.'/ispconfig.conf', $tpl->grab());
 2349         unset($tpl);
 2350 
 2351         if(!@is_link($vhost_conf_enabled_dir.'/000-ispconfig.conf')) {
 2352             symlink($vhost_conf_dir.'/ispconfig.conf', $vhost_conf_enabled_dir.'/000-ispconfig.conf');
 2353         }
 2354 
 2355         //* make sure that webalizer finds its config file when it is directly in /etc
 2356         if(@is_file('/etc/webalizer.conf') && !@is_dir('/etc/webalizer')) {
 2357             mkdir('/etc/webalizer');
 2358             symlink('/etc/webalizer.conf', '/etc/webalizer/webalizer.conf');
 2359         }
 2360 
 2361         if(is_file('/etc/webalizer/webalizer.conf')) {
 2362             // Change webalizer mode to incremental
 2363             replaceLine('/etc/webalizer/webalizer.conf', '#IncrementalName', 'IncrementalName webalizer.current', 0, 0);
 2364             replaceLine('/etc/webalizer/webalizer.conf', '#Incremental', 'Incremental     yes', 0, 0);
 2365             replaceLine('/etc/webalizer/webalizer.conf', '#HistoryName', 'HistoryName     webalizer.hist', 0, 0);
 2366         }
 2367 
 2368         // Check the awsatst script
 2369         if(!is_dir('/usr/share/awstats/tools')) exec('mkdir -p /usr/share/awstats/tools');
 2370         if(!file_exists('/usr/share/awstats/tools/awstats_buildstaticpages.pl') && file_exists('/usr/share/doc/awstats/examples/awstats_buildstaticpages.pl')) symlink('/usr/share/doc/awstats/examples/awstats_buildstaticpages.pl', '/usr/share/awstats/tools/awstats_buildstaticpages.pl');
 2371         if(file_exists('/etc/awstats/awstats.conf.local')) replaceLine('/etc/awstats/awstats.conf.local', 'LogFormat=4', 'LogFormat=1', 0, 1);
 2372 
 2373         //* add a sshusers group
 2374         $command = 'groupadd sshusers';
 2375         if(!is_group('sshusers')) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2376 
 2377     }
 2378 
 2379     public function configure_nginx(){
 2380         global $conf;
 2381 
 2382         if($conf['nginx']['installed'] == false) return;
 2383         //* Create the logging directory for the vhost logfiles
 2384         if(!@is_dir($conf['ispconfig_log_dir'].'/httpd')) mkdir($conf['ispconfig_log_dir'].'/httpd', 0755, true);
 2385 
 2386         //* make sure that webalizer finds its config file when it is directly in /etc
 2387         if(@is_file('/etc/webalizer.conf') && !@is_dir('/etc/webalizer')) {
 2388             mkdir('/etc/webalizer');
 2389             symlink('/etc/webalizer.conf', '/etc/webalizer/webalizer.conf');
 2390         }
 2391 
 2392         if(is_file('/etc/webalizer/webalizer.conf')) {
 2393             // Change webalizer mode to incremental
 2394             replaceLine('/etc/webalizer/webalizer.conf', '#IncrementalName', 'IncrementalName webalizer.current', 0, 0);
 2395             replaceLine('/etc/webalizer/webalizer.conf', '#Incremental', 'Incremental     yes', 0, 0);
 2396             replaceLine('/etc/webalizer/webalizer.conf', '#HistoryName', 'HistoryName     webalizer.hist', 0, 0);
 2397         }
 2398 
 2399         // Check the awsatst script
 2400         if(!is_dir('/usr/share/awstats/tools')) exec('mkdir -p /usr/share/awstats/tools');
 2401         if(!file_exists('/usr/share/awstats/tools/awstats_buildstaticpages.pl') && file_exists('/usr/share/doc/awstats/examples/awstats_buildstaticpages.pl')) symlink('/usr/share/doc/awstats/examples/awstats_buildstaticpages.pl', '/usr/share/awstats/tools/awstats_buildstaticpages.pl');
 2402         if(file_exists('/etc/awstats/awstats.conf.local')) replaceLine('/etc/awstats/awstats.conf.local', 'LogFormat=4', 'LogFormat=1', 0, 1);
 2403 
 2404         //* add a sshusers group
 2405         $command = 'groupadd sshusers';
 2406         if(!is_group('sshusers')) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2407 
 2408         // add anonymized log option to nginxx.conf file
 2409         $nginx_conf_file = $conf['nginx']['config_dir'].'/nginx.conf';
 2410         if(is_file($nginx_conf_file)) {
 2411             $tmp = file_get_contents($nginx_conf_file);
 2412             if(!stristr($tmp, 'log_format anonymized')) {
 2413                 copy($nginx_conf_file,$nginx_conf_file.'~');
 2414                 replaceLine($nginx_conf_file, 'http {', "http {\n\n".file_get_contents('tpl/nginx_anonlog.master'), 0, 0);
 2415             }
 2416         }
 2417 
 2418     }
 2419 
 2420     public function configure_fail2ban() {
 2421         // To Do
 2422     }
 2423 
 2424     public function configure_squid()
 2425     {
 2426         global $conf;
 2427         $row = $this->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = ?", $conf["server_id"]);
 2428         $ip_address = gethostbyname($row["server_name"]);
 2429         $server_name = $row["server_name"];
 2430 
 2431         $configfile = 'squid.conf';
 2432         if(is_file($conf["squid"]["config_dir"].'/'.$configfile)) copy($conf["squid"]["config_dir"].'/'.$configfile, $conf["squid"]["config_dir"].'/'.$configfile.'~');
 2433         if(is_file($conf["squid"]["config_dir"].'/'.$configfile.'~')) exec('chmod 400 '.$conf["squid"]["config_dir"].'/'.$configfile.'~');
 2434         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', "tpl/".$configfile.".master");
 2435         $content = str_replace('{server_name}', $server_name, $content);
 2436         $content = str_replace('{ip_address}', $ip_address, $content);
 2437         $content = str_replace('{config_dir}', $conf['squid']['config_dir'], $content);
 2438         wf($conf["squid"]["config_dir"].'/'.$configfile, $content);
 2439         exec('chmod 600 '.$conf["squid"]["config_dir"].'/'.$configfile);
 2440         exec('chown root:root '.$conf["squid"]["config_dir"].'/'.$configfile);
 2441     }
 2442 
 2443     public function configure_ufw_firewall()
 2444     {
 2445         if($this->is_update == false) {
 2446             $configfile = 'ufw.conf';
 2447             if(is_file('/etc/ufw/ufw.conf')) copy('/etc/ufw/ufw.conf', '/etc/ufw/ufw.conf~');
 2448             $content = rf("tpl/".$configfile.".master");
 2449             wf('/etc/ufw/ufw.conf', $content);
 2450             exec('chmod 600 /etc/ufw/ufw.conf');
 2451             exec('chown root:root /etc/ufw/ufw.conf');
 2452         }
 2453     }
 2454 
 2455     public function configure_bastille_firewall() {
 2456         global $conf;
 2457 
 2458         $dist_init_scripts = $conf['init_scripts'];
 2459 
 2460         if(is_dir('/etc/Bastille.backup')) caselog('rm -rf /etc/Bastille.backup', __FILE__, __LINE__);
 2461         if(is_dir('/etc/Bastille')) caselog('mv -f /etc/Bastille /etc/Bastille.backup', __FILE__, __LINE__);
 2462         @mkdir('/etc/Bastille', 0700);
 2463         if(is_dir('/etc/Bastille.backup/firewall.d')) caselog('cp -pfr /etc/Bastille.backup/firewall.d /etc/Bastille/', __FILE__, __LINE__);
 2464         if(is_file($conf['ispconfig_install_dir'].'/server/conf-custom/install/bastille-firewall.cfg.master')) {
 2465             caselog('cp -f ' . $conf['ispconfig_install_dir'].'/server/conf-custom/install/bastille-firewall.cfg.master /etc/Bastille/bastille-firewall.cfg', __FILE__, __LINE__);
 2466         } else {
 2467             caselog('cp -f tpl/bastille-firewall.cfg.master /etc/Bastille/bastille-firewall.cfg', __FILE__, __LINE__);
 2468         }
 2469         caselog('chmod 644 /etc/Bastille/bastille-firewall.cfg', __FILE__, __LINE__);
 2470         $content = rf('/etc/Bastille/bastille-firewall.cfg');
 2471         $content = str_replace('{DNS_SERVERS}', '', $content);
 2472 
 2473         $tcp_public_services = '';
 2474         $udp_public_services = '';
 2475 
 2476         $row = $this->db->queryOneRecord('SELECT * FROM ?? WHERE server_id = ?', $conf["mysql"]["database"] . '.firewall', $conf['server_id']);
 2477 
 2478         if(trim($row['tcp_port']) != '' || trim($row['udp_port']) != '') {
 2479             $tcp_public_services = trim(str_replace(',', ' ', $row['tcp_port']));
 2480             $udp_public_services = trim(str_replace(',', ' ', $row['udp_port']));
 2481         } else {
 2482             $tcp_public_services = '21 22 25 53 80 110 143 443 3306 8080 10000';
 2483             $udp_public_services = '53';
 2484         }
 2485 
 2486         if(!stristr($tcp_public_services, $conf['apache']['vhost_port'])) {
 2487             $tcp_public_services .= ' '.intval($conf['apache']['vhost_port']);
 2488             if($row['tcp_port'] != '') $this->db->query("UPDATE firewall SET tcp_port = tcp_port + ? WHERE server_id = ?", ',' . intval($conf['apache']['vhost_port']), $conf['server_id']);
 2489         }
 2490 
 2491         $content = str_replace('{TCP_PUBLIC_SERVICES}', $tcp_public_services, $content);
 2492         $content = str_replace('{UDP_PUBLIC_SERVICES}', $udp_public_services, $content);
 2493 
 2494         wf('/etc/Bastille/bastille-firewall.cfg', $content);
 2495 
 2496         if(is_file($dist_init_scripts.'/bastille-firewall')) caselog('mv -f '.$dist_init_scripts.'/bastille-firewall '.$dist_init_scripts.'/bastille-firewall.backup', __FILE__, __LINE__);
 2497         caselog('cp -f apps/bastille-firewall '.$dist_init_scripts, __FILE__, __LINE__);
 2498         caselog('chmod 700 '.$dist_init_scripts.'/bastille-firewall', __FILE__, __LINE__);
 2499 
 2500         if(is_file('/sbin/bastille-ipchains')) caselog('mv -f /sbin/bastille-ipchains /sbin/bastille-ipchains.backup', __FILE__, __LINE__);
 2501         caselog('cp -f apps/bastille-ipchains /sbin', __FILE__, __LINE__);
 2502         caselog('chmod 700 /sbin/bastille-ipchains', __FILE__, __LINE__);
 2503 
 2504         if(is_file('/sbin/bastille-netfilter')) caselog('mv -f /sbin/bastille-netfilter /sbin/bastille-netfilter.backup', __FILE__, __LINE__);
 2505         caselog('cp -f apps/bastille-netfilter /sbin', __FILE__, __LINE__);
 2506         caselog('chmod 700 /sbin/bastille-netfilter', __FILE__, __LINE__);
 2507 
 2508         if(!@is_dir('/var/lock/subsys')) caselog('mkdir /var/lock/subsys', __FILE__, __LINE__);
 2509 
 2510         exec('which ipchains &> /dev/null', $ipchains_location, $ret_val);
 2511         if(!is_file('/sbin/ipchains') && !is_link('/sbin/ipchains') && $ret_val == 0) phpcaselog(@symlink(shell_exec('which ipchains'), '/sbin/ipchains'), 'create symlink', __FILE__, __LINE__);
 2512         unset($ipchains_location);
 2513         exec('which iptables &> /dev/null', $iptables_location, $ret_val);
 2514         if(!is_file('/sbin/iptables') && !is_link('/sbin/iptables') && $ret_val == 0) phpcaselog(@symlink(trim(shell_exec('which iptables')), '/sbin/iptables'), 'create symlink', __FILE__, __LINE__);
 2515         unset($iptables_location);
 2516 
 2517     }
 2518 
 2519     public function configure_vlogger() {
 2520         global $conf;
 2521 
 2522         //** Configure vlogger to use traffic logging to mysql (master) db
 2523         $configfile = 'vlogger-dbi.conf';
 2524         if(is_file($conf['vlogger']['config_dir'].'/'.$configfile)) copy($conf['vlogger']['config_dir'].'/'.$configfile, $conf['vlogger']['config_dir'].'/'.$configfile.'~');
 2525         if(is_file($conf['vlogger']['config_dir'].'/'.$configfile.'~')) chmod($conf['vlogger']['config_dir'].'/'.$configfile.'~', 0400);
 2526         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 2527         if($conf['mysql']['master_slave_setup'] == 'y') {
 2528             $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['master_ispconfig_user'], $content);
 2529             $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['master_ispconfig_password'], $content);
 2530             $content = str_replace('{mysql_server_database}', $conf['mysql']['master_database'], $content);
 2531             $content = str_replace('{mysql_server_ip}', $conf['mysql']['master_host'], $content);
 2532         } else {
 2533             $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 2534             $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 2535             $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 2536             $content = str_replace('{mysql_server_ip}', $conf['mysql']['ip'], $content);
 2537         }
 2538         wf($conf['vlogger']['config_dir'].'/'.$configfile, $content);
 2539         chmod($conf['vlogger']['config_dir'].'/'.$configfile, 0600);
 2540         chown($conf['vlogger']['config_dir'].'/'.$configfile, 'root');
 2541         chgrp($conf['vlogger']['config_dir'].'/'.$configfile, 'root');
 2542 
 2543     }
 2544 
 2545     public function configure_apps_vhost() {
 2546         global $conf;
 2547 
 2548         //* Create the ispconfig apps vhost user and group
 2549         if($conf['apache']['installed'] == true){
 2550             $apps_vhost_user = escapeshellcmd($conf['web']['apps_vhost_user']);
 2551             $apps_vhost_group = escapeshellcmd($conf['web']['apps_vhost_group']);
 2552             $install_dir = escapeshellcmd($conf['web']['website_basedir'].'/apps');
 2553 
 2554             $command = 'groupadd '.$apps_vhost_user;
 2555             if(!is_group($apps_vhost_group)) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2556 
 2557             $command = 'useradd -g '.$apps_vhost_group.' -d '.$install_dir.' '.$apps_vhost_group;
 2558             if(!is_user($apps_vhost_user)) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2559 
 2560 
 2561             //$command = 'adduser '.$conf['apache']['user'].' '.$apps_vhost_group;
 2562             $command = 'usermod -a -G '.$apps_vhost_group.' '.$conf['apache']['user'];
 2563             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2564 
 2565             if(!@is_dir($install_dir)){
 2566                 mkdir($install_dir, 0755, true);
 2567             } else {
 2568                 chmod($install_dir, 0755);
 2569             }
 2570             chown($install_dir, $apps_vhost_user);
 2571             chgrp($install_dir, $apps_vhost_group);
 2572 
 2573             //* Copy the apps vhost file
 2574             $vhost_conf_dir = $conf['apache']['vhost_conf_dir'];
 2575             $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir'];
 2576             $apps_vhost_servername = ($conf['web']['apps_vhost_servername'] == '')?'':'ServerName '.$conf['web']['apps_vhost_servername'];
 2577 
 2578             //* Get the apps vhost port
 2579             if($this->is_update == true) {
 2580                 $conf['web']['apps_vhost_port'] = get_apps_vhost_port_number();
 2581             }
 2582 
 2583             // Dont just copy over the virtualhost template but add some custom settings
 2584             $tpl = new tpl('apache_apps.vhost.master');
 2585             $tpl->setVar('apps_vhost_ip',$conf['web']['apps_vhost_ip']);
 2586             $tpl->setVar('apps_vhost_port',$conf['web']['apps_vhost_port']);
 2587             $tpl->setVar('apps_vhost_dir',$conf['web']['website_basedir'].'/apps');
 2588             $tpl->setVar('apps_vhost_basedir',$conf['web']['website_basedir']);
 2589             $tpl->setVar('apps_vhost_servername',$apps_vhost_servername);
 2590             if(is_file($conf['ispconfig_install_dir'].'/interface/ssl/ispserver.crt') && is_file($conf['ispconfig_install_dir'].'/interface/ssl/ispserver.key')) {
 2591                 $tpl->setVar('ssl_comment','');
 2592             } else {
 2593                 $tpl->setVar('ssl_comment','#');
 2594             }
 2595             if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key') && is_file($install_dir.'/interface/ssl/ispserver.bundle')) {
 2596                 $tpl->setVar('ssl_bundle_comment','');
 2597             } else {
 2598                 $tpl->setVar('ssl_bundle_comment','#');
 2599             }
 2600             $tpl->setVar('apache_version',getapacheversion());
 2601             if($this->is_update == true) {
 2602                 $tpl->setVar('logging',get_logging_state());
 2603             } else {
 2604                 $tpl->setVar('logging','yes');
 2605             }
 2606 
 2607             if($conf['rspamd']['installed'] == true) {
 2608                 $tpl->setVar('use_rspamd', 'yes');
 2609             }
 2610 
 2611             // comment out the listen directive if port is 80 or 443
 2612             if($conf['web']['apps_vhost_port'] == 80 or $conf['web']['apps_vhost_port'] == 443) {
 2613                 $tpl->setVar('vhost_port_listen','#');
 2614             } else {
 2615                 $tpl->setVar('vhost_port_listen','');
 2616             }
 2617 
 2618             wf($vhost_conf_dir.'/apps.vhost', $tpl->grab());
 2619             unset($tpl);
 2620 
 2621             //copy('tpl/apache_ispconfig.vhost.master', "$vhost_conf_dir/ispconfig.vhost");
 2622             //* and create the symlink
 2623             if(@is_link($vhost_conf_enabled_dir.'/apps.vhost')) unlink($vhost_conf_enabled_dir.'/apps.vhost');
 2624             if(!@is_link($vhost_conf_enabled_dir.'/000-apps.vhost') && @is_file($vhost_conf_dir.'/apps.vhost')) {
 2625                 @symlink($vhost_conf_dir.'/apps.vhost', $vhost_conf_enabled_dir.'/000-apps.vhost');
 2626             }
 2627 
 2628             if(!is_file($conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter')) {
 2629                 $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_apps_fcgi_starter.master', 'tpl/apache_apps_fcgi_starter.master');
 2630                 $content = str_replace('{fastcgi_bin}', $conf['fastcgi']['fastcgi_bin'], $content);
 2631                 $content = str_replace('{fastcgi_phpini_path}', $conf['fastcgi']['fastcgi_phpini_path'], $content);
 2632                 mkdir($conf['web']['website_basedir'].'/php-fcgi-scripts/apps', 0755, true);
 2633                 $this->set_immutable($conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter', false);
 2634                 //copy('tpl/apache_apps_fcgi_starter.master',$conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter');
 2635                 wf($conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter', $content);
 2636                 exec('chmod +x '.$conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter');
 2637                 exec('chown -R ispapps:ispapps '.$conf['web']['website_basedir'].'/php-fcgi-scripts/apps');
 2638                 $this->set_immutable($conf['web']['website_basedir'].'/php-fcgi-scripts/apps/.php-fcgi-starter', true);
 2639             }
 2640         }
 2641         if($conf['nginx']['installed'] == true){
 2642             $apps_vhost_user = escapeshellcmd($conf['web']['apps_vhost_user']);
 2643             $apps_vhost_group = escapeshellcmd($conf['web']['apps_vhost_group']);
 2644             $install_dir = escapeshellcmd($conf['web']['website_basedir'].'/apps');
 2645 
 2646             $command = 'groupadd '.$apps_vhost_user;
 2647             if(!is_group($apps_vhost_group)) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2648 
 2649             $command = 'useradd -g '.$apps_vhost_group.' -d '.$install_dir.' '.$apps_vhost_group;
 2650             if(!is_user($apps_vhost_user)) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2651 
 2652 
 2653             //$command = 'adduser '.$conf['nginx']['user'].' '.$apps_vhost_group;
 2654             $command = 'usermod -a -G '.$apps_vhost_group.' '.$conf['nginx']['user'];
 2655             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2656 
 2657             if(!@is_dir($install_dir)){
 2658                 mkdir($install_dir, 0755, true);
 2659             } else {
 2660                 chmod($install_dir, 0755);
 2661             }
 2662             chown($install_dir, $apps_vhost_user);
 2663             chgrp($install_dir, $apps_vhost_group);
 2664 
 2665             //* Copy the apps vhost file
 2666             $vhost_conf_dir = $conf['nginx']['vhost_conf_dir'];
 2667             $vhost_conf_enabled_dir = $conf['nginx']['vhost_conf_enabled_dir'];
 2668             $apps_vhost_servername = ($conf['web']['apps_vhost_servername'] == '')?'_':$conf['web']['apps_vhost_servername'];
 2669 
 2670             // Dont just copy over the virtualhost template but add some custom settings
 2671             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/nginx_apps.vhost.master', 'tpl/nginx_apps.vhost.master');
 2672 
 2673             // Enable SSL if a cert is in place.
 2674             if(is_file($conf['ispconfig_install_dir'].'/interface/ssl/ispserver.crt') && is_file($conf['ispconfig_install_dir'].'/interface/ssl/ispserver.key')) {
 2675                 $content = str_replace('{ssl_on}', 'ssl http2', $content);
 2676                 $content = str_replace('{ssl_comment}', '', $content);
 2677             } else {
 2678                 $content = str_replace('{ssl_on}', '', $content);
 2679                 $content = str_replace('{ssl_comment}', '#', $content);
 2680             }
 2681 
 2682             if($conf['web']['apps_vhost_ip'] == '_default_'){
 2683                 $apps_vhost_ip = '';
 2684             } else {
 2685                 $apps_vhost_ip = $conf['web']['apps_vhost_ip'].':';
 2686             }
 2687 
 2688             if($conf['rspamd']['installed'] == true) {
 2689                 $content = str_replace('{use_rspamd}', '', $content);
 2690             } else {
 2691                 $content = str_replace('{use_rspamd}', '# ', $content);
 2692             }
 2693 
 2694             $socket_dir = escapeshellcmd($conf['nginx']['php_fpm_socket_dir']);
 2695             if(substr($socket_dir, -1) != '/') $socket_dir .= '/';
 2696             if(!is_dir($socket_dir)) exec('mkdir -p '.$socket_dir);
 2697             $fpm_socket = $socket_dir.'apps.sock';
 2698             $cgi_socket = escapeshellcmd($conf['nginx']['cgi_socket']);
 2699 
 2700             $content = str_replace('{apps_vhost_ip}', $apps_vhost_ip, $content);
 2701             $content = str_replace('{apps_vhost_port}', $conf['web']['apps_vhost_port'], $content);
 2702             $content = str_replace('{apps_vhost_dir}', $conf['web']['website_basedir'].'/apps', $content);
 2703             $content = str_replace('{apps_vhost_servername}', $apps_vhost_servername, $content);
 2704             //$content = str_replace('{fpm_port}', ($conf['nginx']['php_fpm_start_port']+1), $content);
 2705             $content = str_replace('{fpm_socket}', $fpm_socket, $content);
 2706             $content = str_replace('{cgi_socket}', $cgi_socket, $content);
 2707 
 2708             if( file_exists('/var/run/php5-fpm.sock')
 2709                 || file_exists('/var/run/php/php7.0-fpm.sock')
 2710                 || file_exists('/var/run/php/php7.1-fpm.sock')
 2711                 || file_exists('/var/run/php/php7.2-fpm.sock')
 2712                 || file_exists('/var/run/php/php7.3-fpm.sock')
 2713                 || file_exists('/var/run/php/php7.4-fpm.sock')
 2714             ){
 2715                 $use_tcp = '#';
 2716                 $use_socket = '';
 2717             } else {
 2718                 $use_tcp = '';
 2719                 $use_socket = '#';
 2720             }
 2721             $content = str_replace('{use_tcp}', $use_tcp, $content);
 2722             $content = str_replace('{use_socket}', $use_socket, $content);
 2723 
 2724             // Fix socket path on PHP 7 systems
 2725             if(file_exists('/var/run/php/php7.0-fpm.sock')) $content = str_replace('/var/run/php5-fpm.sock', '/var/run/php/php7.0-fpm.sock', $content);
 2726             if(file_exists('/var/run/php/php7.1-fpm.sock')) $content = str_replace('/var/run/php5-fpm.sock', '/var/run/php/php7.1-fpm.sock', $content);
 2727             if(file_exists('/var/run/php/php7.2-fpm.sock')) $content = str_replace('/var/run/php5-fpm.sock', '/var/run/php/php7.2-fpm.sock', $content);
 2728             if(file_exists('/var/run/php/php7.3-fpm.sock')) $content = str_replace('/var/run/php5-fpm.sock', '/var/run/php/php7.3-fpm.sock', $content);
 2729             if(file_exists('/var/run/php/php7.4-fpm.sock')) $content = str_replace('/var/run/php5-fpm.sock', '/var/run/php/php7.4-fpm.sock', $content);
 2730 
 2731             wf($vhost_conf_dir.'/apps.vhost', $content);
 2732 
 2733             // PHP-FPM
 2734             // Dont just copy over the php-fpm pool template but add some custom settings
 2735             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apps_php_fpm_pool.conf.master', 'tpl/apps_php_fpm_pool.conf.master');
 2736             $content = str_replace('{fpm_pool}', 'apps', $content);
 2737             //$content = str_replace('{fpm_port}', ($conf['nginx']['php_fpm_start_port']+1), $content);
 2738             $content = str_replace('{fpm_socket}', $fpm_socket, $content);
 2739             $content = str_replace('{fpm_user}', $apps_vhost_user, $content);
 2740             $content = str_replace('{fpm_group}', $apps_vhost_group, $content);
 2741             wf($conf['nginx']['php_fpm_pool_dir'].'/apps.conf', $content);
 2742 
 2743             //copy('tpl/nginx_ispconfig.vhost.master', "$vhost_conf_dir/ispconfig.vhost");
 2744             //* and create the symlink
 2745             if(@is_link($vhost_conf_enabled_dir.'/apps.vhost')) unlink($vhost_conf_enabled_dir.'/apps.vhost');
 2746             if(!@is_link($vhost_conf_enabled_dir.'/000-apps.vhost')) {
 2747                 symlink($vhost_conf_dir.'/apps.vhost', $vhost_conf_enabled_dir.'/000-apps.vhost');
 2748             }
 2749         }
 2750     }
 2751 
 2752     private function curl_request($url, $use_ipv6 = false) {
 2753         $set_headers = [
 2754             'Connection: Close',
 2755             'User-Agent: ISPConfig/3',
 2756             'Accept: */*'
 2757         ];
 2758 
 2759         $ch = curl_init($url);
 2760         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 2761         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 2762         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
 2763         curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
 2764         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
 2765         curl_setopt($ch, CURLOPT_HTTPHEADER, $set_headers);
 2766         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
 2767         curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
 2768 
 2769         if($use_ipv6) {
 2770             if(defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V6')) {
 2771                 curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
 2772             }
 2773         } else {
 2774             if(defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')) {
 2775                 curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
 2776             }
 2777         }
 2778 
 2779         $response = curl_exec($ch);
 2780         curl_close($ch);
 2781 
 2782         return $response;
 2783     }
 2784 
 2785     public function make_acme_vhost($server = 'apache') {
 2786         global $conf;
 2787 
 2788         if($conf['hostname'] !== 'localhost' && $conf['hostname'] !== '') {
 2789             $server_name = $conf['hostname'];
 2790         } else {
 2791             $server_name = exec('hostname -f');
 2792         }
 2793 
 2794         $use_template = 'apache_acme.conf.master';
 2795         $use_symlink = '999-acme.conf';
 2796         $use_name = 'acme.conf';
 2797         if($server === 'nginx') {
 2798             $use_template = 'nginx_acme.vhost.master';
 2799             $use_symlink = '999-acme.vhost';
 2800             $use_name = 'acme.vhost';
 2801         }
 2802 
 2803         $vhost_conf_dir = $conf[$server]['vhost_conf_dir'];
 2804         $vhost_conf_enabled_dir = $conf[$server]['vhost_conf_enabled_dir'];
 2805 
 2806         $tpl = new tpl($use_template);
 2807         $tpl->setVar('domain', $server_name);
 2808 
 2809         if($server !== 'nginx') {
 2810             $tpl->setVar('apache_version',getapacheversion());
 2811         }
 2812 
 2813         $acme_dir = $conf['ispconfig_install_dir'] . '/interface/acme';
 2814 
 2815         //* Create the ISPConfig installation directory
 2816         if(!@is_dir($acme_dir)) {
 2817             $command = "mkdir -p $acme_dir";
 2818             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 2819         }
 2820 
 2821         wf($vhost_conf_dir.'/' . $use_name, $tpl->grab());
 2822 
 2823         if(@is_link($vhost_conf_enabled_dir.'/' . $use_symlink)) {
 2824             unlink($vhost_conf_enabled_dir.'/' . $use_symlink);
 2825         }
 2826         if(!@is_link($vhost_conf_enabled_dir.'/' . $use_symlink)) {
 2827             symlink($vhost_conf_dir.'/' . $use_name, $vhost_conf_enabled_dir.'/' . $use_symlink);
 2828         }
 2829     }
 2830 
 2831     public function make_ispconfig_ssl_cert() {
 2832         global $conf, $autoinstall;
 2833 
 2834         //* Get hostname from user entry or shell command */
 2835         if($conf['hostname'] !== 'localhost' && $conf['hostname'] !== '') {
 2836             $hostname = $conf['hostname'];
 2837         } else {
 2838             $hostname = exec('hostname -f');
 2839         }
 2840 
 2841         // Check dns a record exist and its ip equal to server public ip
 2842         $svr_ip4 = $this->curl_request('https://ispconfig.org/remoteip.php', false);
 2843         $svr_ip6 = $this->curl_request('https://ispconfig.org/remoteip.php', true);
 2844 
 2845         if(function_exists('idn_to_ascii')) {
 2846             if(defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46') && constant('IDNA_NONTRANSITIONAL_TO_ASCII')) {
 2847                 $hostname = idn_to_ascii($hostname, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
 2848             } else {
 2849                 $hostname = idn_to_ascii($hostname);
 2850             }
 2851         }
 2852         $dns_ips = array();
 2853         if (checkdnsrr($hostname, 'A')) {
 2854             $dnsa=dns_get_record($hostname, DNS_A);
 2855             if($dnsa) {
 2856                 foreach ($dnsa as $rec) {
 2857                     $dns_ips[] = $rec['ip'];
 2858                 }
 2859             }
 2860         }
 2861         if (checkdnsrr($hostname, 'AAAA')) {
 2862             $dnsaaaa=dns_get_record($hostname, DNS_AAAA);
 2863             if($dnsaaaa) {
 2864                 foreach ($dnsaaaa as $rec) {
 2865                     $dns_ips[] = $rec['ip'];
 2866                 }
 2867             }
 2868         }
 2869 
 2870         //* Define and check ISPConfig SSL folder */
 2871         $ssl_dir = $conf['ispconfig_install_dir'].'/interface/ssl';
 2872         if(!@is_dir($ssl_dir)) {
 2873             mkdir($ssl_dir, 0755, true);
 2874         }
 2875 
 2876         $ssl_crt_file = $ssl_dir.'/ispserver.crt';
 2877         $ssl_csr_file = $ssl_dir.'/ispserver.csr';
 2878         $ssl_key_file = $ssl_dir.'/ispserver.key';
 2879         $ssl_pem_file = $ssl_dir.'/ispserver.pem';
 2880 
 2881         $date = new DateTime();
 2882 
 2883         // Request for certs if no LE SSL folder for server fqdn exist
 2884 
 2885         swriteln('Checking / creating certificate for ' . $hostname);
 2886 
 2887         $acme_cert_dir = '/usr/local/ispconfig/server/scripts/' . $hostname;
 2888         $check_acme_file = $acme_cert_dir . '/' . $hostname . '.cer';
 2889         if(!@is_dir($acme_cert_dir)) {
 2890             $acme_cert_dir = '/root/.acme.sh/' . $hostname;
 2891             $check_acme_file = $acme_cert_dir . '/' . $hostname . '.cer';
 2892             if(!@is_dir($acme_cert_dir)) {
 2893                 $acme_cert_dir = '/etc/letsencrypt/live/' . $hostname;
 2894                 $check_acme_file = $acme_cert_dir . '/cert.pem';
 2895             }
 2896         }
 2897 
 2898         swriteln('Using certificate path ' . $acme_cert_dir);
 2899         $ip_address_match = false;
 2900         if(!(($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) {
 2901             swriteln('Server\'s public ip(s) (' . $svr_ip4 . ($svr_ip6 ? ', ' . $svr_ip6 : '') . ') not found in A/AAAA records for ' . $hostname . ': ' . implode(', ', $dns_ips));
 2902             if(strtolower($this->simple_query('Ignore DNS check and continue to request certificate?', array('y', 'n') , 'n','ignore_hostname_dns')) == 'y') {
 2903                 $ip_address_match = true;
 2904             }
 2905         } else {
 2906             $ip_address_match = true;
 2907         }
 2908 
 2909         // Get subject and issuer of ispserver.crt to check if it is self-signed cert
 2910         if (file_exists($ssl_crt_file)) {
 2911             $crt_subject = exec("openssl x509 -in ".escapeshellarg($ssl_crt_file)." -inform PEM -noout -subject");
 2912             $crt_issuer = exec("openssl x509 -in ".escapeshellarg($ssl_crt_file)." -inform PEM -noout -issuer");
 2913         }
 2914 
 2915         if ((@file_exists($ssl_crt_file) && ($crt_subject == $crt_issuer)) || (!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file) || !@file_exists($ssl_crt_file) || md5_file($check_acme_file) != md5_file($ssl_crt_file)) && $ip_address_match == true) {
 2916 
 2917             // This script is needed earlier to check and open http port 80 or standalone might fail
 2918             // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install
 2919             if(file_exists(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_pre_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_pre_hook.sh')) {
 2920                 symlink(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_pre_hook.sh', '/usr/local/bin/letsencrypt_pre_hook.sh');
 2921                 chown('/usr/local/bin/letsencrypt_pre_hook.sh', 'root');
 2922                 chmod('/usr/local/bin/letsencrypt_pre_hook.sh', 0700);
 2923             }
 2924             if(file_exists(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_post_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_post_hook.sh')) {
 2925                 symlink(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_post_hook.sh', '/usr/local/bin/letsencrypt_post_hook.sh');
 2926                 chown('/usr/local/bin/letsencrypt_post_hook.sh', 'root');
 2927                 chmod('/usr/local/bin/letsencrypt_post_hook.sh', 0700);
 2928             }
 2929             if(file_exists(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_renew_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_renew_hook.sh')) {
 2930                 symlink(ISPC_INSTALL_ROOT . '/server/scripts/letsencrypt_renew_hook.sh', '/usr/local/bin/letsencrypt_renew_hook.sh');
 2931                 chown('/usr/local/bin/letsencrypt_renew_hook.sh', 'root');
 2932                 chmod('/usr/local/bin/letsencrypt_renew_hook.sh', 0700);
 2933             }
 2934 
 2935             // Check http port 80 status as it cannot be determined at post hook stage
 2936             $port80_status=exec('true &>/dev/null </dev/tcp/127.0.0.1/80 && echo open || echo close');
 2937 
 2938             // Set pre-, post- and renew hook
 2939             $pre_hook = "--pre-hook \"letsencrypt_pre_hook.sh\"";
 2940             $renew_hook = "  --renew-hook \"letsencrypt_renew_hook.sh\"";
 2941             if($port80_status == 'close') {
 2942                 $post_hook = " --post-hook \"letsencrypt_post_hook.sh\"";
 2943                 $hook = $pre_hook . $post_hook . $renew_hook;
 2944             } else {
 2945                 $hook = $pre_hook . $renew_hook;
 2946             }
 2947 
 2948             // Get the default LE client name and version
 2949             $le_client = explode("\n", shell_exec('which certbot /root/.local/share/letsencrypt/bin/letsencrypt /opt/eff.org/certbot/venv/bin/certbot letsencrypt'));
 2950             $le_client = reset($le_client);
 2951 
 2952             // Check for Neilpang acme.sh as well
 2953             $acme = explode("\n", shell_exec('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh'));
 2954             $acme = reset($acme);
 2955 
 2956             if((!$acme || !is_executable($acme)) && (!$le_client || !is_executable($le_client))) {
 2957                 $success = $this->install_acme();
 2958                 if(!$success) {
 2959                     swriteln('Failed installing acme.sh. Will not be able to issue certificate during install.');
 2960                 } else {
 2961                     $acme = explode("\n", shell_exec('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh'));
 2962                     $acme = reset($acme);
 2963                     if($acme && is_executable($acme)) {
 2964                         swriteln('Installed acme.sh and using it for certificate creation during install.');
 2965 
 2966                         // we do this even on install to enable automatic updates
 2967                         $this->update_acme();
 2968                     } else {
 2969                         swriteln('Failed installing acme.sh. Will not be able to issue certificate during install.');
 2970                     }
 2971                 }
 2972             }
 2973 
 2974             $restore_conf_symlink = false;
 2975 
 2976             // we only need this for apache, so use fixed conf index
 2977             $vhost_conf_dir = $conf['apache']['vhost_conf_dir'];
 2978             $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir'];
 2979 
 2980             // first of all create the acme vhosts if not existing
 2981             if($conf['nginx']['installed'] == true) {
 2982                 swriteln('Using nginx for certificate validation');
 2983                 $server = 'nginx';
 2984             } elseif($conf['apache']['installed'] == true) {
 2985                 swriteln('Using apache for certificate validation');
 2986                 if($this->is_update == false && @is_link($vhost_conf_enabled_dir.'/000-ispconfig.conf')) {
 2987                     $restore_conf_symlink = true;
 2988                     unlink($vhost_conf_enabled_dir.'/000-ispconfig.conf');
 2989                 }
 2990                 $server = 'apache';
 2991             }
 2992 
 2993             if($conf[$server]['installed'] == true && $conf[$server]['init_script'] != '') {
 2994                 if($this->is_update) {
 2995                     system($this->getinitcommand($conf[$server]['init_script'], 'force-reload').' &> /dev/null || ' . $this->getinitcommand($conf[$server]['init_script'], 'restart').' &> /dev/null');
 2996                 } else {
 2997                     system($this->getinitcommand($conf[$server]['init_script'], 'restart').' &> /dev/null');
 2998                 }
 2999             }
 3000 
 3001             $issued_successfully = false;
 3002 
 3003             // Backup existing ispserver ssl files
 3004             if(file_exists($ssl_crt_file) || is_link($ssl_crt_file)) {
 3005                 rename($ssl_crt_file, $ssl_crt_file . '-temporary.bak');
 3006             }
 3007             if(file_exists($ssl_key_file) || is_link($ssl_key_file)) {
 3008                 rename($ssl_key_file, $ssl_key_file . '-temporary.bak');
 3009             }
 3010             if(file_exists($ssl_pem_file) || is_link($ssl_pem_file)) {
 3011                 rename($ssl_pem_file, $ssl_pem_file . '-temporary.bak');
 3012             }
 3013 
 3014             // Attempt to use Neilpang acme.sh first, as it is now the preferred LE client
 3015             if (is_executable($acme)) {
 3016                 $acme_cert_dir = dirname($acme) . '/' . $hostname;
 3017 
 3018                 swriteln('acme.sh is installed, overriding certificate path to use ' . $acme_cert_dir);
 3019 
 3020                 # acme.sh does not set umask, resulting in incorrect permissions (ispconfig issue #6015)
 3021                 $old_umask = umask(0022);
 3022 
 3023                 $out = null;
 3024                 $ret = null;
 3025                 if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) {
 3026                     exec("$acme --issue -w /usr/local/ispconfig/interface/acme -d " . escapeshellarg($hostname) . " $renew_hook", $out, $ret);
 3027                 }
 3028                 // Else, it is not webserver, so we use standalone
 3029                 else {
 3030                     exec("$acme --issue --standalone -d " . escapeshellarg($hostname) . " $hook", $out, $ret);
 3031                 }
 3032 
 3033                 if($ret == 0 || ($ret == 2 && file_exists($check_acme_file))) {
 3034                     // acme.sh returns with 2 on issue for already existing certificate
 3035 
 3036                     $check_acme_file = $ssl_crt_file;
 3037 
 3038                     // Define LE certs name and path, then install them
 3039                     //$acme_cert = "--cert-file $acme_cert_dir/cert.pem";
 3040                     $acme_key = "--key-file " . escapeshellarg($ssl_key_file);
 3041                     $acme_chain = "--fullchain-file " . escapeshellarg($ssl_crt_file);
 3042                     exec("$acme --install-cert -d " . escapeshellarg($hostname) . " $acme_key $acme_chain");
 3043                     $issued_successfully = true;
 3044                     umask($old_umask);
 3045 
 3046                     // Make temporary backup of self-signed certs permanent
 3047                     if(file_exists($ssl_crt_file.'-temporary.bak') || is_link($ssl_crt_file.'-temporary.bak'))
 3048                         rename($ssl_crt_file.'-temporary.bak', $ssl_crt_file.'-'.$date->format('YmdHis').'.bak');
 3049                     if(file_exists($ssl_key_file.'-temporary.bak') || is_link($ssl_key_file.'-temporary.bak'))
 3050                         rename($ssl_key_file.'-temporary.bak', $ssl_key_file.'-'.$date->format('YmdHis').'.bak');
 3051                     if(file_exists($ssl_pem_file.'-temporary.bak') || is_link($ssl_pem_file.'-temporary.bak'))
 3052                         rename($ssl_pem_file.'-temporary.bak', $ssl_pem_file.'-'.$date->format('YmdHis').'.bak');
 3053 
 3054                 } else {
 3055                     swriteln('Issuing certificate via acme.sh failed. Please check that your hostname can be verified by letsencrypt');
 3056 
 3057                     umask($old_umask);
 3058 
 3059                     // Restore temporary backup of self-signed certs
 3060                     if(file_exists($ssl_crt_file.'-temporary.bak') || is_link($ssl_crt_file.'-temporary.bak'))
 3061                         rename($ssl_crt_file.'-temporary.bak', $ssl_crt_file);
 3062                     if(file_exists($ssl_key_file.'-temporary.bak') || is_link($ssl_key_file.'-temporary.bak'))
 3063                         rename($ssl_key_file.'-temporary.bak', $ssl_key_file);
 3064                     if(file_exists($ssl_pem_file.'-temporary.bak') || is_link($ssl_pem_file.'-temporary.bak'))
 3065                         rename($ssl_pem_file.'-temporary.bak', $ssl_pem_file);
 3066 
 3067                 }
 3068             // Else, we attempt to use the official LE certbot client certbot
 3069             } else {
 3070 
 3071                 //  But only if it is otherwise available
 3072                 if(is_executable($le_client)) {
 3073                     $out = null;
 3074                     $ret = null;
 3075 
 3076                     // Get its version info due to be used for webroot arguement issues
 3077                     $le_info = exec($le_client . ' --version  2>&1', $ret, $val);
 3078                     if(preg_match('/^(\S+|\w+)\s+(\d+(\.\d+)+)$/', $le_info, $matches)) {
 3079                         $le_version = $matches[2];
 3080                     }
 3081 
 3082                     // Define certbot commands
 3083                     $acme_version = '--server https://acme-v0' . (($le_version >=0.22) ? '2' : '1') . '.api.letsencrypt.org/directory';
 3084                     $certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096';
 3085 
 3086                     // If this is a webserver
 3087                     if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) {
 3088                         exec("$le_client $certonly $acme_version --authenticator webroot --webroot-path /usr/local/ispconfig/interface/acme --email " . escapeshellarg('postmaster@' . $hostname) . " -d " . escapeshellarg($hostname) . " $renew_hook", $out, $ret);
 3089                     }
 3090                     // Else, it is not webserver, so we use standalone
 3091                     else {
 3092                         exec("$le_client $certonly $acme_version --standalone --email " . escapeshellarg('postmaster@' . $hostname) . " -d " . escapeshellarg($hostname) . " $hook", $out, $ret);
 3093                     }
 3094 
 3095                     if($ret == 0) {
 3096                         // certbot returns with 0 on issue for already existing certificate
 3097 
 3098                         $acme_cert_dir = '/etc/letsencrypt/live/' . $hostname;
 3099                         symlink($acme_cert_dir . '/fullchain.pem', $ssl_crt_file);
 3100                         symlink($acme_cert_dir . '/privkey.pem', $ssl_key_file);
 3101 
 3102                         $issued_successfully = true;
 3103 
 3104                         // Make temporary backup of self-signed certs permanent
 3105                         if(file_exists($ssl_crt_file.'-temporary.bak') || is_link($ssl_crt_file.'-temporary.bak'))
 3106                             rename($ssl_crt_file.'-temporary.bak', $ssl_crt_file.'-'.$date->format('YmdHis').'.bak');
 3107                         if(file_exists($ssl_key_file.'-temporary.bak') || is_link($ssl_key_file.'-temporary.bak'))
 3108                             rename($ssl_key_file.'-temporary.bak', $ssl_key_file.'-'.$date->format('YmdHis').'.bak');
 3109                         if(file_exists($ssl_pem_file.'-temporary.bak') || is_link($ssl_pem_file.'-temporary.bak'))
 3110                             rename($ssl_pem_file.'-temporary.bak', $ssl_pem_file.'-'.$date->format('YmdHis').'.bak');
 3111 
 3112                     } else {
 3113                         swriteln('Issuing certificate via certbot failed. Please check log files and make sure that your hostname can be verified by letsencrypt');
 3114 
 3115                         // Restore temporary backup of self-signed certs
 3116                         if(file_exists($ssl_crt_file.'-temporary.bak') || is_link($ssl_crt_file.'-temporary.bak'))
 3117                             rename($ssl_crt_file.'-temporary.bak', $ssl_crt_file);
 3118                         if(file_exists($ssl_key_file.'-temporary.bak') || is_link($ssl_key_file.'-temporary.bak'))
 3119                             rename($ssl_key_file.'-temporary.bak', $ssl_key_file);
 3120                         if(file_exists($ssl_pem_file.'-temporary.bak') || is_link($ssl_pem_file.'-temporary.bak'))
 3121                             rename($ssl_pem_file.'-temporary.bak', $ssl_pem_file);
 3122 
 3123                     }
 3124                 } else {
 3125                     swriteln('Did not find any valid acme client (acme.sh or certbot)');
 3126                 }
 3127             }
 3128 
 3129             if($restore_conf_symlink) {
 3130                 if(!@is_link($vhost_conf_enabled_dir.'/000-ispconfig.conf')) {
 3131                     symlink($vhost_conf_dir.'/ispconfig.conf', $vhost_conf_enabled_dir.'/000-ispconfig.conf');
 3132                 }
 3133             }
 3134         } else {
 3135             if($ip_address_match) {
 3136                 // the directory already exists so we have to assume that it was created previously
 3137                 $issued_successfully = true;
 3138             }
 3139         }
 3140 
 3141         // If the LE SSL certs for this hostname exists
 3142         if(!is_dir($acme_cert_dir) || !file_exists($check_acme_file) || !$issued_successfully) {
 3143             if(!$issued_successfully) {
 3144                 swriteln('Could not issue letsencrypt certificate, falling back to self-signed.');
 3145             } else {
 3146                 swriteln('Issuing certificate seems to have succeeded but ' . $check_acme_file . ' seems to be missing. Falling back to self-signed.');
 3147             }
 3148 
 3149             // We can still use the old self-signed method
 3150             $openssl_cmd = 'openssl req -nodes -newkey rsa:4096 -x509 -days 3650 -keyout ' . escapeshellarg($ssl_key_file) . ' -out ' . escapeshellarg($ssl_crt_file);
 3151             if(AUTOINSTALL){
 3152                 $openssl_cmd .= ' -subj ' . escapeshellarg('/C=' . $autoinstall['ssl_cert_country'] . '/ST=' . $autoinstall['ssl_cert_state'] . '/L=' . $autoinstall['ssl_cert_locality'] . '/O=' . $autoinstall['ssl_cert_organisation'] . '/OU=' . $autoinstall['ssl_cert_organisation_unit'] . '/CN=' . $autoinstall['ssl_cert_common_name']);
 3153             }
 3154             exec($openssl_cmd);
 3155         }
 3156 
 3157         // Build ispserver.pem file and chmod it
 3158         if(file_exists($ssl_key_file)) {
 3159             exec("cat $ssl_key_file $ssl_crt_file > $ssl_pem_file; chmod 600 $ssl_pem_file");
 3160 
 3161             // Extend LE SSL certs to postfix
 3162             if ($conf['postfix']['installed'] == true && strtolower($this->simple_query('Symlink ISPConfig SSL certs to Postfix?', array('y', 'n'), 'y','ispconfig_postfix_ssl_symlink')) == 'y') {
 3163 
 3164                 // Define folder, file(s)
 3165                 $cf = $conf['postfix'];
 3166                 $postfix_dir = $cf['config_dir'];
 3167                 if(!is_dir($postfix_dir)) $this->error("The Postfix configuration directory '$postfix_dir' does not exist.");
 3168                 $smtpd_crt = $postfix_dir.'/smtpd.cert';
 3169                 $smtpd_key = $postfix_dir.'/smtpd.key';
 3170 
 3171                 // Backup existing postfix ssl files
 3172                 if (file_exists($smtpd_crt)) rename($smtpd_crt, $smtpd_crt . '-' .$date->format('YmdHis') . '.bak');
 3173                 if (file_exists($smtpd_key)) rename($smtpd_key, $smtpd_key . '-' .$date->format('YmdHis') . '.bak');
 3174 
 3175                 // Create symlink to ISPConfig SSL files
 3176                 symlink($ssl_crt_file, $smtpd_crt);
 3177                 symlink($ssl_key_file, $smtpd_key);
 3178             }
 3179 
 3180             // Extend LE SSL certs to pureftpd
 3181             if ($conf['pureftpd']['installed'] == true && strtolower($this->simple_query('Symlink ISPConfig SSL certs to Pure-FTPd? Creating dhparam file may take some time.', array('y', 'n'), 'y','ispconfig_pureftpd_ssl_symlink')) == 'y') {
 3182 
 3183                 // Define folder, file(s)
 3184                 $pureftpd_dir = '/etc/ssl/private';
 3185                 if(!is_dir($pureftpd_dir)) mkdir($pureftpd_dir, 0755, true);
 3186                 $pureftpd_pem = $pureftpd_dir.'/pure-ftpd.pem';
 3187 
 3188                 // Backup existing pureftpd ssl files
 3189                 if (file_exists($pureftpd_pem)) rename($pureftpd_pem, $pureftpd_pem . '-' .$date->format('YmdHis') . '.bak');
 3190 
 3191                 // Create symlink to ISPConfig SSL files
 3192                 symlink($ssl_pem_file, $pureftpd_pem);
 3193                 if (!file_exists("$pureftpd_dir/pure-ftpd-dhparams.pem"))
 3194                     exec("cd $pureftpd_dir; openssl dhparam -out dhparam2048.pem 2048; ln -sf dhparam2048.pem pure-ftpd-dhparams.pem");
 3195             }
 3196         }
 3197 
 3198         exec("chown -R root:root $ssl_dir");
 3199 
 3200     }
 3201 
 3202     public function install_ispconfig() {
 3203         global $conf;
 3204 
 3205         $install_dir = $conf['ispconfig_install_dir'];
 3206 
 3207         //* Create the ISPConfig installation directory
 3208         if(!@is_dir($install_dir)) {
 3209             $command = "mkdir $install_dir";
 3210             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3211         }
 3212 
 3213         //* Create a ISPConfig user and group
 3214         $command = 'groupadd ispconfig';
 3215         if(!is_group('ispconfig')) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3216 
 3217         $command = 'useradd -g ispconfig -d '.$install_dir.' ispconfig';
 3218         if(!is_user('ispconfig')) caselog($command.' &> /dev/null 2> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3219 
 3220         //* copy the ISPConfig interface part
 3221         $command = 'cp -rf ../interface '.$install_dir;
 3222         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3223 
 3224         //* copy the ISPConfig server part
 3225         $command = 'cp -rf ../server '.$install_dir;
 3226         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3227 
 3228         //* Make a backup of the security settings
 3229         if(is_file('/usr/local/ispconfig/security/security_settings.ini')) copy('/usr/local/ispconfig/security/security_settings.ini','/usr/local/ispconfig/security/security_settings.ini~');
 3230 
 3231         //* copy the ISPConfig security part
 3232         $command = 'cp -rf ../security '.$install_dir;
 3233         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3234 
 3235         $configfile = 'security_settings.ini';
 3236         if(is_file($install_dir.'/security/'.$configfile)) {
 3237             copy($install_dir.'/security/'.$configfile, $install_dir.'/security/'.$configfile.'~');
 3238         }
 3239         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 3240         wf($install_dir.'/security/'.$configfile, $content);
 3241 
 3242         //* Create a symlink, so ISPConfig is accessible via web
 3243         // Replaced by a separate vhost definition for port 8080
 3244         // $command = "ln -s $install_dir/interface/web/ /var/www/ispconfig";
 3245         // caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3246 
 3247         //* Create the config file for ISPConfig interface
 3248         $configfile = 'config.inc.php';
 3249         if(is_file($install_dir.'/interface/lib/'.$configfile)) {
 3250             copy($install_dir.'/interface/lib/'.$configfile, $install_dir.'/interface/lib/'.$configfile.'~');
 3251         }
 3252         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 3253         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 3254         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 3255         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 3256         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 3257         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 3258 
 3259         $content = str_replace('{mysql_master_server_ispconfig_user}', $conf['mysql']['master_ispconfig_user'], $content);
 3260         $content = str_replace('{mysql_master_server_ispconfig_password}', $conf['mysql']['master_ispconfig_password'], $content);
 3261         $content = str_replace('{mysql_master_server_database}', $conf['mysql']['master_database'], $content);
 3262         $content = str_replace('{mysql_master_server_host}', $conf['mysql']['master_host'], $content);
 3263         $content = str_replace('{mysql_master_server_port}', $conf['mysql']['master_port'], $content);
 3264 
 3265         $content = str_replace('{server_id}', $conf['server_id'], $content);
 3266         $content = str_replace('{ispconfig_log_priority}', $conf['ispconfig_log_priority'], $content);
 3267         $content = str_replace('{language}', $conf['language'], $content);
 3268         $content = str_replace('{timezone}', $conf['timezone'], $content);
 3269         $content = str_replace('{theme}', $conf['theme'], $content);
 3270         $content = str_replace('{language_file_import_enabled}', ($conf['language_file_import_enabled'] == true)?'true':'false', $content);
 3271 
 3272         wf($install_dir.'/interface/lib/'.$configfile, $content);
 3273 
 3274         //* Create the config file for ISPConfig server
 3275         $configfile = 'config.inc.php';
 3276         if(is_file($install_dir.'/server/lib/'.$configfile)) {
 3277             copy($install_dir.'/server/lib/'.$configfile, $install_dir.'/interface/lib/'.$configfile.'~');
 3278         }
 3279         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/'.$configfile.'.master', 'tpl/'.$configfile.'.master');
 3280         $content = str_replace('{mysql_server_ispconfig_user}', $conf['mysql']['ispconfig_user'], $content);
 3281         $content = str_replace('{mysql_server_ispconfig_password}', $conf['mysql']['ispconfig_password'], $content);
 3282         $content = str_replace('{mysql_server_database}', $conf['mysql']['database'], $content);
 3283         $content = str_replace('{mysql_server_host}', $conf['mysql']['host'], $content);
 3284         $content = str_replace('{mysql_server_port}', $conf['mysql']['port'], $content);
 3285 
 3286         $content = str_replace('{mysql_master_server_ispconfig_user}', $conf['mysql']['master_ispconfig_user'], $content);
 3287         $content = str_replace('{mysql_master_server_ispconfig_password}', $conf['mysql']['master_ispconfig_password'], $content);
 3288         $content = str_replace('{mysql_master_server_database}', $conf['mysql']['master_database'], $content);
 3289         $content = str_replace('{mysql_master_server_host}', $conf['mysql']['master_host'], $content);
 3290         $content = str_replace('{mysql_master_server_port}', $conf['mysql']['master_port'], $content);
 3291 
 3292         $content = str_replace('{server_id}', $conf['server_id'], $content);
 3293         $content = str_replace('{ispconfig_log_priority}', $conf['ispconfig_log_priority'], $content);
 3294         $content = str_replace('{language}', $conf['language'], $content);
 3295         $content = str_replace('{timezone}', $conf['timezone'], $content);
 3296         $content = str_replace('{theme}', $conf['theme'], $content);
 3297         $content = str_replace('{language_file_import_enabled}', ($conf['language_file_import_enabled'] == true)?'true':'false', $content);
 3298 
 3299         wf($install_dir.'/server/lib/'.$configfile, $content);
 3300 
 3301         //* Create the config file for remote-actions (but only, if it does not exist, because
 3302         //  the value is a autoinc-value and so changed by the remoteaction_core_module
 3303         if (!file_exists($install_dir.'/server/lib/remote_action.inc.php')) {
 3304             $content = '<?php' . "\n" . '$maxid_remote_action = 0;' . "\n" . '?>';
 3305             wf($install_dir.'/server/lib/remote_action.inc.php', $content);
 3306         }
 3307 
 3308         //* Enable the server modules and plugins.
 3309         // TODO: Implement a selector which modules and plugins shall be enabled.
 3310         $dir = $install_dir.'/server/mods-available/';
 3311         if (is_dir($dir)) {
 3312             if ($dh = opendir($dir)) {
 3313                 while (($file = readdir($dh)) !== false) {
 3314                     if($file != '.' && $file != '..' && substr($file, -8, 8) == '.inc.php') {
 3315                         include_once $install_dir.'/server/mods-available/'.$file;
 3316                         $module_name = substr($file, 0, -8);
 3317                         $tmp = new $module_name;
 3318                         if($tmp->onInstall()) {
 3319                             if(!@is_link($install_dir.'/server/mods-enabled/'.$file)) {
 3320                                 @symlink($install_dir.'/server/mods-available/'.$file, $install_dir.'/server/mods-enabled/'.$file);
 3321                                 // @symlink($install_dir.'/server/mods-available/'.$file, '../mods-enabled/'.$file);
 3322                             }
 3323                             if (strpos($file, '_core_module') !== false) {
 3324                                 if(!@is_link($install_dir.'/server/mods-core/'.$file)) {
 3325                                     @symlink($install_dir.'/server/mods-available/'.$file, $install_dir.'/server/mods-core/'.$file);
 3326                                     // @symlink($install_dir.'/server/mods-available/'.$file, '../mods-core/'.$file);
 3327                                 }
 3328                             }
 3329                         }
 3330                         unset($tmp);
 3331                     }
 3332                 }
 3333                 closedir($dh);
 3334             }
 3335         }
 3336 
 3337         $dir = $install_dir.'/server/plugins-available/';
 3338         if (is_dir($dir)) {
 3339             if ($dh = opendir($dir)) {
 3340                 while (($file = readdir($dh)) !== false) {
 3341                     if($conf['apache']['installed'] == true && $file == 'nginx_plugin.inc.php') continue;
 3342                     if($conf['nginx']['installed'] == true && $file == 'apache2_plugin.inc.php') continue;
 3343                     if($file != '.' && $file != '..' && substr($file, -8, 8) == '.inc.php') {
 3344                         include_once $install_dir.'/server/plugins-available/'.$file;
 3345                         $plugin_name = substr($file, 0, -8);
 3346                         $tmp = new $plugin_name;
 3347                         if(method_exists($tmp, 'onInstall') && $tmp->onInstall()) {
 3348                             if(!@is_link($install_dir.'/server/plugins-enabled/'.$file)) {
 3349                                 @symlink($install_dir.'/server/plugins-available/'.$file, $install_dir.'/server/plugins-enabled/'.$file);
 3350                                 //@symlink($install_dir.'/server/plugins-available/'.$file, '../plugins-enabled/'.$file);
 3351                             }
 3352                             if (strpos($file, '_core_plugin') !== false) {
 3353                                 if(!@is_link($install_dir.'/server/plugins-core/'.$file)) {
 3354                                     @symlink($install_dir.'/server/plugins-available/'.$file, $install_dir.'/server/plugins-core/'.$file);
 3355                                     //@symlink($install_dir.'/server/plugins-available/'.$file, '../plugins-core/'.$file);
 3356                                 }
 3357                             }
 3358                         }
 3359                         unset($tmp);
 3360                     }
 3361                 }
 3362                 closedir($dh);
 3363             }
 3364         }
 3365 
 3366         // Update the server config
 3367         $mail_server_enabled = ($conf['services']['mail'])?1:0;
 3368         $web_server_enabled = ($conf['services']['web'])?1:0;
 3369         $dns_server_enabled = ($conf['services']['dns'])?1:0;
 3370         $file_server_enabled = ($conf['services']['file'])?1:0;
 3371         $db_server_enabled = ($conf['services']['db'])?1:0;
 3372         $vserver_server_enabled = ($conf['openvz']['installed'])?1:0;
 3373         $proxy_server_enabled = ($conf['services']['proxy'])?1:0;
 3374         $firewall_server_enabled = ($conf['services']['firewall'])?1:0;
 3375         $xmpp_server_enabled = ($conf['services']['xmpp'])?1:0;
 3376 
 3377         $sql = "UPDATE `server` SET mail_server = '$mail_server_enabled', web_server = '$web_server_enabled', dns_server = '$dns_server_enabled', file_server = '$file_server_enabled', db_server = '$db_server_enabled', vserver_server = '$vserver_server_enabled', proxy_server = '$proxy_server_enabled', firewall_server = '$firewall_server_enabled', xmpp_server = '$xmpp_server_enabled' WHERE server_id = ?";
 3378 
 3379         $this->db->query($sql, $conf['server_id']);
 3380         if($conf['mysql']['master_slave_setup'] == 'y') {
 3381             $this->dbmaster->query($sql, $conf['server_id']);
 3382         }
 3383 
 3384 
 3385         // chown install dir to root and chmod 755
 3386         $command = 'chown root:root '.$install_dir;
 3387         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3388         $command = 'chmod 755 '.$install_dir;
 3389         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3390 
 3391         //* Chmod the files and directories in the install dir
 3392         $command = 'chmod -R 750 '.$install_dir.'/*';
 3393         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3394 
 3395         //* chown the interface files to the ispconfig user and group
 3396         $command = 'chown -R ispconfig:ispconfig '.$install_dir.'/interface';
 3397         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3398 
 3399         //* Chmod the files and directories in the acme dir
 3400         $command = 'chmod -R 755 '.$install_dir.'/interface/acme';
 3401         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3402 
 3403         //* chown the server files to the root user and group
 3404         $command = 'chown -R root:root '.$install_dir.'/server';
 3405         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3406 
 3407         //* chown the security files to the root user and group
 3408         $command = 'chown -R root:root '.$install_dir.'/security';
 3409         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3410 
 3411         //* chown the security directory and security_settings.ini to root:ispconfig
 3412         $command = 'chown root:ispconfig '.$install_dir.'/security/security_settings.ini';
 3413         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3414         $command = 'chown root:ispconfig '.$install_dir.'/security';
 3415         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3416         $command = 'chown root:ispconfig '.$install_dir.'/security/ids.whitelist';
 3417         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3418         $command = 'chown root:ispconfig '.$install_dir.'/security/ids.htmlfield';
 3419         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3420         $command = 'chown root:ispconfig '.$install_dir.'/security/apache_directives.blacklist';
 3421         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3422         $command = 'chown root:ispconfig '.$install_dir.'/security/nginx_directives.blacklist';
 3423         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3424 
 3425         //* Make the global language file directory group writable
 3426         exec("chmod -R 770 $install_dir/interface/lib/lang");
 3427 
 3428         //* Make the temp directory for language file exports writable
 3429         if(is_dir($install_dir.'/interface/web/temp')) exec("chmod -R 770 $install_dir/interface/web/temp");
 3430 
 3431         //* Make all interface language file directories group writable
 3432         $handle = @opendir($install_dir.'/interface/web');
 3433         while ($file = @readdir($handle)) {
 3434             if ($file != '.' && $file != '..') {
 3435                 if(@is_dir($install_dir.'/interface/web'.'/'.$file.'/lib/lang')) {
 3436                     $handle2 = opendir($install_dir.'/interface/web'.'/'.$file.'/lib/lang');
 3437                     chmod($install_dir.'/interface/web'.'/'.$file.'/lib/lang', 0770);
 3438                     while ($lang_file = @readdir($handle2)) {
 3439                         if ($lang_file != '.' && $lang_file != '..') {
 3440                             chmod($install_dir.'/interface/web'.'/'.$file.'/lib/lang/'.$lang_file, 0770);
 3441                         }
 3442                     }
 3443                 }
 3444             }
 3445         }
 3446 
 3447         //* Make the APS directories group writable
 3448         exec("chmod -R 770 $install_dir/interface/web/sites/aps_meta_packages");
 3449         exec("chmod -R 770 $install_dir/server/aps_packages");
 3450 
 3451         //* make sure that the server config file (not the interface one) is only readable by the root user
 3452         chmod($install_dir.'/server/lib/config.inc.php', 0600);
 3453         chown($install_dir.'/server/lib/config.inc.php', 'root');
 3454         chgrp($install_dir.'/server/lib/config.inc.php', 'root');
 3455 
 3456         //* Make sure thet the interface config file is readable by user ispconfig only
 3457         chmod($install_dir.'/interface/lib/config.inc.php', 0600);
 3458         chown($install_dir.'/interface/lib/config.inc.php', 'ispconfig');
 3459         chgrp($install_dir.'/interface/lib/config.inc.php', 'ispconfig');
 3460 
 3461         chmod($install_dir.'/server/lib/remote_action.inc.php', 0600);
 3462         chown($install_dir.'/server/lib/remote_action.inc.php', 'root');
 3463         chgrp($install_dir.'/server/lib/remote_action.inc.php', 'root');
 3464 
 3465         if(@is_file($install_dir.'/server/lib/mysql_clientdb.conf')) {
 3466             chmod($install_dir.'/server/lib/mysql_clientdb.conf', 0600);
 3467             chown($install_dir.'/server/lib/mysql_clientdb.conf', 'root');
 3468             chgrp($install_dir.'/server/lib/mysql_clientdb.conf', 'root');
 3469         }
 3470 
 3471         if(is_dir($install_dir.'/interface/invoices')) {
 3472             exec('chmod -R 770 '.escapeshellarg($install_dir.'/interface/invoices'));
 3473             exec('chown -R ispconfig:ispconfig '.escapeshellarg($install_dir.'/interface/invoices'));
 3474         }
 3475 
 3476         exec('chown -R root:root /usr/local/ispconfig/interface/ssl');
 3477 
 3478         // TODO: FIXME: add the www-data user to the ispconfig group. This is just for testing
 3479         // and must be fixed as this will allow the apache user to read the ispconfig files.
 3480         // Later this must run as own apache server or via suexec!
 3481         if($conf['apache']['installed'] == true){
 3482             $command = 'adduser '.$conf['apache']['user'].' ispconfig';
 3483             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3484             if(is_group('ispapps')){
 3485                 $command = 'adduser '.$conf['apache']['user'].' ispapps';
 3486                 caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3487             }
 3488         }
 3489         if($conf['nginx']['installed'] == true){
 3490             $command = 'adduser '.$conf['nginx']['user'].' ispconfig';
 3491             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3492             if(is_group('ispapps')){
 3493                 $command = 'adduser '.$conf['nginx']['user'].' ispapps';
 3494                 caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3495             }
 3496         }
 3497 
 3498         //* Make the shell scripts executable
 3499         $command = "chmod +x $install_dir/server/scripts/*.sh";
 3500         caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3501 
 3502         if ($this->install_ispconfig_interface == true && isset($conf['interface_password']) && $conf['interface_password']!='admin') {
 3503             $sql = "UPDATE sys_user SET passwort = ? WHERE username = 'admin';";
 3504             $this->db->query($sql, $this->crypt_password($conf['interface_password']));
 3505         }
 3506 
 3507         if($conf['apache']['installed'] == true && $this->install_ispconfig_interface == true){
 3508             //* Copy the ISPConfig vhost for the controlpanel
 3509             $vhost_conf_dir = $conf['apache']['vhost_conf_dir'];
 3510             $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir'];
 3511 
 3512             // Dont just copy over the virtualhost template but add some custom settings
 3513             $tpl = new tpl('apache_ispconfig.vhost.master');
 3514             $tpl->setVar('vhost_port',$conf['apache']['vhost_port']);
 3515 
 3516             // comment out the listen directive if port is 80 or 443
 3517             if($conf['apache']['vhost_port'] == 80 or $conf['apache']['vhost_port'] == 443) {
 3518                 $tpl->setVar('vhost_port_listen','#');
 3519             } else {
 3520                 $tpl->setVar('vhost_port_listen','');
 3521             }
 3522 
 3523             if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key')) {
 3524                 $tpl->setVar('ssl_comment','');
 3525             } else {
 3526                 $tpl->setVar('ssl_comment','#');
 3527             }
 3528             if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key') && is_file($install_dir.'/interface/ssl/ispserver.bundle')) {
 3529                 $tpl->setVar('ssl_bundle_comment','');
 3530             } else {
 3531                 $tpl->setVar('ssl_bundle_comment','#');
 3532             }
 3533 
 3534             $tpl->setVar('apache_version',getapacheversion());
 3535 
 3536             wf($vhost_conf_dir.'/ispconfig.vhost', $tpl->grab());
 3537 
 3538             //* and create the symlink
 3539             if($this->is_update == false) {
 3540                 if(@is_link($vhost_conf_enabled_dir.'/ispconfig.vhost')) unlink($vhost_conf_enabled_dir.'/ispconfig.vhost');
 3541                 if(!@is_link($vhost_conf_enabled_dir.'/000-ispconfig.vhost')) {
 3542                     symlink($vhost_conf_dir.'/ispconfig.vhost', $vhost_conf_enabled_dir.'/000-ispconfig.vhost');
 3543                 }
 3544             }
 3545             //if(!is_file('/var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter')) {
 3546             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig_fcgi_starter.master', 'tpl/apache_ispconfig_fcgi_starter.master');
 3547             $content = str_replace('{fastcgi_bin}', $conf['fastcgi']['fastcgi_bin'], $content);
 3548             $content = str_replace('{fastcgi_phpini_path}', $conf['fastcgi']['fastcgi_phpini_path'], $content);
 3549             @mkdir('/var/www/php-fcgi-scripts/ispconfig', 0755, true);
 3550             $this->set_immutable('/var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter', false);
 3551             wf('/var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter', $content);
 3552             exec('chmod +x /var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter');
 3553             @symlink($install_dir.'/interface/web', '/var/www/ispconfig');
 3554             exec('chown -R ispconfig:ispconfig /var/www/php-fcgi-scripts/ispconfig');
 3555             $this->set_immutable('/var/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter', true);
 3556             //}
 3557         }
 3558 
 3559         if($conf['nginx']['installed'] == true && $this->install_ispconfig_interface == true){
 3560             //* Copy the ISPConfig vhost for the controlpanel
 3561             $vhost_conf_dir = $conf['nginx']['vhost_conf_dir'];
 3562             $vhost_conf_enabled_dir = $conf['nginx']['vhost_conf_enabled_dir'];
 3563 
 3564             // Dont just copy over the virtualhost template but add some custom settings
 3565             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/nginx_ispconfig.vhost.master', 'tpl/nginx_ispconfig.vhost.master');
 3566             $content = str_replace('{vhost_port}', $conf['nginx']['vhost_port'], $content);
 3567 
 3568             if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key')) {
 3569                 $content = str_replace('{ssl_on}', 'ssl http2', $content);
 3570                 $content = str_replace('{ssl_comment}', '', $content);
 3571                 $content = str_replace('{fastcgi_ssl}', 'on', $content);
 3572             } else {
 3573                 $content = str_replace('{ssl_on}', '', $content);
 3574                 $content = str_replace('{ssl_comment}', '#', $content);
 3575                 $content = str_replace('{fastcgi_ssl}', 'off', $content);
 3576             }
 3577 
 3578             $socket_dir = escapeshellcmd($conf['nginx']['php_fpm_socket_dir']);
 3579             if(substr($socket_dir, -1) != '/') $socket_dir .= '/';
 3580             if(!is_dir($socket_dir)) exec('mkdir -p '.$socket_dir);
 3581             $fpm_socket = $socket_dir.'ispconfig.sock';
 3582 
 3583             //$content = str_replace('{fpm_port}', $conf['nginx']['php_fpm_start_port'], $content);
 3584             $content = str_replace('{fpm_socket}', $fpm_socket, $content);
 3585 
 3586             wf($vhost_conf_dir.'/ispconfig.vhost', $content);
 3587 
 3588             unset($content);
 3589 
 3590             // PHP-FPM
 3591             // Dont just copy over the php-fpm pool template but add some custom settings
 3592             $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/php_fpm_pool.conf.master', 'tpl/php_fpm_pool.conf.master');
 3593             $content = str_replace('{fpm_pool}', 'ispconfig', $content);
 3594             //$content = str_replace('{fpm_port}', $conf['nginx']['php_fpm_start_port'], $content);
 3595             $content = str_replace('{fpm_socket}', $fpm_socket, $content);
 3596             $content = str_replace('{fpm_user}', 'ispconfig', $content);
 3597             $content = str_replace('{fpm_group}', 'ispconfig', $content);
 3598             wf($conf['nginx']['php_fpm_pool_dir'].'/ispconfig.conf', $content);
 3599 
 3600             //copy('tpl/nginx_ispconfig.vhost.master', $vhost_conf_dir.'/ispconfig.vhost');
 3601             //* and create the symlink
 3602             if($this->is_update == false) {
 3603                 if(@is_link($vhost_conf_enabled_dir.'/ispconfig.vhost')) unlink($vhost_conf_enabled_dir.'/ispconfig.vhost');
 3604                 if(!@is_link($vhost_conf_enabled_dir.'/000-ispconfig.vhost')) {
 3605                     symlink($vhost_conf_dir.'/ispconfig.vhost', $vhost_conf_enabled_dir.'/000-ispconfig.vhost');
 3606                 }
 3607             }
 3608         }
 3609 
 3610         //* Install the update script
 3611         if(is_file('/usr/local/bin/ispconfig_update_from_dev.sh')) unlink('/usr/local/bin/ispconfig_update_from_dev.sh');
 3612         chown($install_dir.'/server/scripts/update_from_dev.sh', 'root');
 3613         chmod($install_dir.'/server/scripts/update_from_dev.sh', 0700);
 3614 //      chown($install_dir.'/server/scripts/update_from_tgz.sh', 'root');
 3615 //      chmod($install_dir.'/server/scripts/update_from_tgz.sh', 0700);
 3616         chown($install_dir.'/server/scripts/ispconfig_update.sh', 'root');
 3617         chmod($install_dir.'/server/scripts/ispconfig_update.sh', 0700);
 3618         if(!is_link('/usr/local/bin/ispconfig_update_from_dev.sh')) symlink($install_dir.'/server/scripts/ispconfig_update.sh', '/usr/local/bin/ispconfig_update_from_dev.sh');
 3619         if(!is_link('/usr/local/bin/ispconfig_update.sh')) symlink($install_dir.'/server/scripts/ispconfig_update.sh', '/usr/local/bin/ispconfig_update.sh');
 3620 
 3621         // Make executable then unlink and symlink letsencrypt pre, post and renew hook scripts
 3622         chown($install_dir.'/server/scripts/letsencrypt_pre_hook.sh', 'root');
 3623         chown($install_dir.'/server/scripts/letsencrypt_post_hook.sh', 'root');
 3624         chown($install_dir.'/server/scripts/letsencrypt_renew_hook.sh', 'root');
 3625         chmod($install_dir.'/server/scripts/letsencrypt_pre_hook.sh', 0700);
 3626         chmod($install_dir.'/server/scripts/letsencrypt_post_hook.sh', 0700);
 3627         chmod($install_dir.'/server/scripts/letsencrypt_renew_hook.sh', 0700);
 3628         if(is_link('/usr/local/bin/letsencrypt_pre_hook.sh')) unlink('/usr/local/bin/letsencrypt_pre_hook.sh');
 3629         if(is_link('/usr/local/bin/letsencrypt_post_hook.sh')) unlink('/usr/local/bin/letsencrypt_post_hook.sh');
 3630         if(is_link('/usr/local/bin/letsencrypt_renew_hook.sh')) unlink('/usr/local/bin/letsencrypt_renew_hook.sh');
 3631         symlink($install_dir.'/server/scripts/letsencrypt_pre_hook.sh', '/usr/local/bin/letsencrypt_pre_hook.sh');
 3632         symlink($install_dir.'/server/scripts/letsencrypt_post_hook.sh', '/usr/local/bin/letsencrypt_post_hook.sh');
 3633         symlink($install_dir.'/server/scripts/letsencrypt_renew_hook.sh', '/usr/local/bin/letsencrypt_renew_hook.sh');
 3634 
 3635         //* Make the logs readable for the ispconfig user
 3636         if(@is_file('/var/log/mail.log')) exec('chmod +r /var/log/mail.log');
 3637         if(@is_file('/var/log/mail.warn')) exec('chmod +r /var/log/mail.warn');
 3638         if(@is_file('/var/log/mail.err')) exec('chmod +r /var/log/mail.err');
 3639         if(@is_file('/var/log/messages')) exec('chmod +r /var/log/messages');
 3640         if(@is_file('/var/log/clamav/clamav.log')) exec('chmod +r /var/log/clamav/clamav.log');
 3641         if(@is_file('/var/log/clamav/freshclam.log')) exec('chmod +r /var/log/clamav/freshclam.log');
 3642 
 3643         //* Create the ispconfig log file and directory
 3644         if(!is_file($conf['ispconfig_log_dir'].'/ispconfig.log')) {
 3645             if(!is_dir($conf['ispconfig_log_dir'])) mkdir($conf['ispconfig_log_dir'], 0755);
 3646             touch($conf['ispconfig_log_dir'].'/ispconfig.log');
 3647         }
 3648         chmod($conf['ispconfig_log_dir'].'/ispconfig.log', 0600);
 3649 
 3650         //* Create the ispconfig auth log file and set uid/gid
 3651         if(!is_file($conf['ispconfig_log_dir'].'/auth.log')) {
 3652             touch($conf['ispconfig_log_dir'].'/auth.log');
 3653         }
 3654         exec('chown ispconfig:ispconfig '. $conf['ispconfig_log_dir'].'/auth.log');
 3655         exec('chmod 660 '. $conf['ispconfig_log_dir'].'/auth.log');
 3656 
 3657         if(is_user('getmail')) {
 3658             rename($install_dir.'/server/scripts/run-getmail.sh', '/usr/local/bin/run-getmail.sh');
 3659             if(is_user('getmail')) chown('/usr/local/bin/run-getmail.sh', 'getmail');
 3660             chmod('/usr/local/bin/run-getmail.sh', 0744);
 3661         }
 3662 
 3663         //* Add Log-Rotation
 3664         if (is_dir('/etc/logrotate.d')) {
 3665             @unlink('/etc/logrotate.d/logispc3'); // ignore, if the file is not there
 3666             /* We rotate these logs in cron_daily.php
 3667             $fh = fopen('/etc/logrotate.d/logispc3', 'w');
 3668             fwrite($fh,
 3669                     "$conf['ispconfig_log_dir']/ispconfig.log { \n" .
 3670                     "   weekly \n" .
 3671                     "   missingok \n" .
 3672                     "   rotate 4 \n" .
 3673                     "   compress \n" .
 3674                     "   delaycompress \n" .
 3675                     "} \n" .
 3676                     "$conf['ispconfig_log_dir']/cron.log { \n" .
 3677                     "   weekly \n" .
 3678                     "   missingok \n" .
 3679                     "   rotate 4 \n" .
 3680                     "   compress \n" .
 3681                     "   delaycompress \n" .
 3682                     "}");
 3683             fclose($fh);
 3684             */
 3685         }
 3686 
 3687         //* Remove Domain module as its functions are available in the client module now
 3688         if(@is_dir('/usr/local/ispconfig/interface/web/domain')) exec('rm -rf /usr/local/ispconfig/interface/web/domain');
 3689 
 3690         //* Disable rkhunter run and update in debian cronjob as ispconfig is running and updating rkhunter
 3691         if(is_file('/etc/default/rkhunter')) {
 3692             replaceLine('/etc/default/rkhunter', 'CRON_DAILY_RUN="yes"', 'CRON_DAILY_RUN="no"', 1, 0);
 3693             replaceLine('/etc/default/rkhunter', 'CRON_DB_UPDATE="yes"', 'CRON_DB_UPDATE="no"', 1, 0);
 3694         }
 3695 
 3696         // Add symlink for patch tool
 3697         if(!is_link('/usr/local/bin/ispconfig_patch')) exec('ln -s /usr/local/ispconfig/server/scripts/ispconfig_patch /usr/local/bin/ispconfig_patch');
 3698 
 3699         // Change mode of a few files from amavisd
 3700         if(is_file($conf['amavis']['config_dir'].'/conf.d/50-user')) chmod($conf['amavis']['config_dir'].'/conf.d/50-user', 0640);
 3701         if(is_file($conf['amavis']['config_dir'].'/50-user~')) chmod($conf['amavis']['config_dir'].'/50-user~', 0400);
 3702         if(is_file($conf['amavis']['config_dir'].'/amavisd.conf')) chmod($conf['amavis']['config_dir'].'/amavisd.conf', 0640);
 3703         if(is_file($conf['amavis']['config_dir'].'/amavisd.conf~')) chmod($conf['amavis']['config_dir'].'/amavisd.conf~', 0400);
 3704     }
 3705 
 3706     public function configure_dbserver() {
 3707         global $conf;
 3708 
 3709         //* If this server shall act as database server for client DB's, we configure this here
 3710         $install_dir = $conf['ispconfig_install_dir'];
 3711 
 3712         // Create a file with the database login details which
 3713         // are used to create the client databases.
 3714 
 3715         if(!is_dir($install_dir.'/server/lib')) {
 3716             $command = "mkdir $install_dir/server/lib";
 3717             caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
 3718         }
 3719 
 3720         $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/mysql_clientdb.conf.master', 'tpl/mysql_clientdb.conf.master');
 3721         $content = str_replace('{hostname}', $conf['mysql']['host'], $content);
 3722         $content = str_replace('{username}', $conf['mysql']['admin_user'], $content);
 3723         $content = str_replace('{password}', addslashes($conf['mysql']['admin_password']), $content);
 3724         wf($install_dir.'/server/lib/mysql_clientdb.conf', $content);
 3725         chmod($install_dir.'/server/lib/mysql_clientdb.conf', 0600);
 3726         chown($install_dir.'/server/lib/mysql_clientdb.conf', 'root');
 3727         chgrp($install_dir.'/server/lib/mysql_clientdb.conf', 'root');
 3728 
 3729     }
 3730 
 3731     public function install_crontab() {
 3732         global $conf;
 3733 
 3734         $install_dir = $conf['ispconfig_install_dir'];
 3735 
 3736         //* Root Crontab
 3737         exec('crontab -u root -l > crontab.txt');
 3738         $existing_root_cron_jobs = file('crontab.txt');
 3739 
 3740         // remove existing ispconfig cronjobs, in case the syntax has changed
 3741         foreach($existing_root_cron_jobs as $key => $val) {
 3742             if(stristr($val, $install_dir)) unset($existing_root_cron_jobs[$key]);
 3743         }
 3744 
 3745         $root_cron_jobs = array(
 3746             "* * * * * ".$install_dir."/server/server.sh 2>&1 | while read line; do echo `/bin/date` \"\$line\" >> ".$conf['ispconfig_log_dir']."/cron.log; done",
 3747             "* * * * * ".$install_dir."/server/cron.sh 2>&1 | while read line; do echo `/bin/date` \"\$line\" >> ".$conf['ispconfig_log_dir']."/cron.log; done"
 3748         );
 3749 
 3750         if ($conf['nginx']['installed'] == true) {
 3751             $root_cron_jobs[] = "0 0 * * * ".$install_dir."/server/scripts/create_daily_nginx_access_logs.sh &> /dev/null";
 3752         }
 3753 
 3754         foreach($root_cron_jobs as $cron_job) {
 3755             if(!in_array($cron_job."\n", $existing_root_cron_jobs)) {
 3756                 $existing_root_cron_jobs[] = $cron_job."\n";
 3757             }
 3758         }
 3759         file_put_contents('crontab.txt', $existing_root_cron_jobs);
 3760         exec('crontab -u root crontab.txt &> /dev/null');
 3761         unlink('crontab.txt');
 3762 
 3763         //* Getmail crontab
 3764         if(is_user('getmail')) {
 3765             $cf = $conf['getmail'];
 3766             exec('crontab -u getmail -l > crontab.txt');
 3767             $existing_cron_jobs = file('crontab.txt');
 3768 
 3769             $cron_jobs = array(
 3770                 '*/5 * * * * /usr/local/bin/run-getmail.sh > /dev/null 2>> /dev/null'
 3771             );
 3772 
 3773             // remove existing ispconfig cronjobs, in case the syntax has changed
 3774             foreach($existing_cron_jobs as $key => $val) {
 3775                 if(stristr($val, 'getmail')) unset($existing_cron_jobs[$key]);
 3776             }
 3777 
 3778             foreach($cron_jobs as $cron_job) {
 3779                 if(!in_array($cron_job."\n", $existing_cron_jobs)) {
 3780                     $existing_cron_jobs[] = $cron_job."\n";
 3781                 }
 3782             }
 3783             file_put_contents('crontab.txt', $existing_cron_jobs);
 3784             exec('crontab -u getmail crontab.txt &> /dev/null');
 3785             unlink('crontab.txt');
 3786         }
 3787 
 3788         touch($conf['ispconfig_log_dir'].'/cron.log');
 3789         chmod($conf['ispconfig_log_dir'].'/cron.log', 0660);
 3790 
 3791     }
 3792 
 3793     public function create_mount_script(){
 3794         global $app, $conf;
 3795         $mount_script = '/usr/local/ispconfig/server/scripts/backup_dir_mount.sh';
 3796         $mount_command = '';
 3797 
 3798         if(is_file($mount_script)) return;
 3799         if(is_file('/etc/rc.local')){
 3800             $rc_local = file('/etc/rc.local');
 3801             if(is_array($rc_local) && !empty($rc_local)){
 3802                 foreach($rc_local as $line){
 3803                     $line = trim($line);
 3804                     if(substr($line, 0, 1) == '#') continue;
 3805                     if(strpos($line, 'sshfs') !== false && strpos($line, '/var/backup') !== false){
 3806                         $mount_command = "#!/bin/sh\n\n";
 3807                         $mount_command .= $line."\n\n";
 3808                         file_put_contents($mount_script, $mount_command);
 3809                         chmod($mount_script, 0755);
 3810                         chown($mount_script, 'root');
 3811                         chgrp($mount_script, 'root');
 3812                         break;
 3813                     }
 3814                 }
 3815             }
 3816         }
 3817     }
 3818 
 3819     // This function is called at the end of the update process and contains code to clean up parts of old ISPCONfig releases
 3820     public function cleanup_ispconfig() {
 3821         global $app,$conf;
 3822 
 3823         // Remove directories recursively
 3824         if(is_dir('/usr/local/ispconfig/interface/web/designer')) exec('rm -rf /usr/local/ispconfig/interface/web/designer');
 3825         if(is_dir('/usr/local/ispconfig/interface/web/themes/default-304')) exec('rm -rf /usr/local/ispconfig/interface/web/themes/default-304');
 3826 
 3827         // Remove files
 3828         if(is_file('/usr/local/ispconfig/interface/lib/classes/db_firebird.inc.php')) unlink('/usr/local/ispconfig/interface/lib/classes/db_firebird.inc.php');
 3829         if(is_file('/usr/local/ispconfig/interface/lib/classes/form.inc.php')) unlink('/usr/local/ispconfig/interface/lib/classes/form.inc.php');
 3830 
 3831         // Change mode of a few files from amavisd
 3832         if(is_file($conf['amavis']['config_dir'].'/conf.d/50-user'