<?php

/*
  ----------------------------------------------------------------------
  LICENSE

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License (GPL)
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  To read the license please visit http://www.gnu.org/copyleft/gpl.html
  ----------------------------------------------------------------------
*/

/**
 * Manages APACHE 2.4+ vhosts templates in AlternC 3.5+
 * 
 * @copyright AlternC-Team 2000-2018 https://alternc.com/
 */
class m_apache {

    var $shouldreload;

    // only values allowed for https in subdomaines table.
    var $httpsmodes=array("http","https","both"); 
    
    // Slave AlternC instances can know the last reload time thanks to this
    var $reloadfile="/run/alternc/apache-reload";
    // Where do we find apache template files ?
    var $templatedir="/etc/alternc/templates/apache2";
    // Where do we store all Apache vhosts ?
    var $vhostroot="/var/lib/alternc/apache-vhost/";

    var $port_http_default="80";
    var $port_https_default="443";

    // launched before any action by updatedomains
    function hook_updatedomains_web_pre() {
        $this->shouldreload=false;
    }

    // launched for each FQDN for which we want a new vhost template 
    function hook_updatedomains_web_add($subdomid) {
        global $msg,$db,$ssl,$L_FQDN;

        $db->query("SELECT sd.*, dt.only_dns, dt.has_https_option, m.login FROM domaines_type dt, sub_domaines sd LEFT JOIN membres m ON m.uid=sd.compte WHERE dt.name=sd.type AND sd.web_action!='OK' AND id=?;",array($subdomid));
        $db->next_record();
        $subdom=$db->Record;

        // security : only AlternC account's UIDs
        if ($subdom["compte"]<1999) {
            $msg->raise("ERROR","apache","Subdom ".$subdom["id"]." for domain ".$subdom["sub"].".".$subdom["domaine"]." has id ".$subdom["compte"].". Skipped");
            return 1;
        }

        // search for the template file:
        $template = $this->templatedir."/".strtolower($subdom["type"]);
        if ($subdom["has_https_option"] && in_array($subdom["https"],$this->httpsmodes)) {
            $template.="-".$subdom["https"];
        }
        $template.=".conf";
        if (!is_file($template)) {
            $msg->raise("ERROR","apache","Template $template not found for subdom ".$subdom["id"]." for domain ".$subdom["sub"].".".$subdom["domaine"].". Skipped");
            return 1;
        }

        $subdom["fqdn"]=$subdom["sub"].(($subdom["sub"])?".":"").$subdom["domaine"];
        // SSL information $subdom["certificate_id"] may be ZERO => it means "take id 0 which is snakeoil cert"
        $cert = $ssl->get_certificate_path($subdom["certificate_id"]);
        if ($cert["chain"]) {
            $chainline="SSLCertificateChainFile ".$cert["chain"];
        } else {
            $chainline="";
        }

        //Retrieve APACHE port value
        $port_http  = (!empty($GLOBALS['L_APACHE_PORT_HTTP']) && intval($GLOBALS['L_APACHE_PORT_HTTP']) > 0) ? intval($GLOBALS['L_APACHE_PORT_HTTP']) :  $this->port_http_default;
        $port_https  = (!empty($GLOBALS['L_APACHE_PORT_HTTPS']) && intval($GLOBALS['L_APACHE_PORT_HTTPS']) > 0) ? intval($GLOBALS['L_APACHE_PORT_HTTPS']) : $this->port_https_default;

        // Replace needed vars in template file
        $tpl=file_get_contents($template);
        $tpl = strtr($tpl, array(
            "%%PORT_HTTP%%" => $port_http,
            "%%PORT_HTTPS%%" => $port_https,
            "%%LOGIN%%" => $subdom['login'],
            "%%fqdn%%" => $subdom['fqdn'],
            "%%document_root%%" => getuserpath($subdom['login']) . $subdom['valeur'],
            "%%account_root%%" => getuserpath($subdom['login']),
            "%%redirect%%" => $subdom['valeur'],
            "%%UID%%" => $subdom['compte'],
            "%%GID%%" => $subdom['compte'],
            "%%mail_account%%" => $subdom['login']."@".$L_FQDN,
            "%%user%%" => "FIXME",
            "%%CRT%%" => $cert["cert"],
            "%%KEY%%" => $cert["key"],
            "%%CHAINLINE%%" => $chainline,
        ));
        // and write the template
        $confdir = $this->vhostroot."/".substr($subdom["compte"],-1)."/".$subdom["compte"];
        @mkdir($confdir,0755,true);
        file_put_contents($confdir."/".$subdom["fqdn"].".conf",$tpl);
        $this->shouldreload=true;

        return 0; // shell meaning => OK ;) 
    } // hook_updatedomains_web_add


    // ------------------------------------------------------------
    /**
     *  launched for each FQDN for which we want to delete a vhost template 
     */
    function hook_updatedomains_web_del($subdomid) {
        global $db,$msg;
        $db->query("SELECT sd.*, dt.only_dns, dt.has_https_option, m.login FROM domaines_type dt, sub_domaines sd LEFT JOIN membres m ON m.uid=sd.compte WHERE dt.name=sd.type AND sd.web_action!='OK' AND id=?;",array($subdomid));
        $db->next_record();
        $subdom=$db->Record;
        $confdir = $this->vhostroot."/".substr($subdom["compte"],-1)."/".$subdom["compte"];
        $deleteme= $subdom["sub"].(($subdom["sub"])?".":"").$subdom["domaine"].".conf";
        @unlink($confdir."/".$deleteme);
        $this->shouldreload=true;
        return 0;
    }

    
    // ------------------------------------------------------------
    /** 
     * launched at the very end of updatedomains 
     */
    function hook_updatedomains_web_post() {
        global $msg;
        if ($this->shouldreload) {

            // concatenate all files into one
            $this->concat();

            // reload apache 
            $ret=0;
            exec("apache2ctl graceful 2>&1",$out,$ret);
            touch($this->reloadfile);
            if ($ret!=0) {
                $msg->raise("ERROR","apache","Error while reloading apache, error code is $ret\n".implode("\n",$out));
            } else {
                $msg->raise("INFO","apache","Apache reloaded");
            }
        }
        
    }

    // ------------------------------------------------------------
    /** 
     * Concatenate all files under $this->vhostroot
     * into one (mindepth=2 though), 
     * this function is faster than any shell stuff :D 
     */
    private function concat() {
        global $msg;
        $d=opendir($this->vhostroot);
        $f=fopen($this->vhostroot."/vhosts_all.conf.new","wb");
        if (!$f) {
            $msg->raise("FATAL","apache","Can't write vhosts_all file");
            return false;
        }
        while (($c=readdir($d))!==false) {
            if (substr($c,0,1)!="." && is_dir($this->vhostroot."/".$c)) {
                $this->subconcat($f,$this->vhostroot."/".$c);
            }
        }
        closedir($d);
        fclose($f);
        rename($this->vhostroot."/vhosts_all.conf.new", $this->vhostroot."/vhosts_all.conf");
    }
    
    private function subconcat($f,$root) {
        // recursive cat :)
        $d=opendir($root);
        while (($c=readdir($d))!==false) {
            if (substr($c,0,1)!=".") {
                if (is_dir($root."/".$c)) {
                    $this->subconcat($f,$root."/".$c); // RECURSIVE CALL
                }
                if (is_file($root."/".$c)) {
                    fputs($f,file_get_contents($root."/".$c)."\n");
                }
            }
        }
        closedir($d);
    }
    
} // m_apache

