[enh] adding DKIM and AUTODISCOVER management in SUB_DOMAINES, finishing BIND update_domains.php
This commit is contained in:
		
							parent
							
								
									ed7aaa3151
								
							
						
					
					
						commit
						9b7332f354
					
				| 
						 | 
				
			
			@ -1245,3 +1245,54 @@ function _dovecot_hash($password) {
 | 
			
		|||
    $hash = _sha512cr($password);
 | 
			
		||||
    return '{SHA512-CRYPT}' . $hash;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
// ------------------------------------------------------------
 | 
			
		||||
/** 
 | 
			
		||||
 * Add the line of text $line into file $file.
 | 
			
		||||
 * do not duplicate (check)
 | 
			
		||||
 * @param $file string the full path to the file where we should add the line
 | 
			
		||||
 * @param $line string the line to add (without the termination \n, WILL BE ADDED)
 | 
			
		||||
 * @return boolean TRUE if the line has been added, or FALSE if the line ALREADY EXISTED
 | 
			
		||||
 */ 
 | 
			
		||||
function add_line_to_file($file,$line) {
 | 
			
		||||
    $f=fopen($file,"rb");
 | 
			
		||||
    $found=false;
 | 
			
		||||
    while($s=fgets($f,1024)) {
 | 
			
		||||
        if (trim($s)==$line) {
 | 
			
		||||
            $found=true;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fclose($f);
 | 
			
		||||
    $f=fopen($file,"ab");
 | 
			
		||||
    fputs($f,trim($line)."\n");
 | 
			
		||||
    fclose($f);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------
 | 
			
		||||
/** 
 | 
			
		||||
 * Remove the line of text $line from file $file.
 | 
			
		||||
 * @param $file string the full path to the file where we should remove the line
 | 
			
		||||
 * @param $line string the line to add (without the termination \n, WILL BE REMOVED)
 | 
			
		||||
 * @return boolean TRUE if the line has been found and removed, or FALSE if the line DIDN'T EXIST
 | 
			
		||||
 */ 
 | 
			
		||||
function del_line_from_file($file,$line) {
 | 
			
		||||
    $f=fopen($file,"rb");
 | 
			
		||||
    $g=fopen($file.".new","wb");
 | 
			
		||||
    $found=false;
 | 
			
		||||
    while($s=fgets($f,1024)) {
 | 
			
		||||
        if (trim($s)!=$line) {
 | 
			
		||||
            fputs($g,$s);
 | 
			
		||||
        } else {
 | 
			
		||||
            $found=true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fclose($f);
 | 
			
		||||
    fclose($g);
 | 
			
		||||
    rename($file.".new",$file); // overwrite atomically
 | 
			
		||||
    return $found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,41 +27,132 @@ class m_bind {
 | 
			
		|||
 | 
			
		||||
    var $shouldreload;
 | 
			
		||||
    var $shouldreconfig;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    var $ZONE_TEMPLATE ="/etc/alternc/templates/bind/templates/zone.template";
 | 
			
		||||
    var $NAMED_TEMPLATE ="/etc/alternc/templates/bind/templates/named.template";
 | 
			
		||||
    var $NAMED_CONF ="/var/lib/alternc/bind/automatic.conf";
 | 
			
		||||
    var $RNDC ="/usr/sbin/rndc";
 | 
			
		||||
 | 
			
		||||
    var $dkim_trusted_host_file = "/etc/opendkim/TrustedHosts";
 | 
			
		||||
    var $dkim_keytable_file = "/etc/opendkim/KeyTable";
 | 
			
		||||
    var $dkim_signingtable_file = "/etc/opendkim/SigningTable";
 | 
			
		||||
    var $zone_file_directory = '/var/lib/alternc/bind/zones';
 | 
			
		||||
 | 
			
		||||
    var $cache_conf_db = array();
 | 
			
		||||
    var $cache_get_persistent = array();
 | 
			
		||||
    var $cache_zone_file = array();
 | 
			
		||||
    var $cache_domain_summary = array();
 | 
			
		||||
    var $zone_file_directory = '/var/lib/alternc/bind/zones/';
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // launched before any action by updatedomains 
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** Hook launched before any action by updatedomains 
 | 
			
		||||
     * initialize the reload/reconfig flags used by POST
 | 
			
		||||
     * @NOTE launched as ROOT 
 | 
			
		||||
     */
 | 
			
		||||
    function hook_updatedomains_dns_pre() {
 | 
			
		||||
        $this->shouldreload=false;
 | 
			
		||||
        $this->shouldreconfig=false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // launched for each ZONE for which we want a zone update (or create)
 | 
			
		||||
    function hook_updatedomains_dns_add($domain) {
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * Hook launched for each ZONE for which we want a zone update (or create)
 | 
			
		||||
     * update the zone, create it if necessary, 
 | 
			
		||||
     * and ask for reload or reconfig of bind9 depending on what happened
 | 
			
		||||
     * @NOTE launched as ROOT 
 | 
			
		||||
     */
 | 
			
		||||
    function hook_updatedomains_dns_add($dominfo) {
 | 
			
		||||
        global $L_FQDN,$L_NS1_HOSTNAME,$L_NS2_HOSTNAME,$L_DEFAULT_MX,$L_DEFAULT_SECONDARY_MX,$L_PUBLIC_IP,$L_PUBLIC_IPV6;
 | 
			
		||||
 | 
			
		||||
        $domain = $dominfo["domaine"];
 | 
			
		||||
        $ttl = $dominfo["zonettl"];
 | 
			
		||||
 | 
			
		||||
        // does it already exist?
 | 
			
		||||
        if (file_exists($this->zone_file_directory."/".$domain)) {
 | 
			
		||||
            list($islocked,$serial,$more)=$this->read_zone($domain);
 | 
			
		||||
            $serial++; // only increment serial for new zones
 | 
			
		||||
        } else {
 | 
			
		||||
            $more="";
 | 
			
		||||
            $serial=date("Ymd")."00";
 | 
			
		||||
            $islocked=false;
 | 
			
		||||
        }
 | 
			
		||||
        if ($islocked) return;
 | 
			
		||||
 | 
			
		||||
        // Prepare a new zonefile from a template
 | 
			
		||||
        $zone = file_get_contents($this->ZONE_TEMPLATE);
 | 
			
		||||
        // substitute ALTERNC & domain variables
 | 
			
		||||
        $zone = strtr($zone, array(
 | 
			
		||||
            "%%fqdn%%" => "$L_FQDN",
 | 
			
		||||
            "%%ns1%%" => "$L_NS1_HOSTNAME",
 | 
			
		||||
            "%%ns2%%" => "$L_NS2_HOSTNAME",
 | 
			
		||||
            "%%DEFAULT_MX%%" => "$L_DEFAULT_MX",
 | 
			
		||||
            "%%DEFAULT_SECONDARY_MX%%" => "$L_DEFAULT_SECONDARY_MX",
 | 
			
		||||
            "@@fqdn@@" => "$L_FQDN",
 | 
			
		||||
            "@@ns1@@" => "$L_NS1_HOSTNAME",
 | 
			
		||||
            "@@ns2@@" => "$L_NS2_HOSTNAME",
 | 
			
		||||
            "@@DEFAULT_MX@@" => "$L_DEFAULT_MX",
 | 
			
		||||
            "@@DEFAULT_SECONDARY_MX@@" => "$L_DEFAULT_SECONDARY_MX",
 | 
			
		||||
            "@@DOMAINE@@" => $domain,
 | 
			
		||||
            "@@SERIAL@@" => $serial,
 | 
			
		||||
            "@@PUBLIC_IP@@" => "$L_PUBLIC_IP",
 | 
			
		||||
            "@@PUBLIC_IPV6@@" => "$L_PUBLIC_IPV6",
 | 
			
		||||
            "@@ZONETTL@@" => $ttl,
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // add the SUBDOMAIN entries
 | 
			
		||||
        $zone .= $this->conf_from_db($domain);
 | 
			
		||||
 | 
			
		||||
        // add the "END ALTERNC CONF line";
 | 
			
		||||
        $zone .= ";;; END ALTERNC AUTOGENERATE CONFIGURATION\n";
 | 
			
		||||
 | 
			
		||||
        // add the manually entered info:
 | 
			
		||||
        $zone .= $more;
 | 
			
		||||
        file_put_contents($this->zone_file_directory."/".$domain,$zone);
 | 
			
		||||
 | 
			
		||||
        // add the line into bind9 conf:
 | 
			
		||||
        if (add_line_to_file(
 | 
			
		||||
            $this->NAMED_CONF,
 | 
			
		||||
            trim(strtr(
 | 
			
		||||
                file_get_contents($this->NAMED_TEMPLATE),
 | 
			
		||||
                array(
 | 
			
		||||
                    "@@DOMAIN@@" => $DOMAIN,
 | 
			
		||||
                    "@@ZONE_FILE@@" => $this->zone_file_directory."/".$domain
 | 
			
		||||
                )
 | 
			
		||||
            )))
 | 
			
		||||
        ) {
 | 
			
		||||
            $this->shouldreconfig=true;
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->shouldreload=true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // launched for each ZONE for which we want a zone DELETE
 | 
			
		||||
    function hook_updatedomains_dns_del($domain) {
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Hook launched for each ZONE for which we want a zone DELETE
 | 
			
		||||
     * remove the zone and its file,
 | 
			
		||||
     * and if any action happened, ask for bind RECONFIG at posttime
 | 
			
		||||
     * @NOTE launched as ROOT 
 | 
			
		||||
     */
 | 
			
		||||
    function hook_updatedomains_dns_del($dominfo) {
 | 
			
		||||
        $domain = $dominfo["domaine"];
 | 
			
		||||
        if (remove_line_from_file(
 | 
			
		||||
            $this->NAMED_CONF,
 | 
			
		||||
            trim(strtr(
 | 
			
		||||
                file_get_contents($this->NAMED_TEMPLATE),
 | 
			
		||||
                array(
 | 
			
		||||
                    "@@DOMAIN@@" => $domain,
 | 
			
		||||
                    "@@ZONE_FILE@@" => $this->zone_file_directory."/".$domain
 | 
			
		||||
                )
 | 
			
		||||
            )))
 | 
			
		||||
        ) {
 | 
			
		||||
            $this->shouldreconfig=true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        @unlink($this->zone_file_directory."/".$domain);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // launched at the very end of updatedomains 
 | 
			
		||||
    
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Hook function launched at the very end of updatedomains 
 | 
			
		||||
     * here, we just reload OR reconfig (or both) bind9 depending 
 | 
			
		||||
     * on what happened before.
 | 
			
		||||
     * @NOTE launched as ROOT 
 | 
			
		||||
     */ 
 | 
			
		||||
    function hook_updatedomains_dns_post() {
 | 
			
		||||
        global $msg;
 | 
			
		||||
        if ($this->shouldreload) {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,489 +175,63 @@ class m_bind {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * read a zone file for $domain, 
 | 
			
		||||
     * @param $domain string the domain name 
 | 
			
		||||
     * @return array with 3 informations: 
 | 
			
		||||
     * is the domain locked? (boolean), what's the current serial (integer), the data after alternc conf (string of lines)
 | 
			
		||||
     */
 | 
			
		||||
    function read_zone($domain) {
 | 
			
		||||
        $f=fopen($this->zone_file_directory."/".$domain,"rb");
 | 
			
		||||
        $islocked=false;
 | 
			
		||||
        $more="";
 | 
			
		||||
        $serial=date("Ymd")."00";
 | 
			
		||||
        while ($s=fgets($f,4096)) {
 | 
			
		||||
            if (preg_match("#\;\s*LOCKED:YES#i",$s)) {
 | 
			
		||||
                $islocked=true;
 | 
			
		||||
            }
 | 
			
		||||
            if (preg_match("/\s*(\d{10})\s+\;\sserial\s?/", $s,$mat)) {
 | 
			
		||||
                $serial=$mat[1];
 | 
			
		||||
            }
 | 
			
		||||
            if (preg_match('/\;\s*END\sALTERNC\sAUTOGENERATE\sCONFIGURATION(.*)/s', $s)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        while ($s=fgets($f,4096)) {
 | 
			
		||||
            $more.=$s;
 | 
			
		||||
        }
 | 
			
		||||
        return array($islocked,$serial,$more);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the part of the conf we got from the database
 | 
			
		||||
     * 
 | 
			
		||||
     * Return the part of the conf we got from the sub_domaines table
 | 
			
		||||
     * @global m_mysql $db
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return array $this->cache_conf_db
 | 
			
		||||
     * @return string a zonefile excerpt
 | 
			
		||||
     */
 | 
			
		||||
    function conf_from_db($domain=false) {
 | 
			
		||||
    function conf_from_db($domain) {
 | 
			
		||||
        global $db;
 | 
			
		||||
        // Use cache, fill cache if empty
 | 
			
		||||
        if (empty($this->cache_conf_db)) {
 | 
			
		||||
            $db->query("
 | 
			
		||||
        select 
 | 
			
		||||
          sd.domaine, 
 | 
			
		||||
          replace(replace(dt.entry,'%TARGET%',sd.valeur), '%SUB%', if(length(sd.sub)>0,sd.sub,'@')) as entry 
 | 
			
		||||
        from 
 | 
			
		||||
        $db->query("
 | 
			
		||||
        SELECT 
 | 
			
		||||
          REPLACE(REPLACE(dt.entry,'%TARGET%',sd.valeur), '%SUB%', if(length(sd.sub)>0,sd.sub,'@')) AS ENTRY 
 | 
			
		||||
        FROM 
 | 
			
		||||
          sub_domaines sd,
 | 
			
		||||
          domaines_type dt 
 | 
			
		||||
        where 
 | 
			
		||||
        WHERE 
 | 
			
		||||
          sd.type=dt.name 
 | 
			
		||||
          and sd.enable in ('ENABLE', 'ENABLED') 
 | 
			
		||||
        order by entry ;");
 | 
			
		||||
            $t=array();
 | 
			
		||||
            while ($db->next_record()) {
 | 
			
		||||
                $t[$db->f('domaine')][] = $db->f('entry');
 | 
			
		||||
            }
 | 
			
		||||
            $this->cache_conf_db = $t;
 | 
			
		||||
          AND sd.enable IN ('ENABLE', 'ENABLED') 
 | 
			
		||||
        ORDER BY ENTRY ;");
 | 
			
		||||
        $t=array();
 | 
			
		||||
        while ($db->next_record()) {
 | 
			
		||||
            $t.= $db->f('entry')."\n";
 | 
			
		||||
        }
 | 
			
		||||
        if ($domain) {
 | 
			
		||||
            if (isset($this->cache_conf_db[$domain])) {
 | 
			
		||||
                return $this->cache_conf_db[$domain];
 | 
			
		||||
            } else {
 | 
			
		||||
                return array();
 | 
			
		||||
            }
 | 
			
		||||
        } // if domain
 | 
			
		||||
        return $this->cache_conf_db;
 | 
			
		||||
        return $t;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return full path of the zone configuration file
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    function get_zone_file_uri($domain) {
 | 
			
		||||
        return $this->zone_file_directory.$domain;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string zone file path
 | 
			
		||||
     */
 | 
			
		||||
    function get_zone_file($domain) {
 | 
			
		||||
        // Use cache, fill cache if empty
 | 
			
		||||
        if (!isset($this->cache_zone_file[$domain]) ) {
 | 
			
		||||
            if (file_exists($this->get_zone_file_uri($domain))) {
 | 
			
		||||
                $this->cache_zone_file[$domain] = @file_get_contents($this->get_zone_file_uri($domain));
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->cache_zone_file[$domain] = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return $this->cache_zone_file[$domain] ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string 
 | 
			
		||||
     */
 | 
			
		||||
    function get_serial($domain) {
 | 
			
		||||
        // Return the next serial the domain must have.
 | 
			
		||||
        // Choose between a generated and an incremented.
 | 
			
		||||
    
 | 
			
		||||
        // Calculated :
 | 
			
		||||
        $calc = date('Ymd').'00'."\n";
 | 
			
		||||
 | 
			
		||||
        // Old one :
 | 
			
		||||
        $old=$calc; // default value
 | 
			
		||||
        $file = $this->get_zone_file($domain);
 | 
			
		||||
        preg_match_all("/\s*(\d{10})\s+\;\sserial\s?/", $file, $output_array);
 | 
			
		||||
        if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
            $old = $output_array[1][0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Return max between newly calculated, and old one incremented
 | 
			
		||||
        return max(array($calc,$old)) + 1 ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return lines that are after ;;; END ALTERNC AUTOGENERATE CONFIGURATION
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    function get_persistent($domain) {
 | 
			
		||||
        if ( ! isset($this->cache_get_persistent[$domain] )) {
 | 
			
		||||
            preg_match_all('/\;\s*END\sALTERNC\sAUTOGENERATE\sCONFIGURATION(.*)/s', $this->get_zone_file($domain), $output_array);
 | 
			
		||||
            if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
                $this->cache_get_persistent[$domain] = $output_array[1][0];
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->cache_get_persistent[$domain] = false;
 | 
			
		||||
            }
 | 
			
		||||
        } // isset
 | 
			
		||||
        return $this->cache_get_persistent[$domain];
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @return string 
 | 
			
		||||
     */
 | 
			
		||||
    function get_zone_header() {
 | 
			
		||||
        return file_get_contents($this->ZONE_TEMPLATE);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @global m_dom $dom
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return array Retourne un tableau 
 | 
			
		||||
     */
 | 
			
		||||
    function get_domain_summary($domain=false) {
 | 
			
		||||
        global $dom;
 | 
			
		||||
 | 
			
		||||
        // Use cache if is filled, if not, fill it
 | 
			
		||||
        if (empty($this->cache_domain_summary)) {
 | 
			
		||||
            $this->cache_domain_summary = $dom->get_domain_all_summary();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($domain) return $this->cache_domain_summary[$domain];
 | 
			
		||||
        else return $this->cache_domain_summary;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function dkim_delete($domain) {
 | 
			
		||||
        $target_dir = "/etc/opendkim/keys/$domain";
 | 
			
		||||
        if (file_exists($target_dir)) {
 | 
			
		||||
            @unlink("$target_dir/alternc_private");
 | 
			
		||||
            @unlink("$target_dir/alternc.txt");
 | 
			
		||||
            @rmdir($target_dir);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generate the domain DKIM key
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return null|boolean
 | 
			
		||||
     */
 | 
			
		||||
    function dkim_generate_key($domain) {
 | 
			
		||||
        // Stop here if we do not manage the mail
 | 
			
		||||
        $domainInfo = $this->get_domain_summary($domain);
 | 
			
		||||
        if ( !  $domainInfo['gesmx'] ) return;
 | 
			
		||||
 | 
			
		||||
        $target_dir = "/etc/opendkim/keys/$domain";
 | 
			
		||||
 | 
			
		||||
        if (file_exists($target_dir.'/alternc.txt')) return; // Do not generate if exist
 | 
			
		||||
 | 
			
		||||
        if (! is_dir($target_dir)) mkdir($target_dir); // create dir
 | 
			
		||||
 | 
			
		||||
        // Generate the key
 | 
			
		||||
        $old_dir=getcwd();
 | 
			
		||||
        chdir($target_dir);
 | 
			
		||||
        exec('opendkim-genkey -r -d '.escapeshellarg($domain).' -s "alternc" ');
 | 
			
		||||
        chdir($old_dir);
 | 
			
		||||
 | 
			
		||||
        // opendkim must be owner of the key
 | 
			
		||||
        chown("$target_dir/alternc.private", 'opendkim');
 | 
			
		||||
        chgrp("$target_dir/alternc.private", 'opendkim');
 | 
			
		||||
 | 
			
		||||
        return true; // FIXME handle error
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh DKIM configuration: be sure to list the domain having a private key (and only them)
 | 
			
		||||
     */
 | 
			
		||||
    function dkim_refresh_list() { 
 | 
			
		||||
        // so ugly... but there is only 1 pass, not 3. Still ugly.
 | 
			
		||||
        $trusted_host_new = "# WARNING: this file is auto generated by AlternC.\n# Add your changes after the last line\n";
 | 
			
		||||
        $keytable_new     = "# WARNING: this file is auto generated by AlternC.\n# Add your changes after the last line\n";
 | 
			
		||||
        $signingtable_new = "# WARNING: this file is auto generated by AlternC.\n# Add your changes after the last line\n";
 | 
			
		||||
 | 
			
		||||
        # Generate automatic entry
 | 
			
		||||
        foreach ($this->get_domain_summary() as $domain => $ds ) {
 | 
			
		||||
            // Skip if delete in progress, or if we do not manage dns or mail
 | 
			
		||||
            if ( ! $ds['gesdns'] || ! $ds['gesmx'] || strtoupper($ds['dns_action']) == 'DELETE' ) continue;
 | 
			
		||||
 | 
			
		||||
            // Skip if there is no key generated
 | 
			
		||||
            if (! file_exists("/etc/opendkim/keys/$domain/alternc.txt")) continue; 
 | 
			
		||||
 | 
			
		||||
            // Modif the files.
 | 
			
		||||
            $trusted_host_new.="$domain\n";
 | 
			
		||||
            $keytable_new    .="alternc._domainkey.$domain $domain:alternc:/etc/opendkim/keys/$domain/alternc.private\n";
 | 
			
		||||
            $signingtable_new.="$domain alternc._domainkey.$domain\n";
 | 
			
		||||
        }
 | 
			
		||||
        $trusted_host_new.="# END AUTOMATIC FILE. ADD YOUR CHANGES AFTER THIS LINE\n";
 | 
			
		||||
        $keytable_new    .="# END AUTOMATIC FILE. ADD YOUR CHANGES AFTER THIS LINE\n";
 | 
			
		||||
        $signingtable_new.="# END AUTOMATIC FILE. ADD YOUR CHANGES AFTER THIS LINE\n";
 | 
			
		||||
 | 
			
		||||
        # Get old files
 | 
			
		||||
        $trusted_host_old=@file_get_contents($this->dkim_trusted_host_file);
 | 
			
		||||
        $keytable_old    =@file_get_contents($this->dkim_keytable_file);
 | 
			
		||||
        $signingtable_old=@file_get_contents($this->dkim_signingtable_file);
 | 
			
		||||
    
 | 
			
		||||
        # Keep manuel entry
 | 
			
		||||
        preg_match_all('/\#\s*END\ AUTOMATIC\ FILE\.\ ADD\ YOUR\ CHANGES\ AFTER\ THIS\ LINE(.*)/s', $trusted_host_old, $output_array);
 | 
			
		||||
        if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
            $trusted_host_new.=$output_array[1][0];
 | 
			
		||||
        } 
 | 
			
		||||
        preg_match_all('/\#\s*END\ AUTOMATIC\ FILE\.\ ADD\ YOUR\ CHANGES\ AFTER\ THIS\ LINE(.*)/s', $keytable_old, $output_array);
 | 
			
		||||
        if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
            $keytable_new.=$output_array[1][0];
 | 
			
		||||
        } 
 | 
			
		||||
        preg_match_all('/\#\s*END\ AUTOMATIC\ FILE\.\ ADD\ YOUR\ CHANGES\ AFTER\ THIS\ LINE(.*)/s', $signingtable_old, $output_array);
 | 
			
		||||
        if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
            $signingtable_new.=$output_array[1][0];
 | 
			
		||||
        } 
 | 
			
		||||
    
 | 
			
		||||
        // Save if there are some diff
 | 
			
		||||
        if ( $trusted_host_new != $trusted_host_old ) {
 | 
			
		||||
            file_put_contents($this->dkim_trusted_host_file, $trusted_host_new);
 | 
			
		||||
        }
 | 
			
		||||
        if ( $keytable_new != $keytable_old ) {
 | 
			
		||||
            file_put_contents($this->dkim_keytable_file, $keytable_new);
 | 
			
		||||
        }
 | 
			
		||||
        if ( $signingtable_new != $signingtable_old ) {
 | 
			
		||||
            file_put_contents($this->dkim_signingtable_file, $signingtable_new);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    function dkim_entry($domain) {
 | 
			
		||||
        $keyfile="/etc/opendkim/keys/$domain/alternc.txt";
 | 
			
		||||
        $domainInfo         = $this->get_domain_summary($domain);
 | 
			
		||||
        if (! file_exists($keyfile) &&  $domainInfo['gesmx'] ) {
 | 
			
		||||
            $this->dkim_generate_key($domain);
 | 
			
		||||
        }
 | 
			
		||||
        return @file_get_contents($keyfile);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Conditionnal generation autoconfig entry for outlook / thunderbird
 | 
			
		||||
     * If entry with the same name allready exist, skip it.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    function mail_autoconfig_entry($domain) {
 | 
			
		||||
        $zone= implode("\n",$this->conf_from_db($domain))."\n".$this->get_persistent($domain);
 | 
			
		||||
 | 
			
		||||
        $entry='';
 | 
			
		||||
        $domainInfo                 = $this->get_domain_summary($domain);
 | 
			
		||||
        if ( $domainInfo['gesmx'] ) {
 | 
			
		||||
            // If we manage the mail
 | 
			
		||||
 | 
			
		||||
            // Check if there is no the same entry (defined or manual)
 | 
			
		||||
            // can be toto IN A or toto.fqdn.tld. IN A
 | 
			
		||||
            if (! preg_match("/autoconfig(\s|\.".str_replace('.','\.',$domain)."\.)/", $zone )) {
 | 
			
		||||
                $entry.="autoconfig IN CNAME %%fqdn%%.\n";
 | 
			
		||||
            }
 | 
			
		||||
            if (! preg_match("/autodiscover(\s|\.".str_replace('.','\.',$domain)."\.)/", $zone )) {
 | 
			
		||||
                $entry.="autodiscover IN CNAME %%fqdn%%.\n";
 | 
			
		||||
            }
 | 
			
		||||
        } // if gesmx
 | 
			
		||||
        return $entry;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * Return a fully generated zone
 | 
			
		||||
     * 
 | 
			
		||||
     * @global string $L_FQDN
 | 
			
		||||
     * @global string $L_NS1_HOSTNAME
 | 
			
		||||
     * @global string $L_NS2_HOSTNAME
 | 
			
		||||
     * @global string $L_DEFAULT_MX
 | 
			
		||||
     * @global string $L_DEFAULT_SECONDARY_MX
 | 
			
		||||
     * @global string $L_PUBLIC_IP
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    function get_zone($domain) {
 | 
			
		||||
        global $L_FQDN, $L_NS1_HOSTNAME, $L_NS2_HOSTNAME, $L_DEFAULT_MX, $L_DEFAULT_SECONDARY_MX, $L_PUBLIC_IP;
 | 
			
		||||
 | 
			
		||||
        $zone =$this->get_zone_header();
 | 
			
		||||
        $zone.=implode("\n",$this->conf_from_db($domain));
 | 
			
		||||
        $zone.="\n;;;HOOKED ENTRY\n";
 | 
			
		||||
 | 
			
		||||
        $zone.= $this->dkim_entry($domain);
 | 
			
		||||
        $zone.= $this->mail_autoconfig_entry($domain);
 | 
			
		||||
 | 
			
		||||
        $zone.="\n;;; END ALTERNC AUTOGENERATE CONFIGURATION\n";
 | 
			
		||||
        $zone.=$this->get_persistent($domain);
 | 
			
		||||
        $domainInfo = $this->get_domain_summary($domain);
 | 
			
		||||
 | 
			
		||||
        // FIXME check those vars
 | 
			
		||||
        $zone = strtr($zone, array(
 | 
			
		||||
            "%%fqdn%%"=>"$L_FQDN",
 | 
			
		||||
            "%%ns1%%"=>"$L_NS1_HOSTNAME",
 | 
			
		||||
            "%%ns2%%"=>"$L_NS2_HOSTNAME",
 | 
			
		||||
            "%%DEFAULT_MX%%"=>"$L_DEFAULT_MX",
 | 
			
		||||
            "%%DEFAULT_SECONDARY_MX%%"=>"$L_DEFAULT_SECONDARY_MX",
 | 
			
		||||
            "@@fqdn@@"=>"$L_FQDN",
 | 
			
		||||
            "@@ns1@@"=>"$L_NS1_HOSTNAME",
 | 
			
		||||
            "@@ns2@@"=>"$L_NS2_HOSTNAME",
 | 
			
		||||
            "@@DEFAULT_MX@@"=>"$L_DEFAULT_MX",
 | 
			
		||||
            "@@DEFAULT_SECONDARY_MX@@"=>"$L_DEFAULT_SECONDARY_MX",
 | 
			
		||||
            "@@DOMAINE@@"=>"$domain",
 | 
			
		||||
            "@@SERIAL@@"=>$this->get_serial($domain),
 | 
			
		||||
            "@@PUBLIC_IP@@"=>"$L_PUBLIC_IP",
 | 
			
		||||
            "@@ZONETTL@@"=> $domainInfo['zonettl'],
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        return $zone;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     */
 | 
			
		||||
    function reload_zone($domain) {
 | 
			
		||||
        exec($this->RNDC." reload ".escapeshellarg($domain), $output, $return_value);
 | 
			
		||||
        if ($return_value != 0 ) {
 | 
			
		||||
            echo "ERROR: Reload zone failed for zone $domain\n";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * return true if zone is locked
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function is_locked($domain) {
 | 
			
		||||
        preg_match_all("/(\;\s*LOCKED:YES)/i", $this->get_zone_file($domain), $output_array);
 | 
			
		||||
        if (isset($output_array[1][0]) && !empty($output_array[1][0])) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @global m_mysql $db
 | 
			
		||||
     * @global m_dom $dom
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function save_zone($domain) {
 | 
			
		||||
        global $db, $dom;
 | 
			
		||||
 | 
			
		||||
        // Do not save if the zone is LOCKED
 | 
			
		||||
        if ( $this->is_locked($domain)) {
 | 
			
		||||
            $dom->set_dns_result($domain, "The zone file of this domain is locked. Contact your administrator."); // If edit, change dummy_for_translation
 | 
			
		||||
            $dom->set_dns_action($domain, 'OK');
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
        // Save file, and apply chmod/chown
 | 
			
		||||
        $file=$this->get_zone_file_uri($domain);
 | 
			
		||||
        file_put_contents($file, $this->get_zone($domain));
 | 
			
		||||
        chown($file, 'bind');
 | 
			
		||||
        chmod($file, 0640);
 | 
			
		||||
 | 
			
		||||
        $dom->set_dns_action($domain, 'OK');
 | 
			
		||||
        return true; // fixme add tests
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete the zone configuration file
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $domain
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function delete_zone($domain) {
 | 
			
		||||
        $file=$this->get_zone_file_uri($domain);
 | 
			
		||||
        if (file_exists($file)) {
 | 
			
		||||
            unlink($file);
 | 
			
		||||
        }
 | 
			
		||||
        $this->dkim_delete($domain);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @global m_hooks $hooks
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function reload_named() {
 | 
			
		||||
        global $hooks;
 | 
			
		||||
        // Generate the new conf file
 | 
			
		||||
        $new_named_conf="// DO NOT EDIT\n// This file is generated by Alternc.\n// Every changes you'll make will be overwrited.\n";
 | 
			
		||||
        $tpl=file_get_contents($this->NAMED_TEMPLATE);
 | 
			
		||||
        foreach ($this->get_domain_summary() as $domain => $ds ) {
 | 
			
		||||
            if ( ! $ds['gesdns'] || strtoupper($ds['dns_action']) == 'DELETE' ) continue;
 | 
			
		||||
            $new_named_conf.=strtr($tpl, array("@@DOMAINE@@"=>$domain, "@@ZONE_FILE@@"=>$this->get_zone_file_uri($domain)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get the actual conf file
 | 
			
		||||
        $old_named_conf = @file_get_contents($this->NAMED_CONF);
 | 
			
		||||
 | 
			
		||||
        // Apply new configuration only if there are some differences
 | 
			
		||||
        if ($old_named_conf != $new_named_conf ) {
 | 
			
		||||
            file_put_contents($this->NAMED_CONF,$new_named_conf);
 | 
			
		||||
            chown($this->NAMED_CONF, 'bind');
 | 
			
		||||
            chmod($this->NAMED_CONF, 0640);
 | 
			
		||||
            exec($this->RNDC." reconfig");
 | 
			
		||||
            $hooks->invoke_scripts("/usr/lib/alternc/reload.d", array('dns_reconfig')  );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Regenerate bind configuration and load it
 | 
			
		||||
     * 
 | 
			
		||||
     * @global m_hooks $hooks
 | 
			
		||||
     * @param boolean $all
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    function regenerate_conf($all=false) {
 | 
			
		||||
        global $hooks;
 | 
			
		||||
 | 
			
		||||
        foreach ($this->get_domain_summary() as $domain => $ds ) {
 | 
			
		||||
            if ( ! $ds['gesdns'] && strtoupper($ds['dns_action']) == 'OK' ) continue; // Skip if we do not manage DNS and is up-to-date for this domain
 | 
			
		||||
 | 
			
		||||
            if ( (strtoupper($ds['dns_action']) == 'DELETE' ) || 
 | 
			
		||||
            (strtoupper($ds['dns_action']) == 'UPDATE' && $ds['gesdns']==false ) // in case we update the zone to disable DNS management
 | 
			
		||||
            ) { 
 | 
			
		||||
                $this->delete_zone($domain);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ( ( $all || strtoupper($ds['dns_action']) == 'UPDATE' ) && $ds['gesdns'] ) {
 | 
			
		||||
                $this->save_zone($domain);
 | 
			
		||||
                $this->reload_zone($domain);
 | 
			
		||||
                $hooks->invoke_scripts("/usr/lib/alternc/reload.d", array('dns_reload_zone', $domain)  );
 | 
			
		||||
            }
 | 
			
		||||
        } // end foreach domain
 | 
			
		||||
 | 
			
		||||
        $this->dkim_refresh_list();
 | 
			
		||||
        $this->reload_named();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    private function dummy_for_translation() {
 | 
			
		||||
        _("The zone file of this domain is locked. Contact your administrator.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
} // m_bind
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1442,7 +1442,7 @@ class m_dom {
 | 
			
		|||
     *  TRUE sinon.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    function edit_domain($dom, $dns, $gesmx, $force = false, $ttl = 86400) {
 | 
			
		||||
    function edit_domain($dom, $dns, $gesmx, $force = false, $ttl = 3600) {
 | 
			
		||||
        global $db, $msg, $hooks;
 | 
			
		||||
        $msg->log("dom", "edit_domain", $dom . "/" . $dns . "/" . $gesmx);
 | 
			
		||||
        // Locked ?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -469,9 +469,9 @@ ORDER BY
 | 
			
		|||
        if ($db->next_record()) {
 | 
			
		||||
            $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND type='txt' AND (sub='' AND valeur LIKE 'v=spf1 %') OR (sub='_dmarc' AND valeur LIKE 'v=dmarc1;%');", array($db->Record["domaine"]));
 | 
			
		||||
            $db->query("UPDATE sub_domaines SET web_action='DELETE' WHERE domaine= ? AND (type='defmx' OR type='defmx2');", array($db->Record["domaine"]));
 | 
			
		||||
            $db->query("UPDATE domaines SET dns_action='UPDATE' WHERE id= ? ;", array($dom_id));
 | 
			
		||||
            $db->query("UPDATE domaines SET dns_action='UPDATE' WHERE id= ? ;", array($dom_id));  
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -912,6 +912,7 @@ ORDER BY
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * hook function called by AlternC when a domain is created for
 | 
			
		||||
     * the current user account using the SLAVE DOMAIN feature
 | 
			
		||||
| 
						 | 
				
			
			@ -928,6 +929,7 @@ ORDER BY
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * hook function called by AlternC when a domain is created for
 | 
			
		||||
     * the current user account 
 | 
			
		||||
| 
						 | 
				
			
			@ -937,7 +939,7 @@ ORDER BY
 | 
			
		|||
     * @access private
 | 
			
		||||
     */
 | 
			
		||||
    function hook_dom_add_mx_domain($domain_id) {
 | 
			
		||||
        global $msg, $mem, $db;
 | 
			
		||||
        global $msg, $mem, $db, $L_FQDN;
 | 
			
		||||
        $msg->log("mail", "hook_dom_add_mx_domain", $domain_id);
 | 
			
		||||
 | 
			
		||||
        $db->query("SELECT value FROM variable where name='mailname_bounce';");
 | 
			
		||||
| 
						 | 
				
			
			@ -947,8 +949,9 @@ ORDER BY
 | 
			
		|||
        }
 | 
			
		||||
        $mailname = $db->f("value");
 | 
			
		||||
        // set spf & dmarc for this domain
 | 
			
		||||
        $db->query("SELECT domaine FROM domaines WHERE id= ?;", array($domain_id));
 | 
			
		||||
        $db->query("SELECT domaine,compte FROM domaines WHERE id= ?;", array($domain_id));
 | 
			
		||||
        if ($db->next_record()) {
 | 
			
		||||
            $this->set_dns_autoconf($db->Record["domaine"],$db->Record["compte"]);
 | 
			
		||||
            if ($spf = variable_get("default_spf_value")) {
 | 
			
		||||
                $this->set_dns_spf($db->Record["domaine"], $spf);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -960,13 +963,14 @@ ORDER BY
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * hook function called by variables when a variable is changed
 | 
			
		||||
     * @access private
 | 
			
		||||
     */
 | 
			
		||||
    function hook_variable_set($name, $old, $new) {
 | 
			
		||||
        global $msg, $db;
 | 
			
		||||
        $msg->log("mail", "hook_variable_set($name,$old,$new)");
 | 
			
		||||
        $msg->log("mail", "hook_variable_set($name,$old,$new)");      
 | 
			
		||||
 | 
			
		||||
        if ($name == "default_spf_value") {
 | 
			
		||||
            $new = trim($new);
 | 
			
		||||
| 
						 | 
				
			
			@ -991,7 +995,34 @@ ORDER BY
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /**
 | 
			
		||||
     * Add dns entries for autodiscover / autoconf on the domain
 | 
			
		||||
     */
 | 
			
		||||
    function set_dns_autoconf($domain,$uid=-1) {
 | 
			
		||||
        global $db, $L_FQDN, $cuid;
 | 
			
		||||
        $changed=false;
 | 
			
		||||
        if ($uid==-1) $uid=$cuid;
 | 
			
		||||
 | 
			
		||||
        $db->query("SELECT domaine,sub,type,valeur FROM sub_domaines WHERE domaine=? AND sub='autodiscover' AND type='autodiscover';",array($domain));
 | 
			
		||||
        if (!$db->next_record()) {
 | 
			
		||||
            $db->query("INSERT INTO sub_domaines SET domaine=?, compte=?, sub='autodiscover', type='autodiscover';",array($domain,$uid));
 | 
			
		||||
            $changed=true;
 | 
			
		||||
        }
 | 
			
		||||
        $db->query("SELECT domaine,sub,type,valeur FROM sub_domaines WHERE domaine=? AND sub='autoconfig' AND type='autodiscover';",array($domain));
 | 
			
		||||
        if (!$db->next_record()) {
 | 
			
		||||
            $db->query("INSERT INTO sub_domaines SET domaine=?, compte=?, sub='autoconfig', type='autodiscover';",array($domain,$uid));
 | 
			
		||||
            $changed=true;
 | 
			
		||||
        }
 | 
			
		||||
        if ($changed) {
 | 
			
		||||
            $db->query("UPDATE domaines SET dns_action='UPDATE' WHERE domaine= ?;", array($domain));
 | 
			
		||||
        }
 | 
			
		||||
        return $changed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Set or UPDATE the DNS record for the domain $dom(str) to be $spf
 | 
			
		||||
     * account's login is current and if not it's $login.
 | 
			
		||||
| 
						 | 
				
			
			@ -1022,6 +1053,7 @@ ORDER BY
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Set or UPDATE the DNS record for the domain $dom(str) to be $dmarc
 | 
			
		||||
     * account's login is current and if not it's $login.
 | 
			
		||||
| 
						 | 
				
			
			@ -1055,5 +1087,110 @@ ORDER BY
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Manage DKIM when adding / removing a domain MX management */
 | 
			
		||||
    var $shouldreloaddkim;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Hook launched before doing anything dns-related
 | 
			
		||||
     */    
 | 
			
		||||
    function hook_updatedomains_dns_pre() {
 | 
			
		||||
        global $db;
 | 
			
		||||
        // for each domain where we don't have the MX or the DNS, remove the DKIM setup
 | 
			
		||||
        $this->shouldreloaddkim=false;
 | 
			
		||||
        $db->query("SELECT domaine,gesdns,gesmx FROM domaines WHERE dns_action!='OK';");
 | 
			
		||||
        $add=array();
 | 
			
		||||
        $del=array();
 | 
			
		||||
        while ($db->next_record()) {
 | 
			
		||||
            if ($db->Record["gesdns"]==0 || $db->Record["gesmx"]==0) {
 | 
			
		||||
                $del[]=$db->Record["domaine"];
 | 
			
		||||
            } else {
 | 
			
		||||
                $add[]=$db->Record["domaine"];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        foreach($add as $domain) {
 | 
			
		||||
            $this->dkim_add($domain);
 | 
			
		||||
        }
 | 
			
		||||
        foreach($del as $domain) {
 | 
			
		||||
            $this->dkim_del($domain);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Hook launched after doing anything dns-related
 | 
			
		||||
     */    
 | 
			
		||||
    function hook_updatedomains_dns_post() {
 | 
			
		||||
        if ($this->shouldreloaddkim) {
 | 
			
		||||
            exec("service opendkim reload");
 | 
			
		||||
            $this->shouldreloaddkim=false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Add a domain into OpenDKIM configuration
 | 
			
		||||
     */    
 | 
			
		||||
    function dkim_add($domain) {
 | 
			
		||||
        global $db;
 | 
			
		||||
        $target_dir = "/etc/opendkim/keys/$domain";
 | 
			
		||||
        if (file_exists($target_dir.'/alternc.txt')) return; // Do not generate if exist
 | 
			
		||||
        $this->shouldreloaddkim=true;
 | 
			
		||||
        if (! is_dir($target_dir)) mkdir($target_dir); // create dir
 | 
			
		||||
        // Generate the key
 | 
			
		||||
        $old_dir=getcwd();
 | 
			
		||||
        chdir($target_dir);
 | 
			
		||||
        exec('opendkim-genkey -b 1200 -r -d '.escapeshellarg($domain).' -s "alternc" ');
 | 
			
		||||
        chdir($old_dir);
 | 
			
		||||
        // opendkim must be owner of the key
 | 
			
		||||
        chown("$target_dir/alternc.private", 'opendkim');
 | 
			
		||||
        chgrp("$target_dir/alternc.private", 'opendkim');
 | 
			
		||||
 | 
			
		||||
        // Add line into files:
 | 
			
		||||
        add_line_to_file("/etc/opendkim/KeyTable","alternc._domainkey.".$domain." ".$domain.":alternc:/etc/opendkim/keys/".$domain."/alternc.private");
 | 
			
		||||
        add_line_to_file("/etc/opendkim/SigningTable",$domain." alternc._domainkey.".$domain);
 | 
			
		||||
        // Add subdomaine entry
 | 
			
		||||
        $dkim_key=$this->dkim_get_entry($domain);
 | 
			
		||||
        $db->query("INSERT INTO sub_domaines SET domaine=?, compte=?, sub='', type='dkim', valeur=?;",array($uid,$domain,$dkim_key));
 | 
			
		||||
        // no need to do DNS_ACTION="UPDATE" => we are in the middle of a HOOK, so dns WILL BE reloaded for this domain
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * Delete a domain from OpenDKIM configuration
 | 
			
		||||
     */    
 | 
			
		||||
    function dkim_del($domain) {
 | 
			
		||||
        $target_dir = "/etc/opendkim/keys/$domain";
 | 
			
		||||
        if (file_exists($target_dir)) {
 | 
			
		||||
            $this->shouldreloaddkim=true;
 | 
			
		||||
            @unlink("$target_dir/alternc_private");
 | 
			
		||||
            @unlink("$target_dir/alternc.txt");
 | 
			
		||||
            @rmdir($target_dir);
 | 
			
		||||
            del_line_from_file("/etc/opendkim/KeyTable","alternc._domainkey.".$domain." ".$domain.":alternc:/etc/opendkim/keys/".$domain."/alternc.private");
 | 
			
		||||
            del_line_from_file("/etc/opendkim/SigningTable",$domain." alternc._domainkey.".$domain);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // ------------------------------------------------------------
 | 
			
		||||
    /** 
 | 
			
		||||
     * return the content of the TXT information to be added into the DB for DKIM subdomains
 | 
			
		||||
     * @param $domain string the name of the domain name
 | 
			
		||||
     * @return string the TXT entry (without quotes)
 | 
			
		||||
     * or false if an error occurred
 | 
			
		||||
     **/
 | 
			
		||||
    function dkim_get_entry($domain) {
 | 
			
		||||
        $key=file_get_contents("/etc/opendkim/keys/".$domain."/alternc.txt");
 | 
			
		||||
        if (preg_match('#alternc._domainkey IN TXT "(.*)"#',$key,$mat)) {
 | 
			
		||||
            return $mat[1];
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // @TODO hook after reloading DNS zones => if necessary, restart opendkim
 | 
			
		||||
 | 
			
		||||
} /* Class m_mail */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ CREATE TABLE IF NOT EXISTS domaines (
 | 
			
		|||
  noerase tinyint(4) NOT NULL default '0',
 | 
			
		||||
  dns_action enum ('OK','UPDATE','DELETE') NOT NULL default 'UPDATE',
 | 
			
		||||
  dns_result varchar(255) not null default '',
 | 
			
		||||
  zonettl int(10) unsigned NOT NULL default '86400',
 | 
			
		||||
  zonettl int(10) unsigned NOT NULL default '3600',
 | 
			
		||||
  PRIMARY KEY (id),
 | 
			
		||||
  UNIQUE KEY (domaine)
 | 
			
		||||
) ENGINE=InnoDB;
 | 
			
		||||
| 
						 | 
				
			
			@ -479,8 +479,10 @@ CREATE TABLE IF NOT EXISTS `domaines_type` (
 | 
			
		|||
    PRIMARY KEY ( `name` )
 | 
			
		||||
) ENGINE=InnoDB COMMENT = 'Type of domains allowed';
 | 
			
		||||
 | 
			
		||||
INSERT IGNORE INTO `domaines_type` (name, description, target, entry,                             compatibility,                               only_dns, need_dns, advanced, enable) values
 | 
			
		||||
('vhost',  'Locally hosted',             'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@',                 'txt,defmx,defmx2,mx,mx2',                   false,    false,    false, 'ALL'),
 | 
			
		||||
INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable) VALUES
 | 
			
		||||
('dkim',  'DKIM Key',             'NONE', '%SUB% IN TXT "%TARGET%"',                 'txt,defmx,defmx2,mx,mx2,url,ip,ipv6',                   true,    true,    true, 'ADMIN'),
 | 
			
		||||
('autodiscover',  'Autodiscover and autoconf for email', 'NONE', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, true, true, 'ADMIN'),
 | 
			
		||||
 ('vhost',  'Locally hosted',             'DIRECTORY', '%SUB% IN A @@PUBLIC_IP@@',                 'txt,defmx,defmx2,mx,mx2',                   false,    false,    false, 'ALL'),
 | 
			
		||||
('url',    'URL redirection',            'URL',       '%SUB% IN A @@PUBLIC_IP@@',                 'txt,defmx,defmx2',                          false,    false,    false, 'ALL'),
 | 
			
		||||
('ip',     'IPv4 redirect',              'IP',        '%SUB% IN A %TARGET%',                      'url,ip,ipv6,txt,mx,mx2,defmx,defmx2',       true,     true,     false, 'ALL'),
 | 
			
		||||
('ipv6',   'IPv6 redirect',              'IPV6',      '%SUB% IN AAAA %TARGET%',                   'ip,ipv6,txt,mx,mx2,defmx,defmx2',           true,     true,     true,  'ALL'),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,22 @@
 | 
			
		|||
-- upgrade from 3.4.10 and 3.4.11 (a bug prevented them to be inserted :/ )
 | 
			
		||||
 | 
			
		||||
-- migrating DKIM to be inside sub_domaines table
 | 
			
		||||
INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable) VALUES
 | 
			
		||||
('dkim',  'DKIM Key', 'NONE', '%SUB% IN TXT "%TARGET%"', 'txt,defmx,defmx2,mx,mx2,url,ip,ipv6', true, true, true, 'ADMIN');
 | 
			
		||||
-- migrating AUTODISCOVER / AUTOCONF to be inside sub_domaines table
 | 
			
		||||
INSERT IGNORE INTO `domaines_type` (name, description, target, entry, compatibility, only_dns, need_dns, advanced, enable) VALUES
 | 
			
		||||
('autodiscover',  'Autodiscover and autoconf for email', 'NONE', '%SUB% IN A @@PUBLIC_IP@@', 'txt,defmx,defmx2,mx,mx2', false, true, true, 'ADMIN');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- upgrade from 3.4.10 and 3.4.11 (a bug prevented them to be inserted :/ )
 | 
			
		||||
ALTER TABLE mailbox MODIFY  `lastlogin` DATETIME NOT NULL DEFAULT 0;
 | 
			
		||||
ALTER TABLE mailbox ADD  `lastloginsasl` DATETIME NOT NULL DEFAULT 0 AFTER `lastlogin`;
 | 
			
		||||
ALTER TABLE `domaines` MODIFY `zonettl` INT(10) UNSIGNED NOT NULL default '3600';
 | 
			
		||||
 | 
			
		||||
ALTER TABLE `membres` MODIFY `pass` varchar(255);
 | 
			
		||||
ALTER TABLE `ftpusers` MODIFY `encrypted_password` varchar(255);
 | 
			
		||||
-- upgrade to better hashes ($6$, 20000 loops) in membres and ftpusers
 | 
			
		||||
ALTER TABLE `membres` MODIFY `pass` VARCHAR(255);
 | 
			
		||||
ALTER TABLE `ftpusers` MODIFY `encrypted_password` VARCHAR(255);
 | 
			
		||||
 | 
			
		||||
-- upgrade to merge alternc-ssl into alternc + change the way we work on SSL
 | 
			
		||||
 | 
			
		||||
DROP TABLE IF EXISTS `certif_alias`;
 | 
			
		||||
 | 
			
		||||
ALTER TABLE `certificates`
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +37,8 @@ ALTER TABLE `domaines_type`
 | 
			
		|||
UPDATE `domaines_type` SET `has_https_option`=1 WHERE name='vhost';
 | 
			
		||||
 | 
			
		||||
-- Backport old certif_hosts data to sub_domaines
 | 
			
		||||
UPDATE `sub_domaines` LEFT JOIN `certif_hosts` ON `sub_domaines`.`id` = `certif_hosts`.`sub` SET `sub_domaines`.`certificate_id` = `certif_hosts`.`certif` WHERE 1;
 | 
			
		||||
UPDATE `sub_domaines` LEFT JOIN `certif_hosts` ON `sub_domaines`.`id` = `certif_hosts`.`sub`
 | 
			
		||||
       SET `sub_domaines`.`certificate_id` = `certif_hosts`.`certif`;
 | 
			
		||||
DROP TABLE IF EXISTS `certif_hosts`;
 | 
			
		||||
 | 
			
		||||
-- Set https status  (http,https,both)
 | 
			
		||||
| 
						 | 
				
			
			@ -37,21 +47,22 @@ UPDATE `sub_domaines` SET `https` = "both" WHERE `type` LIKE '%-mixssl' AND http
 | 
			
		|||
UPDATE `sub_domaines` SET `https` = "http" WHERE https = '';
 | 
			
		||||
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-ssl','');
 | 
			
		||||
UPDATE `sub_domaines` SET `type` = REPLACE(`type`,'-mixssl','');
 | 
			
		||||
-- Disable https status when domains_type don't provide this
 | 
			
		||||
UPDATE `sub_domaines` SET `https` = '' WHERE type IN (select name FROM domaines_type WHERE has_https_option = 0);
 | 
			
		||||
-- Disable https status when domains_type don't use it
 | 
			
		||||
UPDATE `sub_domaines` SET `https` = '' WHERE type IN (SELECT name FROM domaines_type WHERE has_https_option = 0);
 | 
			
		||||
 | 
			
		||||
-- When two sudomain exists, we consider sub_domains with http and https feature
 | 
			
		||||
-- When two subdomain exists, we consider sub_domains with http and https feature
 | 
			
		||||
UPDATE sub_domaines AS sd  INNER JOIN
 | 
			
		||||
    (SELECT MIN(id) id FROM `sub_domaines` GROUP BY domaine,sub,type HAVING count(id) > 1) sd1
 | 
			
		||||
        ON sd.id = sd1.id
 | 
			
		||||
    SET `https` = "both";
 | 
			
		||||
-- Delete duplicate lines
 | 
			
		||||
DELETE sd1 FROM sub_domaines sd1, sub_domaines sd2 WHERE sd1.id > sd2.id AND sd1.domaine = sd2.domaine AND sd1.sub = sd2.sub AND sd1.type = sd2.type AND sd1.https <> '' AND sd2.https <> '';
 | 
			
		||||
DELETE sd1 FROM sub_domaines sd1, sub_domaines sd2
 | 
			
		||||
    WHERE sd1.id > sd2.id AND sd1.domaine = sd2.domaine AND sd1.sub = sd2.sub AND sd1.type = sd2.type
 | 
			
		||||
    AND sd1.https <> '' AND sd2.https <> '';
 | 
			
		||||
 | 
			
		||||
-- we need to regenerate all vhost, they will be by AlternC.install
 | 
			
		||||
-- UPDATE `sub_domaines` SET `web_action` = 'UPDATE';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- change some variable names :
 | 
			
		||||
 | 
			
		||||
UPDATE variable
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +83,6 @@ DELETE FROM variable WHERE name IN (
 | 
			
		|||
  'ftp_human_name'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
-- we'd like to prepare IPv6 ;) 
 | 
			
		||||
-- we'd like to prepare for IPv6 ;) 
 | 
			
		||||
ALTER TABLE  `domaines_type` CHANGE  `entry`  `entry` TEXT DEFAULT '';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
// we don't check our AlternC session
 | 
			
		||||
if(!chdir("/usr/share/alternc/panel"))
 | 
			
		||||
exit(1);
 | 
			
		||||
require("/usr/share/alternc/panel/class/config_nochk.php");
 | 
			
		||||
 | 
			
		||||
$db->query("SELECT * FROM domaines WHERE gesdns=1 AND gesmx=1;");
 | 
			
		||||
$add=array();
 | 
			
		||||
while ($db->next_record()) {
 | 
			
		||||
    $add[$db->Record["domaine"]]=$db->Record["compte"];
 | 
			
		||||
}
 | 
			
		||||
foreach($add as $domain => $id) {
 | 
			
		||||
    // Convert DKIM keys into SUB_DOMAINES table
 | 
			
		||||
    if (file_exists("/etc/opendkim/keys/".$domain."/alternc.txt")) {
 | 
			
		||||
        $dkim_key = $mail->dkim_get_entry($domain);
 | 
			
		||||
        if ($dkim_key) {
 | 
			
		||||
            // Add subdomain dkim entry
 | 
			
		||||
            $db->query("INSERT INTO sub_domaines 
 | 
			
		||||
        SET compte=?, domaine=?, sub='@', valeur=?, type='dkim', web_action='OK', web_result=0, enable='ENABLED';",
 | 
			
		||||
            array($id, $domain, $dkim_key)
 | 
			
		||||
            );
 | 
			
		||||
            // Alternc.INSTALL WILL reload DNS zones anyway, so fear not we don't set dns_action="RELOAD" here.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Convert autodiscover into SUB_DOMAINES table
 | 
			
		||||
    $db->query("INSERT INTO sub_domaines 
 | 
			
		||||
    SET compte=?, domaine=?, sub='@', valeur='', type='autodiscover', web_action='UPDATE', web_result=0, enable='ENABLED';",
 | 
			
		||||
    array($id, $domain)
 | 
			
		||||
    );    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue